@nathanclaire/edge-telemetry-sdk 3.0.0 → 4.0.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 (298) hide show
  1. package/README.md +831 -186
  2. package/dist/appLifecycle-CECgRVu_.cjs +2 -0
  3. package/dist/appLifecycle-CECgRVu_.cjs.map +1 -0
  4. package/dist/appLifecycle-DQErzJIR.js +22 -0
  5. package/dist/appLifecycle-DQErzJIR.js.map +1 -0
  6. package/dist/batch-CwoO7noL.js +56 -0
  7. package/dist/batch-CwoO7noL.js.map +1 -0
  8. package/dist/batch-DNu8Xr9T.cjs +2 -0
  9. package/dist/batch-DNu8Xr9T.cjs.map +1 -0
  10. package/dist/crashCapture-BOJ8nSAZ.cjs +4 -0
  11. package/dist/crashCapture-BOJ8nSAZ.cjs.map +1 -0
  12. package/dist/crashCapture-BW8WuyaU.js +70 -0
  13. package/dist/crashCapture-BW8WuyaU.js.map +1 -0
  14. package/dist/crashHandler.web-8F_k2veo.js +29 -0
  15. package/dist/crashHandler.web-8F_k2veo.js.map +1 -0
  16. package/dist/crashHandler.web-CWmF56mJ.cjs +2 -0
  17. package/dist/crashHandler.web-CWmF56mJ.cjs.map +1 -0
  18. package/dist/crashHandlerNative.native-C2kSikDt.cjs +2 -0
  19. package/dist/crashHandlerNative.native-C2kSikDt.cjs.map +1 -0
  20. package/dist/crashHandlerNative.native-FupMnr1U.js +39 -0
  21. package/dist/crashHandlerNative.native-FupMnr1U.js.map +1 -0
  22. package/dist/deviceInfo.native-BJ-3Jj1T.js +53 -0
  23. package/dist/deviceInfo.native-BJ-3Jj1T.js.map +1 -0
  24. package/dist/deviceInfo.native-BoeTZcD6.cjs +2 -0
  25. package/dist/deviceInfo.native-BoeTZcD6.cjs.map +1 -0
  26. package/dist/deviceInfo.web-3L3IDQQA.cjs +2 -0
  27. package/dist/deviceInfo.web-3L3IDQQA.cjs.map +1 -0
  28. package/dist/deviceInfo.web-BFB1-pcA.js +41 -0
  29. package/dist/deviceInfo.web-BFB1-pcA.js.map +1 -0
  30. package/dist/frameTracker-CHG6sIx9.cjs +2 -0
  31. package/dist/frameTracker-CHG6sIx9.cjs.map +1 -0
  32. package/dist/frameTracker-DdB8W_kC.js +54 -0
  33. package/dist/frameTracker-DdB8W_kC.js.map +1 -0
  34. package/dist/httpAttributes-BrrtM8zh.js +70 -0
  35. package/dist/httpAttributes-BrrtM8zh.js.map +1 -0
  36. package/dist/httpAttributes-D0m6UID7.cjs +2 -0
  37. package/dist/httpAttributes-D0m6UID7.cjs.map +1 -0
  38. package/dist/index-BtLlV1HA.js +57 -0
  39. package/dist/index-BtLlV1HA.js.map +1 -0
  40. package/dist/{deviceInfo.native-D2k0LDhI.js → index-C2XQ-EYw.js} +362 -411
  41. package/dist/index-C2XQ-EYw.js.map +1 -0
  42. package/dist/index-CXsVZY35.cjs +2 -0
  43. package/dist/index-CXsVZY35.cjs.map +1 -0
  44. package/dist/index-DLquF88M.cjs +2 -0
  45. package/dist/index-DLquF88M.cjs.map +1 -0
  46. package/dist/index.native.cjs +1 -1
  47. package/dist/index.native.cjs.map +1 -1
  48. package/dist/index.native.js +94 -59
  49. package/dist/index.native.js.map +1 -1
  50. package/dist/index.web.cjs +1 -1
  51. package/dist/index.web.cjs.map +1 -1
  52. package/dist/index.web.js +88 -33
  53. package/dist/index.web.js.map +1 -1
  54. package/dist/interactionWeb.web-Bl_cZlgh.cjs +2 -0
  55. package/dist/interactionWeb.web-Bl_cZlgh.cjs.map +1 -0
  56. package/dist/interactionWeb.web-CJAviVQ7.js +109 -0
  57. package/dist/interactionWeb.web-CJAviVQ7.js.map +1 -0
  58. package/dist/interceptFetchWeb.web-T88kO-bE.cjs +2 -0
  59. package/dist/interceptFetchWeb.web-T88kO-bE.cjs.map +1 -0
  60. package/dist/interceptFetchWeb.web-UXC2Lb6X.js +61 -0
  61. package/dist/interceptFetchWeb.web-UXC2Lb6X.js.map +1 -0
  62. package/dist/interceptHttpNative.native-BVpFuoNB.cjs +2 -0
  63. package/dist/interceptHttpNative.native-BVpFuoNB.cjs.map +1 -0
  64. package/dist/interceptHttpNative.native-rX-lPNST.js +18 -0
  65. package/dist/interceptHttpNative.native-rX-lPNST.js.map +1 -0
  66. package/dist/loadingTime-Bhomd9qq.cjs +2 -0
  67. package/dist/loadingTime-Bhomd9qq.cjs.map +1 -0
  68. package/dist/loadingTime-ZkYvFijA.js +70 -0
  69. package/dist/loadingTime-ZkYvFijA.js.map +1 -0
  70. package/dist/memoryNative.native-C42h9SjK.js +54 -0
  71. package/dist/memoryNative.native-C42h9SjK.js.map +1 -0
  72. package/dist/memoryNative.native-CA-7w9w1.cjs +2 -0
  73. package/dist/memoryNative.native-CA-7w9w1.cjs.map +1 -0
  74. package/dist/memoryStore-BIGZmmfD.cjs +2 -0
  75. package/dist/memoryStore-BIGZmmfD.cjs.map +1 -0
  76. package/dist/memoryStore-F5I-GQKM.js +193 -0
  77. package/dist/memoryStore-F5I-GQKM.js.map +1 -0
  78. package/dist/nativeSender-CfQaRuDK.cjs +2 -0
  79. package/dist/nativeSender-CfQaRuDK.cjs.map +1 -0
  80. package/dist/nativeSender-pgVSIv-X.js +59 -0
  81. package/dist/nativeSender-pgVSIv-X.js.map +1 -0
  82. package/dist/navigationRef-BzYbs8cm.js +28 -0
  83. package/dist/navigationRef-BzYbs8cm.js.map +1 -0
  84. package/dist/navigationRef-C-_qhb43.cjs +2 -0
  85. package/dist/navigationRef-C-_qhb43.cjs.map +1 -0
  86. package/dist/{navigationTracker-Cts68dgG.js → navigationTracker-BmywA_Bg.js} +4 -4
  87. package/dist/navigationTracker-BmywA_Bg.js.map +1 -0
  88. package/dist/navigationTracker-HkwVyywz.cjs +2 -0
  89. package/dist/navigationTracker-HkwVyywz.cjs.map +1 -0
  90. package/dist/navigationWeb.web-CW_z7Ca4.cjs +2 -0
  91. package/dist/navigationWeb.web-CW_z7Ca4.cjs.map +1 -0
  92. package/dist/navigationWeb.web-CcwgKuIZ.js +55 -0
  93. package/dist/navigationWeb.web-CcwgKuIZ.js.map +1 -0
  94. package/dist/{networkInfo.native-BK5fpAOL.js → networkInfo.native-CGrx9cnH.js} +15 -15
  95. package/dist/{networkInfo.native-BK5fpAOL.js.map → networkInfo.native-CGrx9cnH.js.map} +1 -1
  96. package/dist/{networkInfo.native-cxuw93Uy.cjs → networkInfo.native-YVySdv3S.cjs} +2 -2
  97. package/dist/{networkInfo.native-cxuw93Uy.cjs.map → networkInfo.native-YVySdv3S.cjs.map} +1 -1
  98. package/dist/{networkInfo.web-twcNn_hc.js → networkInfo.web-B2YlLNsI.js} +3 -3
  99. package/dist/networkInfo.web-B2YlLNsI.js.map +1 -0
  100. package/dist/networkInfo.web-PltJTHsy.cjs +2 -0
  101. package/dist/networkInfo.web-PltJTHsy.cjs.map +1 -0
  102. package/dist/runtimeReady.native-Bh7EcYmK.js +14 -0
  103. package/dist/runtimeReady.native-Bh7EcYmK.js.map +1 -0
  104. package/dist/runtimeReady.native-jUmuE1lV.cjs +2 -0
  105. package/dist/runtimeReady.native-jUmuE1lV.cjs.map +1 -0
  106. package/dist/runtimeReady.web-C8fdIbVR.js +25 -0
  107. package/dist/runtimeReady.web-C8fdIbVR.js.map +1 -0
  108. package/dist/runtimeReady.web-DHW682RN.cjs +2 -0
  109. package/dist/runtimeReady.web-DHW682RN.cjs.map +1 -0
  110. package/dist/seedRuntimeReady-BKwkBEAF.cjs +2 -0
  111. package/dist/seedRuntimeReady-BKwkBEAF.cjs.map +1 -0
  112. package/dist/seedRuntimeReady-Cz8nOKoo.js +10 -0
  113. package/dist/seedRuntimeReady-Cz8nOKoo.js.map +1 -0
  114. package/dist/src/adapters/appLifecycle.d.ts +8 -1
  115. package/dist/src/adapters/batch.d.ts +2 -0
  116. package/dist/src/adapters/crashCapture.d.ts +38 -9
  117. package/dist/src/adapters/failedEvents.d.ts +43 -0
  118. package/dist/src/adapters/frameAggregate.d.ts +8 -3
  119. package/dist/src/adapters/frameTracker.d.ts +30 -0
  120. package/dist/src/adapters/httpAttributes.d.ts +18 -0
  121. package/dist/src/adapters/loadingTime.d.ts +67 -0
  122. package/dist/src/adapters/native/interceptHttpNative.native.d.ts +18 -0
  123. package/dist/src/adapters/native/memoryNative.native.d.ts +15 -11
  124. package/dist/src/adapters/native/runtimeReady.native.d.ts +1 -0
  125. package/dist/src/adapters/native/store.native.d.ts +10 -0
  126. package/dist/src/adapters/nativeSender.d.ts +2 -2
  127. package/dist/src/adapters/navigationRef.d.ts +21 -0
  128. package/dist/src/adapters/navigationTracker.d.ts +1 -1
  129. package/dist/src/adapters/screenTiming.d.ts +8 -2
  130. package/dist/src/adapters/seedRuntimeReady.d.ts +8 -0
  131. package/dist/src/adapters/traceHeader.d.ts +33 -0
  132. package/dist/src/adapters/traceManager.d.ts +131 -0
  133. package/dist/src/adapters/uiInteraction.d.ts +111 -0
  134. package/dist/src/adapters/viewManager.d.ts +161 -0
  135. package/dist/src/adapters/viewport.d.ts +15 -0
  136. package/dist/src/adapters/web/interactionWeb.web.d.ts +36 -0
  137. package/dist/src/adapters/web/interceptFetchWeb.web.d.ts +3 -11
  138. package/dist/src/adapters/web/navigationWeb.web.d.ts +10 -0
  139. package/dist/src/adapters/web/runtimeReady.web.d.ts +5 -0
  140. package/dist/src/adapters/web/store.web.d.ts +12 -0
  141. package/dist/src/adapters/web/webVitals.web.d.ts +49 -0
  142. package/dist/src/adapters/webSender.d.ts +2 -2
  143. package/dist/src/adapters/webVitals.d.ts +25 -0
  144. package/dist/src/adapters/xhrIntercept.d.ts +53 -0
  145. package/dist/src/core/beforeSend.d.ts +20 -0
  146. package/dist/src/core/debug.d.ts +7 -0
  147. package/dist/src/core/memoryStore.d.ts +23 -0
  148. package/dist/src/core/store.d.ts +41 -0
  149. package/dist/src/core/telemetry.d.ts +305 -35
  150. package/dist/src/core/userProfile.d.ts +12 -0
  151. package/dist/src/core/utils/json.d.ts +7 -0
  152. package/dist/src/core/utils/uuid.d.ts +10 -1
  153. package/dist/src/createTelemetry.native.d.ts +7 -0
  154. package/dist/src/createTelemetry.web.d.ts +7 -0
  155. package/dist/src/index.base.d.ts +17 -1
  156. package/dist/src/index.native.d.ts +46 -9
  157. package/dist/src/index.web.d.ts +33 -2
  158. package/dist/store.native-BYBJcy6o.js +32 -0
  159. package/dist/store.native-BYBJcy6o.js.map +1 -0
  160. package/dist/store.native-TPqXngmF.cjs +2 -0
  161. package/dist/store.native-TPqXngmF.cjs.map +1 -0
  162. package/dist/store.web-CvqqN-_Z.cjs +2 -0
  163. package/dist/store.web-CvqqN-_Z.cjs.map +1 -0
  164. package/dist/store.web-DJAlN0nc.js +31 -0
  165. package/dist/store.web-DJAlN0nc.js.map +1 -0
  166. package/dist/telemetry-ByDJIz_9.js +1280 -0
  167. package/dist/telemetry-ByDJIz_9.js.map +1 -0
  168. package/dist/telemetry-CrU7i1Jc.cjs +2 -0
  169. package/dist/telemetry-CrU7i1Jc.cjs.map +1 -0
  170. package/dist/uiInteraction-CdzvEI1p.cjs +2 -0
  171. package/dist/uiInteraction-CdzvEI1p.cjs.map +1 -0
  172. package/dist/uiInteraction-DAqxxz0q.js +104 -0
  173. package/dist/uiInteraction-DAqxxz0q.js.map +1 -0
  174. package/dist/viewport-Dd85GUNO.cjs +2 -0
  175. package/dist/viewport-Dd85GUNO.cjs.map +1 -0
  176. package/dist/viewport-Dzmt5QwK.js +15 -0
  177. package/dist/viewport-Dzmt5QwK.js.map +1 -0
  178. package/dist/web-vitals.attribution-CVCPiX-h.cjs +2 -0
  179. package/dist/web-vitals.attribution-CVCPiX-h.cjs.map +1 -0
  180. package/dist/web-vitals.attribution-xw9N5MKQ.js +488 -0
  181. package/dist/web-vitals.attribution-xw9N5MKQ.js.map +1 -0
  182. package/dist/webSender-BIwslfpT.js +63 -0
  183. package/dist/webSender-BIwslfpT.js.map +1 -0
  184. package/dist/webSender-CVtE4sOF.cjs +2 -0
  185. package/dist/webSender-CVtE4sOF.cjs.map +1 -0
  186. package/dist/webVitals.web-CNIpsKlA.js +85 -0
  187. package/dist/webVitals.web-CNIpsKlA.js.map +1 -0
  188. package/dist/webVitals.web-DpWJ-iYp.cjs +2 -0
  189. package/dist/webVitals.web-DpWJ-iYp.cjs.map +1 -0
  190. package/dist/xhrIntercept-BADex6Cq.cjs +2 -0
  191. package/dist/xhrIntercept-BADex6Cq.cjs.map +1 -0
  192. package/dist/xhrIntercept-BNiA41Mj.js +53 -0
  193. package/dist/xhrIntercept-BNiA41Mj.js.map +1 -0
  194. package/docs/migration-v4.md +190 -0
  195. package/package.json +12 -4
  196. package/dist/appLifecycle-Cynw0kAv.js +0 -14
  197. package/dist/appLifecycle-Cynw0kAv.js.map +0 -1
  198. package/dist/appLifecycle-DvJIt7ym.cjs +0 -2
  199. package/dist/appLifecycle-DvJIt7ym.cjs.map +0 -1
  200. package/dist/batch-CLBFgYPC.cjs +0 -2
  201. package/dist/batch-CLBFgYPC.cjs.map +0 -1
  202. package/dist/batch-DLG_gtOm.js +0 -12
  203. package/dist/batch-DLG_gtOm.js.map +0 -1
  204. package/dist/crashCapture-BYTM4FLC.cjs +0 -2
  205. package/dist/crashCapture-BYTM4FLC.cjs.map +0 -1
  206. package/dist/crashCapture-D_rkkBVa.js +0 -31
  207. package/dist/crashCapture-D_rkkBVa.js.map +0 -1
  208. package/dist/crashHandler.web-BSxDpFTo.cjs +0 -2
  209. package/dist/crashHandler.web-BSxDpFTo.cjs.map +0 -1
  210. package/dist/crashHandler.web-D59bmhg9.js +0 -32
  211. package/dist/crashHandler.web-D59bmhg9.js.map +0 -1
  212. package/dist/crashHandlerNative.native-DeAFze4E.cjs +0 -2
  213. package/dist/crashHandlerNative.native-DeAFze4E.cjs.map +0 -1
  214. package/dist/crashHandlerNative.native-d7qJkzA6.js +0 -41
  215. package/dist/crashHandlerNative.native-d7qJkzA6.js.map +0 -1
  216. package/dist/debug-DsvQ9y3W.js +0 -68
  217. package/dist/debug-DsvQ9y3W.js.map +0 -1
  218. package/dist/debug-rnOOxFpN.cjs +0 -2
  219. package/dist/debug-rnOOxFpN.cjs.map +0 -1
  220. package/dist/deviceInfo.native-7hbRYixR.cjs +0 -2
  221. package/dist/deviceInfo.native-7hbRYixR.cjs.map +0 -1
  222. package/dist/deviceInfo.native-D2k0LDhI.js.map +0 -1
  223. package/dist/deviceInfo.web-ByNAlEJh.cjs +0 -2
  224. package/dist/deviceInfo.web-ByNAlEJh.cjs.map +0 -1
  225. package/dist/deviceInfo.web-DzQyEku6.js +0 -40
  226. package/dist/deviceInfo.web-DzQyEku6.js.map +0 -1
  227. package/dist/frameAggregate-C_HoVFcK.cjs +0 -2
  228. package/dist/frameAggregate-C_HoVFcK.cjs.map +0 -1
  229. package/dist/frameAggregate-Cwh1juw1.js +0 -17
  230. package/dist/frameAggregate-Cwh1juw1.js.map +0 -1
  231. package/dist/frameDropsNative.native-CP7zrXDf.js +0 -23
  232. package/dist/frameDropsNative.native-CP7zrXDf.js.map +0 -1
  233. package/dist/frameDropsNative.native-DKqEDqip.cjs +0 -2
  234. package/dist/frameDropsNative.native-DKqEDqip.cjs.map +0 -1
  235. package/dist/frameDropsWeb.web-C9Lt3Fuj.js +0 -22
  236. package/dist/frameDropsWeb.web-C9Lt3Fuj.js.map +0 -1
  237. package/dist/frameDropsWeb.web-azpwQCUz.cjs +0 -2
  238. package/dist/frameDropsWeb.web-azpwQCUz.cjs.map +0 -1
  239. package/dist/httpAttributes-BV50UKQU.js +0 -19
  240. package/dist/httpAttributes-BV50UKQU.js.map +0 -1
  241. package/dist/httpAttributes-xXOD9trQ.cjs +0 -2
  242. package/dist/httpAttributes-xXOD9trQ.cjs.map +0 -1
  243. package/dist/interaction-CH8yoY5-.js +0 -23
  244. package/dist/interaction-CH8yoY5-.js.map +0 -1
  245. package/dist/interaction-DcNFBW7a.cjs +0 -2
  246. package/dist/interaction-DcNFBW7a.cjs.map +0 -1
  247. package/dist/interceptFetchNative.native-VlhtMG-U.js +0 -49
  248. package/dist/interceptFetchNative.native-VlhtMG-U.js.map +0 -1
  249. package/dist/interceptFetchNative.native-jEAldH14.cjs +0 -2
  250. package/dist/interceptFetchNative.native-jEAldH14.cjs.map +0 -1
  251. package/dist/interceptFetchWeb.web-DFzZliik.cjs +0 -2
  252. package/dist/interceptFetchWeb.web-DFzZliik.cjs.map +0 -1
  253. package/dist/interceptFetchWeb.web-DfsMfoRP.js +0 -77
  254. package/dist/interceptFetchWeb.web-DfsMfoRP.js.map +0 -1
  255. package/dist/memoryNative.native-BWLh2S9L.js +0 -48
  256. package/dist/memoryNative.native-BWLh2S9L.js.map +0 -1
  257. package/dist/memoryNative.native-DCXSOd4Q.cjs +0 -2
  258. package/dist/memoryNative.native-DCXSOd4Q.cjs.map +0 -1
  259. package/dist/memoryWeb.web-B3YuV-cB.js +0 -48
  260. package/dist/memoryWeb.web-B3YuV-cB.js.map +0 -1
  261. package/dist/memoryWeb.web-CheXAcJn.cjs +0 -2
  262. package/dist/memoryWeb.web-CheXAcJn.cjs.map +0 -1
  263. package/dist/nativeSender-BE_mzw_S.js +0 -70
  264. package/dist/nativeSender-BE_mzw_S.js.map +0 -1
  265. package/dist/nativeSender-DyAUGY7c.cjs +0 -2
  266. package/dist/nativeSender-DyAUGY7c.cjs.map +0 -1
  267. package/dist/navigationNative.native-3tO5JxSd.cjs +0 -2
  268. package/dist/navigationNative.native-3tO5JxSd.cjs.map +0 -1
  269. package/dist/navigationNative.native-BUCGPQX2.js +0 -25
  270. package/dist/navigationNative.native-BUCGPQX2.js.map +0 -1
  271. package/dist/navigationTracker-B2GMwyKk.cjs +0 -2
  272. package/dist/navigationTracker-B2GMwyKk.cjs.map +0 -1
  273. package/dist/navigationTracker-Cts68dgG.js.map +0 -1
  274. package/dist/navigationWeb.web-B0necr5j.cjs +0 -2
  275. package/dist/navigationWeb.web-B0necr5j.cjs.map +0 -1
  276. package/dist/navigationWeb.web-CORzE_Id.js +0 -46
  277. package/dist/navigationWeb.web-CORzE_Id.js.map +0 -1
  278. package/dist/networkInfo.web-DJmw1sNK.cjs +0 -2
  279. package/dist/networkInfo.web-DJmw1sNK.cjs.map +0 -1
  280. package/dist/networkInfo.web-twcNn_hc.js.map +0 -1
  281. package/dist/src/adapters/interaction.d.ts +0 -17
  282. package/dist/src/adapters/native/frameDropsNative.native.d.ts +0 -16
  283. package/dist/src/adapters/native/interceptFetchNative.native.d.ts +0 -23
  284. package/dist/src/adapters/native/navigationNative.native.d.ts +0 -12
  285. package/dist/src/adapters/web/frameDropsWeb.web.d.ts +0 -16
  286. package/dist/src/adapters/web/memoryWeb.web.d.ts +0 -26
  287. package/dist/telemetry-Co4MYdwa.cjs +0 -2
  288. package/dist/telemetry-Co4MYdwa.cjs.map +0 -1
  289. package/dist/telemetry-KI0x4gzC.js +0 -389
  290. package/dist/telemetry-KI0x4gzC.js.map +0 -1
  291. package/dist/v4-BysszJq8.js +0 -31
  292. package/dist/v4-BysszJq8.js.map +0 -1
  293. package/dist/v4-CqdK_b8Y.cjs +0 -2
  294. package/dist/v4-CqdK_b8Y.cjs.map +0 -1
  295. package/dist/webSender-B27tmT1w.js +0 -42
  296. package/dist/webSender-B27tmT1w.js.map +0 -1
  297. package/dist/webSender-BWi4x1df.cjs +0 -2
  298. package/dist/webSender-BWi4x1df.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadingTime-Bhomd9qq.cjs","sources":["../src/adapters/loadingTime.ts"],"sourcesContent":["// `view.loading_time` — network settle, one definition, both builds (§4.5.2, #97).\n//\n// Scoped to exactly one job: p75 route-change responsiveness by `view.name`, compared across\n// releases. That framing licenses a crude stable heuristic over a clever one, and makes a\n// **null strictly better than a plausible guess** — a wrong-but-believable 300 ms poisons a\n// release comparison silently, and a `0` makes p75 track the cache-hit rate, so a backend\n// caching win renders as a frontend regression, reversed.\n//\n// Network-only, because in-flight fetch/XHR is the one settle signal both builds genuinely\n// have. DOM-mutation quiet is meaningless under React's routine re-rendering; rAF quiet never\n// settles against RN's animation driver. So this module is shared and neither build gets its\n// own definition of the same column.\n\n/**\n * The quiet window, and **the same constant as §4.6's dead-click window** — one constant, not\n * two. `ui.dead` (web only, not built yet) must import this rather than declare a second 1000.\n */\nexport const QUIET_WINDOW_MS = 1000;\n\n/** Hard cap (§4.5.2). A capped view emits **null, not the cap**: at 30 s, 30 s and 90 s are the same row. */\nexport const LOADING_TIME_CAP_MS = 30_000;\n\n/** §4.5's `view.loading_time_outcome` domain — never null, exactly four values. */\nexport type LoadingTimeOutcome = \"settled\" | \"no_activity\" | \"capped\" | \"abandoned\";\n\nexport type LoadingTimeResult = {\n /** Milliseconds, or null — and null has three causes, which is why the outcome ships beside it. */\n loadingTime: number | null;\n outcome: LoadingTimeOutcome;\n};\n\nexport type NetworkSettleOpts = {\n /**\n * `initial_load` only: the view starts **busy** until the platform's own runtime-ready\n * marker (`loadEventEnd` on web, `performance.rnStartupTiming` on native), then settles.\n * Every other `load_type` runs the same column with no seed.\n */\n awaitRuntimeReady?: boolean;\n};\n\n/**\n * One view's settle state. Constructed per view and handed the requests that **started** in\n * it — a request in flight across a view boundary belongs to the old view and does not hold\n * the new one open (§4.5.2), which is why the completion callback is bound to this instance\n * rather than looked up on whatever view is live when the response lands.\n */\nexport class NetworkSettle {\n private started = 0;\n private inFlight = 0;\n private lastEnd?: number;\n /** Frozen the first time quiet is *observed*, so a later request cannot un-settle the view. */\n private settledAt?: number;\n private awaitingRuntimeReady: boolean;\n private runtimeReadyAt?: number;\n\n constructor(private readonly viewStart: number, opts?: NetworkSettleOpts) {\n this.awaitingRuntimeReady = opts?.awaitRuntimeReady ?? false;\n }\n\n /** `view.request_count` — requests **started** in this view, failures included (§4.5). */\n get requestCount(): number {\n return this.started;\n }\n\n /**\n * The platform's runtime-ready marker, or `undefined` where the platform has none —\n * Old Architecture, or a runtime that omits it (§4.3). Either way this releases the gate:\n * a marker that never arrives must not make every launch report `abandoned`.\n */\n seedRuntimeReady(at?: number): void {\n // A successor was never gated on the marker, and on web the `load` event routinely\n // arrives *after* the first route change — flooring that view's settle at the page's\n // load time would inflate a route-change measurement with the launch's cost.\n if (!this.awaitingRuntimeReady) return;\n this.awaitingRuntimeReady = false;\n this.runtimeReadyAt = at;\n }\n\n /**\n * A request started in this view. Returns its completion callback — idempotent, because an\n * XHR `loadend` can fire more than once for a reused instance and an unbalanced in-flight\n * count would hold the view open forever.\n */\n requestStarted(now: number = Date.now()): (endedAt?: number) => void {\n this.started++;\n this.freezeIfQuiet(now);\n // Already settled: it counts toward `request_count` but must not re-arm the view, or a\n // 30-second poller keeps one screen \"loading\" for as long as the user stays on it.\n if (this.settledAt !== undefined) return () => { };\n\n this.inFlight++;\n let done = false;\n return (endedAt: number = Date.now()) => {\n if (done) return;\n done = true;\n this.inFlight--;\n if (this.lastEnd === undefined || endedAt > this.lastEnd) this.lastEnd = endedAt;\n };\n }\n\n /**\n * The view's verdict at exit. Idempotent, not pure: it may freeze the settle timestamp as\n * a side effect, which is deliberate — once quiet has been *observed* it cannot be undone\n * by a later call, and calling this twice must not produce two different answers.\n */\n resolve(now: number = Date.now()): LoadingTimeResult {\n // The contract's free invariant, and the branch that establishes it: `no_activity` ⇔\n // `view.request_count = 0`. It is checked before the runtime-ready seed on purpose —\n // the seed is a *floor* on when settle may happen, not a source of activity, so a\n // launch that fetched nothing has no loading time to report rather than one measuring\n // the platform's own startup.\n if (this.started === 0) return { loadingTime: null, outcome: \"no_activity\" };\n\n this.freezeIfQuiet(now);\n // The view is exiting, so no further request can *start* in it — quiet is confirmed by\n // construction and the rest of the window is pure detection delay, which §4.5.2 says is\n // free. Charging it as `abandoned` would drop the fastest views out of the `settled`\n // population and bias the p75 this column exists to serve, in the wrong direction.\n // `abandoned` is left meaning what it says: the user left while it was still loading.\n const settledAt = this.settledAt ?? this.quietSince();\n if (settledAt === undefined) {\n // Capped and abandoned are different populations, read as different series, and\n // must not be merged.\n return {\n loadingTime: null,\n outcome: now - this.viewStart >= LOADING_TIME_CAP_MS ? \"capped\" : \"abandoned\",\n };\n }\n\n const settleAt = Math.max(settledAt, this.runtimeReadyAt ?? 0);\n const value = settleAt - this.viewStart;\n if (value >= LOADING_TIME_CAP_MS) return { loadingTime: null, outcome: \"capped\" };\n return { loadingTime: Math.max(0, value), outcome: \"settled\" };\n }\n\n /**\n * Settle is the *completion* timestamp, not the moment we noticed it — the quiet window is\n * detection delay and is subtracted back out. That is free precisely because the `view`\n * event emits at view exit rather than at settle, so nothing waits on the window.\n */\n private freezeIfQuiet(now: number): void {\n if (this.settledAt !== undefined) return;\n const quiet = this.quietSince();\n if (quiet !== undefined && now - quiet >= QUIET_WINDOW_MS) this.settledAt = quiet;\n }\n\n /** When the network last went quiet, or undefined while the view is still busy. */\n private quietSince(): number | undefined {\n if (this.awaitingRuntimeReady) return undefined; // initial_load is busy until the marker\n if (this.inFlight > 0) return undefined;\n return this.lastEnd;\n }\n}\n"],"names":["NetworkSettle","viewStart","opts","at","now","done","endedAt","settledAt","value","quiet"],"mappings":"aA8CO,MAAMA,CAAc,CASvB,YAA6BC,EAAmBC,EAA0B,CAA7C,KAAA,UAAAD,EAR7B,KAAQ,QAAU,EAClB,KAAQ,SAAW,EAQf,KAAK,qBAAuBC,GAAM,mBAAqB,EAC3D,CAGA,IAAI,cAAuB,CACvB,OAAO,KAAK,OAChB,CAOA,iBAAiBC,EAAmB,CAI3B,KAAK,uBACV,KAAK,qBAAuB,GAC5B,KAAK,eAAiBA,EAC1B,CAOA,eAAeC,EAAc,KAAK,MAAmC,CAKjE,GAJA,KAAK,UACL,KAAK,cAAcA,CAAG,EAGlB,KAAK,YAAc,OAAW,MAAO,IAAM,CAAE,EAEjD,KAAK,WACL,IAAIC,EAAO,GACX,MAAO,CAACC,EAAkB,KAAK,QAAU,CACjCD,IACJA,EAAO,GACP,KAAK,YACD,KAAK,UAAY,QAAaC,EAAU,KAAK,gBAAc,QAAUA,GAC7E,CACJ,CAOA,QAAQF,EAAc,KAAK,MAA0B,CAMjD,GAAI,KAAK,UAAY,EAAG,MAAO,CAAE,YAAa,KAAM,QAAS,aAAA,EAE7D,KAAK,cAAcA,CAAG,EAMtB,MAAMG,EAAY,KAAK,WAAa,KAAK,WAAA,EACzC,GAAIA,IAAc,OAGd,MAAO,CACH,YAAa,KACb,QAASH,EAAM,KAAK,WAAa,IAAsB,SAAW,WAAA,EAK1E,MAAMI,EADW,KAAK,IAAID,EAAW,KAAK,gBAAkB,CAAC,EACpC,KAAK,UAC9B,OAAIC,GAAS,IAA4B,CAAE,YAAa,KAAM,QAAS,QAAA,EAChE,CAAE,YAAa,KAAK,IAAI,EAAGA,CAAK,EAAG,QAAS,SAAA,CACvD,CAOQ,cAAcJ,EAAmB,CACrC,GAAI,KAAK,YAAc,OAAW,OAClC,MAAMK,EAAQ,KAAK,WAAA,EACfA,IAAU,QAAaL,EAAMK,GAAS,WAAsB,UAAYA,EAChF,CAGQ,YAAiC,CACrC,GAAI,MAAK,sBACL,OAAK,SAAW,GACpB,OAAO,KAAK,OAChB,CACJ"}
@@ -0,0 +1,70 @@
1
+ const a = 1e3, r = 3e4;
2
+ class u {
3
+ constructor(e, t) {
4
+ this.viewStart = e, this.started = 0, this.inFlight = 0, this.awaitingRuntimeReady = t?.awaitRuntimeReady ?? !1;
5
+ }
6
+ /** `view.request_count` — requests **started** in this view, failures included (§4.5). */
7
+ get requestCount() {
8
+ return this.started;
9
+ }
10
+ /**
11
+ * The platform's runtime-ready marker, or `undefined` where the platform has none —
12
+ * Old Architecture, or a runtime that omits it (§4.3). Either way this releases the gate:
13
+ * a marker that never arrives must not make every launch report `abandoned`.
14
+ */
15
+ seedRuntimeReady(e) {
16
+ this.awaitingRuntimeReady && (this.awaitingRuntimeReady = !1, this.runtimeReadyAt = e);
17
+ }
18
+ /**
19
+ * A request started in this view. Returns its completion callback — idempotent, because an
20
+ * XHR `loadend` can fire more than once for a reused instance and an unbalanced in-flight
21
+ * count would hold the view open forever.
22
+ */
23
+ requestStarted(e = Date.now()) {
24
+ if (this.started++, this.freezeIfQuiet(e), this.settledAt !== void 0) return () => {
25
+ };
26
+ this.inFlight++;
27
+ let t = !1;
28
+ return (i = Date.now()) => {
29
+ t || (t = !0, this.inFlight--, (this.lastEnd === void 0 || i > this.lastEnd) && (this.lastEnd = i));
30
+ };
31
+ }
32
+ /**
33
+ * The view's verdict at exit. Idempotent, not pure: it may freeze the settle timestamp as
34
+ * a side effect, which is deliberate — once quiet has been *observed* it cannot be undone
35
+ * by a later call, and calling this twice must not produce two different answers.
36
+ */
37
+ resolve(e = Date.now()) {
38
+ if (this.started === 0) return { loadingTime: null, outcome: "no_activity" };
39
+ this.freezeIfQuiet(e);
40
+ const t = this.settledAt ?? this.quietSince();
41
+ if (t === void 0)
42
+ return {
43
+ loadingTime: null,
44
+ outcome: e - this.viewStart >= 3e4 ? "capped" : "abandoned"
45
+ };
46
+ const s = Math.max(t, this.runtimeReadyAt ?? 0) - this.viewStart;
47
+ return s >= 3e4 ? { loadingTime: null, outcome: "capped" } : { loadingTime: Math.max(0, s), outcome: "settled" };
48
+ }
49
+ /**
50
+ * Settle is the *completion* timestamp, not the moment we noticed it — the quiet window is
51
+ * detection delay and is subtracted back out. That is free precisely because the `view`
52
+ * event emits at view exit rather than at settle, so nothing waits on the window.
53
+ */
54
+ freezeIfQuiet(e) {
55
+ if (this.settledAt !== void 0) return;
56
+ const t = this.quietSince();
57
+ t !== void 0 && e - t >= 1e3 && (this.settledAt = t);
58
+ }
59
+ /** When the network last went quiet, or undefined while the view is still busy. */
60
+ quietSince() {
61
+ if (!this.awaitingRuntimeReady && !(this.inFlight > 0))
62
+ return this.lastEnd;
63
+ }
64
+ }
65
+ export {
66
+ r as L,
67
+ u as N,
68
+ a as Q
69
+ };
70
+ //# sourceMappingURL=loadingTime-ZkYvFijA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadingTime-ZkYvFijA.js","sources":["../src/adapters/loadingTime.ts"],"sourcesContent":["// `view.loading_time` — network settle, one definition, both builds (§4.5.2, #97).\n//\n// Scoped to exactly one job: p75 route-change responsiveness by `view.name`, compared across\n// releases. That framing licenses a crude stable heuristic over a clever one, and makes a\n// **null strictly better than a plausible guess** — a wrong-but-believable 300 ms poisons a\n// release comparison silently, and a `0` makes p75 track the cache-hit rate, so a backend\n// caching win renders as a frontend regression, reversed.\n//\n// Network-only, because in-flight fetch/XHR is the one settle signal both builds genuinely\n// have. DOM-mutation quiet is meaningless under React's routine re-rendering; rAF quiet never\n// settles against RN's animation driver. So this module is shared and neither build gets its\n// own definition of the same column.\n\n/**\n * The quiet window, and **the same constant as §4.6's dead-click window** — one constant, not\n * two. `ui.dead` (web only, not built yet) must import this rather than declare a second 1000.\n */\nexport const QUIET_WINDOW_MS = 1000;\n\n/** Hard cap (§4.5.2). A capped view emits **null, not the cap**: at 30 s, 30 s and 90 s are the same row. */\nexport const LOADING_TIME_CAP_MS = 30_000;\n\n/** §4.5's `view.loading_time_outcome` domain — never null, exactly four values. */\nexport type LoadingTimeOutcome = \"settled\" | \"no_activity\" | \"capped\" | \"abandoned\";\n\nexport type LoadingTimeResult = {\n /** Milliseconds, or null — and null has three causes, which is why the outcome ships beside it. */\n loadingTime: number | null;\n outcome: LoadingTimeOutcome;\n};\n\nexport type NetworkSettleOpts = {\n /**\n * `initial_load` only: the view starts **busy** until the platform's own runtime-ready\n * marker (`loadEventEnd` on web, `performance.rnStartupTiming` on native), then settles.\n * Every other `load_type` runs the same column with no seed.\n */\n awaitRuntimeReady?: boolean;\n};\n\n/**\n * One view's settle state. Constructed per view and handed the requests that **started** in\n * it — a request in flight across a view boundary belongs to the old view and does not hold\n * the new one open (§4.5.2), which is why the completion callback is bound to this instance\n * rather than looked up on whatever view is live when the response lands.\n */\nexport class NetworkSettle {\n private started = 0;\n private inFlight = 0;\n private lastEnd?: number;\n /** Frozen the first time quiet is *observed*, so a later request cannot un-settle the view. */\n private settledAt?: number;\n private awaitingRuntimeReady: boolean;\n private runtimeReadyAt?: number;\n\n constructor(private readonly viewStart: number, opts?: NetworkSettleOpts) {\n this.awaitingRuntimeReady = opts?.awaitRuntimeReady ?? false;\n }\n\n /** `view.request_count` — requests **started** in this view, failures included (§4.5). */\n get requestCount(): number {\n return this.started;\n }\n\n /**\n * The platform's runtime-ready marker, or `undefined` where the platform has none —\n * Old Architecture, or a runtime that omits it (§4.3). Either way this releases the gate:\n * a marker that never arrives must not make every launch report `abandoned`.\n */\n seedRuntimeReady(at?: number): void {\n // A successor was never gated on the marker, and on web the `load` event routinely\n // arrives *after* the first route change — flooring that view's settle at the page's\n // load time would inflate a route-change measurement with the launch's cost.\n if (!this.awaitingRuntimeReady) return;\n this.awaitingRuntimeReady = false;\n this.runtimeReadyAt = at;\n }\n\n /**\n * A request started in this view. Returns its completion callback — idempotent, because an\n * XHR `loadend` can fire more than once for a reused instance and an unbalanced in-flight\n * count would hold the view open forever.\n */\n requestStarted(now: number = Date.now()): (endedAt?: number) => void {\n this.started++;\n this.freezeIfQuiet(now);\n // Already settled: it counts toward `request_count` but must not re-arm the view, or a\n // 30-second poller keeps one screen \"loading\" for as long as the user stays on it.\n if (this.settledAt !== undefined) return () => { };\n\n this.inFlight++;\n let done = false;\n return (endedAt: number = Date.now()) => {\n if (done) return;\n done = true;\n this.inFlight--;\n if (this.lastEnd === undefined || endedAt > this.lastEnd) this.lastEnd = endedAt;\n };\n }\n\n /**\n * The view's verdict at exit. Idempotent, not pure: it may freeze the settle timestamp as\n * a side effect, which is deliberate — once quiet has been *observed* it cannot be undone\n * by a later call, and calling this twice must not produce two different answers.\n */\n resolve(now: number = Date.now()): LoadingTimeResult {\n // The contract's free invariant, and the branch that establishes it: `no_activity` ⇔\n // `view.request_count = 0`. It is checked before the runtime-ready seed on purpose —\n // the seed is a *floor* on when settle may happen, not a source of activity, so a\n // launch that fetched nothing has no loading time to report rather than one measuring\n // the platform's own startup.\n if (this.started === 0) return { loadingTime: null, outcome: \"no_activity\" };\n\n this.freezeIfQuiet(now);\n // The view is exiting, so no further request can *start* in it — quiet is confirmed by\n // construction and the rest of the window is pure detection delay, which §4.5.2 says is\n // free. Charging it as `abandoned` would drop the fastest views out of the `settled`\n // population and bias the p75 this column exists to serve, in the wrong direction.\n // `abandoned` is left meaning what it says: the user left while it was still loading.\n const settledAt = this.settledAt ?? this.quietSince();\n if (settledAt === undefined) {\n // Capped and abandoned are different populations, read as different series, and\n // must not be merged.\n return {\n loadingTime: null,\n outcome: now - this.viewStart >= LOADING_TIME_CAP_MS ? \"capped\" : \"abandoned\",\n };\n }\n\n const settleAt = Math.max(settledAt, this.runtimeReadyAt ?? 0);\n const value = settleAt - this.viewStart;\n if (value >= LOADING_TIME_CAP_MS) return { loadingTime: null, outcome: \"capped\" };\n return { loadingTime: Math.max(0, value), outcome: \"settled\" };\n }\n\n /**\n * Settle is the *completion* timestamp, not the moment we noticed it — the quiet window is\n * detection delay and is subtracted back out. That is free precisely because the `view`\n * event emits at view exit rather than at settle, so nothing waits on the window.\n */\n private freezeIfQuiet(now: number): void {\n if (this.settledAt !== undefined) return;\n const quiet = this.quietSince();\n if (quiet !== undefined && now - quiet >= QUIET_WINDOW_MS) this.settledAt = quiet;\n }\n\n /** When the network last went quiet, or undefined while the view is still busy. */\n private quietSince(): number | undefined {\n if (this.awaitingRuntimeReady) return undefined; // initial_load is busy until the marker\n if (this.inFlight > 0) return undefined;\n return this.lastEnd;\n }\n}\n"],"names":["QUIET_WINDOW_MS","LOADING_TIME_CAP_MS","NetworkSettle","viewStart","opts","at","now","done","endedAt","settledAt","value","quiet"],"mappings":"AAiBO,MAAMA,IAAkB,KAGlBC,IAAsB;AA0B5B,MAAMC,EAAc;AAAA,EASvB,YAA6BC,GAAmBC,GAA0B;AAA7C,SAAA,YAAAD,GAR7B,KAAQ,UAAU,GAClB,KAAQ,WAAW,GAQf,KAAK,uBAAuBC,GAAM,qBAAqB;AAAA,EAC3D;AAAA;AAAA,EAGA,IAAI,eAAuB;AACvB,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiBC,GAAmB;AAIhC,IAAK,KAAK,yBACV,KAAK,uBAAuB,IAC5B,KAAK,iBAAiBA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAeC,IAAc,KAAK,OAAmC;AAKjE,QAJA,KAAK,WACL,KAAK,cAAcA,CAAG,GAGlB,KAAK,cAAc,OAAW,QAAO,MAAM;AAAA,IAAE;AAEjD,SAAK;AACL,QAAIC,IAAO;AACX,WAAO,CAACC,IAAkB,KAAK,UAAU;AACrC,MAAID,MACJA,IAAO,IACP,KAAK,aACD,KAAK,YAAY,UAAaC,IAAU,KAAK,kBAAc,UAAUA;AAAA,IAC7E;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQF,IAAc,KAAK,OAA0B;AAMjD,QAAI,KAAK,YAAY,EAAG,QAAO,EAAE,aAAa,MAAM,SAAS,cAAA;AAE7D,SAAK,cAAcA,CAAG;AAMtB,UAAMG,IAAY,KAAK,aAAa,KAAK,WAAA;AACzC,QAAIA,MAAc;AAGd,aAAO;AAAA,QACH,aAAa;AAAA,QACb,SAASH,IAAM,KAAK,aAAa,MAAsB,WAAW;AAAA,MAAA;AAK1E,UAAMI,IADW,KAAK,IAAID,GAAW,KAAK,kBAAkB,CAAC,IACpC,KAAK;AAC9B,WAAIC,KAAS,MAA4B,EAAE,aAAa,MAAM,SAAS,SAAA,IAChE,EAAE,aAAa,KAAK,IAAI,GAAGA,CAAK,GAAG,SAAS,UAAA;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAcJ,GAAmB;AACrC,QAAI,KAAK,cAAc,OAAW;AAClC,UAAMK,IAAQ,KAAK,WAAA;AACnB,IAAIA,MAAU,UAAaL,IAAMK,KAAS,aAAsB,YAAYA;AAAA,EAChF;AAAA;AAAA,EAGQ,aAAiC;AACrC,QAAI,MAAK,wBACL,OAAK,WAAW;AACpB,aAAO,KAAK;AAAA,EAChB;AACJ;"}
@@ -0,0 +1,54 @@
1
+ import { Platform as n } from "react-native";
2
+ import { D as a } from "./index-C2XQ-EYw.js";
3
+ import { d as m } from "./memoryStore-F5I-GQKM.js";
4
+ const l = 3e4, o = 1024 * 1024;
5
+ class u {
6
+ constructor(t) {
7
+ this.telemetry = t, this.intervalId = null;
8
+ }
9
+ /**
10
+ * One sample: `value` = resident MB, with the device total alongside so headroom is
11
+ * readable without a second join. An unusable read emits nothing — a fabricated 0 would
12
+ * drag every percentile down and read as a memory *win*.
13
+ *
14
+ * The two reads are guarded separately on purpose: `value` is what §5.2 makes primary,
15
+ * so a device-info build whose `getTotalMemory()` throws must still ship the resident
16
+ * figure with `memory.total_mb` simply absent.
17
+ */
18
+ async recordMemoryUsage() {
19
+ const t = await i(() => a.getUsedMemory());
20
+ if (t === void 0) return;
21
+ const s = {
22
+ "memory.type": "rss",
23
+ "memory.source": n.OS
24
+ }, e = await i(() => a.getTotalMemory());
25
+ e !== void 0 && e > 0 && (s["memory.total_mb"] = e / o), await this.telemetry.logMetric("memory_usage", t / o, s);
26
+ }
27
+ /**
28
+ * Starts the periodic sampler. v3 never called this — `trackMemoryUsage()` fired the
29
+ * one-shot read and applied `.catch` to its `void` return — so the metric was
30
+ * single-shot at best.
31
+ */
32
+ async start() {
33
+ this.intervalId === null && (this.intervalId = setInterval(() => {
34
+ this.recordMemoryUsage();
35
+ }, l), await this.recordMemoryUsage());
36
+ }
37
+ /** Stops the periodic sampler. Called by `Telemetry.shutdown()`. */
38
+ stop() {
39
+ this.intervalId !== null && (clearInterval(this.intervalId), this.intervalId = null);
40
+ }
41
+ }
42
+ async function i(r) {
43
+ try {
44
+ const t = await r();
45
+ return Number.isFinite(t) && t >= 0 ? t : void 0;
46
+ } catch (t) {
47
+ m.warn("memory_usage read failed:", t);
48
+ return;
49
+ }
50
+ }
51
+ export {
52
+ u as TelemetryMemoryUsageNative
53
+ };
54
+ //# sourceMappingURL=memoryNative.native-C42h9SjK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryNative.native-C42h9SjK.js","sources":["../src/adapters/native/memoryNative.native.ts"],"sourcesContent":["import { Platform } from \"react-native\";\nimport DeviceInfoLib from \"react-native-device-info\";\nimport { Telemetry } from \"../../core/telemetry\";\nimport { debug } from \"../../core/debug\";\n\n/** §5.2 default sampling interval. */\nconst SAMPLE_INTERVAL_MS = 30000;\n\nconst BYTES_PER_MB = 1024 * 1024;\n\n/**\n * §5.2 / #105 — `memory_usage`: RSS, **native only**, sampled every 30 s. The rationale for\n * every part of that sentence lives in CLAUDE.md's `memory_usage` section; this file is the\n * mechanism.\n */\nexport class TelemetryMemoryUsageNative {\n private intervalId: ReturnType<typeof setInterval> | null = null;\n\n constructor(private telemetry: Telemetry) { }\n\n /**\n * One sample: `value` = resident MB, with the device total alongside so headroom is\n * readable without a second join. An unusable read emits nothing — a fabricated 0 would\n * drag every percentile down and read as a memory *win*.\n *\n * The two reads are guarded separately on purpose: `value` is what §5.2 makes primary,\n * so a device-info build whose `getTotalMemory()` throws must still ship the resident\n * figure with `memory.total_mb` simply absent.\n */\n async recordMemoryUsage(): Promise<void> {\n const usedBytes = await readBytes(() => DeviceInfoLib.getUsedMemory());\n if (usedBytes === undefined) return;\n\n const attrs: Record<string, string | number> = {\n \"memory.type\": \"rss\",\n \"memory.source\": Platform.OS,\n };\n const totalBytes = await readBytes(() => DeviceInfoLib.getTotalMemory());\n if (totalBytes !== undefined && totalBytes > 0) {\n attrs[\"memory.total_mb\"] = totalBytes / BYTES_PER_MB;\n }\n\n await this.telemetry.logMetric(\"memory_usage\", usedBytes / BYTES_PER_MB, attrs);\n }\n\n /**\n * Starts the periodic sampler. v3 never called this — `trackMemoryUsage()` fired the\n * one-shot read and applied `.catch` to its `void` return — so the metric was\n * single-shot at best.\n */\n async start(): Promise<void> {\n if (this.intervalId !== null) return; // idempotent: one loop per instance\n this.intervalId = setInterval(() => {\n void this.recordMemoryUsage();\n }, SAMPLE_INTERVAL_MS);\n await this.recordMemoryUsage();\n }\n\n /** Stops the periodic sampler. Called by `Telemetry.shutdown()`. */\n stop(): void {\n if (this.intervalId !== null) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n}\n\n/**\n * One device-info read, reduced to `number | undefined`. Both a throw (the package is a\n * peer dep — a consumer can be on a build without the native module) and a non-finite or\n * negative reading mean \"nothing to report\", and the caller treats them the same.\n */\nasync function readBytes(read: () => Promise<number>): Promise<number | undefined> {\n try {\n const bytes = await read();\n return Number.isFinite(bytes) && bytes >= 0 ? bytes : undefined;\n } catch (err) {\n debug.warn(\"memory_usage read failed:\", err);\n return undefined;\n }\n}\n"],"names":["SAMPLE_INTERVAL_MS","BYTES_PER_MB","TelemetryMemoryUsageNative","telemetry","usedBytes","readBytes","DeviceInfoLib","attrs","Platform","totalBytes","read","bytes","err","debug"],"mappings":";;;AAMA,MAAMA,IAAqB,KAErBC,IAAe,OAAO;AAOrB,MAAMC,EAA2B;AAAA,EAGpC,YAAoBC,GAAsB;AAAtB,SAAA,YAAAA,GAFpB,KAAQ,aAAoD;AAAA,EAEhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW5C,MAAM,oBAAmC;AACrC,UAAMC,IAAY,MAAMC,EAAU,MAAMC,EAAc,eAAe;AACrE,QAAIF,MAAc,OAAW;AAE7B,UAAMG,IAAyC;AAAA,MAC3C,eAAe;AAAA,MACf,iBAAiBC,EAAS;AAAA,IAAA,GAExBC,IAAa,MAAMJ,EAAU,MAAMC,EAAc,gBAAgB;AACvE,IAAIG,MAAe,UAAaA,IAAa,MACzCF,EAAM,iBAAiB,IAAIE,IAAaR,IAG5C,MAAM,KAAK,UAAU,UAAU,gBAAgBG,IAAYH,GAAcM,CAAK;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAuB;AACzB,IAAI,KAAK,eAAe,SACxB,KAAK,aAAa,YAAY,MAAM;AAChC,MAAK,KAAK,kBAAA;AAAA,IACd,GAAGP,CAAkB,GACrB,MAAM,KAAK,kBAAA;AAAA,EACf;AAAA;AAAA,EAGA,OAAa;AACT,IAAI,KAAK,eAAe,SACpB,cAAc,KAAK,UAAU,GAC7B,KAAK,aAAa;AAAA,EAE1B;AACJ;AAOA,eAAeK,EAAUK,GAA0D;AAC/E,MAAI;AACA,UAAMC,IAAQ,MAAMD,EAAA;AACpB,WAAO,OAAO,SAASC,CAAK,KAAKA,KAAS,IAAIA,IAAQ;AAAA,EAC1D,SAASC,GAAK;AACV,IAAAC,EAAM,KAAK,6BAA6BD,CAAG;AAC3C;AAAA,EACJ;AACJ;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react-native"),s=require("./index-CXsVZY35.cjs"),l=require("./memoryStore-BIGZmmfD.cjs"),c=3e4,o=1024*1024;class y{constructor(e){this.telemetry=e,this.intervalId=null}async recordMemoryUsage(){const e=await a(()=>s.DeviceInfo.getUsedMemory());if(e===void 0)return;const i={"memory.type":"rss","memory.source":n.Platform.OS},t=await a(()=>s.DeviceInfo.getTotalMemory());t!==void 0&&t>0&&(i["memory.total_mb"]=t/o),await this.telemetry.logMetric("memory_usage",e/o,i)}async start(){this.intervalId===null&&(this.intervalId=setInterval(()=>{this.recordMemoryUsage()},c),await this.recordMemoryUsage())}stop(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null)}}async function a(r){try{const e=await r();return Number.isFinite(e)&&e>=0?e:void 0}catch(e){l.debug.warn("memory_usage read failed:",e);return}}exports.TelemetryMemoryUsageNative=y;
2
+ //# sourceMappingURL=memoryNative.native-CA-7w9w1.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryNative.native-CA-7w9w1.cjs","sources":["../src/adapters/native/memoryNative.native.ts"],"sourcesContent":["import { Platform } from \"react-native\";\nimport DeviceInfoLib from \"react-native-device-info\";\nimport { Telemetry } from \"../../core/telemetry\";\nimport { debug } from \"../../core/debug\";\n\n/** §5.2 default sampling interval. */\nconst SAMPLE_INTERVAL_MS = 30000;\n\nconst BYTES_PER_MB = 1024 * 1024;\n\n/**\n * §5.2 / #105 — `memory_usage`: RSS, **native only**, sampled every 30 s. The rationale for\n * every part of that sentence lives in CLAUDE.md's `memory_usage` section; this file is the\n * mechanism.\n */\nexport class TelemetryMemoryUsageNative {\n private intervalId: ReturnType<typeof setInterval> | null = null;\n\n constructor(private telemetry: Telemetry) { }\n\n /**\n * One sample: `value` = resident MB, with the device total alongside so headroom is\n * readable without a second join. An unusable read emits nothing — a fabricated 0 would\n * drag every percentile down and read as a memory *win*.\n *\n * The two reads are guarded separately on purpose: `value` is what §5.2 makes primary,\n * so a device-info build whose `getTotalMemory()` throws must still ship the resident\n * figure with `memory.total_mb` simply absent.\n */\n async recordMemoryUsage(): Promise<void> {\n const usedBytes = await readBytes(() => DeviceInfoLib.getUsedMemory());\n if (usedBytes === undefined) return;\n\n const attrs: Record<string, string | number> = {\n \"memory.type\": \"rss\",\n \"memory.source\": Platform.OS,\n };\n const totalBytes = await readBytes(() => DeviceInfoLib.getTotalMemory());\n if (totalBytes !== undefined && totalBytes > 0) {\n attrs[\"memory.total_mb\"] = totalBytes / BYTES_PER_MB;\n }\n\n await this.telemetry.logMetric(\"memory_usage\", usedBytes / BYTES_PER_MB, attrs);\n }\n\n /**\n * Starts the periodic sampler. v3 never called this — `trackMemoryUsage()` fired the\n * one-shot read and applied `.catch` to its `void` return — so the metric was\n * single-shot at best.\n */\n async start(): Promise<void> {\n if (this.intervalId !== null) return; // idempotent: one loop per instance\n this.intervalId = setInterval(() => {\n void this.recordMemoryUsage();\n }, SAMPLE_INTERVAL_MS);\n await this.recordMemoryUsage();\n }\n\n /** Stops the periodic sampler. Called by `Telemetry.shutdown()`. */\n stop(): void {\n if (this.intervalId !== null) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n}\n\n/**\n * One device-info read, reduced to `number | undefined`. Both a throw (the package is a\n * peer dep — a consumer can be on a build without the native module) and a non-finite or\n * negative reading mean \"nothing to report\", and the caller treats them the same.\n */\nasync function readBytes(read: () => Promise<number>): Promise<number | undefined> {\n try {\n const bytes = await read();\n return Number.isFinite(bytes) && bytes >= 0 ? bytes : undefined;\n } catch (err) {\n debug.warn(\"memory_usage read failed:\", err);\n return undefined;\n }\n}\n"],"names":["SAMPLE_INTERVAL_MS","BYTES_PER_MB","TelemetryMemoryUsageNative","telemetry","usedBytes","readBytes","DeviceInfoLib","attrs","Platform","totalBytes","read","bytes","err","debug"],"mappings":"0LAMMA,EAAqB,IAErBC,EAAe,KAAO,KAOrB,MAAMC,CAA2B,CAGpC,YAAoBC,EAAsB,CAAtB,KAAA,UAAAA,EAFpB,KAAQ,WAAoD,IAEhB,CAW5C,MAAM,mBAAmC,CACrC,MAAMC,EAAY,MAAMC,EAAU,IAAMC,EAAAA,WAAc,eAAe,EACrE,GAAIF,IAAc,OAAW,OAE7B,MAAMG,EAAyC,CAC3C,cAAe,MACf,gBAAiBC,EAAAA,SAAS,EAAA,EAExBC,EAAa,MAAMJ,EAAU,IAAMC,EAAAA,WAAc,gBAAgB,EACnEG,IAAe,QAAaA,EAAa,IACzCF,EAAM,iBAAiB,EAAIE,EAAaR,GAG5C,MAAM,KAAK,UAAU,UAAU,eAAgBG,EAAYH,EAAcM,CAAK,CAClF,CAOA,MAAM,OAAuB,CACrB,KAAK,aAAe,OACxB,KAAK,WAAa,YAAY,IAAM,CAC3B,KAAK,kBAAA,CACd,EAAGP,CAAkB,EACrB,MAAM,KAAK,kBAAA,EACf,CAGA,MAAa,CACL,KAAK,aAAe,OACpB,cAAc,KAAK,UAAU,EAC7B,KAAK,WAAa,KAE1B,CACJ,CAOA,eAAeK,EAAUK,EAA0D,CAC/E,GAAI,CACA,MAAMC,EAAQ,MAAMD,EAAA,EACpB,OAAO,OAAO,SAASC,CAAK,GAAKA,GAAS,EAAIA,EAAQ,MAC1D,OAASC,EAAK,CACVC,QAAM,KAAK,4BAA6BD,CAAG,EAC3C,MACJ,CACJ"}
@@ -0,0 +1,2 @@
1
+ "use strict";let u=!1;function h(s){u=s}const o={log:(...s)=>{u&&console.log(...s)},warn:(...s)=>{u&&console.warn(...s)},error:(...s)=>{u&&console.error(...s)}};function l(){const s=globalThis.__DEV__;if(typeof s=="boolean")return s;const t=globalThis.process?.env?.NODE_ENV;return t!==void 0&&t!=="production"}class w{async log(t,e){const r=await this.instancePromise;if(t==="app.crash"){o.warn("app.crash is SDK-owned (§4.7); routing to app.error — use captureError()");const n=e?.["error.message"]??e?.message??e?.["crash.message"];return r.captureError(n,e)}return r.log(t,e)}async flush(){return(await this.instancePromise).flush()}async shutdown(){return(await this.instancePromise).shutdown()}async attachNavigation(t){if(o.log("Attaching navigation tracker"),!t){o.warn("Navigation reference is undefined. Cannot attach navigation tracker.");return}const e=await this.instancePromise,{NavigationRefTracker:r}=await Promise.resolve().then(()=>require("./navigationRef-C-_qhb43.cjs"));new r(e).attach(t)}async captureError(t,e){return(await this.instancePromise).captureError(t,e)}async trackErrors(t){const{CrashHandlerNative:e}=await Promise.resolve().then(()=>require("./crashHandlerNative.native-C2kSikDt.cjs")),r=await this.instancePromise,n=new e(r);return r.trackErrors(n,t)}async setUserId(t){(await this.instancePromise).setUserId(t)}async setUserProfile(t){(await this.instancePromise).setUserProfile(t)}async setUserDetails(t){(await this.instancePromise).setUserDetails(t)}async updateUserProfile(t){(await this.instancePromise).updateUserProfile(t)}async getUserProfile(){return(await this.instancePromise).getUserProfile()}async clearUserProfile(){(await this.instancePromise).clearUserProfile()}async setUserName(t,e,r){(await this.instancePromise).setUserName(t,e,r)}async setUserContact(t,e){(await this.instancePromise).setUserContact(t,e)}async identify(t){return(await this.instancePromise).identify(t)}}const m="traceparent";function y(s){if(typeof s!="string")return;const t=s.trim();if(!(!t||/[\s/?#@*:]/.test(t)))try{return new URL(`http://${t}`).hostname||void 0}catch{return}}function g(s){const t=new Set;if(s==null)return t;if(!Array.isArray(s)){if(l())throw new Error("traceHostAllowlist must be an array of bare hosts");return o.warn("Telemetry: traceHostAllowlist must be an array of bare hosts — ignored"),t}for(const e of s){const r=y(e);if(r){t.add(r);continue}if(l())throw new Error(`traceHostAllowlist: "${String(e)}" is not a bare host (no scheme, path, port or wildcard)`);o.warn(`Telemetry: traceHostAllowlist entry "${String(e)}" is not a bare host — dropped`)}return t}function d(s,t){if(s.size===0)return!1;const e=globalThis.location?.href;try{return s.has((e?new URL(t,e):new URL(t)).hostname)}catch{return!1}}function p(s){if(typeof s!="string")return;const t=/^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/.exec(s.trim());if(!(!t||/^0+$/.test(t[1])||/^0+$/.test(t[2])))return{traceId:t[1],spanId:t[2]}}function v(s,t){return`00-${s}-${t}-01`}function f(s,t){if(s){if(Array.isArray(s))for(const e of s)e&&t(String(e[0]),String(e[1]));else if(typeof s.forEach=="function")s.forEach((e,r)=>t(String(r),String(e)));else if(typeof s=="object")for(const[e,r]of Object.entries(s))t(e,String(r))}}function P(s,t){let e;return f(s,(r,n)=>{r.toLowerCase()===t&&(e=n)}),e}function b(s,t,e){const r=[];return f(s,(n,c)=>r.push([n,c])),r.push([t,e]),r}function U(s={}){const t=new Map(Object.entries(s.seed??{})),e=s.unavailable===!0,r=a=>{if(e)return{status:"unavailable"};const i=t.get(a);return i===void 0?{status:"miss"}:{status:"hit",value:i}},n=(a,i)=>e?{status:"unavailable"}:(t.set(a,i),{status:"ok"}),c=a=>e?{status:"unavailable"}:(t.delete(a),{status:"ok"});return s.async?{sync:!1,get:async a=>r(a),set:async(a,i)=>n(a,i),remove:async a=>c(a)}:{sync:!0,get:r,set:n,remove:c}}exports.TRACEPARENT=m;exports.TelemetryBase=w;exports.allowsHost=d;exports.debug=o;exports.formatTraceparent=v;exports.isDev=l;exports.memoryStore=U;exports.normalizeAllowlist=g;exports.parseTraceparent=p;exports.readHeader=P;exports.setDebug=h;exports.withHeader=b;
2
+ //# sourceMappingURL=memoryStore-BIGZmmfD.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryStore-BIGZmmfD.cjs","sources":["../src/core/debug.ts","../src/index.base.ts","../src/adapters/traceHeader.ts","../src/core/memoryStore.ts"],"sourcesContent":["// SDK-internal debug gate (#23, Workstream E). Silent by default so v3 never spams the\n// host app's console; `createTelemetry({ debug: true })` flips it on. Gates log AND\n// warn/error — nothing prints unless debug is enabled.\nlet enabled = false;\n\nexport function setDebug(on: boolean): void {\n enabled = on;\n}\n\nexport const debug = {\n log: (...args: any[]) => { if (enabled) console.log(...args); },\n warn: (...args: any[]) => { if (enabled) console.warn(...args); },\n error: (...args: any[]) => { if (enabled) console.error(...args); },\n};\n\n/**\n * `__DEV__` on RN, `NODE_ENV` elsewhere. Dev-only *config* diagnostics (a malformed\n * allowlist, the `Error.stackTraceLimit` advisory) surface through this rather than the\n * `debug` gate above: they are wiring mistakes the consumer has to see while building,\n * and `debug: true` is exactly what a consumer with a wiring mistake has not set.\n */\nexport function isDev(): boolean {\n const dev = (globalThis as any).__DEV__;\n if (typeof dev === \"boolean\") return dev;\n const env = (globalThis as any).process?.env?.NODE_ENV;\n return env !== undefined && env !== \"production\";\n}\n","// Shared delegation base for TelemetryWeb / TelemetryNative.\n// Both platform classes lazily build a core `Telemetry` behind `instancePromise`\n// and forward every public call to it; these methods are identical across platforms.\n// Platform-specific capture (getDeviceInfo, track*, screen) stays in the subclasses\n// because each imports a different platform adapter.\n\nimport { debug } from \"./core/debug\";\n\ntype ProfileInput = {\n userId?: string;\n /** @deprecated Removed in v5 — use `identify({ name })`. */\n fullName?: string;\n /** @deprecated Removed in v5 — never reaches the wire (§3.4). */\n firstName?: string;\n /** @deprecated Removed in v5 — never reaches the wire (§3.4). */\n lastName?: string;\n email?: string;\n phone?: string;\n /** @deprecated Removed in v5 — never reaches the wire (§3.4). */\n avatar?: string;\n customAttributes?: Record<string, any>;\n};\n\nexport abstract class TelemetryBase {\n protected instancePromise!: Promise<any>;\n\n async log(event: string, data?: Record<string, any>) {\n const inst = await this.instancePromise;\n // §4.7 — **there is no public path to `app.crash`.** It is the one name an unfiltered\n // `COUNT(event_name='app.crash') / sessions` is read from, so a consumer's own code\n // must not be able to manufacture rows in it. Routed to `app.error` rather than\n // dropped: a reported error is data, it just isn't a crash. (#100)\n if (event === \"app.crash\") {\n debug.warn(\"app.crash is SDK-owned (§4.7); routing to app.error — use captureError()\");\n // The whole bag still rides as context; this only decides which key gets promoted\n // to `error.message`. `crash.message` is here for v3 callers the rename stranded.\n const message = data?.[\"error.message\"] ?? data?.[\"message\"] ?? data?.[\"crash.message\"];\n return inst.captureError(message, data);\n }\n return inst.log(event, data);\n }\n\n async flush() {\n const inst = await this.instancePromise;\n return inst.flush();\n }\n\n async shutdown() {\n const inst = await this.instancePromise;\n return inst.shutdown();\n }\n\n /**\n * React Navigation → rung 2 of the name ladder, on **both** builds (§4.5.1, #96).\n * `getCurrentRoute()` is a navigation-tree API that works identically on RN-Web, so a\n * consumer wires navigation once and gets the same `view.name` on web and native.\n */\n async attachNavigation(navigationRef: any) {\n debug.log(\"Attaching navigation tracker\");\n if (!navigationRef) {\n debug.warn(\"Navigation reference is undefined. Cannot attach navigation tracker.\");\n return;\n }\n const inst = await this.instancePromise;\n const { NavigationRefTracker } = await import(\"./adapters/navigationRef\");\n new NavigationRefTracker(inst).attach(navigationRef);\n }\n\n /**\n * §4.7 — report a handled error as `app.error`. Accepts `unknown`, so a `catch` block\n * that received a string or an axios rejection object needs no narrowing first.\n * There is no public path to `app.crash`, by design (#100).\n */\n async captureError(error: unknown, context?: Record<string, any>) {\n const inst = await this.instancePromise;\n return inst.captureError(error, context);\n }\n\n async trackErrors(options?: { captureConsole?: boolean }) {\n const { CrashHandlerNative } = await import(\"./adapters/native/crashHandlerNative.native\");\n const inst = await this.instancePromise;\n const crashHandler = new CrashHandlerNative(inst);\n return inst.trackErrors(crashHandler, options);\n }\n\n // ---------- User Profile Management ----------\n\n async setUserId(id: string) {\n const inst = await this.instancePromise;\n inst.setUserId(id);\n }\n\n async setUserProfile(profile: ProfileInput) {\n const inst = await this.instancePromise;\n inst.setUserProfile(profile);\n }\n\n async setUserDetails(details: ProfileInput) {\n const inst = await this.instancePromise;\n inst.setUserDetails(details);\n }\n\n async updateUserProfile(updates: ProfileInput) {\n const inst = await this.instancePromise;\n inst.updateUserProfile(updates);\n }\n\n async getUserProfile() {\n const inst = await this.instancePromise;\n return inst.getUserProfile();\n }\n\n async clearUserProfile() {\n const inst = await this.instancePromise;\n inst.clearUserProfile();\n }\n\n async setUserName(fullName: string, firstName?: string, lastName?: string) {\n const inst = await this.instancePromise;\n inst.setUserName(fullName, firstName, lastName);\n }\n\n async setUserContact(email?: string, phone?: string) {\n const inst = await this.instancePromise;\n inst.setUserContact(email, phone);\n }\n\n // EdgeRum-style identify(): emits `user.profile.update`, the **only** event carrying\n // `user.name` / `.email` / `.phone` / `user.custom.*` (§4.10, #107).\n // `userId` is optional and sets the consumer-owned `user.id` the profile upserts on —\n // omit it and `user.id` is untouched; the SDK still never mints one (§3.2).\n async identify(profile: { userId?: string; name?: string; email?: string; phone?: string; avatar?: string; customAttributes?: Record<string, any> }) {\n const inst = await this.instancePromise;\n return inst.identify(profile);\n }\n}\n","// Distributed trace header injection (§6.4/§6.5, #99) — the pure half: allowlist\n// normalization, `traceparent` parse/format and header reading. Shared by both builds; the\n// stateful half (attribution, which decides *which* `injected_*` rung fires) lives on\n// TraceManager, which owns the carrier.\n//\n// **`traceparent` only. No `b3`, no `tracestate`, ever.** The SDK reads exactly one header\n// name, for exactly one purpose (a presence check), and writes exactly one header name. That\n// is a sentence a consumer must be able to state during a security review, so it is enforced\n// by there being no other header name anywhere in this file.\n\nimport { debug, isDev } from \"../core/debug\";\n\n/** Lowercase on purpose: header names are compared case-insensitively (§6.4). */\nexport const TRACEPARENT = \"traceparent\";\n\n/** §6.5's ladder. Precedence is declaration order; **absent means not traced**. */\nexport type TraceOutcome =\n | \"skipped_off_allowlist\"\n | \"skipped_no_cors\" // fetch-only: `mode` is a concept XHR cannot express\n | \"skipped_consumer_set\" // consumer header present and **unparseable**\n | \"adopted\" // consumer header present and **valid**\n | \"injected_attributed\"\n | \"injected_expired\"\n | \"injected_unattributed\";\n\n// A malformed allowlist entry throws in dev and is dropped in production (§6.4) — a stated\n// divergence from Android's unconditional `require`, because a RUM SDK crashing a shipped\n// banking app over a config typo is the one failure worse than no tracing at all. `isDev`\n// itself lives in core/debug, shared with §4.8's stackTraceLimit advisory.\n\n/**\n * A **bare host**: no scheme, no path, no port, no wildcard. Ports are ignored by matching\n * too — ⚠ a deliberate mismatch with `http.host`, which keeps the port. Do not join them.\n *\n * `new URL()` does the punycode fold, so a unicode entry and a unicode URL land on the same\n * ASCII string. An IPv6 literal contains `:` and is therefore rejected; bare hosts only.\n */\nfunction normalizeHost(entry: unknown): string | undefined {\n if (typeof entry !== \"string\") return undefined;\n const raw = entry.trim();\n if (!raw || /[\\s/?#@*:]/.test(raw)) return undefined;\n try {\n const host = new URL(`http://${raw}`).hostname;\n return host || undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Constructor-only, exact match, empty by default — v4 is **dark on upgrade**, so nobody's\n * CORS breaks until they opt in. Listing a host is the consumer's assertion that that host\n * allows the header; that is why regexes and predicates were rejected rather than deferred.\n */\nexport function normalizeAllowlist(entries: unknown): ReadonlySet<string> {\n const out = new Set<string>();\n if (entries === undefined || entries === null) return out;\n if (!Array.isArray(entries)) {\n if (isDev()) throw new Error(\"traceHostAllowlist must be an array of bare hosts\");\n debug.warn(\"Telemetry: traceHostAllowlist must be an array of bare hosts — ignored\");\n return out;\n }\n for (const entry of entries) {\n const host = normalizeHost(entry);\n if (host) { out.add(host); continue; }\n if (isDev()) {\n throw new Error(\n `traceHostAllowlist: \"${String(entry)}\" is not a bare host (no scheme, path, port or wildcard)`\n );\n }\n debug.warn(`Telemetry: traceHostAllowlist entry \"${String(entry)}\" is not a bare host — dropped`);\n }\n return out;\n}\n\n/** Matching is on `hostname` — **ports ignored**, exact-only, no wildcards, no same-origin exemption. */\nexport function allowsHost(allowlist: ReadonlySet<string>, url: string): boolean {\n if (allowlist.size === 0) return false;\n const base = (globalThis as any).location?.href;\n try {\n return allowlist.has((base ? new URL(url, base) : new URL(url)).hostname);\n } catch {\n return false; // a relative URL with no base has no host to allow\n }\n}\n\n/**\n * W3C `traceparent`, version `00`. Used for exactly one decision: is the consumer's own\n * header valid (`adopted`) or not (`skipped_consumer_set`)? An all-zero trace-id or span-id\n * is invalid by the spec. ⚠ Its price, said out loud: Android *repairs* a malformed consumer\n * header; §6.4's never-strip forbids that here, so it goes out broken and is unattributed on\n * both ends — visible in the outcome distribution rather than silently fixed.\n */\nexport function parseTraceparent(value: string | null | undefined): { traceId: string; spanId: string } | undefined {\n if (typeof value !== \"string\") return undefined;\n const m = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/.exec(value.trim());\n if (!m || /^0+$/.test(m[1]) || /^0+$/.test(m[2])) return undefined;\n return { traceId: m[1], spanId: m[2] };\n}\n\n/** Flags are always `01`: an unsampled session injects no header at all, not a `flags=00` id. */\nexport function formatTraceparent(traceId: string, spanId: string): string {\n return `00-${traceId}-${spanId}-01`;\n}\n\n/** Walks every `HeadersInit` shape without needing a `Headers` constructor to exist. */\nfunction forEachHeader(headers: unknown, fn: (name: string, value: string) => void): void {\n if (!headers) return;\n if (Array.isArray(headers)) {\n for (const pair of headers) if (pair) fn(String(pair[0]), String(pair[1]));\n } else if (typeof (headers as any).forEach === \"function\") {\n (headers as any).forEach((v: string, k: string) => fn(String(k), String(v))); // Headers\n } else if (typeof headers === \"object\") {\n for (const [k, v] of Object.entries(headers as object)) fn(k, String(v));\n }\n}\n\n/** Presence check only — the one purpose §6.4's read-scope invariant permits. */\nexport function readHeader(headers: unknown, name: string): string | undefined {\n let found: string | undefined;\n forEachHeader(headers, (k, v) => { if (k.toLowerCase() === name) found = v; });\n return found;\n}\n\n/**\n * A **copy** with our header appended. The consumer's `Headers`/`Request`/object is never\n * mutated, which is how never-strip is satisfied by construction rather than by discipline.\n * An array of pairs is a valid `HeadersInit` everywhere, so no `Headers` global is required.\n */\nexport function withHeader(headers: unknown, name: string, value: string): [string, string][] {\n const out: [string, string][] = [];\n forEachHeader(headers, (k, v) => out.push([k, v]));\n out.push([name, value]);\n return out;\n}\n","import type { AsyncStore, Store, StoreRead, StoreWrite, SyncStore } from \"./store\";\n\nexport type MemoryStoreOpts = {\n /** Mirror the native build's Promise-returning shape instead of the web build's. */\n async?: boolean;\n /** Behave like incognito / a full disk: every call reports `unavailable`. */\n unavailable?: boolean;\n /** Pre-seeded contents. */\n seed?: Record<string, string>;\n};\n\n/**\n * In-memory Store (#89). A production-shaped seam that tests get to use, not a\n * test-only affordance — it ships, and it is the right injection for a consumer\n * that wants telemetry state to die with the process.\n *\n * Configurable to either build's shape so the sync/async asymmetry can be tested\n * deliberately rather than assumed away.\n */\nexport function memoryStore(opts: MemoryStoreOpts & { async: true }): AsyncStore;\nexport function memoryStore(opts?: MemoryStoreOpts & { async?: false }): SyncStore;\nexport function memoryStore(opts: MemoryStoreOpts = {}): Store {\n const map = new Map<string, string>(Object.entries(opts.seed ?? {}));\n const unavailable = opts.unavailable === true;\n\n const get = (key: string): StoreRead => {\n if (unavailable) return { status: \"unavailable\" };\n const value = map.get(key);\n return value === undefined ? { status: \"miss\" } : { status: \"hit\", value };\n };\n const set = (key: string, value: string): StoreWrite => {\n if (unavailable) return { status: \"unavailable\" };\n map.set(key, value);\n return { status: \"ok\" };\n };\n const remove = (key: string): StoreWrite => {\n if (unavailable) return { status: \"unavailable\" };\n map.delete(key);\n return { status: \"ok\" };\n };\n\n return opts.async\n ? {\n sync: false,\n get: async k => get(k),\n set: async (k, v) => set(k, v),\n remove: async k => remove(k),\n }\n : { sync: true, get, set, remove };\n}\n"],"names":["enabled","setDebug","on","debug","args","isDev","dev","env","TelemetryBase","event","data","inst","message","navigationRef","NavigationRefTracker","error","context","options","CrashHandlerNative","crashHandler","id","profile","details","updates","fullName","firstName","lastName","email","phone","TRACEPARENT","normalizeHost","entry","raw","normalizeAllowlist","entries","out","host","allowsHost","allowlist","url","base","parseTraceparent","value","m","formatTraceparent","traceId","spanId","forEachHeader","headers","fn","pair","v","k","readHeader","name","found","withHeader","memoryStore","opts","map","unavailable","get","key","set","remove"],"mappings":"aAGA,IAAIA,EAAU,GAEP,SAASC,EAASC,EAAmB,CAC1CF,EAAUE,CACZ,CAEO,MAAMC,EAAQ,CACnB,IAAK,IAAIC,IAAgB,CAAMJ,GAAS,QAAQ,IAAI,GAAGI,CAAI,CAAG,EAC9D,KAAM,IAAIA,IAAgB,CAAMJ,GAAS,QAAQ,KAAK,GAAGI,CAAI,CAAG,EAChE,MAAO,IAAIA,IAAgB,CAAMJ,GAAS,QAAQ,MAAM,GAAGI,CAAI,CAAG,CACpE,EAQO,SAASC,GAAiB,CAC/B,MAAMC,EAAO,WAAmB,QAChC,GAAI,OAAOA,GAAQ,UAAW,OAAOA,EACrC,MAAMC,EAAO,WAAmB,SAAS,KAAK,SAC9C,OAAOA,IAAQ,QAAaA,IAAQ,YACtC,CCHO,MAAeC,CAAc,CAGhC,MAAM,IAAIC,EAAeC,EAA4B,CACjD,MAAMC,EAAO,MAAM,KAAK,gBAKxB,GAAIF,IAAU,YAAa,CACvBN,EAAM,KAAK,0EAA0E,EAGrF,MAAMS,EAAUF,IAAO,eAAe,GAAKA,GAAO,SAAcA,IAAO,eAAe,EACtF,OAAOC,EAAK,aAAaC,EAASF,CAAI,CAC1C,CACA,OAAOC,EAAK,IAAIF,EAAOC,CAAI,CAC/B,CAEA,MAAM,OAAQ,CAEV,OADa,MAAM,KAAK,iBACZ,MAAA,CAChB,CAEA,MAAM,UAAW,CAEb,OADa,MAAM,KAAK,iBACZ,SAAA,CAChB,CAOA,MAAM,iBAAiBG,EAAoB,CAEvC,GADAV,EAAM,IAAI,8BAA8B,EACpC,CAACU,EAAe,CAChBV,EAAM,KAAK,sEAAsE,EACjF,MACJ,CACA,MAAMQ,EAAO,MAAM,KAAK,gBAClB,CAAE,qBAAAG,CAAA,EAAyB,MAAM,QAAA,QAAA,EAAA,KAAA,IAAA,QAAO,8BAA0B,CAAA,EACxE,IAAIA,EAAqBH,CAAI,EAAE,OAAOE,CAAa,CACvD,CAOA,MAAM,aAAaE,EAAgBC,EAA+B,CAE9D,OADa,MAAM,KAAK,iBACZ,aAAaD,EAAOC,CAAO,CAC3C,CAEA,MAAM,YAAYC,EAAwC,CACtD,KAAM,CAAE,mBAAAC,CAAA,EAAuB,MAAM,QAAA,QAAA,EAAA,KAAA,IAAA,QAAO,0CAA6C,CAAA,EACnFP,EAAO,MAAM,KAAK,gBAClBQ,EAAe,IAAID,EAAmBP,CAAI,EAChD,OAAOA,EAAK,YAAYQ,EAAcF,CAAO,CACjD,CAIA,MAAM,UAAUG,EAAY,EACX,MAAM,KAAK,iBACnB,UAAUA,CAAE,CACrB,CAEA,MAAM,eAAeC,EAAuB,EAC3B,MAAM,KAAK,iBACnB,eAAeA,CAAO,CAC/B,CAEA,MAAM,eAAeC,EAAuB,EAC3B,MAAM,KAAK,iBACnB,eAAeA,CAAO,CAC/B,CAEA,MAAM,kBAAkBC,EAAuB,EAC9B,MAAM,KAAK,iBACnB,kBAAkBA,CAAO,CAClC,CAEA,MAAM,gBAAiB,CAEnB,OADa,MAAM,KAAK,iBACZ,eAAA,CAChB,CAEA,MAAM,kBAAmB,EACR,MAAM,KAAK,iBACnB,iBAAA,CACT,CAEA,MAAM,YAAYC,EAAkBC,EAAoBC,EAAmB,EAC1D,MAAM,KAAK,iBACnB,YAAYF,EAAUC,EAAWC,CAAQ,CAClD,CAEA,MAAM,eAAeC,EAAgBC,EAAgB,EACpC,MAAM,KAAK,iBACnB,eAAeD,EAAOC,CAAK,CACpC,CAMA,MAAM,SAASP,EAAsI,CAEjJ,OADa,MAAM,KAAK,iBACZ,SAASA,CAAO,CAChC,CACJ,CC1HO,MAAMQ,EAAc,cAwB3B,SAASC,EAAcC,EAAoC,CACvD,GAAI,OAAOA,GAAU,SAAU,OAC/B,MAAMC,EAAMD,EAAM,KAAA,EAClB,GAAI,GAACC,GAAO,aAAa,KAAKA,CAAG,GACjC,GAAI,CAEA,OADa,IAAI,IAAI,UAAUA,CAAG,EAAE,EAAE,UACvB,MACnB,MAAQ,CACJ,MACJ,CACJ,CAOO,SAASC,EAAmBC,EAAuC,CACtE,MAAMC,MAAU,IAChB,GAA6BD,GAAY,KAAM,OAAOC,EACtD,GAAI,CAAC,MAAM,QAAQD,CAAO,EAAG,CACzB,GAAI7B,EAAA,EAAS,MAAM,IAAI,MAAM,mDAAmD,EAChF,OAAAF,EAAM,KAAK,wEAAwE,EAC5EgC,CACX,CACA,UAAWJ,KAASG,EAAS,CACzB,MAAME,EAAON,EAAcC,CAAK,EAChC,GAAIK,EAAM,CAAED,EAAI,IAAIC,CAAI,EAAG,QAAU,CACrC,GAAI/B,IACA,MAAM,IAAI,MACN,wBAAwB,OAAO0B,CAAK,CAAC,0DAAA,EAG7C5B,EAAM,KAAK,wCAAwC,OAAO4B,CAAK,CAAC,gCAAgC,CACpG,CACA,OAAOI,CACX,CAGO,SAASE,EAAWC,EAAgCC,EAAsB,CAC7E,GAAID,EAAU,OAAS,EAAG,MAAO,GACjC,MAAME,EAAQ,WAAmB,UAAU,KAC3C,GAAI,CACA,OAAOF,EAAU,KAAKE,EAAO,IAAI,IAAID,EAAKC,CAAI,EAAI,IAAI,IAAID,CAAG,GAAG,QAAQ,CAC5E,MAAQ,CACJ,MAAO,EACX,CACJ,CASO,SAASE,EAAiBC,EAAmF,CAChH,GAAI,OAAOA,GAAU,SAAU,OAC/B,MAAMC,EAAI,iDAAiD,KAAKD,EAAM,MAAM,EAC5E,GAAI,GAACC,GAAK,OAAO,KAAKA,EAAE,CAAC,CAAC,GAAK,OAAO,KAAKA,EAAE,CAAC,CAAC,GAC/C,MAAO,CAAE,QAASA,EAAE,CAAC,EAAG,OAAQA,EAAE,CAAC,CAAA,CACvC,CAGO,SAASC,EAAkBC,EAAiBC,EAAwB,CACvE,MAAO,MAAMD,CAAO,IAAIC,CAAM,KAClC,CAGA,SAASC,EAAcC,EAAkBC,EAAiD,CACtF,GAAKD,GACL,GAAI,MAAM,QAAQA,CAAO,EACrB,UAAWE,KAAQF,EAAaE,KAAS,OAAOA,EAAK,CAAC,CAAC,EAAG,OAAOA,EAAK,CAAC,CAAC,CAAC,UAClE,OAAQF,EAAgB,SAAY,WAC1CA,EAAgB,QAAQ,CAACG,EAAWC,IAAcH,EAAG,OAAOG,CAAC,EAAG,OAAOD,CAAC,CAAC,CAAC,UACpE,OAAOH,GAAY,SAC1B,SAAW,CAACI,EAAGD,CAAC,IAAK,OAAO,QAAQH,CAAiB,EAAGC,EAAGG,EAAG,OAAOD,CAAC,CAAC,EAE/E,CAGO,SAASE,EAAWL,EAAkBM,EAAkC,CAC3E,IAAIC,EACJ,OAAAR,EAAcC,EAAS,CAACI,EAAGD,IAAM,CAAMC,EAAE,YAAA,IAAkBE,IAAMC,EAAQJ,EAAG,CAAC,EACtEI,CACX,CAOO,SAASC,EAAWR,EAAkBM,EAAcZ,EAAmC,CAC1F,MAAMP,EAA0B,CAAA,EAChC,OAAAY,EAAcC,EAAS,CAACI,EAAGD,IAAMhB,EAAI,KAAK,CAACiB,EAAGD,CAAC,CAAC,CAAC,EACjDhB,EAAI,KAAK,CAACmB,EAAMZ,CAAK,CAAC,EACfP,CACX,CCjHO,SAASsB,EAAYC,EAAwB,GAAW,CAC3D,MAAMC,EAAM,IAAI,IAAoB,OAAO,QAAQD,EAAK,MAAQ,CAAA,CAAE,CAAC,EAC7DE,EAAcF,EAAK,cAAgB,GAEnCG,EAAOC,GAA2B,CACpC,GAAIF,EAAa,MAAO,CAAE,OAAQ,aAAA,EAClC,MAAMlB,EAAQiB,EAAI,IAAIG,CAAG,EACzB,OAAOpB,IAAU,OAAY,CAAE,OAAQ,QAAW,CAAE,OAAQ,MAAO,MAAAA,CAAA,CACvE,EACMqB,EAAM,CAACD,EAAapB,IAClBkB,EAAoB,CAAE,OAAQ,aAAA,GAClCD,EAAI,IAAIG,EAAKpB,CAAK,EACX,CAAE,OAAQ,IAAA,GAEfsB,EAAUF,GACRF,EAAoB,CAAE,OAAQ,aAAA,GAClCD,EAAI,OAAOG,CAAG,EACP,CAAE,OAAQ,IAAA,GAGrB,OAAOJ,EAAK,MACN,CACE,KAAM,GACN,IAAK,MAAMN,GAAKS,EAAIT,CAAC,EACrB,IAAK,MAAOA,EAAGD,IAAMY,EAAIX,EAAGD,CAAC,EAC7B,OAAQ,MAAMC,GAAKY,EAAOZ,CAAC,CAAA,EAE7B,CAAE,KAAM,GAAM,IAAAS,EAAK,IAAAE,EAAK,OAAAC,CAAA,CAClC"}
@@ -0,0 +1,193 @@
1
+ let u = !1;
2
+ function w(n) {
3
+ u = n;
4
+ }
5
+ const o = {
6
+ log: (...n) => {
7
+ u && console.log(...n);
8
+ },
9
+ warn: (...n) => {
10
+ u && console.warn(...n);
11
+ },
12
+ error: (...n) => {
13
+ u && console.error(...n);
14
+ }
15
+ };
16
+ function f() {
17
+ const n = globalThis.__DEV__;
18
+ if (typeof n == "boolean") return n;
19
+ const t = globalThis.process?.env?.NODE_ENV;
20
+ return t !== void 0 && t !== "production";
21
+ }
22
+ class m {
23
+ async log(t, s) {
24
+ const r = await this.instancePromise;
25
+ if (t === "app.crash") {
26
+ o.warn("app.crash is SDK-owned (§4.7); routing to app.error — use captureError()");
27
+ const e = s?.["error.message"] ?? s?.message ?? s?.["crash.message"];
28
+ return r.captureError(e, s);
29
+ }
30
+ return r.log(t, s);
31
+ }
32
+ async flush() {
33
+ return (await this.instancePromise).flush();
34
+ }
35
+ async shutdown() {
36
+ return (await this.instancePromise).shutdown();
37
+ }
38
+ /**
39
+ * React Navigation → rung 2 of the name ladder, on **both** builds (§4.5.1, #96).
40
+ * `getCurrentRoute()` is a navigation-tree API that works identically on RN-Web, so a
41
+ * consumer wires navigation once and gets the same `view.name` on web and native.
42
+ */
43
+ async attachNavigation(t) {
44
+ if (o.log("Attaching navigation tracker"), !t) {
45
+ o.warn("Navigation reference is undefined. Cannot attach navigation tracker.");
46
+ return;
47
+ }
48
+ const s = await this.instancePromise, { NavigationRefTracker: r } = await import("./navigationRef-BzYbs8cm.js");
49
+ new r(s).attach(t);
50
+ }
51
+ /**
52
+ * §4.7 — report a handled error as `app.error`. Accepts `unknown`, so a `catch` block
53
+ * that received a string or an axios rejection object needs no narrowing first.
54
+ * There is no public path to `app.crash`, by design (#100).
55
+ */
56
+ async captureError(t, s) {
57
+ return (await this.instancePromise).captureError(t, s);
58
+ }
59
+ async trackErrors(t) {
60
+ const { CrashHandlerNative: s } = await import("./crashHandlerNative.native-FupMnr1U.js"), r = await this.instancePromise, e = new s(r);
61
+ return r.trackErrors(e, t);
62
+ }
63
+ // ---------- User Profile Management ----------
64
+ async setUserId(t) {
65
+ (await this.instancePromise).setUserId(t);
66
+ }
67
+ async setUserProfile(t) {
68
+ (await this.instancePromise).setUserProfile(t);
69
+ }
70
+ async setUserDetails(t) {
71
+ (await this.instancePromise).setUserDetails(t);
72
+ }
73
+ async updateUserProfile(t) {
74
+ (await this.instancePromise).updateUserProfile(t);
75
+ }
76
+ async getUserProfile() {
77
+ return (await this.instancePromise).getUserProfile();
78
+ }
79
+ async clearUserProfile() {
80
+ (await this.instancePromise).clearUserProfile();
81
+ }
82
+ async setUserName(t, s, r) {
83
+ (await this.instancePromise).setUserName(t, s, r);
84
+ }
85
+ async setUserContact(t, s) {
86
+ (await this.instancePromise).setUserContact(t, s);
87
+ }
88
+ // EdgeRum-style identify(): emits `user.profile.update`, the **only** event carrying
89
+ // `user.name` / `.email` / `.phone` / `user.custom.*` (§4.10, #107).
90
+ // `userId` is optional and sets the consumer-owned `user.id` the profile upserts on —
91
+ // omit it and `user.id` is untouched; the SDK still never mints one (§3.2).
92
+ async identify(t) {
93
+ return (await this.instancePromise).identify(t);
94
+ }
95
+ }
96
+ const y = "traceparent";
97
+ function h(n) {
98
+ if (typeof n != "string") return;
99
+ const t = n.trim();
100
+ if (!(!t || /[\s/?#@*:]/.test(t)))
101
+ try {
102
+ return new URL(`http://${t}`).hostname || void 0;
103
+ } catch {
104
+ return;
105
+ }
106
+ }
107
+ function p(n) {
108
+ const t = /* @__PURE__ */ new Set();
109
+ if (n == null) return t;
110
+ if (!Array.isArray(n)) {
111
+ if (f()) throw new Error("traceHostAllowlist must be an array of bare hosts");
112
+ return o.warn("Telemetry: traceHostAllowlist must be an array of bare hosts — ignored"), t;
113
+ }
114
+ for (const s of n) {
115
+ const r = h(s);
116
+ if (r) {
117
+ t.add(r);
118
+ continue;
119
+ }
120
+ if (f())
121
+ throw new Error(
122
+ `traceHostAllowlist: "${String(s)}" is not a bare host (no scheme, path, port or wildcard)`
123
+ );
124
+ o.warn(`Telemetry: traceHostAllowlist entry "${String(s)}" is not a bare host — dropped`);
125
+ }
126
+ return t;
127
+ }
128
+ function g(n, t) {
129
+ if (n.size === 0) return !1;
130
+ const s = globalThis.location?.href;
131
+ try {
132
+ return n.has((s ? new URL(t, s) : new URL(t)).hostname);
133
+ } catch {
134
+ return !1;
135
+ }
136
+ }
137
+ function d(n) {
138
+ if (typeof n != "string") return;
139
+ const t = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/.exec(n.trim());
140
+ if (!(!t || /^0+$/.test(t[1]) || /^0+$/.test(t[2])))
141
+ return { traceId: t[1], spanId: t[2] };
142
+ }
143
+ function v(n, t) {
144
+ return `00-${n}-${t}-01`;
145
+ }
146
+ function l(n, t) {
147
+ if (n) {
148
+ if (Array.isArray(n))
149
+ for (const s of n) s && t(String(s[0]), String(s[1]));
150
+ else if (typeof n.forEach == "function")
151
+ n.forEach((s, r) => t(String(r), String(s)));
152
+ else if (typeof n == "object")
153
+ for (const [s, r] of Object.entries(n)) t(s, String(r));
154
+ }
155
+ }
156
+ function P(n, t) {
157
+ let s;
158
+ return l(n, (r, e) => {
159
+ r.toLowerCase() === t && (s = e);
160
+ }), s;
161
+ }
162
+ function b(n, t, s) {
163
+ const r = [];
164
+ return l(n, (e, c) => r.push([e, c])), r.push([t, s]), r;
165
+ }
166
+ function U(n = {}) {
167
+ const t = new Map(Object.entries(n.seed ?? {})), s = n.unavailable === !0, r = (a) => {
168
+ if (s) return { status: "unavailable" };
169
+ const i = t.get(a);
170
+ return i === void 0 ? { status: "miss" } : { status: "hit", value: i };
171
+ }, e = (a, i) => s ? { status: "unavailable" } : (t.set(a, i), { status: "ok" }), c = (a) => s ? { status: "unavailable" } : (t.delete(a), { status: "ok" });
172
+ return n.async ? {
173
+ sync: !1,
174
+ get: async (a) => r(a),
175
+ set: async (a, i) => e(a, i),
176
+ remove: async (a) => c(a)
177
+ } : { sync: !0, get: r, set: e, remove: c };
178
+ }
179
+ export {
180
+ m as T,
181
+ y as a,
182
+ g as b,
183
+ o as d,
184
+ v as f,
185
+ f as i,
186
+ U as m,
187
+ p as n,
188
+ d as p,
189
+ P as r,
190
+ w as s,
191
+ b as w
192
+ };
193
+ //# sourceMappingURL=memoryStore-F5I-GQKM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryStore-F5I-GQKM.js","sources":["../src/core/debug.ts","../src/index.base.ts","../src/adapters/traceHeader.ts","../src/core/memoryStore.ts"],"sourcesContent":["// SDK-internal debug gate (#23, Workstream E). Silent by default so v3 never spams the\n// host app's console; `createTelemetry({ debug: true })` flips it on. Gates log AND\n// warn/error — nothing prints unless debug is enabled.\nlet enabled = false;\n\nexport function setDebug(on: boolean): void {\n enabled = on;\n}\n\nexport const debug = {\n log: (...args: any[]) => { if (enabled) console.log(...args); },\n warn: (...args: any[]) => { if (enabled) console.warn(...args); },\n error: (...args: any[]) => { if (enabled) console.error(...args); },\n};\n\n/**\n * `__DEV__` on RN, `NODE_ENV` elsewhere. Dev-only *config* diagnostics (a malformed\n * allowlist, the `Error.stackTraceLimit` advisory) surface through this rather than the\n * `debug` gate above: they are wiring mistakes the consumer has to see while building,\n * and `debug: true` is exactly what a consumer with a wiring mistake has not set.\n */\nexport function isDev(): boolean {\n const dev = (globalThis as any).__DEV__;\n if (typeof dev === \"boolean\") return dev;\n const env = (globalThis as any).process?.env?.NODE_ENV;\n return env !== undefined && env !== \"production\";\n}\n","// Shared delegation base for TelemetryWeb / TelemetryNative.\n// Both platform classes lazily build a core `Telemetry` behind `instancePromise`\n// and forward every public call to it; these methods are identical across platforms.\n// Platform-specific capture (getDeviceInfo, track*, screen) stays in the subclasses\n// because each imports a different platform adapter.\n\nimport { debug } from \"./core/debug\";\n\ntype ProfileInput = {\n userId?: string;\n /** @deprecated Removed in v5 — use `identify({ name })`. */\n fullName?: string;\n /** @deprecated Removed in v5 — never reaches the wire (§3.4). */\n firstName?: string;\n /** @deprecated Removed in v5 — never reaches the wire (§3.4). */\n lastName?: string;\n email?: string;\n phone?: string;\n /** @deprecated Removed in v5 — never reaches the wire (§3.4). */\n avatar?: string;\n customAttributes?: Record<string, any>;\n};\n\nexport abstract class TelemetryBase {\n protected instancePromise!: Promise<any>;\n\n async log(event: string, data?: Record<string, any>) {\n const inst = await this.instancePromise;\n // §4.7 — **there is no public path to `app.crash`.** It is the one name an unfiltered\n // `COUNT(event_name='app.crash') / sessions` is read from, so a consumer's own code\n // must not be able to manufacture rows in it. Routed to `app.error` rather than\n // dropped: a reported error is data, it just isn't a crash. (#100)\n if (event === \"app.crash\") {\n debug.warn(\"app.crash is SDK-owned (§4.7); routing to app.error — use captureError()\");\n // The whole bag still rides as context; this only decides which key gets promoted\n // to `error.message`. `crash.message` is here for v3 callers the rename stranded.\n const message = data?.[\"error.message\"] ?? data?.[\"message\"] ?? data?.[\"crash.message\"];\n return inst.captureError(message, data);\n }\n return inst.log(event, data);\n }\n\n async flush() {\n const inst = await this.instancePromise;\n return inst.flush();\n }\n\n async shutdown() {\n const inst = await this.instancePromise;\n return inst.shutdown();\n }\n\n /**\n * React Navigation → rung 2 of the name ladder, on **both** builds (§4.5.1, #96).\n * `getCurrentRoute()` is a navigation-tree API that works identically on RN-Web, so a\n * consumer wires navigation once and gets the same `view.name` on web and native.\n */\n async attachNavigation(navigationRef: any) {\n debug.log(\"Attaching navigation tracker\");\n if (!navigationRef) {\n debug.warn(\"Navigation reference is undefined. Cannot attach navigation tracker.\");\n return;\n }\n const inst = await this.instancePromise;\n const { NavigationRefTracker } = await import(\"./adapters/navigationRef\");\n new NavigationRefTracker(inst).attach(navigationRef);\n }\n\n /**\n * §4.7 — report a handled error as `app.error`. Accepts `unknown`, so a `catch` block\n * that received a string or an axios rejection object needs no narrowing first.\n * There is no public path to `app.crash`, by design (#100).\n */\n async captureError(error: unknown, context?: Record<string, any>) {\n const inst = await this.instancePromise;\n return inst.captureError(error, context);\n }\n\n async trackErrors(options?: { captureConsole?: boolean }) {\n const { CrashHandlerNative } = await import(\"./adapters/native/crashHandlerNative.native\");\n const inst = await this.instancePromise;\n const crashHandler = new CrashHandlerNative(inst);\n return inst.trackErrors(crashHandler, options);\n }\n\n // ---------- User Profile Management ----------\n\n async setUserId(id: string) {\n const inst = await this.instancePromise;\n inst.setUserId(id);\n }\n\n async setUserProfile(profile: ProfileInput) {\n const inst = await this.instancePromise;\n inst.setUserProfile(profile);\n }\n\n async setUserDetails(details: ProfileInput) {\n const inst = await this.instancePromise;\n inst.setUserDetails(details);\n }\n\n async updateUserProfile(updates: ProfileInput) {\n const inst = await this.instancePromise;\n inst.updateUserProfile(updates);\n }\n\n async getUserProfile() {\n const inst = await this.instancePromise;\n return inst.getUserProfile();\n }\n\n async clearUserProfile() {\n const inst = await this.instancePromise;\n inst.clearUserProfile();\n }\n\n async setUserName(fullName: string, firstName?: string, lastName?: string) {\n const inst = await this.instancePromise;\n inst.setUserName(fullName, firstName, lastName);\n }\n\n async setUserContact(email?: string, phone?: string) {\n const inst = await this.instancePromise;\n inst.setUserContact(email, phone);\n }\n\n // EdgeRum-style identify(): emits `user.profile.update`, the **only** event carrying\n // `user.name` / `.email` / `.phone` / `user.custom.*` (§4.10, #107).\n // `userId` is optional and sets the consumer-owned `user.id` the profile upserts on —\n // omit it and `user.id` is untouched; the SDK still never mints one (§3.2).\n async identify(profile: { userId?: string; name?: string; email?: string; phone?: string; avatar?: string; customAttributes?: Record<string, any> }) {\n const inst = await this.instancePromise;\n return inst.identify(profile);\n }\n}\n","// Distributed trace header injection (§6.4/§6.5, #99) — the pure half: allowlist\n// normalization, `traceparent` parse/format and header reading. Shared by both builds; the\n// stateful half (attribution, which decides *which* `injected_*` rung fires) lives on\n// TraceManager, which owns the carrier.\n//\n// **`traceparent` only. No `b3`, no `tracestate`, ever.** The SDK reads exactly one header\n// name, for exactly one purpose (a presence check), and writes exactly one header name. That\n// is a sentence a consumer must be able to state during a security review, so it is enforced\n// by there being no other header name anywhere in this file.\n\nimport { debug, isDev } from \"../core/debug\";\n\n/** Lowercase on purpose: header names are compared case-insensitively (§6.4). */\nexport const TRACEPARENT = \"traceparent\";\n\n/** §6.5's ladder. Precedence is declaration order; **absent means not traced**. */\nexport type TraceOutcome =\n | \"skipped_off_allowlist\"\n | \"skipped_no_cors\" // fetch-only: `mode` is a concept XHR cannot express\n | \"skipped_consumer_set\" // consumer header present and **unparseable**\n | \"adopted\" // consumer header present and **valid**\n | \"injected_attributed\"\n | \"injected_expired\"\n | \"injected_unattributed\";\n\n// A malformed allowlist entry throws in dev and is dropped in production (§6.4) — a stated\n// divergence from Android's unconditional `require`, because a RUM SDK crashing a shipped\n// banking app over a config typo is the one failure worse than no tracing at all. `isDev`\n// itself lives in core/debug, shared with §4.8's stackTraceLimit advisory.\n\n/**\n * A **bare host**: no scheme, no path, no port, no wildcard. Ports are ignored by matching\n * too — ⚠ a deliberate mismatch with `http.host`, which keeps the port. Do not join them.\n *\n * `new URL()` does the punycode fold, so a unicode entry and a unicode URL land on the same\n * ASCII string. An IPv6 literal contains `:` and is therefore rejected; bare hosts only.\n */\nfunction normalizeHost(entry: unknown): string | undefined {\n if (typeof entry !== \"string\") return undefined;\n const raw = entry.trim();\n if (!raw || /[\\s/?#@*:]/.test(raw)) return undefined;\n try {\n const host = new URL(`http://${raw}`).hostname;\n return host || undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Constructor-only, exact match, empty by default — v4 is **dark on upgrade**, so nobody's\n * CORS breaks until they opt in. Listing a host is the consumer's assertion that that host\n * allows the header; that is why regexes and predicates were rejected rather than deferred.\n */\nexport function normalizeAllowlist(entries: unknown): ReadonlySet<string> {\n const out = new Set<string>();\n if (entries === undefined || entries === null) return out;\n if (!Array.isArray(entries)) {\n if (isDev()) throw new Error(\"traceHostAllowlist must be an array of bare hosts\");\n debug.warn(\"Telemetry: traceHostAllowlist must be an array of bare hosts — ignored\");\n return out;\n }\n for (const entry of entries) {\n const host = normalizeHost(entry);\n if (host) { out.add(host); continue; }\n if (isDev()) {\n throw new Error(\n `traceHostAllowlist: \"${String(entry)}\" is not a bare host (no scheme, path, port or wildcard)`\n );\n }\n debug.warn(`Telemetry: traceHostAllowlist entry \"${String(entry)}\" is not a bare host — dropped`);\n }\n return out;\n}\n\n/** Matching is on `hostname` — **ports ignored**, exact-only, no wildcards, no same-origin exemption. */\nexport function allowsHost(allowlist: ReadonlySet<string>, url: string): boolean {\n if (allowlist.size === 0) return false;\n const base = (globalThis as any).location?.href;\n try {\n return allowlist.has((base ? new URL(url, base) : new URL(url)).hostname);\n } catch {\n return false; // a relative URL with no base has no host to allow\n }\n}\n\n/**\n * W3C `traceparent`, version `00`. Used for exactly one decision: is the consumer's own\n * header valid (`adopted`) or not (`skipped_consumer_set`)? An all-zero trace-id or span-id\n * is invalid by the spec. ⚠ Its price, said out loud: Android *repairs* a malformed consumer\n * header; §6.4's never-strip forbids that here, so it goes out broken and is unattributed on\n * both ends — visible in the outcome distribution rather than silently fixed.\n */\nexport function parseTraceparent(value: string | null | undefined): { traceId: string; spanId: string } | undefined {\n if (typeof value !== \"string\") return undefined;\n const m = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/.exec(value.trim());\n if (!m || /^0+$/.test(m[1]) || /^0+$/.test(m[2])) return undefined;\n return { traceId: m[1], spanId: m[2] };\n}\n\n/** Flags are always `01`: an unsampled session injects no header at all, not a `flags=00` id. */\nexport function formatTraceparent(traceId: string, spanId: string): string {\n return `00-${traceId}-${spanId}-01`;\n}\n\n/** Walks every `HeadersInit` shape without needing a `Headers` constructor to exist. */\nfunction forEachHeader(headers: unknown, fn: (name: string, value: string) => void): void {\n if (!headers) return;\n if (Array.isArray(headers)) {\n for (const pair of headers) if (pair) fn(String(pair[0]), String(pair[1]));\n } else if (typeof (headers as any).forEach === \"function\") {\n (headers as any).forEach((v: string, k: string) => fn(String(k), String(v))); // Headers\n } else if (typeof headers === \"object\") {\n for (const [k, v] of Object.entries(headers as object)) fn(k, String(v));\n }\n}\n\n/** Presence check only — the one purpose §6.4's read-scope invariant permits. */\nexport function readHeader(headers: unknown, name: string): string | undefined {\n let found: string | undefined;\n forEachHeader(headers, (k, v) => { if (k.toLowerCase() === name) found = v; });\n return found;\n}\n\n/**\n * A **copy** with our header appended. The consumer's `Headers`/`Request`/object is never\n * mutated, which is how never-strip is satisfied by construction rather than by discipline.\n * An array of pairs is a valid `HeadersInit` everywhere, so no `Headers` global is required.\n */\nexport function withHeader(headers: unknown, name: string, value: string): [string, string][] {\n const out: [string, string][] = [];\n forEachHeader(headers, (k, v) => out.push([k, v]));\n out.push([name, value]);\n return out;\n}\n","import type { AsyncStore, Store, StoreRead, StoreWrite, SyncStore } from \"./store\";\n\nexport type MemoryStoreOpts = {\n /** Mirror the native build's Promise-returning shape instead of the web build's. */\n async?: boolean;\n /** Behave like incognito / a full disk: every call reports `unavailable`. */\n unavailable?: boolean;\n /** Pre-seeded contents. */\n seed?: Record<string, string>;\n};\n\n/**\n * In-memory Store (#89). A production-shaped seam that tests get to use, not a\n * test-only affordance — it ships, and it is the right injection for a consumer\n * that wants telemetry state to die with the process.\n *\n * Configurable to either build's shape so the sync/async asymmetry can be tested\n * deliberately rather than assumed away.\n */\nexport function memoryStore(opts: MemoryStoreOpts & { async: true }): AsyncStore;\nexport function memoryStore(opts?: MemoryStoreOpts & { async?: false }): SyncStore;\nexport function memoryStore(opts: MemoryStoreOpts = {}): Store {\n const map = new Map<string, string>(Object.entries(opts.seed ?? {}));\n const unavailable = opts.unavailable === true;\n\n const get = (key: string): StoreRead => {\n if (unavailable) return { status: \"unavailable\" };\n const value = map.get(key);\n return value === undefined ? { status: \"miss\" } : { status: \"hit\", value };\n };\n const set = (key: string, value: string): StoreWrite => {\n if (unavailable) return { status: \"unavailable\" };\n map.set(key, value);\n return { status: \"ok\" };\n };\n const remove = (key: string): StoreWrite => {\n if (unavailable) return { status: \"unavailable\" };\n map.delete(key);\n return { status: \"ok\" };\n };\n\n return opts.async\n ? {\n sync: false,\n get: async k => get(k),\n set: async (k, v) => set(k, v),\n remove: async k => remove(k),\n }\n : { sync: true, get, set, remove };\n}\n"],"names":["enabled","setDebug","on","debug","args","isDev","dev","env","TelemetryBase","event","data","inst","message","navigationRef","NavigationRefTracker","error","context","options","CrashHandlerNative","crashHandler","id","profile","details","updates","fullName","firstName","lastName","email","phone","TRACEPARENT","normalizeHost","entry","raw","normalizeAllowlist","entries","out","host","allowsHost","allowlist","url","base","parseTraceparent","value","m","formatTraceparent","traceId","spanId","forEachHeader","headers","fn","pair","v","k","readHeader","name","found","withHeader","memoryStore","opts","map","unavailable","get","key","set","remove"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("./memoryStore-BIGZmmfD.cjs"),w=require("./store.native-TPqXngmF.cjs"),t=require("./batch-DNu8Xr9T.cjs");async function l(a,n){const r=t.decodeFailed(await a.get(t.FAILED_EVENTS_KEY)),{json:e,dropped:i}=t.encodeFailed(r,n);return(await a.set(t.FAILED_EVENTS_KEY,e)).status==="unavailable"&&d.debug.warn("Telemetry could not persist failed events: storage unavailable"),i}async function E(a){const n=await a.get(t.FAILED_EVENTS_KEY);return n.status==="hit"&&await a.remove(t.FAILED_EVENTS_KEY),t.decodeFailed(n)}async function c(a,n,r,e=3){let i=0,o;for(;i<e;)try{const s=await fetch(a,{method:"POST",headers:t.buildHeaders(n),body:t.buildBatch(r)});if(!s.ok)throw d.debug.warn("Telemetry send failed with status:",s.status),new Error(`Telemetry send failed: ${s.status}`);d.debug.log("Telemetry send succeeded, events sent:",r.length??0);return}catch(s){o=s,i++,i<e&&await new Promise(u=>setTimeout(u,500*2**i+Math.random()*200))}throw o}function h(a=t.DEFAULT_ENDPOINT,n,r=w.nativeStore()){return{async send(e){await c(a,n,e)},async onFailure(e){return l(r,e)},replayFailed:t.guardedDrain(async()=>{const e=await E(r);if(e.length!==0){d.debug.log("Replaying failed events, count:",e.length);try{await c(a,n,e)}catch(i){throw await l(r,e),i}}})}}exports.nativeSender=h;
2
+ //# sourceMappingURL=nativeSender-CfQaRuDK.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeSender-CfQaRuDK.cjs","sources":["../src/adapters/nativeSender.ts"],"sourcesContent":["import { debug } from \"../core/debug\";\nimport type { TelemetryEvent, Sender } from \"../core/telemetry\";\nimport type { Store } from \"../core/store\";\nimport { nativeStore } from \"./native/store.native\";\nimport { decodeFailed, encodeFailed, guardedDrain, FAILED_EVENTS_KEY } from \"./failedEvents\";\nimport { buildBatch, buildHeaders, DEFAULT_ENDPOINT } from \"./batch\";\n\n// The offline queue goes through the Store port (#89). Unlike web, these await: on the\n// native build a write is not guaranteed to have landed when the app is killed, so the\n// crash-loss window narrows here rather than closing. That asymmetry is the port's point.\n//\n// They take the `Store` union, not `AsyncStore`. Awaiting a synchronous store is a no-op,\n// so nothing breaks if a consumer injects one — the reverse is what the types must forbid,\n// and webSender below is where that matters.\n// Returns how many rows the §9.4 cap evicted, for core's `sdk.events_dropped`.\nasync function persistFailed(store: Store, events: TelemetryEvent[]): Promise<number> {\n const existing = decodeFailed(await store.get(FAILED_EVENTS_KEY));\n const { json, dropped } = encodeFailed(existing, events);\n const written = await store.set(FAILED_EVENTS_KEY, json);\n // Storage refusing (no native module linked, full disk) is an outcome, not an error:\n // the batch is already lost, and throwing here would only lose the next one too.\n if (written.status === \"unavailable\") {\n debug.warn(\"Telemetry could not persist failed events: storage unavailable\");\n }\n return dropped;\n}\n\n// Read the queue and clear it in one step, so a replay that fails again re-persists\n// rather than double-sending on the next launch.\nasync function takeFailed(store: Store): Promise<TelemetryEvent[]> {\n const read = await store.get(FAILED_EVENTS_KEY);\n // Clear on any hit, including a payload that decoded to nothing: a half-written queue\n // is unreplayable, and keying the removal off the decoded length would make it\n // permanent as well — re-read and re-dropped on every launch, forever.\n if (read.status === \"hit\") await store.remove(FAILED_EVENTS_KEY);\n return decodeFailed(read);\n}\n\n// ⬇️ Helper: send with retries (exponential backoff + jitter)\nasync function sendWithRetry(endpoint: string, apiKey: string | undefined, events: TelemetryEvent[], retryCount: number = 3) {\n let attempts = 0;\n let lastError: any;\n\n while (attempts < retryCount) {\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: buildHeaders(apiKey),\n body: buildBatch(events),\n });\n\n if (!res.ok) {\n\n debug.warn(\"Telemetry send failed with status:\", res.status);\n throw new Error(`Telemetry send failed: ${res.status}`);\n }\n\n debug.log(\"Telemetry send succeeded, events sent:\", events.length ?? 0);\n\n return; // ✅ success\n } catch (err) {\n lastError = err;\n attempts++;\n if (attempts < retryCount) {\n // ⬇️ exponential backoff with jitter\n await new Promise(res =>\n setTimeout(res, 500 * 2 ** attempts + Math.random() * 200)\n );\n }\n }\n }\n\n // ❌ after retries still failed\n throw lastError;\n}\n\nexport function nativeSender(\n endpoint: string = DEFAULT_ENDPOINT,\n apiKey?: string,\n store: Store = nativeStore(),\n): Sender {\n return {\n async send(events) {\n // Retry + backoff here; persistence on final failure is the core flush()'s\n // job via onFailure() — kept single, so a failed batch isn't persisted twice.\n await sendWithRetry(endpoint, apiKey, events);\n },\n async onFailure(events) {\n return persistFailed(store, events);\n },\n // The single replay path on this build (#113). Core calls it once per launch from\n // its constructor; the entry no longer calls a standalone twin, which is what sent\n // every recovered batch twice.\n replayFailed: guardedDrain(async () => {\n const stored = await takeFailed(store);\n if (stored.length === 0) return;\n debug.log(\"Replaying failed events, count:\", stored.length);\n try {\n await sendWithRetry(endpoint, apiKey, stored);\n } catch (err) {\n // If replay fails again, re-store. Exactly one copy: this path never goes\n // through core's flush(), so onFailure() does not also persist it.\n await persistFailed(store, stored);\n throw err;\n }\n }),\n };\n}\n"],"names":["persistFailed","store","events","existing","decodeFailed","FAILED_EVENTS_KEY","json","dropped","encodeFailed","debug","takeFailed","read","sendWithRetry","endpoint","apiKey","retryCount","attempts","lastError","res","buildHeaders","buildBatch","err","nativeSender","DEFAULT_ENDPOINT","nativeStore","guardedDrain","stored"],"mappings":"yMAeA,eAAeA,EAAcC,EAAcC,EAA2C,CAClF,MAAMC,EAAWC,EAAAA,aAAa,MAAMH,EAAM,IAAII,EAAAA,iBAAiB,CAAC,EAC1D,CAAE,KAAAC,EAAM,QAAAC,CAAA,EAAYC,EAAAA,aAAaL,EAAUD,CAAM,EAIvD,OAHgB,MAAMD,EAAM,IAAII,EAAAA,kBAAmBC,CAAI,GAG3C,SAAW,eACnBG,EAAAA,MAAM,KAAK,gEAAgE,EAExEF,CACX,CAIA,eAAeG,EAAWT,EAAyC,CAC/D,MAAMU,EAAO,MAAMV,EAAM,IAAII,EAAAA,iBAAiB,EAI9C,OAAIM,EAAK,SAAW,OAAO,MAAMV,EAAM,OAAOI,mBAAiB,EACxDD,EAAAA,aAAaO,CAAI,CAC5B,CAGA,eAAeC,EAAcC,EAAkBC,EAA4BZ,EAA0Ba,EAAqB,EAAG,CACzH,IAAIC,EAAW,EACXC,EAEJ,KAAOD,EAAWD,GACd,GAAI,CACA,MAAMG,EAAM,MAAM,MAAML,EAAU,CAC9B,OAAQ,OACR,QAASM,EAAAA,aAAaL,CAAM,EAC5B,KAAMM,EAAAA,WAAWlB,CAAM,CAAA,CAC1B,EAED,GAAI,CAACgB,EAAI,GAELT,MAAAA,EAAAA,MAAM,KAAK,qCAAsCS,EAAI,MAAM,EACrD,IAAI,MAAM,0BAA0BA,EAAI,MAAM,EAAE,EAG1DT,EAAAA,MAAM,IAAI,yCAA0CP,EAAO,QAAU,CAAC,EAEtE,MACJ,OAASmB,EAAK,CACVJ,EAAYI,EACZL,IACIA,EAAWD,GAEX,MAAM,IAAI,QAAQG,GACd,WAAWA,EAAK,IAAM,GAAKF,EAAW,KAAK,OAAA,EAAW,GAAG,CAAA,CAGrE,CAIJ,MAAMC,CACV,CAEO,SAASK,EACZT,EAAmBU,EAAAA,iBACnBT,EACAb,EAAeuB,EAAAA,cACT,CACN,MAAO,CACH,MAAM,KAAKtB,EAAQ,CAGf,MAAMU,EAAcC,EAAUC,EAAQZ,CAAM,CAChD,EACA,MAAM,UAAUA,EAAQ,CACpB,OAAOF,EAAcC,EAAOC,CAAM,CACtC,EAIA,aAAcuB,EAAAA,aAAa,SAAY,CACnC,MAAMC,EAAS,MAAMhB,EAAWT,CAAK,EACrC,GAAIyB,EAAO,SAAW,EACtBjB,CAAAA,EAAAA,MAAM,IAAI,kCAAmCiB,EAAO,MAAM,EAC1D,GAAI,CACA,MAAMd,EAAcC,EAAUC,EAAQY,CAAM,CAChD,OAASL,EAAK,CAGV,YAAMrB,EAAcC,EAAOyB,CAAM,EAC3BL,CACV,EACJ,CAAC,CAAA,CAET"}
@@ -0,0 +1,59 @@
1
+ import { d as i } from "./memoryStore-F5I-GQKM.js";
2
+ import { nativeStore as f } from "./store.native-BYBJcy6o.js";
3
+ import { D as h, g as m, d as u, F as d, e as y, b as g, a as p } from "./batch-CwoO7noL.js";
4
+ async function l(t, a) {
5
+ const r = u(await t.get(d)), { json: e, dropped: n } = y(r, a);
6
+ return (await t.set(d, e)).status === "unavailable" && i.warn("Telemetry could not persist failed events: storage unavailable"), n;
7
+ }
8
+ async function F(t) {
9
+ const a = await t.get(d);
10
+ return a.status === "hit" && await t.remove(d), u(a);
11
+ }
12
+ async function c(t, a, r, e = 3) {
13
+ let n = 0, o;
14
+ for (; n < e; )
15
+ try {
16
+ const s = await fetch(t, {
17
+ method: "POST",
18
+ headers: p(a),
19
+ body: g(r)
20
+ });
21
+ if (!s.ok)
22
+ throw i.warn("Telemetry send failed with status:", s.status), new Error(`Telemetry send failed: ${s.status}`);
23
+ i.log("Telemetry send succeeded, events sent:", r.length ?? 0);
24
+ return;
25
+ } catch (s) {
26
+ o = s, n++, n < e && await new Promise(
27
+ (w) => setTimeout(w, 500 * 2 ** n + Math.random() * 200)
28
+ );
29
+ }
30
+ throw o;
31
+ }
32
+ function v(t = h, a, r = f()) {
33
+ return {
34
+ async send(e) {
35
+ await c(t, a, e);
36
+ },
37
+ async onFailure(e) {
38
+ return l(r, e);
39
+ },
40
+ // The single replay path on this build (#113). Core calls it once per launch from
41
+ // its constructor; the entry no longer calls a standalone twin, which is what sent
42
+ // every recovered batch twice.
43
+ replayFailed: m(async () => {
44
+ const e = await F(r);
45
+ if (e.length !== 0) {
46
+ i.log("Replaying failed events, count:", e.length);
47
+ try {
48
+ await c(t, a, e);
49
+ } catch (n) {
50
+ throw await l(r, e), n;
51
+ }
52
+ }
53
+ })
54
+ };
55
+ }
56
+ export {
57
+ v as nativeSender
58
+ };
59
+ //# sourceMappingURL=nativeSender-pgVSIv-X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeSender-pgVSIv-X.js","sources":["../src/adapters/nativeSender.ts"],"sourcesContent":["import { debug } from \"../core/debug\";\nimport type { TelemetryEvent, Sender } from \"../core/telemetry\";\nimport type { Store } from \"../core/store\";\nimport { nativeStore } from \"./native/store.native\";\nimport { decodeFailed, encodeFailed, guardedDrain, FAILED_EVENTS_KEY } from \"./failedEvents\";\nimport { buildBatch, buildHeaders, DEFAULT_ENDPOINT } from \"./batch\";\n\n// The offline queue goes through the Store port (#89). Unlike web, these await: on the\n// native build a write is not guaranteed to have landed when the app is killed, so the\n// crash-loss window narrows here rather than closing. That asymmetry is the port's point.\n//\n// They take the `Store` union, not `AsyncStore`. Awaiting a synchronous store is a no-op,\n// so nothing breaks if a consumer injects one — the reverse is what the types must forbid,\n// and webSender below is where that matters.\n// Returns how many rows the §9.4 cap evicted, for core's `sdk.events_dropped`.\nasync function persistFailed(store: Store, events: TelemetryEvent[]): Promise<number> {\n const existing = decodeFailed(await store.get(FAILED_EVENTS_KEY));\n const { json, dropped } = encodeFailed(existing, events);\n const written = await store.set(FAILED_EVENTS_KEY, json);\n // Storage refusing (no native module linked, full disk) is an outcome, not an error:\n // the batch is already lost, and throwing here would only lose the next one too.\n if (written.status === \"unavailable\") {\n debug.warn(\"Telemetry could not persist failed events: storage unavailable\");\n }\n return dropped;\n}\n\n// Read the queue and clear it in one step, so a replay that fails again re-persists\n// rather than double-sending on the next launch.\nasync function takeFailed(store: Store): Promise<TelemetryEvent[]> {\n const read = await store.get(FAILED_EVENTS_KEY);\n // Clear on any hit, including a payload that decoded to nothing: a half-written queue\n // is unreplayable, and keying the removal off the decoded length would make it\n // permanent as well — re-read and re-dropped on every launch, forever.\n if (read.status === \"hit\") await store.remove(FAILED_EVENTS_KEY);\n return decodeFailed(read);\n}\n\n// ⬇️ Helper: send with retries (exponential backoff + jitter)\nasync function sendWithRetry(endpoint: string, apiKey: string | undefined, events: TelemetryEvent[], retryCount: number = 3) {\n let attempts = 0;\n let lastError: any;\n\n while (attempts < retryCount) {\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: buildHeaders(apiKey),\n body: buildBatch(events),\n });\n\n if (!res.ok) {\n\n debug.warn(\"Telemetry send failed with status:\", res.status);\n throw new Error(`Telemetry send failed: ${res.status}`);\n }\n\n debug.log(\"Telemetry send succeeded, events sent:\", events.length ?? 0);\n\n return; // ✅ success\n } catch (err) {\n lastError = err;\n attempts++;\n if (attempts < retryCount) {\n // ⬇️ exponential backoff with jitter\n await new Promise(res =>\n setTimeout(res, 500 * 2 ** attempts + Math.random() * 200)\n );\n }\n }\n }\n\n // ❌ after retries still failed\n throw lastError;\n}\n\nexport function nativeSender(\n endpoint: string = DEFAULT_ENDPOINT,\n apiKey?: string,\n store: Store = nativeStore(),\n): Sender {\n return {\n async send(events) {\n // Retry + backoff here; persistence on final failure is the core flush()'s\n // job via onFailure() — kept single, so a failed batch isn't persisted twice.\n await sendWithRetry(endpoint, apiKey, events);\n },\n async onFailure(events) {\n return persistFailed(store, events);\n },\n // The single replay path on this build (#113). Core calls it once per launch from\n // its constructor; the entry no longer calls a standalone twin, which is what sent\n // every recovered batch twice.\n replayFailed: guardedDrain(async () => {\n const stored = await takeFailed(store);\n if (stored.length === 0) return;\n debug.log(\"Replaying failed events, count:\", stored.length);\n try {\n await sendWithRetry(endpoint, apiKey, stored);\n } catch (err) {\n // If replay fails again, re-store. Exactly one copy: this path never goes\n // through core's flush(), so onFailure() does not also persist it.\n await persistFailed(store, stored);\n throw err;\n }\n }),\n };\n}\n"],"names":["persistFailed","store","events","existing","decodeFailed","FAILED_EVENTS_KEY","json","dropped","encodeFailed","debug","takeFailed","read","sendWithRetry","endpoint","apiKey","retryCount","attempts","lastError","res","buildHeaders","buildBatch","err","nativeSender","DEFAULT_ENDPOINT","nativeStore","guardedDrain","stored"],"mappings":";;;AAeA,eAAeA,EAAcC,GAAcC,GAA2C;AAClF,QAAMC,IAAWC,EAAa,MAAMH,EAAM,IAAII,CAAiB,CAAC,GAC1D,EAAE,MAAAC,GAAM,SAAAC,EAAA,IAAYC,EAAaL,GAAUD,CAAM;AAIvD,UAHgB,MAAMD,EAAM,IAAII,GAAmBC,CAAI,GAG3C,WAAW,iBACnBG,EAAM,KAAK,gEAAgE,GAExEF;AACX;AAIA,eAAeG,EAAWT,GAAyC;AAC/D,QAAMU,IAAO,MAAMV,EAAM,IAAII,CAAiB;AAI9C,SAAIM,EAAK,WAAW,SAAO,MAAMV,EAAM,OAAOI,CAAiB,GACxDD,EAAaO,CAAI;AAC5B;AAGA,eAAeC,EAAcC,GAAkBC,GAA4BZ,GAA0Ba,IAAqB,GAAG;AACzH,MAAIC,IAAW,GACXC;AAEJ,SAAOD,IAAWD;AACd,QAAI;AACA,YAAMG,IAAM,MAAM,MAAML,GAAU;AAAA,QAC9B,QAAQ;AAAA,QACR,SAASM,EAAaL,CAAM;AAAA,QAC5B,MAAMM,EAAWlB,CAAM;AAAA,MAAA,CAC1B;AAED,UAAI,CAACgB,EAAI;AAEL,cAAAT,EAAM,KAAK,sCAAsCS,EAAI,MAAM,GACrD,IAAI,MAAM,0BAA0BA,EAAI,MAAM,EAAE;AAG1D,MAAAT,EAAM,IAAI,0CAA0CP,EAAO,UAAU,CAAC;AAEtE;AAAA,IACJ,SAASmB,GAAK;AACV,MAAAJ,IAAYI,GACZL,KACIA,IAAWD,KAEX,MAAM,IAAI;AAAA,QAAQ,CAAAG,MACd,WAAWA,GAAK,MAAM,KAAKF,IAAW,KAAK,OAAA,IAAW,GAAG;AAAA,MAAA;AAAA,IAGrE;AAIJ,QAAMC;AACV;AAEO,SAASK,EACZT,IAAmBU,GACnBT,GACAb,IAAeuB,KACT;AACN,SAAO;AAAA,IACH,MAAM,KAAKtB,GAAQ;AAGf,YAAMU,EAAcC,GAAUC,GAAQZ,CAAM;AAAA,IAChD;AAAA,IACA,MAAM,UAAUA,GAAQ;AACpB,aAAOF,EAAcC,GAAOC,CAAM;AAAA,IACtC;AAAA;AAAA;AAAA;AAAA,IAIA,cAAcuB,EAAa,YAAY;AACnC,YAAMC,IAAS,MAAMhB,EAAWT,CAAK;AACrC,UAAIyB,EAAO,WAAW,GACtB;AAAA,QAAAjB,EAAM,IAAI,mCAAmCiB,EAAO,MAAM;AAC1D,YAAI;AACA,gBAAMd,EAAcC,GAAUC,GAAQY,CAAM;AAAA,QAChD,SAASL,GAAK;AAGV,sBAAMrB,EAAcC,GAAOyB,CAAM,GAC3BL;AAAA,QACV;AAAA;AAAA,IACJ,CAAC;AAAA,EAAA;AAET;"}