@grafana/faro-react-native 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) 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/makeRNConfig.js +5 -5
  18. package/dist/cjs/config/makeRNConfig.js.map +1 -1
  19. package/dist/cjs/config/sampling.js.map +1 -1
  20. package/dist/cjs/config/types.js.map +1 -1
  21. package/dist/cjs/dataCollection/DataCollectionPolicy.js +1 -2
  22. package/dist/cjs/dataCollection/DataCollectionPolicy.js.map +1 -1
  23. package/dist/cjs/generated/faroRNPackageMeta.js +1 -1
  24. package/dist/cjs/generated/faroRNPackageMeta.js.map +1 -1
  25. package/dist/cjs/index.js +8 -3
  26. package/dist/cjs/index.js.map +1 -1
  27. package/dist/cjs/instrumentations/anr/instrumentation.js +10 -1
  28. package/dist/cjs/instrumentations/anr/instrumentation.js.map +1 -1
  29. package/dist/cjs/instrumentations/appState/index.js +8 -2
  30. package/dist/cjs/instrumentations/appState/index.js.map +1 -1
  31. package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +19 -6
  32. package/dist/cjs/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
  33. package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +331 -0
  34. package/dist/cjs/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
  35. package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
  36. package/dist/cjs/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
  37. package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
  38. package/dist/cjs/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
  39. package/dist/cjs/instrumentations/crashReporting/types.js.map +1 -1
  40. package/dist/cjs/instrumentations/errors/index.js +8 -3
  41. package/dist/cjs/instrumentations/errors/index.js.map +1 -1
  42. package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js +20 -31
  43. package/dist/cjs/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
  44. package/dist/cjs/instrumentations/frameMonitoring/types.js.map +1 -1
  45. package/dist/cjs/instrumentations/performance/index.js +2 -6
  46. package/dist/cjs/instrumentations/performance/index.js.map +1 -1
  47. package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js +48 -0
  48. package/dist/cjs/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
  49. package/dist/cjs/instrumentations/session/directSessionActivity.js +37 -0
  50. package/dist/cjs/instrumentations/session/directSessionActivity.js.map +1 -0
  51. package/dist/cjs/instrumentations/session/index.js +214 -45
  52. package/dist/cjs/instrumentations/session/index.js.map +1 -1
  53. package/dist/cjs/instrumentations/session/sessionActivity.js +43 -0
  54. package/dist/cjs/instrumentations/session/sessionActivity.js.map +1 -0
  55. package/dist/cjs/instrumentations/session/sessionAttributes.js +8 -8
  56. package/dist/cjs/instrumentations/session/sessionAttributes.js.map +1 -1
  57. package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +199 -24
  58. package/dist/cjs/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
  59. package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -13
  60. package/dist/cjs/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
  61. package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js +72 -0
  62. package/dist/cjs/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
  63. package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js +1 -1
  64. package/dist/cjs/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
  65. package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js +124 -96
  66. package/dist/cjs/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
  67. package/dist/cjs/instrumentations/session/sessionManager/types.js.map +1 -1
  68. package/dist/cjs/instrumentations/session/sessionProcess.js +96 -0
  69. package/dist/cjs/instrumentations/session/sessionProcess.js.map +1 -0
  70. package/dist/cjs/instrumentations/startup/index.js +2 -6
  71. package/dist/cjs/instrumentations/startup/index.js.map +1 -1
  72. package/dist/cjs/navigation/utils.js +3 -1
  73. package/dist/cjs/navigation/utils.js.map +1 -1
  74. package/dist/cjs/transports/fetch/index.js.map +1 -1
  75. package/dist/cjs/transports/fetch/transport.js +56 -25
  76. package/dist/cjs/transports/fetch/transport.js.map +1 -1
  77. package/dist/cjs/transports/fetch/types.js.map +1 -1
  78. package/dist/cjs/transports/offline/ConnectivityService.js +1 -1
  79. package/dist/cjs/transports/offline/ConnectivityService.js.map +1 -1
  80. package/dist/cjs/transports/offline/OfflineCache.js +2 -2
  81. package/dist/cjs/transports/offline/OfflineCache.js.map +1 -1
  82. package/dist/cjs/transports/offline/transport.js +3 -4
  83. package/dist/cjs/transports/offline/transport.js.map +1 -1
  84. package/dist/cjs/userPersistence/UserPersistence.js +1 -2
  85. package/dist/cjs/userPersistence/UserPersistence.js.map +1 -1
  86. package/dist/esm/config/getRNInstrumentations.js +6 -8
  87. package/dist/esm/config/getRNInstrumentations.js.map +1 -1
  88. package/dist/esm/config/makeRNConfig.js +5 -5
  89. package/dist/esm/config/makeRNConfig.js.map +1 -1
  90. package/dist/esm/config/sampling.js.map +1 -1
  91. package/dist/esm/config/types.js.map +1 -1
  92. package/dist/esm/dataCollection/DataCollectionPolicy.js +1 -2
  93. package/dist/esm/dataCollection/DataCollectionPolicy.js.map +1 -1
  94. package/dist/esm/generated/faroRNPackageMeta.js +1 -1
  95. package/dist/esm/generated/faroRNPackageMeta.js.map +1 -1
  96. package/dist/esm/index.js +4 -2
  97. package/dist/esm/index.js.map +1 -1
  98. package/dist/esm/instrumentations/anr/instrumentation.js +6 -1
  99. package/dist/esm/instrumentations/anr/instrumentation.js.map +1 -1
  100. package/dist/esm/instrumentations/appState/index.js +8 -2
  101. package/dist/esm/instrumentations/appState/index.js.map +1 -1
  102. package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js +15 -4
  103. package/dist/esm/instrumentations/crashReporting/BaseCrashReportingInstrumentation.js.map +1 -1
  104. package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js +230 -0
  105. package/dist/esm/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.js.map +1 -0
  106. package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js +2 -2
  107. package/dist/esm/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.js.map +1 -1
  108. package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js +2 -2
  109. package/dist/esm/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.js.map +1 -1
  110. package/dist/esm/instrumentations/crashReporting/types.js.map +1 -1
  111. package/dist/esm/instrumentations/errors/index.js +8 -3
  112. package/dist/esm/instrumentations/errors/index.js.map +1 -1
  113. package/dist/esm/instrumentations/frameMonitoring/instrumentation.js +17 -32
  114. package/dist/esm/instrumentations/frameMonitoring/instrumentation.js.map +1 -1
  115. package/dist/esm/instrumentations/frameMonitoring/types.js.map +1 -1
  116. package/dist/esm/instrumentations/performance/index.js +2 -6
  117. package/dist/esm/instrumentations/performance/index.js.map +1 -1
  118. package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js +34 -0
  119. package/dist/esm/instrumentations/session/FaroSessionActivityBoundary.js.map +1 -0
  120. package/dist/esm/instrumentations/session/directSessionActivity.js +32 -0
  121. package/dist/esm/instrumentations/session/directSessionActivity.js.map +1 -0
  122. package/dist/esm/instrumentations/session/index.js +207 -46
  123. package/dist/esm/instrumentations/session/index.js.map +1 -1
  124. package/dist/esm/instrumentations/session/sessionActivity.js +38 -0
  125. package/dist/esm/instrumentations/session/sessionActivity.js.map +1 -0
  126. package/dist/esm/instrumentations/session/sessionAttributes.js +7 -7
  127. package/dist/esm/instrumentations/session/sessionAttributes.js.map +1 -1
  128. package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js +190 -27
  129. package/dist/esm/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.js.map +1 -1
  130. package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js +31 -14
  131. package/dist/esm/instrumentations/session/sessionManager/VolatileSessionManager.js.map +1 -1
  132. package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js +56 -0
  133. package/dist/esm/instrumentations/session/sessionManager/persistentSessionRecord.js.map +1 -0
  134. package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js +1 -1
  135. package/dist/esm/instrumentations/session/sessionManager/sessionConstants.js.map +1 -1
  136. package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js +120 -44
  137. package/dist/esm/instrumentations/session/sessionManager/sessionManagerUtils.js.map +1 -1
  138. package/dist/esm/instrumentations/session/sessionManager/types.js.map +1 -1
  139. package/dist/esm/instrumentations/session/sessionProcess.js +89 -0
  140. package/dist/esm/instrumentations/session/sessionProcess.js.map +1 -0
  141. package/dist/esm/instrumentations/startup/index.js +2 -6
  142. package/dist/esm/instrumentations/startup/index.js.map +1 -1
  143. package/dist/esm/navigation/utils.js +2 -1
  144. package/dist/esm/navigation/utils.js.map +1 -1
  145. package/dist/esm/transports/fetch/index.js.map +1 -1
  146. package/dist/esm/transports/fetch/transport.js +38 -14
  147. package/dist/esm/transports/fetch/transport.js.map +1 -1
  148. package/dist/esm/transports/fetch/types.js.map +1 -1
  149. package/dist/esm/transports/offline/ConnectivityService.js +1 -1
  150. package/dist/esm/transports/offline/ConnectivityService.js.map +1 -1
  151. package/dist/esm/transports/offline/OfflineCache.js +2 -2
  152. package/dist/esm/transports/offline/OfflineCache.js.map +1 -1
  153. package/dist/esm/transports/offline/transport.js +3 -4
  154. package/dist/esm/transports/offline/transport.js.map +1 -1
  155. package/dist/esm/userPersistence/UserPersistence.js +1 -2
  156. package/dist/esm/userPersistence/UserPersistence.js.map +1 -1
  157. package/dist/types/config/getRNInstrumentations.d.ts +1 -2
  158. package/dist/types/config/sampling.d.ts +0 -3
  159. package/dist/types/config/types.d.ts +5 -3
  160. package/dist/types/dataCollection/DataCollectionPolicy.d.ts +1 -2
  161. package/dist/types/generated/faroRNPackageMeta.d.ts +1 -1
  162. package/dist/types/index.d.ts +4 -1
  163. package/dist/types/instrumentations/crashReporting/BaseCrashReportingInstrumentation.d.ts +14 -4
  164. package/dist/types/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.d.ts +27 -0
  165. package/dist/types/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.d.ts +2 -2
  166. package/dist/types/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.d.ts +2 -2
  167. package/dist/types/instrumentations/crashReporting/types.d.ts +6 -0
  168. package/dist/types/instrumentations/frameMonitoring/instrumentation.d.ts +2 -2
  169. package/dist/types/instrumentations/frameMonitoring/types.d.ts +4 -6
  170. package/dist/types/instrumentations/performance/index.d.ts +0 -2
  171. package/dist/types/instrumentations/session/FaroSessionActivityBoundary.d.ts +8 -0
  172. package/dist/types/instrumentations/session/directSessionActivity.d.ts +13 -0
  173. package/dist/types/instrumentations/session/index.d.ts +20 -1
  174. package/dist/types/instrumentations/session/sessionActivity.d.ts +9 -0
  175. package/dist/types/instrumentations/session/sessionAttributes.d.ts +6 -3
  176. package/dist/types/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.d.ts +16 -3
  177. package/dist/types/instrumentations/session/sessionManager/VolatileSessionManager.d.ts +9 -3
  178. package/dist/types/instrumentations/session/sessionManager/persistentSessionRecord.d.ts +4 -0
  179. package/dist/types/instrumentations/session/sessionManager/sessionManagerUtils.d.ts +19 -7
  180. package/dist/types/instrumentations/session/sessionManager/types.d.ts +6 -0
  181. package/dist/types/instrumentations/session/sessionProcess.d.ts +17 -0
  182. package/dist/types/instrumentations/startup/index.d.ts +2 -6
  183. package/dist/types/navigation/utils.d.ts +1 -0
  184. package/dist/types/transports/fetch/index.d.ts +1 -1
  185. package/dist/types/transports/fetch/transport.d.ts +8 -1
  186. package/dist/types/transports/fetch/types.d.ts +5 -0
  187. package/dist/types/transports/offline/ConnectivityService.d.ts +1 -1
  188. package/dist/types/transports/offline/OfflineCache.d.ts +2 -2
  189. package/dist/types/transports/offline/transport.d.ts +3 -4
  190. package/dist/types/userPersistence/UserPersistence.d.ts +1 -2
  191. package/ios/FaroCrashReporter.swift +214 -21
  192. package/ios/FaroReactNative.swift +24 -0
  193. package/ios/FaroReactNativeModule.h +2 -1
  194. package/ios/FaroReactNativeModule.mm +121 -6
  195. package/ios/RefreshRateVitals.swift +34 -38
  196. package/package.json +7 -5
  197. package/src/config/getRNInstrumentations.ts +6 -8
  198. package/src/config/makeRNConfig.test.ts +6 -0
  199. package/src/config/makeRNConfig.ts +10 -9
  200. package/src/config/sampling.ts +0 -3
  201. package/src/config/types.ts +5 -3
  202. package/src/dataCollection/DataCollectionPolicy.ts +1 -2
  203. package/src/generated/faroRNPackageMeta.ts +1 -1
  204. package/src/index.ts +8 -2
  205. package/src/initialize.test.ts +63 -2
  206. package/src/instrumentations/anr/instrumentation.ts +8 -1
  207. package/src/instrumentations/appState/index.ts +10 -2
  208. package/src/instrumentations/crashReporting/BaseCrashReportingInstrumentation.ts +28 -8
  209. package/src/instrumentations/crashReporting/RecoveredCrashReportingInstrumentation.ts +277 -0
  210. package/src/instrumentations/crashReporting/android/AndroidCrashReportingInstrumentation.ts +2 -2
  211. package/src/instrumentations/crashReporting/instrumentation.test.ts +433 -5
  212. package/src/instrumentations/crashReporting/ios/IosCrashReportingInstrumentation.ts +2 -2
  213. package/src/instrumentations/crashReporting/types.ts +7 -0
  214. package/src/instrumentations/errors/index.ts +12 -4
  215. package/src/instrumentations/errors/instrumentation.test.ts +35 -0
  216. package/src/instrumentations/frameMonitoring/instrumentation.test.ts +155 -0
  217. package/src/instrumentations/frameMonitoring/instrumentation.ts +19 -38
  218. package/src/instrumentations/frameMonitoring/types.ts +4 -6
  219. package/src/instrumentations/performance/index.ts +2 -6
  220. package/src/instrumentations/session/FaroSessionActivityBoundary.test.ts +60 -0
  221. package/src/instrumentations/session/FaroSessionActivityBoundary.tsx +41 -0
  222. package/src/instrumentations/session/beforeSendHook.test.ts +246 -0
  223. package/src/instrumentations/session/directSessionActivity.test.ts +158 -0
  224. package/src/instrumentations/session/directSessionActivity.ts +36 -0
  225. package/src/instrumentations/session/index.ts +269 -46
  226. package/src/instrumentations/session/persistentColdStart.test.ts +196 -0
  227. package/src/instrumentations/session/sessionActivity.test.ts +68 -0
  228. package/src/instrumentations/session/sessionActivity.ts +58 -0
  229. package/src/instrumentations/session/sessionAttributes.test.ts +37 -2
  230. package/src/instrumentations/session/sessionAttributes.ts +12 -6
  231. package/src/instrumentations/session/sessionCleanup.test.ts +410 -0
  232. package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.test.ts +552 -0
  233. package/src/instrumentations/session/sessionManager/MmkvPersistentSessionsManager.ts +249 -33
  234. package/src/instrumentations/session/sessionManager/VolatileSessionManager.ts +38 -18
  235. package/src/instrumentations/session/sessionManager/persistentSessionRecord.test.ts +103 -0
  236. package/src/instrumentations/session/sessionManager/persistentSessionRecord.ts +78 -0
  237. package/src/instrumentations/session/sessionManager/sampling.test.ts +1 -1
  238. package/src/instrumentations/session/sessionManager/sessionConstants.ts +1 -1
  239. package/src/instrumentations/session/sessionManager/sessionManagerUtils.test.ts +256 -18
  240. package/src/instrumentations/session/sessionManager/sessionManagerUtils.ts +180 -39
  241. package/src/instrumentations/session/sessionManager/types.ts +8 -0
  242. package/src/instrumentations/session/sessionManagerInstance.test.ts +65 -0
  243. package/src/instrumentations/session/sessionProcess.test.ts +136 -0
  244. package/src/instrumentations/session/sessionProcess.ts +114 -0
  245. package/src/instrumentations/session/startNewSession.test.ts +337 -0
  246. package/src/instrumentations/startup/index.ts +2 -6
  247. package/src/navigation/utils.ts +3 -1
  248. package/src/transports/fetch/index.ts +6 -1
  249. package/src/transports/fetch/transport.test.ts +86 -2
  250. package/src/transports/fetch/transport.ts +38 -16
  251. package/src/transports/fetch/types.ts +7 -0
  252. package/src/transports/offline/ConnectivityService.ts +1 -1
  253. package/src/transports/offline/OfflineCache.ts +2 -2
  254. package/src/transports/offline/transport.ts +3 -4
  255. package/src/userPersistence/UserPersistence.ts +1 -2
  256. package/dist/cjs/utils/throttle.js +0 -42
  257. package/dist/cjs/utils/throttle.js.map +0 -1
  258. package/dist/esm/utils/throttle.js +0 -34
  259. package/dist/esm/utils/throttle.js.map +0 -1
  260. package/dist/types/utils/throttle.d.ts +0 -9
  261. package/src/utils/throttle.test.ts +0 -141
  262. package/src/utils/throttle.ts +0 -34
@@ -0,0 +1,268 @@
1
+ package com.grafana.faro.reactnative
2
+
3
+ import android.content.Context
4
+ import androidx.test.core.app.ApplicationProvider
5
+ import org.junit.Assert.assertEquals
6
+ import org.junit.Assert.assertFalse
7
+ import org.junit.Assert.assertNull
8
+ import org.junit.Assert.assertTrue
9
+ import org.junit.Before
10
+ import org.junit.Test
11
+ import org.junit.runner.RunWith
12
+ import org.robolectric.RobolectricTestRunner
13
+ import org.robolectric.annotation.Config
14
+
15
+ @RunWith(RobolectricTestRunner::class)
16
+ @Config(manifest = Config.NONE, sdk = [30])
17
+ class FaroCrashSessionStoreTest {
18
+
19
+ private lateinit var context: Context
20
+
21
+ @Before
22
+ fun setUp() {
23
+ context = ApplicationProvider.getApplicationContext()
24
+ context.getSharedPreferences(
25
+ "com.grafana.faro.crash_session_store",
26
+ Context.MODE_PRIVATE,
27
+ ).edit().clear().commit()
28
+ }
29
+
30
+ @Test
31
+ fun recordSessionContext_preservesFirstActivationForSessionUpdates() {
32
+ recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
33
+ recordSession("session-a", activatedAtMs = 2_000L, nowMs = 2_000L)
34
+
35
+ val contexts = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 2_000L)
36
+
37
+ assertEquals(1, contexts.size)
38
+ assertEquals(1_000L, contexts.single().activatedAtMs)
39
+ assertEquals(2_000L, contexts.single().updatedAtMs)
40
+ }
41
+
42
+ @Test
43
+ fun findMatchingContext_usesLatestSessionBeforeCrashInSameProcess() {
44
+ recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
45
+ recordSession("session-b", activatedAtMs = 3_000L, nowMs = 3_000L)
46
+
47
+ val sessionA = FaroCrashSessionStore.findMatchingContext(
48
+ context,
49
+ crashTimestampMs = 2_000L,
50
+ pid = 101,
51
+ processName = "com.example.app",
52
+ nowMs = 4_000L,
53
+ )
54
+ val sessionB = FaroCrashSessionStore.findMatchingContext(
55
+ context,
56
+ crashTimestampMs = 4_000L,
57
+ pid = 101,
58
+ processName = "com.example.app",
59
+ nowMs = 4_000L,
60
+ )
61
+
62
+ assertEquals("session-a", sessionA?.sessionId)
63
+ assertEquals("session-b", sessionB?.sessionId)
64
+ }
65
+
66
+ @Test
67
+ fun findMatchingContext_doesNotCrossProcessBoundaries() {
68
+ recordSession(
69
+ sessionId = "session-a",
70
+ activatedAtMs = 1_000L,
71
+ nowMs = 1_000L,
72
+ pid = 101,
73
+ )
74
+ recordSession(
75
+ sessionId = "session-b",
76
+ activatedAtMs = 2_000L,
77
+ nowMs = 2_000L,
78
+ pid = 202,
79
+ )
80
+
81
+ val match = FaroCrashSessionStore.findMatchingContext(
82
+ context,
83
+ crashTimestampMs = 3_000L,
84
+ pid = 101,
85
+ processName = "com.example.app",
86
+ nowMs = 3_000L,
87
+ )
88
+
89
+ assertEquals("session-a", match?.sessionId)
90
+ }
91
+
92
+ @Test
93
+ fun acknowledgeReports_removesOnlyItsOwnSessionContext() {
94
+ recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L, pid = 101)
95
+ recordSession("session-b", activatedAtMs = 2_000L, nowMs = 2_000L, pid = 202)
96
+ val contexts = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 3_000L)
97
+ val sessionA = contexts.first { it.sessionId == "session-a" }
98
+ val sessionB = contexts.first { it.sessionId == "session-b" }
99
+
100
+ FaroCrashSessionStore.rememberPendingReport(
101
+ context,
102
+ reportId = "report-a",
103
+ crashTimestampMs = 1_500L,
104
+ sessionContext = sessionA,
105
+ usesPendingTrace = true,
106
+ nowMs = 3_000L,
107
+ )
108
+ FaroCrashSessionStore.rememberPendingReport(
109
+ context,
110
+ reportId = "report-b",
111
+ crashTimestampMs = 2_500L,
112
+ sessionContext = sessionB,
113
+ usesPendingTrace = false,
114
+ nowMs = 3_000L,
115
+ )
116
+
117
+ val result = FaroCrashSessionStore.acknowledgeReports(
118
+ context,
119
+ reportIds = listOf("report-a"),
120
+ nowMs = 4_000L,
121
+ )
122
+
123
+ val remaining = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 4_000L)
124
+ assertTrue(result.clearPendingTrace)
125
+ assertTrue(FaroCrashSessionStore.isReportAcknowledged(context, "report-a", nowMs = 4_000L))
126
+ assertFalse(FaroCrashSessionStore.isReportAcknowledged(context, "report-b", nowMs = 4_000L))
127
+ assertEquals(listOf("session-b"), remaining.map { it.sessionId })
128
+ assertEquals(
129
+ "session-b",
130
+ FaroCrashSessionStore.contextForPendingReport(context, "report-b", nowMs = 4_000L)?.sessionId,
131
+ )
132
+ }
133
+
134
+ @Test
135
+ fun acknowledgeReports_keepsContextReferencedByAnotherPendingReport() {
136
+ recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
137
+ val sessionA = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 2_000L).single()
138
+ FaroCrashSessionStore.rememberPendingReport(
139
+ context,
140
+ "report-a",
141
+ 1_500L,
142
+ sessionA,
143
+ usesPendingTrace = false,
144
+ nowMs = 2_000L,
145
+ )
146
+ FaroCrashSessionStore.rememberPendingReport(
147
+ context,
148
+ "report-b",
149
+ 1_600L,
150
+ sessionA,
151
+ usesPendingTrace = false,
152
+ nowMs = 2_000L,
153
+ )
154
+
155
+ FaroCrashSessionStore.acknowledgeReports(context, listOf("report-a"), nowMs = 3_000L)
156
+
157
+ assertEquals(
158
+ "session-a",
159
+ FaroCrashSessionStore.contextForPendingReport(context, "report-b", nowMs = 3_000L)?.sessionId,
160
+ )
161
+ }
162
+
163
+ @Test
164
+ fun acknowledgeReports_clearsSharedTraceOnlyAfterLastReferencingReport() {
165
+ recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
166
+ val sessionA = FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 2_000L).single()
167
+ FaroCrashSessionStore.rememberPendingReport(
168
+ context,
169
+ "report-a",
170
+ 1_500L,
171
+ sessionA,
172
+ usesPendingTrace = true,
173
+ nowMs = 2_000L,
174
+ )
175
+ FaroCrashSessionStore.rememberPendingReport(
176
+ context,
177
+ "report-b",
178
+ 1_600L,
179
+ sessionA,
180
+ usesPendingTrace = true,
181
+ nowMs = 2_000L,
182
+ )
183
+
184
+ val first = FaroCrashSessionStore.acknowledgeReports(context, listOf("report-a"), nowMs = 3_000L)
185
+ val second = FaroCrashSessionStore.acknowledgeReports(context, listOf("report-b"), nowMs = 4_000L)
186
+
187
+ assertTrue(first.persisted)
188
+ assertFalse(first.clearPendingTrace)
189
+ assertTrue(second.persisted)
190
+ assertTrue(second.clearPendingTrace)
191
+ }
192
+
193
+ @Test
194
+ fun acknowledgeReports_canTombstoneAnIgnoredReportWithoutPendingContext() {
195
+ val result = FaroCrashSessionStore.acknowledgeReports(
196
+ context,
197
+ reportIds = listOf("ignored-report"),
198
+ nowMs = 1_000L,
199
+ )
200
+
201
+ assertTrue(result.persisted)
202
+ assertFalse(result.clearPendingTrace)
203
+ assertTrue(FaroCrashSessionStore.isReportAcknowledged(context, "ignored-report", nowMs = 1_000L))
204
+ }
205
+
206
+ @Test
207
+ fun sessionContextExpiresOnlyAfterSevenDayBoundary() {
208
+ val sevenDays = FaroCrashSessionStore.MAX_CONTEXT_AGE_MS
209
+ recordSession("at-boundary", activatedAtMs = 1L, nowMs = 1_000L)
210
+
211
+ assertEquals(
212
+ 1,
213
+ FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 1_000L + sevenDays).size,
214
+ )
215
+ assertTrue(
216
+ FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 1_001L + sevenDays).isEmpty(),
217
+ )
218
+ }
219
+
220
+ @Test
221
+ fun malformedStorageDoesNotPreventNewContextFromBeingRecorded() {
222
+ context.getSharedPreferences(
223
+ "com.grafana.faro.crash_session_store",
224
+ Context.MODE_PRIVATE,
225
+ ).edit().putString("session_contexts", "not-json").commit()
226
+
227
+ assertTrue(recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L))
228
+ assertEquals(
229
+ "session-a",
230
+ FaroCrashSessionStore.sessionContextsForTest(context, nowMs = 1_000L).single().sessionId,
231
+ )
232
+ }
233
+
234
+ @Test
235
+ fun findMatchingContext_returnsNullWithoutUsableProcessIdentity() {
236
+ recordSession("session-a", activatedAtMs = 1_000L, nowMs = 1_000L)
237
+
238
+ val match = FaroCrashSessionStore.findMatchingContext(
239
+ context,
240
+ crashTimestampMs = 2_000L,
241
+ pid = 0,
242
+ processName = "",
243
+ nowMs = 2_000L,
244
+ )
245
+
246
+ assertNull(match)
247
+ }
248
+
249
+ private fun recordSession(
250
+ sessionId: String,
251
+ activatedAtMs: Long,
252
+ nowMs: Long,
253
+ pid: Int = 101,
254
+ ): Boolean {
255
+ return FaroCrashSessionStore.recordSessionContext(
256
+ context = context,
257
+ sessionId = sessionId,
258
+ activatedAtMs = activatedAtMs,
259
+ isSampled = true,
260
+ appVersion = "1.0.0",
261
+ appRelease = "42",
262
+ appBundleId = "com.example.app@42@1.0.0",
263
+ nowMs = nowMs,
264
+ pid = pid,
265
+ processName = "com.example.app",
266
+ )
267
+ }
268
+ }
@@ -0,0 +1,52 @@
1
+ package com.grafana.faro.reactnative
2
+
3
+ import android.content.Context
4
+ import androidx.test.core.app.ApplicationProvider
5
+ import org.junit.Assert.assertEquals
6
+ import org.junit.Assert.assertNotNull
7
+ import org.junit.Assert.assertNull
8
+ import org.junit.Before
9
+ import org.junit.Test
10
+ import org.junit.runner.RunWith
11
+ import org.robolectric.RobolectricTestRunner
12
+ import org.robolectric.annotation.Config
13
+
14
+ @RunWith(RobolectricTestRunner::class)
15
+ @Config(manifest = Config.NONE, sdk = [30])
16
+ class FaroCrashTraceCacheTest {
17
+
18
+ private lateinit var context: Context
19
+
20
+ @Before
21
+ fun setUp() {
22
+ context = ApplicationProvider.getApplicationContext()
23
+ context.getSharedPreferences(
24
+ "com.grafana.faro.crash_trace_cache",
25
+ Context.MODE_PRIVATE,
26
+ ).edit().clear().commit()
27
+ }
28
+
29
+ @Test
30
+ fun timestampMismatchDoesNotClearTraceForLaterMatchingReport() {
31
+ FaroCrashTraceCache.savePendingCrashTrace(context, "java.lang.RuntimeException", 20_000L)
32
+ val pending = FaroCrashTraceCache.peekPendingCrashTrace(context, 20_001L)
33
+
34
+ assertEquals("", FaroCrashTraceCache.traceForExitTimestamp(context, pending, 1_000L))
35
+ assertNotNull(FaroCrashTraceCache.peekPendingCrashTrace(context, 20_001L))
36
+ assertEquals(
37
+ "java.lang.RuntimeException",
38
+ FaroCrashTraceCache.traceForExitTimestamp(context, pending, 20_000L),
39
+ )
40
+ }
41
+
42
+ @Test
43
+ fun traceExpiresAfterReplayWindow() {
44
+ val timestamp = 20_000L
45
+ val replayWindow = FaroCrashSessionStore.MAX_CONTEXT_AGE_MS
46
+ FaroCrashTraceCache.savePendingCrashTrace(context, "java.lang.RuntimeException", timestamp)
47
+
48
+ assertNotNull(FaroCrashTraceCache.peekPendingCrashTrace(context, timestamp + replayWindow))
49
+ assertNull(FaroCrashTraceCache.peekPendingCrashTrace(context, timestamp + replayWindow + 1L))
50
+ assertNull(FaroCrashTraceCache.peekPendingCrashTrace(context, timestamp + replayWindow + 1L))
51
+ }
52
+ }
@@ -0,0 +1,127 @@
1
+ package com.grafana.faro.reactnative
2
+
3
+ import org.junit.After
4
+ import org.junit.Assert.assertEquals
5
+ import org.junit.Assert.assertFalse
6
+ import org.junit.Assert.assertNull
7
+ import org.junit.Assert.assertTrue
8
+ import org.junit.Before
9
+ import org.junit.Test
10
+
11
+ class FaroSessionProcessTest {
12
+
13
+ @Before
14
+ fun setUp() {
15
+ FaroSessionProcess.resetPersistenceClaimForTest()
16
+ }
17
+
18
+ @After
19
+ fun tearDown() {
20
+ FaroSessionProcess.resetPersistenceClaimForTest()
21
+ }
22
+
23
+ @Test
24
+ fun normalizeIdentifier_rejectsMissingProcessNames() {
25
+ assertNull(FaroSessionProcess.normalizeIdentifier(null))
26
+ assertNull(FaroSessionProcess.normalizeIdentifier(" "))
27
+ }
28
+
29
+ @Test
30
+ fun normalizeIdentifier_trimsKnownProcessName() {
31
+ assertEquals(
32
+ "com.example.app:worker",
33
+ FaroSessionProcess.normalizeIdentifier(" com.example.app:worker "),
34
+ )
35
+ }
36
+
37
+ @Test
38
+ fun identifier_usesThePlatformApiOnAndroidPAndNewer() {
39
+ assertEquals(
40
+ "com.example.app:worker",
41
+ FaroSessionProcess.identifier(
42
+ sdkInt = 28,
43
+ currentProcessName = { "com.example.app:worker" },
44
+ legacyProcessName = { error("legacy lookup should not run") },
45
+ ),
46
+ )
47
+ }
48
+
49
+ @Test
50
+ fun identifier_readsTheNullTerminatedCmdlineBeforeAndroidP() {
51
+ assertEquals(
52
+ "com.example.app:worker",
53
+ FaroSessionProcess.identifier(
54
+ sdkInt = 27,
55
+ currentProcessName = { error("platform lookup should not run") },
56
+ legacyProcessName = { "com.example.app:worker\u0000ignored" },
57
+ ),
58
+ )
59
+ }
60
+
61
+ @Test
62
+ fun identifier_failsClosedWhenTheProcessNameCannotBeRead() {
63
+ assertNull(
64
+ FaroSessionProcess.identifier(
65
+ sdkInt = 27,
66
+ currentProcessName = { error("platform lookup should not run") },
67
+ legacyProcessName = { throw IllegalStateException("unavailable") },
68
+ ),
69
+ )
70
+ }
71
+
72
+ @Test
73
+ fun isMainProcess_comparesCurrentProcessWithDeclaredMainProcess() {
74
+ assertEquals(
75
+ true,
76
+ FaroSessionProcess.isMainProcess(
77
+ currentName = "com.example.app",
78
+ declaredMainName = "com.example.app",
79
+ packageName = "com.example.app",
80
+ ),
81
+ )
82
+ assertEquals(
83
+ false,
84
+ FaroSessionProcess.isMainProcess(
85
+ currentName = "com.example.app:worker",
86
+ declaredMainName = "com.example.app",
87
+ packageName = "com.example.app",
88
+ ),
89
+ )
90
+ }
91
+
92
+ @Test
93
+ fun isMainProcess_usesPackageNameWhenMainProcessIsNotDeclared() {
94
+ assertEquals(
95
+ true,
96
+ FaroSessionProcess.isMainProcess(
97
+ currentName = "com.example.app",
98
+ declaredMainName = " ",
99
+ packageName = "com.example.app",
100
+ ),
101
+ )
102
+ }
103
+
104
+ @Test
105
+ fun isMainProcess_failsClosedWithoutCurrentIdentity() {
106
+ assertNull(
107
+ FaroSessionProcess.isMainProcess(
108
+ currentName = null,
109
+ declaredMainName = "com.example.app",
110
+ packageName = "com.example.app",
111
+ ),
112
+ )
113
+ }
114
+
115
+ @Test
116
+ fun claimPersistence_allowsOnlyOneOwnerAtATime() {
117
+ val firstOwner = Any()
118
+ val secondOwner = Any()
119
+
120
+ assertTrue(FaroSessionProcess.claimPersistence(firstOwner))
121
+ assertTrue(FaroSessionProcess.claimPersistence(firstOwner))
122
+ assertFalse(FaroSessionProcess.claimPersistence(secondOwner))
123
+ assertFalse(FaroSessionProcess.releasePersistence(secondOwner))
124
+ assertTrue(FaroSessionProcess.releasePersistence(firstOwner))
125
+ assertTrue(FaroSessionProcess.claimPersistence(secondOwner))
126
+ }
127
+ }
@@ -22,8 +22,7 @@ function toRegExpArray(patterns) {
22
22
  /**
23
23
  * Returns the default set of instrumentations for React Native.
24
24
  *
25
- * Reads all options from the Faro config (single source of truth).
26
- * Property names are aligned with Flutter SDK FaroConfig:
25
+ * Reads all options from the Faro config (single source of truth):
27
26
  * - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals
28
27
  * - enableCrashReporting, enableErrorReporting
29
28
  * - fetchVitalsInterval, ignoreUrls
@@ -44,7 +43,6 @@ function toRegExpArray(patterns) {
44
43
  */
45
44
  function getRNInstrumentations(config) {
46
45
  if (config === void 0) { config = {}; }
47
- // Aligned with Flutter SDK FaroConfig defaults
48
46
  var
49
47
  // Error & crash tracking
50
48
  _a = config.enableErrorReporting,
@@ -67,21 +65,21 @@ function getRNInstrumentations(config) {
67
65
  // Tracing
68
66
  enableTracing = _p === void 0 ? false : _p, _q = config.tracingOptions, tracingOptions = _q === void 0 ? {} : _q;
69
67
  var instrumentations = [];
70
- // Error reporting (Flutter: enableFlutterErrorReporting)
68
+ // Error reporting
71
69
  if (enableErrorReporting) {
72
70
  instrumentations.push(new errors_1.ErrorsInstrumentation({
73
71
  releaseBundleFilename: config.releaseBundleFilename,
74
72
  }));
75
73
  }
76
- // Console capture - not in Flutter SDK, RN-specific
74
+ // Console capture
77
75
  if (enableConsoleCapture) {
78
76
  instrumentations.push(new console_1.ConsoleInstrumentation());
79
77
  }
80
- // Sessions - always enabled in Flutter, same here
78
+ // Sessions
81
79
  instrumentations.push(new session_1.SessionInstrumentation());
82
- // Views - always enabled in Flutter, same here
80
+ // Views
83
81
  instrumentations.push(new view_1.ViewInstrumentation());
84
- // App state - always enabled in Flutter, same here
82
+ // App state
85
83
  instrumentations.push(new appState_1.AppStateInstrumentation());
86
84
  // User actions - enabled by default, opt-out via enableUserActions
87
85
  if (enableUserActions) {
@@ -1 +1 @@
1
- {"version":3,"file":"getRNInstrumentations.js","sourceRoot":"","sources":["../../../src/config/getRNInstrumentations.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\n\nimport type { Instrumentation, Patterns } from '@grafana/faro-core';\n\nimport { ANRInstrumentation } from '../instrumentations/anr';\nimport { AppStateInstrumentation } from '../instrumentations/appState';\nimport { ConsoleInstrumentation } from '../instrumentations/console';\nimport { CrashReportingInstrumentation } from '../instrumentations/crashReporting';\nimport { ErrorsInstrumentation } from '../instrumentations/errors';\nimport { FrameMonitoringInstrumentation } from '../instrumentations/frameMonitoring';\nimport { HttpInstrumentation } from '../instrumentations/http';\nimport { PerformanceInstrumentation } from '../instrumentations/performance';\nimport { SessionInstrumentation } from '../instrumentations/session';\nimport { StartupInstrumentation } from '../instrumentations/startup';\nimport { UserActionInstrumentation } from '../instrumentations/userActions';\nimport { ViewInstrumentation } from '../instrumentations/view';\nimport { XHRInstrumentation } from '../instrumentations/xhr';\n\nimport type { ReactNativeConfig } from './types';\n\n/** Convert Patterns (string | RegExp)[] to RegExp[] for instrumentations that require RegExp[]. */\nfunction toRegExpArray(patterns: Patterns): RegExp[] {\n return patterns.map((p) => (typeof p === 'string' ? new RegExp(p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')) : p));\n}\n\n/**\n * Returns the default set of instrumentations for React Native.\n *\n * Reads all options from the Faro config (single source of truth).\n * Property names are aligned with Flutter SDK FaroConfig:\n * - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals\n * - enableCrashReporting, enableErrorReporting\n * - fetchVitalsInterval, ignoreUrls\n *\n * @example\n * ```ts\n * const config: ReactNativeConfig = {\n * app: { name: 'my-app', version: '1.0.0' },\n * cpuUsageVitals: true,\n * memoryUsageVitals: true,\n * anrTracking: true,\n * refreshRateVitals: true,\n * enableCrashReporting: true,\n * fetchVitalsInterval: 30000,\n * instrumentations: getRNInstrumentations(config),\n * };\n * ```\n */\nexport function getRNInstrumentations(config: Partial<ReactNativeConfig> = {}): Instrumentation[] {\n // Aligned with Flutter SDK FaroConfig defaults\n const {\n // Error & crash tracking\n enableErrorReporting = true,\n enableCrashReporting = false,\n anrTracking = false,\n anrOptions = {},\n\n // Performance vitals\n cpuUsageVitals = true,\n memoryUsageVitals = true,\n refreshRateVitals = false,\n fetchVitalsInterval = 30000,\n frameMonitoringOptions = {},\n\n // Network\n ignoreUrls = [],\n enableHttpInstrumentation = {},\n\n // Console and user actions\n enableConsoleCapture = true,\n enableUserActions = true,\n\n // Tracing\n enableTracing = false,\n tracingOptions = {},\n } = config;\n\n const instrumentations: Instrumentation[] = [];\n\n // Error reporting (Flutter: enableFlutterErrorReporting)\n if (enableErrorReporting) {\n instrumentations.push(\n new ErrorsInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n // Console capture - not in Flutter SDK, RN-specific\n if (enableConsoleCapture) {\n instrumentations.push(new ConsoleInstrumentation());\n }\n\n // Sessions - always enabled in Flutter, same here\n instrumentations.push(new SessionInstrumentation());\n\n // Views - always enabled in Flutter, same here\n instrumentations.push(new ViewInstrumentation());\n\n // App state - always enabled in Flutter, same here\n instrumentations.push(new AppStateInstrumentation());\n\n // User actions - enabled by default, opt-out via enableUserActions\n if (enableUserActions) {\n instrumentations.push(new UserActionInstrumentation());\n }\n\n // HTTP/XHR tracking: when tracing is enabled, TracingInstrumentation patches fetch and XHR.\n // When tracing is disabled, add HttpInstrumentation and/or XHRInstrumentation per enableHttpInstrumentation.\n if (!enableTracing) {\n const { fetch: enableFetch = true, xhr: enableXhr = true } = enableHttpInstrumentation;\n const ignoredUrlsRegExp = toRegExpArray(ignoreUrls);\n if (enableFetch) {\n instrumentations.push(new HttpInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n if (enableXhr) {\n instrumentations.push(new XHRInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n }\n\n // Performance vitals (CPU/memory) - only add if at least one metric is enabled\n if (cpuUsageVitals || memoryUsageVitals) {\n const perfInstrumentation = new PerformanceInstrumentation({\n memoryUsageVitals,\n cpuUsageVitals,\n fetchVitalsInterval,\n });\n instrumentations.push(perfInstrumentation);\n }\n\n // Startup tracking - always enabled\n instrumentations.push(new StartupInstrumentation());\n\n // Frame monitoring: enabled when refreshRateVitals is true\n // The instrumentation reads refreshRateVitals from faro.config (single source of truth)\n if (refreshRateVitals) {\n instrumentations.push(new FrameMonitoringInstrumentation(frameMonitoringOptions));\n }\n\n // ANR detection (Android only)\n if (anrTracking && Platform.OS === 'android') {\n instrumentations.push(new ANRInstrumentation(anrOptions));\n }\n\n // Crash reporting\n if (enableCrashReporting) {\n instrumentations.push(\n new CrashReportingInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n if (enableTracing) {\n try {\n const { TracingInstrumentation } = require('@grafana/faro-react-native-tracing');\n instrumentations.push(new TracingInstrumentation(tracingOptions));\n } catch {\n console.warn(\n '[Faro] enableTracing is true but @grafana/faro-react-native-tracing is not installed. ' +\n 'Add it to use tracing: yarn add @grafana/faro-react-native-tracing'\n );\n }\n }\n\n return instrumentations;\n}\n"]}
1
+ {"version":3,"file":"getRNInstrumentations.js","sourceRoot":"","sources":["../../../src/config/getRNInstrumentations.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from 'react-native';\n\nimport type { Instrumentation, Patterns } from '@grafana/faro-core';\n\nimport { ANRInstrumentation } from '../instrumentations/anr';\nimport { AppStateInstrumentation } from '../instrumentations/appState';\nimport { ConsoleInstrumentation } from '../instrumentations/console';\nimport { CrashReportingInstrumentation } from '../instrumentations/crashReporting';\nimport { ErrorsInstrumentation } from '../instrumentations/errors';\nimport { FrameMonitoringInstrumentation } from '../instrumentations/frameMonitoring';\nimport { HttpInstrumentation } from '../instrumentations/http';\nimport { PerformanceInstrumentation } from '../instrumentations/performance';\nimport { SessionInstrumentation } from '../instrumentations/session';\nimport { StartupInstrumentation } from '../instrumentations/startup';\nimport { UserActionInstrumentation } from '../instrumentations/userActions';\nimport { ViewInstrumentation } from '../instrumentations/view';\nimport { XHRInstrumentation } from '../instrumentations/xhr';\n\nimport type { ReactNativeConfig } from './types';\n\n/** Convert Patterns (string | RegExp)[] to RegExp[] for instrumentations that require RegExp[]. */\nfunction toRegExpArray(patterns: Patterns): RegExp[] {\n return patterns.map((p) => (typeof p === 'string' ? new RegExp(p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')) : p));\n}\n\n/**\n * Returns the default set of instrumentations for React Native.\n *\n * Reads all options from the Faro config (single source of truth):\n * - cpuUsageVitals, memoryUsageVitals, anrTracking, refreshRateVitals\n * - enableCrashReporting, enableErrorReporting\n * - fetchVitalsInterval, ignoreUrls\n *\n * @example\n * ```ts\n * const config: ReactNativeConfig = {\n * app: { name: 'my-app', version: '1.0.0' },\n * cpuUsageVitals: true,\n * memoryUsageVitals: true,\n * anrTracking: true,\n * refreshRateVitals: true,\n * enableCrashReporting: true,\n * fetchVitalsInterval: 30000,\n * instrumentations: getRNInstrumentations(config),\n * };\n * ```\n */\nexport function getRNInstrumentations(config: Partial<ReactNativeConfig> = {}): Instrumentation[] {\n const {\n // Error & crash tracking\n enableErrorReporting = true,\n enableCrashReporting = false,\n anrTracking = false,\n anrOptions = {},\n\n // Performance vitals\n cpuUsageVitals = true,\n memoryUsageVitals = true,\n refreshRateVitals = false,\n fetchVitalsInterval = 30000,\n frameMonitoringOptions = {},\n\n // Network\n ignoreUrls = [],\n enableHttpInstrumentation = {},\n\n // Console and user actions\n enableConsoleCapture = true,\n enableUserActions = true,\n\n // Tracing\n enableTracing = false,\n tracingOptions = {},\n } = config;\n\n const instrumentations: Instrumentation[] = [];\n\n // Error reporting\n if (enableErrorReporting) {\n instrumentations.push(\n new ErrorsInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n // Console capture\n if (enableConsoleCapture) {\n instrumentations.push(new ConsoleInstrumentation());\n }\n\n // Sessions\n instrumentations.push(new SessionInstrumentation());\n\n // Views\n instrumentations.push(new ViewInstrumentation());\n\n // App state\n instrumentations.push(new AppStateInstrumentation());\n\n // User actions - enabled by default, opt-out via enableUserActions\n if (enableUserActions) {\n instrumentations.push(new UserActionInstrumentation());\n }\n\n // HTTP/XHR tracking: when tracing is enabled, TracingInstrumentation patches fetch and XHR.\n // When tracing is disabled, add HttpInstrumentation and/or XHRInstrumentation per enableHttpInstrumentation.\n if (!enableTracing) {\n const { fetch: enableFetch = true, xhr: enableXhr = true } = enableHttpInstrumentation;\n const ignoredUrlsRegExp = toRegExpArray(ignoreUrls);\n if (enableFetch) {\n instrumentations.push(new HttpInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n if (enableXhr) {\n instrumentations.push(new XHRInstrumentation({ ignoredUrls: ignoredUrlsRegExp }));\n }\n }\n\n // Performance vitals (CPU/memory) - only add if at least one metric is enabled\n if (cpuUsageVitals || memoryUsageVitals) {\n const perfInstrumentation = new PerformanceInstrumentation({\n memoryUsageVitals,\n cpuUsageVitals,\n fetchVitalsInterval,\n });\n instrumentations.push(perfInstrumentation);\n }\n\n // Startup tracking - always enabled\n instrumentations.push(new StartupInstrumentation());\n\n // Frame monitoring: enabled when refreshRateVitals is true\n // The instrumentation reads refreshRateVitals from faro.config (single source of truth)\n if (refreshRateVitals) {\n instrumentations.push(new FrameMonitoringInstrumentation(frameMonitoringOptions));\n }\n\n // ANR detection (Android only)\n if (anrTracking && Platform.OS === 'android') {\n instrumentations.push(new ANRInstrumentation(anrOptions));\n }\n\n // Crash reporting\n if (enableCrashReporting) {\n instrumentations.push(\n new CrashReportingInstrumentation({\n releaseBundleFilename: config.releaseBundleFilename,\n })\n );\n }\n\n if (enableTracing) {\n try {\n const { TracingInstrumentation } = require('@grafana/faro-react-native-tracing');\n instrumentations.push(new TracingInstrumentation(tracingOptions));\n } catch {\n console.warn(\n '[Faro] enableTracing is true but @grafana/faro-react-native-tracing is not installed. ' +\n 'Add it to use tracing: yarn add @grafana/faro-react-native-tracing'\n );\n }\n }\n\n return instrumentations;\n}\n"]}
@@ -124,12 +124,12 @@ function makeRNConfig(config, preloadedMobileMeta, appSymbolsBundleId) {
124
124
  var instrumentations = buildInstrumentations(config);
125
125
  var installationId = (_c = config.app.installationId) !== null && _c !== void 0 ? _c : preloadedAppMeta === null || preloadedAppMeta === void 0 ? void 0 : preloadedAppMeta.installationId;
126
126
  var releaseBundleFilename = config.releaseBundleFilename;
127
- // Merge bundleId (from config, Metro, or DeviceInfo) with preloaded app meta
128
127
  var bundleIdValue = resolveAppBundleId(config.app, (_d = config.app) === null || _d === void 0 ? void 0 : _d.name, appSymbolsBundleId);
129
- var appMetasIfPresent = preloadedAppMeta || bundleIdValue
130
- ? [{ app: __assign(__assign({}, preloadedAppMeta), (bundleIdValue && { bundleId: bundleIdValue })) }]
131
- : [];
132
- return __assign(__assign({ app: __assign(__assign({}, config.app), (installationId && { installationId: installationId })) }, (preloadedMobileMeta != null && {
128
+ var app = __assign(__assign(__assign(__assign({}, preloadedAppMeta), config.app), (installationId && { installationId: installationId })), (bundleIdValue && { bundleId: bundleIdValue }));
129
+ // Core merges metadata shallowly. Supply the complete app object so native
130
+ // metadata cannot replace configured fields such as version and environment.
131
+ var appMetasIfPresent = preloadedAppMeta || bundleIdValue ? [{ app: app }] : [];
132
+ return __assign(__assign({ app: app }, (preloadedMobileMeta != null && {
133
133
  preloadedMobileMeta: preloadedMobileMeta.meta,
134
134
  preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,
135
135
  })), { dedupe: (_e = config.dedupe) !== null && _e !== void 0 ? _e : true, globalObjectKey: (_f = config.globalObjectKey) !== null && _f !== void 0 ? _f : faro_core_1.defaultGlobalObjectKey, internalLoggerLevel: (_g = config.internalLoggerLevel) !== null && _g !== void 0 ? _g : internalLogger_1.InternalLoggerLevel.ERROR, isolate: (_h = config.isolate) !== null && _h !== void 0 ? _h : false, parseStacktrace: (_j = config.parseStacktrace) !== null && _j !== void 0 ? _j : createParseStacktrace(releaseBundleFilename), paused: (_k = config.paused) !== null && _k !== void 0 ? _k : false, preventGlobalExposure: (_l = config.preventGlobalExposure) !== null && _l !== void 0 ? _l : false, unpatchedConsole: (_m = config.unpatchedConsole) !== null && _m !== void 0 ? _m : faro_core_1.defaultUnpatchedConsole, batching: {
@@ -1 +1 @@
1
- {"version":3,"file":"makeRNConfig.js","sourceRoot":"","sources":["../../../src/config/makeRNConfig.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultGlobalObjectKey, defaultUnpatchedConsole } from '@grafana/faro-core';\nimport type { Config, MetaApp } from '@grafana/faro-core';\n\nimport { getStackFramesFromError } from '../instrumentations/errors/stackTraceParser';\nimport type { PreloadedMobileMeta } from '../instrumentations/session/sessionAttributes';\nimport { defaultSessionTrackingConfig } from '../instrumentations/session/sessionManager/sessionConstants';\nimport { InternalLoggerLevel, LogLevel } from '../internalLogger';\nimport { getMetroInjectedBundleId } from '../metas/appBuildIdentity';\nimport { getPageMeta } from '../metas/page';\nimport { getScreenMeta } from '../metas/screen';\nimport { getSdkMeta } from '../metas/sdk';\nimport { ConsoleTransport } from '../transports/console';\nimport { FetchTransport } from '../transports/fetch';\nimport { OfflineTransport } from '../transports/offline';\n\nimport { getRNInstrumentations } from './getRNInstrumentations';\nimport type { ReactNativeConfig, ReactNativeFullConfig } from './types';\n\nconst DEFAULT_OFFLINE_CACHE_MS = 3 * 24 * 60 * 60 * 1000; // 3 days\n\n/**\n * Resolves `meta.app.bundleId` when it is not already supplied by faro-core from\n * the Metro preamble (`registerInitialMetas` / `__faroBundleId_<appName>`).\n *\n * Priority: explicit `config.app.bundleId` → Metro preamble (core) → DeviceInfo\n * fallback (`applicationId@versionCode@versionName`, same shape Gradle/Metro use).\n */\nfunction resolveAppBundleId(\n configApp: MetaApp | undefined,\n appName: string | undefined,\n appSymbolsBundleId?: string\n): string | undefined {\n if (configApp?.bundleId) {\n return configApp.bundleId;\n }\n const metroId = getMetroInjectedBundleId(appName);\n if (metroId) {\n return metroId;\n }\n return appSymbolsBundleId;\n}\n\n/**\n * Builds transports. FetchTransport is always added when url is provided.\n * User can enable offline and console via enableTransports.\n */\nfunction buildTransports(config: ReactNativeConfig): Config['transports'] {\n const { enableTransports = { offline: false, console: false } } = config;\n\n if (!config.url) {\n throw new Error('url is required. Provide the Faro collector URL.');\n }\n\n const builtTransports: Config['transports'] = [];\n\n if (enableTransports.offline) {\n builtTransports.push(\n new OfflineTransport({\n maxCacheDurationMs: DEFAULT_OFFLINE_CACHE_MS,\n })\n );\n }\n\n builtTransports.push(\n new FetchTransport({\n url: config.url,\n apiKey: config.apiKey,\n })\n );\n\n if (enableTransports.console) {\n builtTransports.push(new ConsoleTransport({ level: LogLevel.DEBUG }));\n }\n\n const extraTransports = config.transports ?? [];\n return [...builtTransports, ...extraTransports];\n}\n\n/**\n * Builds instrumentations from config flags.\n */\nfunction buildInstrumentations(config: ReactNativeConfig): Config['instrumentations'] {\n const baseInstrumentations = getRNInstrumentations(config);\n const extraInstrumentations = config.instrumentations ?? [];\n return [...baseInstrumentations, ...extraInstrumentations];\n}\n\n/**\n * React Native stacktrace parser. Uses getStackFramesFromError for RN-specific formats.\n */\nfunction createParseStacktrace(releaseBundleFilename: string | undefined): Config['parseStacktrace'] {\n return (err) => ({\n frames: getStackFramesFromError(err, { releaseBundleFilename }),\n });\n}\n\n/**\n * Creates a full Faro config from React Native flag-based config.\n *\n * Based on flags, builds instrumentations and transports automatically.\n * Client just enables what they need; makeRNConfig does the rest.\n *\n * @param preloadedMobileMeta Device/session fields and structured mobile meta (passed from async `initializeFaro`).\n * @param appSymbolsBundleId Encoded `meta.app.bundleId` for server-side symbol retrace.\n */\nexport function makeRNConfig(\n config: ReactNativeConfig,\n preloadedMobileMeta?: PreloadedMobileMeta,\n appSymbolsBundleId?: string\n): ReactNativeFullConfig {\n const { app: preloadedAppMeta, ...structuredMobileMeta } = preloadedMobileMeta?.meta ?? {};\n const mobileMetas = Object.keys(structuredMobileMeta).length > 0 ? [structuredMobileMeta] : [];\n const defaultMetas = [getSdkMeta(), getPageMeta(), getScreenMeta(), ...mobileMetas];\n const customMetas = config.metas ?? [];\n const transports = buildTransports(config);\n const instrumentations = buildInstrumentations(config);\n const installationId = config.app.installationId ?? preloadedAppMeta?.installationId;\n\n const releaseBundleFilename = config.releaseBundleFilename;\n // Merge bundleId (from config, Metro, or DeviceInfo) with preloaded app meta\n const bundleIdValue = resolveAppBundleId(config.app, config.app?.name, appSymbolsBundleId);\n const appMetasIfPresent =\n preloadedAppMeta || bundleIdValue\n ? [{ app: { ...preloadedAppMeta, ...(bundleIdValue && { bundleId: bundleIdValue }) } }]\n : [];\n\n return {\n app: {\n ...config.app,\n ...(installationId && { installationId }),\n },\n ...(preloadedMobileMeta != null && {\n preloadedMobileMeta: preloadedMobileMeta.meta,\n preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,\n }),\n dedupe: config.dedupe ?? true,\n globalObjectKey: config.globalObjectKey ?? defaultGlobalObjectKey,\n internalLoggerLevel: config.internalLoggerLevel ?? InternalLoggerLevel.ERROR,\n isolate: config.isolate ?? false,\n parseStacktrace: config.parseStacktrace ?? createParseStacktrace(releaseBundleFilename),\n paused: config.paused ?? false,\n preventGlobalExposure: config.preventGlobalExposure ?? false,\n unpatchedConsole: config.unpatchedConsole ?? defaultUnpatchedConsole,\n batching: {\n enabled: false,\n sendTimeout: 250,\n itemLimit: 50,\n },\n sessionTracking: {\n ...defaultSessionTrackingConfig,\n ...config.sessionTracking,\n },\n metas: [...defaultMetas, ...customMetas, ...appMetasIfPresent],\n instrumentations,\n transports,\n ignoreUrls: config.ignoreUrls ?? [],\n ignoreErrors: config.ignoreErrors,\n beforeSend: config.beforeSend,\n preserveOriginalError: config.preserveOriginalError,\n userActionsInstrumentation: config.userActionsOptions,\n consoleInstrumentation: config.consoleCaptureOptions,\n };\n}\n"]}
1
+ {"version":3,"file":"makeRNConfig.js","sourceRoot":"","sources":["../../../src/config/makeRNConfig.ts"],"names":[],"mappings":"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","sourcesContent":["import { defaultGlobalObjectKey, defaultUnpatchedConsole } from '@grafana/faro-core';\nimport type { Config, MetaApp } from '@grafana/faro-core';\n\nimport { getStackFramesFromError } from '../instrumentations/errors/stackTraceParser';\nimport type { PreloadedMobileMeta } from '../instrumentations/session/sessionAttributes';\nimport { defaultSessionTrackingConfig } from '../instrumentations/session/sessionManager/sessionConstants';\nimport { InternalLoggerLevel, LogLevel } from '../internalLogger';\nimport { getMetroInjectedBundleId } from '../metas/appBuildIdentity';\nimport { getPageMeta } from '../metas/page';\nimport { getScreenMeta } from '../metas/screen';\nimport { getSdkMeta } from '../metas/sdk';\nimport { ConsoleTransport } from '../transports/console';\nimport { FetchTransport } from '../transports/fetch';\nimport { OfflineTransport } from '../transports/offline';\n\nimport { getRNInstrumentations } from './getRNInstrumentations';\nimport type { ReactNativeConfig, ReactNativeFullConfig } from './types';\n\nconst DEFAULT_OFFLINE_CACHE_MS = 3 * 24 * 60 * 60 * 1000; // 3 days\n\n/**\n * Resolves `meta.app.bundleId` when it is not already supplied by faro-core from\n * the Metro preamble (`registerInitialMetas` / `__faroBundleId_<appName>`).\n *\n * Priority: explicit `config.app.bundleId` → Metro preamble (core) → DeviceInfo\n * fallback (`applicationId@versionCode@versionName`, same shape Gradle/Metro use).\n */\nfunction resolveAppBundleId(\n configApp: MetaApp | undefined,\n appName: string | undefined,\n appSymbolsBundleId?: string\n): string | undefined {\n if (configApp?.bundleId) {\n return configApp.bundleId;\n }\n const metroId = getMetroInjectedBundleId(appName);\n if (metroId) {\n return metroId;\n }\n return appSymbolsBundleId;\n}\n\n/**\n * Builds transports. FetchTransport is always added when url is provided.\n * User can enable offline and console via enableTransports.\n */\nfunction buildTransports(config: ReactNativeConfig): Config['transports'] {\n const { enableTransports = { offline: false, console: false } } = config;\n\n if (!config.url) {\n throw new Error('url is required. Provide the Faro collector URL.');\n }\n\n const builtTransports: Config['transports'] = [];\n\n if (enableTransports.offline) {\n builtTransports.push(\n new OfflineTransport({\n maxCacheDurationMs: DEFAULT_OFFLINE_CACHE_MS,\n })\n );\n }\n\n builtTransports.push(\n new FetchTransport({\n url: config.url,\n apiKey: config.apiKey,\n })\n );\n\n if (enableTransports.console) {\n builtTransports.push(new ConsoleTransport({ level: LogLevel.DEBUG }));\n }\n\n const extraTransports = config.transports ?? [];\n return [...builtTransports, ...extraTransports];\n}\n\n/**\n * Builds instrumentations from config flags.\n */\nfunction buildInstrumentations(config: ReactNativeConfig): Config['instrumentations'] {\n const baseInstrumentations = getRNInstrumentations(config);\n const extraInstrumentations = config.instrumentations ?? [];\n return [...baseInstrumentations, ...extraInstrumentations];\n}\n\n/**\n * React Native stacktrace parser. Uses getStackFramesFromError for RN-specific formats.\n */\nfunction createParseStacktrace(releaseBundleFilename: string | undefined): Config['parseStacktrace'] {\n return (err) => ({\n frames: getStackFramesFromError(err, { releaseBundleFilename }),\n });\n}\n\n/**\n * Creates a full Faro config from React Native flag-based config.\n *\n * Based on flags, builds instrumentations and transports automatically.\n * Client just enables what they need; makeRNConfig does the rest.\n *\n * @param preloadedMobileMeta Device/session fields and structured mobile meta (passed from async `initializeFaro`).\n * @param appSymbolsBundleId Encoded `meta.app.bundleId` for server-side symbol retrace.\n */\nexport function makeRNConfig(\n config: ReactNativeConfig,\n preloadedMobileMeta?: PreloadedMobileMeta,\n appSymbolsBundleId?: string\n): ReactNativeFullConfig {\n const { app: preloadedAppMeta, ...structuredMobileMeta } = preloadedMobileMeta?.meta ?? {};\n const mobileMetas = Object.keys(structuredMobileMeta).length > 0 ? [structuredMobileMeta] : [];\n const defaultMetas = [getSdkMeta(), getPageMeta(), getScreenMeta(), ...mobileMetas];\n const customMetas = config.metas ?? [];\n const transports = buildTransports(config);\n const instrumentations = buildInstrumentations(config);\n const installationId = config.app.installationId ?? preloadedAppMeta?.installationId;\n\n const releaseBundleFilename = config.releaseBundleFilename;\n const bundleIdValue = resolveAppBundleId(config.app, config.app?.name, appSymbolsBundleId);\n const app = {\n ...preloadedAppMeta,\n ...config.app,\n ...(installationId && { installationId }),\n ...(bundleIdValue && { bundleId: bundleIdValue }),\n };\n // Core merges metadata shallowly. Supply the complete app object so native\n // metadata cannot replace configured fields such as version and environment.\n const appMetasIfPresent = preloadedAppMeta || bundleIdValue ? [{ app }] : [];\n\n return {\n app,\n ...(preloadedMobileMeta != null && {\n preloadedMobileMeta: preloadedMobileMeta.meta,\n preloadedSessionDeviceAttributes: preloadedMobileMeta.sessionAttributes,\n }),\n dedupe: config.dedupe ?? true,\n globalObjectKey: config.globalObjectKey ?? defaultGlobalObjectKey,\n internalLoggerLevel: config.internalLoggerLevel ?? InternalLoggerLevel.ERROR,\n isolate: config.isolate ?? false,\n parseStacktrace: config.parseStacktrace ?? createParseStacktrace(releaseBundleFilename),\n paused: config.paused ?? false,\n preventGlobalExposure: config.preventGlobalExposure ?? false,\n unpatchedConsole: config.unpatchedConsole ?? defaultUnpatchedConsole,\n batching: {\n enabled: false,\n sendTimeout: 250,\n itemLimit: 50,\n },\n sessionTracking: {\n ...defaultSessionTrackingConfig,\n ...config.sessionTracking,\n },\n metas: [...defaultMetas, ...customMetas, ...appMetasIfPresent],\n instrumentations,\n transports,\n ignoreUrls: config.ignoreUrls ?? [],\n ignoreErrors: config.ignoreErrors,\n beforeSend: config.beforeSend,\n preserveOriginalError: config.preserveOriginalError,\n userActionsInstrumentation: config.userActionsOptions,\n consoleInstrumentation: config.consoleCaptureOptions,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sampling.js","sourceRoot":"","sources":["../../../src/config/sampling.ts"],"names":[],"mappings":";;;AA+EA;;;;;;;;;;;;GAYG;AACH;IACE;;;;OAIG;IACH,sBAA4B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAE5C,8BAAO,GAAP,UAAQ,QAAyB;QAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IACH,mBAAC;AAAD,CAAC,AAXD,IAWC;AAXY,oCAAY;AAazB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IACE;;;;;OAKG;IACH,0BAA6B,EAAwC;QAAxC,OAAE,GAAF,EAAE,CAAsC;IAAG,CAAC;IAEzE,kCAAO,GAAP,UAAQ,OAAwB;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IACH,uBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,4CAAgB","sourcesContent":["import type { Meta } from '@grafana/faro-core';\n\n/**\n * Context passed to sampling implementations.\n *\n * Provides access to the current metadata state at SDK initialization time,\n * allowing sampling decisions based on session attributes, user info, app\n * environment, and other metadata.\n *\n * This aligns with the Faro Flutter SDK's `SamplingContext` which provides\n * `meta` to the sampler.\n *\n * @example\n * ```ts\n * sampling: SamplingFunction((context) => {\n * // Sample all beta users\n * if (context.meta.user?.attributes?.['role'] === 'beta') {\n * return 1;\n * }\n * // Sample 10% of production sessions\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * })\n * ```\n */\nexport interface SamplingContext {\n /** The current merged metadata state (session, user, app, sdk, view). */\n meta: Meta;\n}\n\n/**\n * Defines how sessions should be sampled.\n *\n * Implement this interface to provide custom sampling logic. Use one of the\n * built-in implementations:\n * - {@link SamplingRate} for a fixed sampling rate\n * - {@link SamplingFunction} for dynamic sampling based on context\n *\n * @example\n * ```ts\n * // Fixed 10% sampling\n * sessionTracking: {\n * sampling: new SamplingRate(0.1),\n * }\n *\n * // Dynamic sampling based on context\n * sessionTracking: {\n * sampling: new SamplingFunction((context) => {\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * }),\n * }\n *\n * // Custom implementation\n * class BetaUserSampling implements Sampling {\n * resolve(context: SamplingContext): number {\n * return context.meta.user?.attributes?.['role'] === 'beta' ? 1 : 0.1;\n * }\n * }\n * sessionTracking: { sampling: new BetaUserSampling() }\n * ```\n */\nexport interface Sampling {\n /**\n * Resolves the sampling rate for the given context.\n *\n * @param context - The current metadata state\n * @returns A value between 0 and 1 (inclusive). Values are clamped to [0, 1].\n * - 1: Sample all sessions (100%)\n * - 0.5: Sample half of sessions (50%)\n * - 0: Sample no sessions (0%)\n */\n resolve(context: SamplingContext): number;\n}\n\n/**\n * Fixed sampling rate.\n *\n * Use this when you want a constant sampling probability regardless of\n * session context.\n *\n * @example\n * ```ts\n * sessionTracking: {\n * sampling: new SamplingRate(0.1), // 10% of sessions\n * }\n * ```\n */\nexport class SamplingRate implements Sampling {\n /**\n * Creates a fixed sampling rate.\n *\n * @param rate - The fixed sampling rate (0 to 1). Values are clamped to [0, 1].\n */\n constructor(public readonly rate: number) {}\n\n resolve(_context: SamplingContext): number {\n return Math.max(0, Math.min(1, this.rate));\n }\n}\n\n/**\n * Dynamic sampling based on context.\n *\n * Use this when you want to make sampling decisions based on session\n * metadata like user attributes, app environment, or other context.\n *\n * @example\n * ```ts\n * sessionTracking: {\n * sampling: new SamplingFunction((context) => {\n * // Sample all beta users\n * if (context.meta.user?.attributes?.['role'] === 'beta') {\n * return 1;\n * }\n * // Sample 10% of production sessions\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * }),\n * }\n * ```\n */\nexport class SamplingFunction implements Sampling {\n /**\n * Creates a dynamic sampler with the given function.\n *\n * @param fn - The function that determines the rate based on context.\n * Receives a {@link SamplingContext} and should return a rate between 0 and 1.\n */\n constructor(private readonly fn: (context: SamplingContext) => number) {}\n\n resolve(context: SamplingContext): number {\n return Math.max(0, Math.min(1, this.fn(context)));\n }\n}\n"]}
1
+ {"version":3,"file":"sampling.js","sourceRoot":"","sources":["../../../src/config/sampling.ts"],"names":[],"mappings":";;;AA4EA;;;;;;;;;;;;GAYG;AACH;IACE;;;;OAIG;IACH,sBAA4B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAE5C,8BAAO,GAAP,UAAQ,QAAyB;QAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IACH,mBAAC;AAAD,CAAC,AAXD,IAWC;AAXY,oCAAY;AAazB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;IACE;;;;;OAKG;IACH,0BAA6B,EAAwC;QAAxC,OAAE,GAAF,EAAE,CAAsC;IAAG,CAAC;IAEzE,kCAAO,GAAP,UAAQ,OAAwB;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IACH,uBAAC;AAAD,CAAC,AAZD,IAYC;AAZY,4CAAgB","sourcesContent":["import type { Meta } from '@grafana/faro-core';\n\n/**\n * Context passed to sampling implementations.\n *\n * Provides access to the current metadata state at SDK initialization time,\n * allowing sampling decisions based on session attributes, user info, app\n * environment, and other metadata.\n *\n * @example\n * ```ts\n * sampling: SamplingFunction((context) => {\n * // Sample all beta users\n * if (context.meta.user?.attributes?.['role'] === 'beta') {\n * return 1;\n * }\n * // Sample 10% of production sessions\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * })\n * ```\n */\nexport interface SamplingContext {\n /** The current merged metadata state (session, user, app, sdk, view). */\n meta: Meta;\n}\n\n/**\n * Defines how sessions should be sampled.\n *\n * Implement this interface to provide custom sampling logic. Use one of the\n * built-in implementations:\n * - {@link SamplingRate} for a fixed sampling rate\n * - {@link SamplingFunction} for dynamic sampling based on context\n *\n * @example\n * ```ts\n * // Fixed 10% sampling\n * sessionTracking: {\n * sampling: new SamplingRate(0.1),\n * }\n *\n * // Dynamic sampling based on context\n * sessionTracking: {\n * sampling: new SamplingFunction((context) => {\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * }),\n * }\n *\n * // Custom implementation\n * class BetaUserSampling implements Sampling {\n * resolve(context: SamplingContext): number {\n * return context.meta.user?.attributes?.['role'] === 'beta' ? 1 : 0.1;\n * }\n * }\n * sessionTracking: { sampling: new BetaUserSampling() }\n * ```\n */\nexport interface Sampling {\n /**\n * Resolves the sampling rate for the given context.\n *\n * @param context - The current metadata state\n * @returns A value between 0 and 1 (inclusive). Values are clamped to [0, 1].\n * - 1: Sample all sessions (100%)\n * - 0.5: Sample half of sessions (50%)\n * - 0: Sample no sessions (0%)\n */\n resolve(context: SamplingContext): number;\n}\n\n/**\n * Fixed sampling rate.\n *\n * Use this when you want a constant sampling probability regardless of\n * session context.\n *\n * @example\n * ```ts\n * sessionTracking: {\n * sampling: new SamplingRate(0.1), // 10% of sessions\n * }\n * ```\n */\nexport class SamplingRate implements Sampling {\n /**\n * Creates a fixed sampling rate.\n *\n * @param rate - The fixed sampling rate (0 to 1). Values are clamped to [0, 1].\n */\n constructor(public readonly rate: number) {}\n\n resolve(_context: SamplingContext): number {\n return Math.max(0, Math.min(1, this.rate));\n }\n}\n\n/**\n * Dynamic sampling based on context.\n *\n * Use this when you want to make sampling decisions based on session\n * metadata like user attributes, app environment, or other context.\n *\n * @example\n * ```ts\n * sessionTracking: {\n * sampling: new SamplingFunction((context) => {\n * // Sample all beta users\n * if (context.meta.user?.attributes?.['role'] === 'beta') {\n * return 1;\n * }\n * // Sample 10% of production sessions\n * if (context.meta.app?.environment === 'production') {\n * return 0.1;\n * }\n * return 1;\n * }),\n * }\n * ```\n */\nexport class SamplingFunction implements Sampling {\n /**\n * Creates a dynamic sampler with the given function.\n *\n * @param fn - The function that determines the rate based on context.\n * Receives a {@link SamplingContext} and should return a rate between 0 and 1.\n */\n constructor(private readonly fn: (context: SamplingContext) => number) {}\n\n resolve(context: SamplingContext): number {\n return Math.max(0, Math.min(1, this.fn(context)));\n }\n}\n"]}