@nathanclaire/edge-telemetry-sdk 3.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 (155) hide show
  1. package/README.md +348 -0
  2. package/dist/appLifecycle-Cynw0kAv.js +14 -0
  3. package/dist/appLifecycle-Cynw0kAv.js.map +1 -0
  4. package/dist/appLifecycle-DvJIt7ym.cjs +2 -0
  5. package/dist/appLifecycle-DvJIt7ym.cjs.map +1 -0
  6. package/dist/batch-CLBFgYPC.cjs +2 -0
  7. package/dist/batch-CLBFgYPC.cjs.map +1 -0
  8. package/dist/batch-DLG_gtOm.js +12 -0
  9. package/dist/batch-DLG_gtOm.js.map +1 -0
  10. package/dist/crashCapture-BYTM4FLC.cjs +2 -0
  11. package/dist/crashCapture-BYTM4FLC.cjs.map +1 -0
  12. package/dist/crashCapture-D_rkkBVa.js +31 -0
  13. package/dist/crashCapture-D_rkkBVa.js.map +1 -0
  14. package/dist/crashHandler.web-BSxDpFTo.cjs +2 -0
  15. package/dist/crashHandler.web-BSxDpFTo.cjs.map +1 -0
  16. package/dist/crashHandler.web-D59bmhg9.js +32 -0
  17. package/dist/crashHandler.web-D59bmhg9.js.map +1 -0
  18. package/dist/crashHandlerNative.native-DeAFze4E.cjs +2 -0
  19. package/dist/crashHandlerNative.native-DeAFze4E.cjs.map +1 -0
  20. package/dist/crashHandlerNative.native-d7qJkzA6.js +41 -0
  21. package/dist/crashHandlerNative.native-d7qJkzA6.js.map +1 -0
  22. package/dist/debug-DsvQ9y3W.js +68 -0
  23. package/dist/debug-DsvQ9y3W.js.map +1 -0
  24. package/dist/debug-rnOOxFpN.cjs +2 -0
  25. package/dist/debug-rnOOxFpN.cjs.map +1 -0
  26. package/dist/deviceInfo.native-7hbRYixR.cjs +2 -0
  27. package/dist/deviceInfo.native-7hbRYixR.cjs.map +1 -0
  28. package/dist/deviceInfo.native-D2k0LDhI.js +1171 -0
  29. package/dist/deviceInfo.native-D2k0LDhI.js.map +1 -0
  30. package/dist/deviceInfo.web-ByNAlEJh.cjs +2 -0
  31. package/dist/deviceInfo.web-ByNAlEJh.cjs.map +1 -0
  32. package/dist/deviceInfo.web-DzQyEku6.js +40 -0
  33. package/dist/deviceInfo.web-DzQyEku6.js.map +1 -0
  34. package/dist/frameAggregate-C_HoVFcK.cjs +2 -0
  35. package/dist/frameAggregate-C_HoVFcK.cjs.map +1 -0
  36. package/dist/frameAggregate-Cwh1juw1.js +17 -0
  37. package/dist/frameAggregate-Cwh1juw1.js.map +1 -0
  38. package/dist/frameDropsNative.native-CP7zrXDf.js +23 -0
  39. package/dist/frameDropsNative.native-CP7zrXDf.js.map +1 -0
  40. package/dist/frameDropsNative.native-DKqEDqip.cjs +2 -0
  41. package/dist/frameDropsNative.native-DKqEDqip.cjs.map +1 -0
  42. package/dist/frameDropsWeb.web-C9Lt3Fuj.js +22 -0
  43. package/dist/frameDropsWeb.web-C9Lt3Fuj.js.map +1 -0
  44. package/dist/frameDropsWeb.web-azpwQCUz.cjs +2 -0
  45. package/dist/frameDropsWeb.web-azpwQCUz.cjs.map +1 -0
  46. package/dist/httpAttributes-BV50UKQU.js +19 -0
  47. package/dist/httpAttributes-BV50UKQU.js.map +1 -0
  48. package/dist/httpAttributes-xXOD9trQ.cjs +2 -0
  49. package/dist/httpAttributes-xXOD9trQ.cjs.map +1 -0
  50. package/dist/index.native.cjs +2 -0
  51. package/dist/index.native.cjs.map +1 -0
  52. package/dist/index.native.d.ts +2 -0
  53. package/dist/index.native.js +109 -0
  54. package/dist/index.native.js.map +1 -0
  55. package/dist/index.web.cjs +2 -0
  56. package/dist/index.web.cjs.map +1 -0
  57. package/dist/index.web.d.ts +2 -0
  58. package/dist/index.web.js +80 -0
  59. package/dist/index.web.js.map +1 -0
  60. package/dist/interaction-CH8yoY5-.js +23 -0
  61. package/dist/interaction-CH8yoY5-.js.map +1 -0
  62. package/dist/interaction-DcNFBW7a.cjs +2 -0
  63. package/dist/interaction-DcNFBW7a.cjs.map +1 -0
  64. package/dist/interceptFetchNative.native-VlhtMG-U.js +49 -0
  65. package/dist/interceptFetchNative.native-VlhtMG-U.js.map +1 -0
  66. package/dist/interceptFetchNative.native-jEAldH14.cjs +2 -0
  67. package/dist/interceptFetchNative.native-jEAldH14.cjs.map +1 -0
  68. package/dist/interceptFetchWeb.web-DFzZliik.cjs +2 -0
  69. package/dist/interceptFetchWeb.web-DFzZliik.cjs.map +1 -0
  70. package/dist/interceptFetchWeb.web-DfsMfoRP.js +77 -0
  71. package/dist/interceptFetchWeb.web-DfsMfoRP.js.map +1 -0
  72. package/dist/memoryNative.native-BWLh2S9L.js +48 -0
  73. package/dist/memoryNative.native-BWLh2S9L.js.map +1 -0
  74. package/dist/memoryNative.native-DCXSOd4Q.cjs +2 -0
  75. package/dist/memoryNative.native-DCXSOd4Q.cjs.map +1 -0
  76. package/dist/memoryWeb.web-B3YuV-cB.js +48 -0
  77. package/dist/memoryWeb.web-B3YuV-cB.js.map +1 -0
  78. package/dist/memoryWeb.web-CheXAcJn.cjs +2 -0
  79. package/dist/memoryWeb.web-CheXAcJn.cjs.map +1 -0
  80. package/dist/nativeSender-BE_mzw_S.js +70 -0
  81. package/dist/nativeSender-BE_mzw_S.js.map +1 -0
  82. package/dist/nativeSender-DyAUGY7c.cjs +2 -0
  83. package/dist/nativeSender-DyAUGY7c.cjs.map +1 -0
  84. package/dist/navigationNative.native-3tO5JxSd.cjs +2 -0
  85. package/dist/navigationNative.native-3tO5JxSd.cjs.map +1 -0
  86. package/dist/navigationNative.native-BUCGPQX2.js +25 -0
  87. package/dist/navigationNative.native-BUCGPQX2.js.map +1 -0
  88. package/dist/navigationTracker-B2GMwyKk.cjs +2 -0
  89. package/dist/navigationTracker-B2GMwyKk.cjs.map +1 -0
  90. package/dist/navigationTracker-Cts68dgG.js +19 -0
  91. package/dist/navigationTracker-Cts68dgG.js.map +1 -0
  92. package/dist/navigationWeb.web-B0necr5j.cjs +2 -0
  93. package/dist/navigationWeb.web-B0necr5j.cjs.map +1 -0
  94. package/dist/navigationWeb.web-CORzE_Id.js +46 -0
  95. package/dist/navigationWeb.web-CORzE_Id.js.map +1 -0
  96. package/dist/networkChange-CUO1hRLj.cjs +2 -0
  97. package/dist/networkChange-CUO1hRLj.cjs.map +1 -0
  98. package/dist/networkChange-D39hdSb0.js +16 -0
  99. package/dist/networkChange-D39hdSb0.js.map +1 -0
  100. package/dist/networkInfo.native-BK5fpAOL.js +343 -0
  101. package/dist/networkInfo.native-BK5fpAOL.js.map +1 -0
  102. package/dist/networkInfo.native-cxuw93Uy.cjs +2 -0
  103. package/dist/networkInfo.native-cxuw93Uy.cjs.map +1 -0
  104. package/dist/networkInfo.web-DJmw1sNK.cjs +2 -0
  105. package/dist/networkInfo.web-DJmw1sNK.cjs.map +1 -0
  106. package/dist/networkInfo.web-twcNn_hc.js +32 -0
  107. package/dist/networkInfo.web-twcNn_hc.js.map +1 -0
  108. package/dist/src/adapters/appLifecycle.d.ts +15 -0
  109. package/dist/src/adapters/batch.d.ts +2 -0
  110. package/dist/src/adapters/crashCapture.d.ts +13 -0
  111. package/dist/src/adapters/frameAggregate.d.ts +12 -0
  112. package/dist/src/adapters/httpAttributes.d.ts +9 -0
  113. package/dist/src/adapters/interaction.d.ts +17 -0
  114. package/dist/src/adapters/native/crashHandlerNative.native.d.ts +9 -0
  115. package/dist/src/adapters/native/deviceInfo.native.d.ts +10 -0
  116. package/dist/src/adapters/native/frameDropsNative.native.d.ts +16 -0
  117. package/dist/src/adapters/native/interceptFetchNative.native.d.ts +23 -0
  118. package/dist/src/adapters/native/memoryNative.native.d.ts +25 -0
  119. package/dist/src/adapters/native/navigationNative.native.d.ts +12 -0
  120. package/dist/src/adapters/native/networkInfo.native.d.ts +12 -0
  121. package/dist/src/adapters/nativeSender.d.ts +3 -0
  122. package/dist/src/adapters/navigationTracker.d.ts +6 -0
  123. package/dist/src/adapters/networkChange.d.ts +15 -0
  124. package/dist/src/adapters/screenTiming.d.ts +9 -0
  125. package/dist/src/adapters/web/crashHandler.web.d.ts +9 -0
  126. package/dist/src/adapters/web/deviceInfo.web.d.ts +7 -0
  127. package/dist/src/adapters/web/frameDropsWeb.web.d.ts +16 -0
  128. package/dist/src/adapters/web/interceptFetchWeb.web.d.ts +29 -0
  129. package/dist/src/adapters/web/memoryWeb.web.d.ts +26 -0
  130. package/dist/src/adapters/web/navigationWeb.web.d.ts +29 -0
  131. package/dist/src/adapters/web/networkInfo.web.d.ts +8 -0
  132. package/dist/src/adapters/webSender.d.ts +3 -0
  133. package/dist/src/core/breadcrumbs.d.ts +12 -0
  134. package/dist/src/core/debug.d.ts +6 -0
  135. package/dist/src/core/telemetry.d.ts +233 -0
  136. package/dist/src/core/utils/uuid.d.ts +2 -0
  137. package/dist/src/createTelemetry.native.d.ts +16 -0
  138. package/dist/src/createTelemetry.web.d.ts +16 -0
  139. package/dist/src/index.base.d.ts +36 -0
  140. package/dist/src/index.native.d.ts +28 -0
  141. package/dist/src/index.web.d.ts +24 -0
  142. package/dist/src/shims/react-native-web-shim.d.ts +6 -0
  143. package/dist/telemetry-Co4MYdwa.cjs +2 -0
  144. package/dist/telemetry-Co4MYdwa.cjs.map +1 -0
  145. package/dist/telemetry-KI0x4gzC.js +389 -0
  146. package/dist/telemetry-KI0x4gzC.js.map +1 -0
  147. package/dist/v4-BysszJq8.js +31 -0
  148. package/dist/v4-BysszJq8.js.map +1 -0
  149. package/dist/v4-CqdK_b8Y.cjs +2 -0
  150. package/dist/v4-CqdK_b8Y.cjs.map +1 -0
  151. package/dist/webSender-B27tmT1w.js +42 -0
  152. package/dist/webSender-B27tmT1w.js.map +1 -0
  153. package/dist/webSender-BWi4x1df.cjs +2 -0
  154. package/dist/webSender-BWi4x1df.cjs.map +1 -0
  155. package/package.json +91 -0
package/README.md ADDED
@@ -0,0 +1,348 @@
1
+ # @nathanclaire/edge-telemetry-sdk
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@nathanclaire/edge-telemetry-sdk.svg)](https://www.npmjs.com/package/@nathanclaire/edge-telemetry-sdk)
4
+ [![React Native](https://img.shields.io/badge/React%20Native-0.64%2B-61DAFB.svg?style=flat&logo=react)](https://reactnative.dev/)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178C6.svg?style=flat&logo=typescript)](https://www.typescriptlang.org/)
6
+
7
+ A lightweight Real User Monitoring (RUM) SDK for **React Native** apps (and a web build via
8
+ React Native Web). It captures performance, errors, network requests, device/network context,
9
+ navigation and user interactions, then ships them as JSON to the shared **EdgeTelemetryProcessor**
10
+ backend — the same backend the web, Android (Ionic) and iOS SDKs feed.
11
+
12
+ One SDK, two builds. The bundler picks `index.native.js` or `index.web.js` from the
13
+ `package.json` `exports` map — you always import from `@nathanclaire/edge-telemetry-sdk`.
14
+
15
+ ---
16
+
17
+ ## Contents
18
+
19
+ - [Upgrading to v3](#upgrading-to-v3-breaking)
20
+ - [Install](#install)
21
+ - [Quick start](#quick-start)
22
+ - [Configuration](#configuration)
23
+ - [API](#api)
24
+ - [What gets captured](#what-gets-captured)
25
+ - [Wire format](#wire-format)
26
+ - [Identity & IDs](#identity--ids)
27
+ - [Reliability](#reliability)
28
+ - [Debugging](#debugging)
29
+ - [Development](#development)
30
+
31
+ ---
32
+
33
+ ## Upgrading to v3 (breaking)
34
+
35
+ v3 is a **single clean break** onto the EdgeRum wire contract — no dual-emit, no v2 fallback.
36
+ If you're coming from v2, the headlines:
37
+
38
+ - `createTelemetry({ apiKey, endpoint, ... })` — **`apiKey` is now required** (must start with
39
+ `edge_`; sent as `X-API-Key`; init throws otherwise).
40
+ - The POST body is the `telemetry_batch` envelope; timestamps are ISO-8601; device/network data
41
+ rides as a Context block on **every** event (the standalone `device_info`/`network_info`
42
+ events are gone).
43
+ - Several event names changed and only the allowlist ships (`network_request` → `http.request`,
44
+ `screen_view` → `navigation`, …); other `log()` names arrive as `custom_event`.
45
+ - New `debug` option (default `false`) silences all SDK console output.
46
+
47
+ Full breaking-change list and migration checklist: **[CHANGELOG.md](./CHANGELOG.md)**.
48
+
49
+ ---
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ npm install @nathanclaire/edge-telemetry-sdk
55
+ ```
56
+
57
+ ### React Native peer dependencies
58
+
59
+ Native capture relies on these (install in your app):
60
+
61
+ ```bash
62
+ npm install @react-native-async-storage/async-storage react-native-device-info @react-native-community/netinfo
63
+ cd ios && pod install
64
+ ```
65
+
66
+ | Peer dep | Used for |
67
+ |---|---|
68
+ | `@react-native-async-storage/async-storage` | persisted replay of failed batches |
69
+ | `react-native-device-info` | `device.*` context (optional — degrades gracefully) |
70
+ | `@react-native-community/netinfo` | `network.*` context + `network_change` |
71
+
72
+ The **web build** uses browser APIs (`navigator`, `localStorage`) and needs none of the above.
73
+
74
+ ---
75
+
76
+ ## Quick start
77
+
78
+ `createTelemetry()` returns a `TelemetryNative` or `TelemetryWeb` instance — the bundler chooses.
79
+ **Every public method is `async`** (each awaits a lazily-built core), so `await` your calls.
80
+
81
+ ### React Native
82
+
83
+ ```typescript
84
+ import { createTelemetry } from "@nathanclaire/edge-telemetry-sdk";
85
+
86
+ const telemetry = createTelemetry({
87
+ apiKey: "edge_xxxxxxxx", // required; must start with "edge_"
88
+ endpoint: "https://collector.example.com/collector/telemetry", // full POST URL, used verbatim
89
+ batchSize: 20,
90
+ flushIntervalMs: 10000,
91
+ });
92
+
93
+ await telemetry.log("checkout_started", { cart_value: 42 });
94
+ ```
95
+
96
+ ### React Web
97
+
98
+ ```typescript
99
+ import { createTelemetry } from "@nathanclaire/edge-telemetry-sdk";
100
+
101
+ const telemetry = createTelemetry({
102
+ apiKey: "edge_xxxxxxxx",
103
+ endpoint: "https://collector.example.com/collector/telemetry",
104
+ batchSize: 20,
105
+ flushIntervalMs: 10000,
106
+ });
107
+
108
+ await telemetry.log("checkout_started", { cart_value: 42 });
109
+ ```
110
+
111
+ Once constructed, the SDK **auto-starts** its collectors — you don't wire them up: session start,
112
+ crash/error capture, HTTP interception, frame + memory sampling, app foreground/background, and
113
+ (web) navigation. You only opt in to navigation and interaction capture on native (below).
114
+
115
+ ---
116
+
117
+ ## Configuration
118
+
119
+ ```typescript
120
+ type TelemetryOpts = {
121
+ apiKey: string; // REQUIRED — must start with "edge_"; sent as X-API-Key
122
+ endpoint?: string; // full collector POST URL (used verbatim). Default is a placeholder — always set it
123
+ batchSize?: number; // events per flush. Core default 2 — set higher (e.g. 20) for production
124
+ flushIntervalMs?: number; // periodic flush. Default 10000; <= 0 disables the timer
125
+ captureConsole?: boolean; // funnel console.error/warn into app.crash. Default on (opt-out)
126
+ debug?: boolean; // SDK-internal console diagnostics. Default false (silent)
127
+ sender?: Sender; // override the transport (mainly for tests)
128
+ };
129
+ ```
130
+
131
+ - **`apiKey`** is validated at `createTelemetry()` — a key not starting with `edge_` throws
132
+ immediately, so misconfiguration fails fast instead of silently dropping data. `tenant_id`
133
+ is never sent; the backend resolves the tenant from the key.
134
+ - **`endpoint`** is the exact URL the SDK POSTs to. Point it at your collector's telemetry path.
135
+
136
+ ---
137
+
138
+ ## API
139
+
140
+ All methods return Promises. Available on both platforms unless marked **native-only**.
141
+
142
+ ### Core
143
+
144
+ ```typescript
145
+ log(event: string, data?: Record<string, any>): Promise<void> // custom event (see allowlist note)
146
+ flush(): Promise<void> // force-send the queue now
147
+ shutdown(): Promise<void> // clear the flush timer + final flush
148
+ ```
149
+
150
+ > **Allowlist note:** only the allowlisted event names reach the backend as-is. Any other name
151
+ > you pass to `log()` is shipped as `custom_event` with your original name in
152
+ > `attributes["event.name"]` — so custom events are preserved, not dropped.
153
+
154
+ ### Identity
155
+
156
+ ```typescript
157
+ identify(profile: { // EdgeRum-style — emits user.profile.update,
158
+ name?: string; email?: string; // attaches identity to subsequent events, and
159
+ phone?: string; avatar?: string; // PRESERVES the anonymous user.id
160
+ customAttributes?: Record<string, any>;
161
+ }): Promise<void>
162
+
163
+ setUserId(id: string): Promise<void>
164
+ generateUserId(): Promise<string>
165
+ setUserProfile(profile): Promise<void>
166
+ setUserDetails(details): Promise<void> // fullName/firstName/lastName/email/phone/avatar/customAttributes
167
+ updateUserProfile(updates): Promise<void>
168
+ getUserProfile(): Promise<UserProfile | undefined>
169
+ clearUserProfile(): Promise<void>
170
+ setUserName(fullName, firstName?, lastName?): Promise<void>
171
+ setUserContact(email?, phone?): Promise<void>
172
+ ```
173
+
174
+ ```typescript
175
+ await telemetry.identify({ name: "Ada Lovelace", email: "ada@example.com" });
176
+ ```
177
+
178
+ ### Context accessors
179
+
180
+ ```typescript
181
+ getDeviceInfo(): Promise<DeviceInfo>
182
+ getNetworkInfo(): Promise<NetworkInfo>
183
+ ```
184
+
185
+ ### Navigation & screens — **native-only**
186
+
187
+ ```typescript
188
+ attachNavigation(navigationRef): Promise<void> // React Navigation container ref → auto route tracking
189
+ trackRoute(from: string, to: string): Promise<void>
190
+ screenStart(name: string): Promise<void> // → navigation
191
+ screenEnd(name: string): Promise<void> // → screen.duration (dwell ms)
192
+ ```
193
+
194
+ ```typescript
195
+ import { NavigationContainer, useNavigationContainerRef } from "@react-navigation/native";
196
+
197
+ const navRef = useNavigationContainerRef();
198
+ // after the container mounts:
199
+ await telemetry.attachNavigation(navRef);
200
+ ```
201
+
202
+ On **web**, navigation is auto-tracked (History API) — no wiring needed.
203
+
204
+ ### User interactions (taps) — **native-only, best-effort**
205
+
206
+ Native has no global tap stream, so the SDK gives you responder props to spread on your app root.
207
+ Each tap emits `user.interaction` with `interaction.type` and the current screen when known. It
208
+ observes the gesture without stealing it (no DOM `target_tag`/`target_class` — those are web-only).
209
+
210
+ ```tsx
211
+ function Root() {
212
+ const [props, setProps] = React.useState({});
213
+ React.useEffect(() => { telemetry.interactionProps().then(setProps); }, []);
214
+ return <View style={{ flex: 1 }} {...props}><App /></View>;
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## What gets captured
221
+
222
+ Auto-started in the constructor (both platforms unless noted):
223
+
224
+ | Signal | `eventName` / `metricName` | Type |
225
+ |---|---|---|
226
+ | Session start / end | `session.started`, `session.finalized` | event |
227
+ | App foreground/background | `app_lifecycle` | event |
228
+ | Route change / screen entry | `navigation` | event |
229
+ | Screen dwell time | `screen.duration` | event |
230
+ | HTTP request (fetch/XHR) | `http.request` | event |
231
+ | Connectivity change | `network_change` | event |
232
+ | JS error / crash / (opt-out) console errors | `app.crash` | event |
233
+ | Identity update via `identify()` | `user.profile.update` | event |
234
+ | Tap (native, best-effort) | `user.interaction` | event |
235
+ | Custom `log()` name (non-allowlisted) | `custom_event` | event |
236
+ | Memory sample | `memory_usage` | metric |
237
+ | Frame render window | `frame_render_time` | metric |
238
+
239
+ `app.crash` carries a `cause` discriminator and `crash.breadcrumbs` (last 20 actions,
240
+ JSON-stringified). Sessions rotate after 30 minutes of inactivity; `session.finalized` flushes
241
+ immediately and includes a journey summary + `sdk.error_count`.
242
+
243
+ **Web-only signals** (`page_load`, `resource_timing`, `long_task`, and Web Vitals
244
+ LCP/FCP/CLS/INP/TTFB) are emitted only by the web build — native never reports metrics it can't
245
+ honestly measure.
246
+
247
+ ---
248
+
249
+ ## Wire format
250
+
251
+ ```
252
+ POST <endpoint>
253
+ Content-Type: application/json
254
+ X-API-Key: edge_xxxxxxxx
255
+
256
+ {
257
+ "type": "telemetry_batch",
258
+ "timestamp": "2026-07-02T06:00:00.000Z", // ISO 8601
259
+ "batch_size": 3,
260
+ "events": [ /* TelemetryEvent, ... */ ]
261
+ }
262
+ ```
263
+
264
+ Each event/metric:
265
+
266
+ ```typescript
267
+ type TelemetryEvent = {
268
+ type: "event" | "metric";
269
+ eventName?: string; // events
270
+ metricName?: string; // metrics
271
+ value?: number; // metrics
272
+ timestamp: string; // ISO 8601
273
+ attributes?: Record<string, any>; // flat, dot-namespaced — includes the Context block
274
+ };
275
+ ```
276
+
277
+ Every record carries the flattened **Context block** in `attributes`: `app.*`, `device.*`,
278
+ `network.*`, `session.*`, `user.id`, and `sdk.*` (`sdk.platform = "react-native"`,
279
+ `sdk.version`). This makes each record self-describing and joinable without correlating against
280
+ separate context events.
281
+
282
+ ---
283
+
284
+ ## Identity & IDs
285
+
286
+ IDs use 16 hex chars of entropy; device/session are suffixed with the device OS, user is not:
287
+
288
+ ```
289
+ device_{ms}_{16hex}_{ios|android}
290
+ session_{ms}_{16hex}_{ios|android}
291
+ user_{ms}_{16hex}
292
+ ```
293
+
294
+ Conform to `^(session|device|user)_\d+_[0-9a-f]{16}(_(ios|android))?$`. The **web build** omits
295
+ the OS suffix (`device.platform = "web"` still rides as an attribute).
296
+
297
+ `identify()` attaches host-app identity (`user.name`/`email`/`phone`) to subsequent events and
298
+ emits one `user.profile.update` — it never changes the SDK-owned anonymous `user.id`.
299
+
300
+ ---
301
+
302
+ ## Reliability
303
+
304
+ - **Batching:** events queue and flush when `batchSize` is reached or every `flushIntervalMs`.
305
+ - **Retry:** failed sends retry with exponential backoff + jitter.
306
+ - **Persisted replay:** after final failure, batches are persisted (AsyncStorage on native,
307
+ `localStorage` on web, key `telemetry_failed_events`) and replayed on next init — telemetry
308
+ survives transient network loss.
309
+ - **Web unload:** the web sender uses `fetch({ keepalive: true })` (not `sendBeacon`, which can't
310
+ set the required `X-API-Key` header) so in-flight batches survive page unload.
311
+
312
+ ---
313
+
314
+ ## Debugging
315
+
316
+ The SDK is **silent by default**. To see its internal diagnostics while developing:
317
+
318
+ ```typescript
319
+ createTelemetry({ apiKey: "edge_xxx", endpoint: "...", debug: true });
320
+ ```
321
+
322
+ `debug: true` routes the SDK's `log`/`warn`/`error` to the console; with it off (the default),
323
+ the SDK writes nothing to the host app's console.
324
+
325
+ ---
326
+
327
+ ## Development
328
+
329
+ ```bash
330
+ npm run build # vite build → dist/ (web + native entries, ESM + CJS)
331
+ npm run dev # vite in watch mode
332
+ npm test # vitest run
333
+ npm run typecheck # tsc --noEmit
334
+ npm run clean # remove dist/
335
+ ```
336
+
337
+ `dist/` and `*.tgz` are git-ignored — `dist/` is regenerated by the build and published via the
338
+ `package.json` `files` list. `prepare` runs the build, so installing this as a git dependency
339
+ builds it automatically.
340
+
341
+ Platform code is split by filename (`*.native.ts` / `*.web.ts`), not by runtime branching — the
342
+ bundler selects the file. When adding a capability, keep the native and web adapters in lockstep.
343
+
344
+ ---
345
+
346
+ ## License
347
+
348
+ ISC
@@ -0,0 +1,14 @@
1
+ class c {
2
+ constructor(t) {
3
+ this.telemetry = t;
4
+ }
5
+ onState(t) {
6
+ this.active !== void 0 && this.active !== t && this.telemetry.log("app_lifecycle", {
7
+ "app_lifecycle.state": t ? "foreground" : "background"
8
+ }), this.active = t;
9
+ }
10
+ }
11
+ export {
12
+ c as AppLifecycleEmitter
13
+ };
14
+ //# sourceMappingURL=appLifecycle-Cynw0kAv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appLifecycle-Cynw0kAv.js","sources":["../src/adapters/appLifecycle.ts"],"sourcesContent":["import { Telemetry } from \"../core/telemetry\";\n\n/**\n * Shared foreground/background emitter — the single source of truth so the native\n * (RN AppState) and web (visibilitychange) lifecycle adapters stay in lockstep on the\n * v3 `app_lifecycle` contract (#30).\n *\n * Feed it the current active state via `onState(isActive)`. It emits `app_lifecycle` only\n * on a transition, carrying the direction as `app_lifecycle.state` (foreground|background).\n */\nexport class AppLifecycleEmitter {\n private active?: boolean;\n\n constructor(private telemetry: Telemetry) {}\n\n onState(isActive: boolean): void {\n if (this.active !== undefined && this.active !== isActive) {\n this.telemetry.log(\"app_lifecycle\", {\n \"app_lifecycle.state\": isActive ? \"foreground\" : \"background\",\n });\n }\n this.active = isActive;\n }\n}\n"],"names":["AppLifecycleEmitter","telemetry","isActive"],"mappings":"AAUO,MAAMA,EAAoB;AAAA,EAG/B,YAAoBC,GAAsB;AAAtB,SAAA,YAAAA;AAAA,EAAuB;AAAA,EAE3C,QAAQC,GAAyB;AAC/B,IAAI,KAAK,WAAW,UAAa,KAAK,WAAWA,KAC/C,KAAK,UAAU,IAAI,iBAAiB;AAAA,MAClC,uBAAuBA,IAAW,eAAe;AAAA,IAAA,CAClD,GAEH,KAAK,SAASA;AAAA,EAChB;AACF;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class t{constructor(e){this.telemetry=e}onState(e){this.active!==void 0&&this.active!==e&&this.telemetry.log("app_lifecycle",{"app_lifecycle.state":e?"foreground":"background"}),this.active=e}}exports.AppLifecycleEmitter=t;
2
+ //# sourceMappingURL=appLifecycle-DvJIt7ym.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appLifecycle-DvJIt7ym.cjs","sources":["../src/adapters/appLifecycle.ts"],"sourcesContent":["import { Telemetry } from \"../core/telemetry\";\n\n/**\n * Shared foreground/background emitter — the single source of truth so the native\n * (RN AppState) and web (visibilitychange) lifecycle adapters stay in lockstep on the\n * v3 `app_lifecycle` contract (#30).\n *\n * Feed it the current active state via `onState(isActive)`. It emits `app_lifecycle` only\n * on a transition, carrying the direction as `app_lifecycle.state` (foreground|background).\n */\nexport class AppLifecycleEmitter {\n private active?: boolean;\n\n constructor(private telemetry: Telemetry) {}\n\n onState(isActive: boolean): void {\n if (this.active !== undefined && this.active !== isActive) {\n this.telemetry.log(\"app_lifecycle\", {\n \"app_lifecycle.state\": isActive ? \"foreground\" : \"background\",\n });\n }\n this.active = isActive;\n }\n}\n"],"names":["AppLifecycleEmitter","telemetry","isActive"],"mappings":"gFAUO,MAAMA,CAAoB,CAG/B,YAAoBC,EAAsB,CAAtB,KAAA,UAAAA,CAAuB,CAE3C,QAAQC,EAAyB,CAC3B,KAAK,SAAW,QAAa,KAAK,SAAWA,GAC/C,KAAK,UAAU,IAAI,gBAAiB,CAClC,sBAAuBA,EAAW,aAAe,YAAA,CAClD,EAEH,KAAK,OAASA,CAChB,CACF"}
@@ -0,0 +1,2 @@
1
+ "use strict";function e(t){return JSON.stringify({type:"telemetry_batch",timestamp:new Date().toISOString(),batch_size:t.length,events:t})}exports.buildBatch=e;
2
+ //# sourceMappingURL=batch-CLBFgYPC.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-CLBFgYPC.cjs","sources":["../src/adapters/batch.ts"],"sourcesContent":["import type { TelemetryEvent } from \"../core/telemetry\";\n\n// v3 wire envelope. Shared by both senders so the web and native POST bodies\n// stay byte-identical to the EdgeRum telemetry_batch contract.\nexport function buildBatch(events: TelemetryEvent[]): string {\n return JSON.stringify({\n type: \"telemetry_batch\",\n timestamp: new Date().toISOString(),\n batch_size: events.length,\n events,\n });\n}\n"],"names":["buildBatch","events"],"mappings":"aAIO,SAASA,EAAWC,EAAkC,CACzD,OAAO,KAAK,UAAU,CAClB,KAAM,kBACN,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,WAAYA,EAAO,OACnB,OAAAA,CAAA,CACH,CACL"}
@@ -0,0 +1,12 @@
1
+ function e(t) {
2
+ return JSON.stringify({
3
+ type: "telemetry_batch",
4
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5
+ batch_size: t.length,
6
+ events: t
7
+ });
8
+ }
9
+ export {
10
+ e as b
11
+ };
12
+ //# sourceMappingURL=batch-DLG_gtOm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-DLG_gtOm.js","sources":["../src/adapters/batch.ts"],"sourcesContent":["import type { TelemetryEvent } from \"../core/telemetry\";\n\n// v3 wire envelope. Shared by both senders so the web and native POST bodies\n// stay byte-identical to the EdgeRum telemetry_batch contract.\nexport function buildBatch(events: TelemetryEvent[]): string {\n return JSON.stringify({\n type: \"telemetry_batch\",\n timestamp: new Date().toISOString(),\n batch_size: events.length,\n events,\n });\n}\n"],"names":["buildBatch","events"],"mappings":"AAIO,SAASA,EAAWC,GAAkC;AACzD,SAAO,KAAK,UAAU;AAAA,IAClB,MAAM;AAAA,IACN,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,IACtB,YAAYA,EAAO;AAAA,IACnB,QAAAA;AAAA,EAAA,CACH;AACL;"}
@@ -0,0 +1,2 @@
1
+ "use strict";function l(n,r={}){const s={"crash.cause":n,"crash.message":r.message??null,"crash.stacktrace":r.stacktrace??null};return r.fatal!==void 0&&(s["crash.fatal"]=r.fatal),s}function u(n,r=console){const s=r.error.bind(r),o=r.warn.bind(r);let a=!1;const c=(t,i)=>(...e)=>{if(!a){a=!0;try{n.log("app.crash",l(t,{message:e.map(String).join(" ")}))}finally{a=!1}}i(...e)};return r.error=c("ConsoleError",s),r.warn=c("ConsoleWarn",o),()=>{r.error=s,r.warn=o}}exports.buildCrashAttributes=l;exports.captureConsole=u;
2
+ //# sourceMappingURL=crashCapture-BYTM4FLC.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashCapture-BYTM4FLC.cjs","sources":["../src/adapters/crashCapture.ts"],"sourcesContent":["import { Telemetry } from \"../core/telemetry\";\n\n// One `app.crash` stream, segmented by cause (lifts the iOS ADR-010 model). #28\nexport type CrashCause = \"Error\" | \"UnhandledRejection\" | \"ConsoleError\" | \"ConsoleWarn\";\n\nexport function buildCrashAttributes(\n cause: CrashCause,\n fields: { message?: unknown; stacktrace?: unknown; fatal?: boolean } = {},\n): Record<string, any> {\n const attrs: Record<string, any> = {\n \"crash.cause\": cause,\n \"crash.message\": fields.message ?? null,\n \"crash.stacktrace\": fields.stacktrace ?? null,\n };\n if (fields.fatal !== undefined) attrs[\"crash.fatal\"] = fields.fatal;\n return attrs;\n}\n\n/**\n * Patch console.error/warn to funnel into `app.crash` (cause ConsoleError/ConsoleWarn).\n * Opt-out: callers only invoke this when console capture is enabled. Returns a restore fn.\n * A reentrancy guard prevents the SDK's own console writes during logging from re-capturing.\n */\nexport function captureConsole(\n telemetry: Telemetry,\n target: Pick<Console, \"error\" | \"warn\"> = console,\n): () => void {\n const origError = target.error.bind(target);\n const origWarn = target.warn.bind(target);\n let inside = false;\n\n const make = (cause: CrashCause, orig: (...a: any[]) => void) =>\n (...args: any[]) => {\n if (!inside) {\n inside = true;\n try {\n telemetry.log(\"app.crash\", buildCrashAttributes(cause, { message: args.map(String).join(\" \") }));\n } finally {\n inside = false;\n }\n }\n orig(...args);\n };\n\n target.error = make(\"ConsoleError\", origError);\n target.warn = make(\"ConsoleWarn\", origWarn);\n\n return () => { target.error = origError; target.warn = origWarn; };\n}\n"],"names":["buildCrashAttributes","cause","fields","attrs","captureConsole","telemetry","target","origError","origWarn","inside","make","orig","args"],"mappings":"aAKO,SAASA,EACdC,EACAC,EAAuE,GAClD,CACrB,MAAMC,EAA6B,CACjC,cAAeF,EACf,gBAAiBC,EAAO,SAAW,KACnC,mBAAoBA,EAAO,YAAc,IAAA,EAE3C,OAAIA,EAAO,QAAU,SAAWC,EAAM,aAAa,EAAID,EAAO,OACvDC,CACT,CAOO,SAASC,EACdC,EACAC,EAA0C,QAC9B,CACZ,MAAMC,EAAYD,EAAO,MAAM,KAAKA,CAAM,EACpCE,EAAWF,EAAO,KAAK,KAAKA,CAAM,EACxC,IAAIG,EAAS,GAEb,MAAMC,EAAO,CAACT,EAAmBU,IAC/B,IAAIC,IAAgB,CAClB,GAAI,CAACH,EAAQ,CACXA,EAAS,GACT,GAAI,CACFJ,EAAU,IAAI,YAAaL,EAAqBC,EAAO,CAAE,QAASW,EAAK,IAAI,MAAM,EAAE,KAAK,GAAG,CAAA,CAAG,CAAC,CACjG,QAAA,CACEH,EAAS,EACX,CACF,CACAE,EAAK,GAAGC,CAAI,CACd,EAEF,OAAAN,EAAO,MAAQI,EAAK,eAAgBH,CAAS,EAC7CD,EAAO,KAAOI,EAAK,cAAeF,CAAQ,EAEnC,IAAM,CAAEF,EAAO,MAAQC,EAAWD,EAAO,KAAOE,CAAU,CACnE"}
@@ -0,0 +1,31 @@
1
+ function t(n, r = {}) {
2
+ const a = {
3
+ "crash.cause": n,
4
+ "crash.message": r.message ?? null,
5
+ "crash.stacktrace": r.stacktrace ?? null
6
+ };
7
+ return r.fatal !== void 0 && (a["crash.fatal"] = r.fatal), a;
8
+ }
9
+ function u(n, r = console) {
10
+ const a = r.error.bind(r), o = r.warn.bind(r);
11
+ let s = !1;
12
+ const c = (l, i) => (...e) => {
13
+ if (!s) {
14
+ s = !0;
15
+ try {
16
+ n.log("app.crash", t(l, { message: e.map(String).join(" ") }));
17
+ } finally {
18
+ s = !1;
19
+ }
20
+ }
21
+ i(...e);
22
+ };
23
+ return r.error = c("ConsoleError", a), r.warn = c("ConsoleWarn", o), () => {
24
+ r.error = a, r.warn = o;
25
+ };
26
+ }
27
+ export {
28
+ t as b,
29
+ u as c
30
+ };
31
+ //# sourceMappingURL=crashCapture-D_rkkBVa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashCapture-D_rkkBVa.js","sources":["../src/adapters/crashCapture.ts"],"sourcesContent":["import { Telemetry } from \"../core/telemetry\";\n\n// One `app.crash` stream, segmented by cause (lifts the iOS ADR-010 model). #28\nexport type CrashCause = \"Error\" | \"UnhandledRejection\" | \"ConsoleError\" | \"ConsoleWarn\";\n\nexport function buildCrashAttributes(\n cause: CrashCause,\n fields: { message?: unknown; stacktrace?: unknown; fatal?: boolean } = {},\n): Record<string, any> {\n const attrs: Record<string, any> = {\n \"crash.cause\": cause,\n \"crash.message\": fields.message ?? null,\n \"crash.stacktrace\": fields.stacktrace ?? null,\n };\n if (fields.fatal !== undefined) attrs[\"crash.fatal\"] = fields.fatal;\n return attrs;\n}\n\n/**\n * Patch console.error/warn to funnel into `app.crash` (cause ConsoleError/ConsoleWarn).\n * Opt-out: callers only invoke this when console capture is enabled. Returns a restore fn.\n * A reentrancy guard prevents the SDK's own console writes during logging from re-capturing.\n */\nexport function captureConsole(\n telemetry: Telemetry,\n target: Pick<Console, \"error\" | \"warn\"> = console,\n): () => void {\n const origError = target.error.bind(target);\n const origWarn = target.warn.bind(target);\n let inside = false;\n\n const make = (cause: CrashCause, orig: (...a: any[]) => void) =>\n (...args: any[]) => {\n if (!inside) {\n inside = true;\n try {\n telemetry.log(\"app.crash\", buildCrashAttributes(cause, { message: args.map(String).join(\" \") }));\n } finally {\n inside = false;\n }\n }\n orig(...args);\n };\n\n target.error = make(\"ConsoleError\", origError);\n target.warn = make(\"ConsoleWarn\", origWarn);\n\n return () => { target.error = origError; target.warn = origWarn; };\n}\n"],"names":["buildCrashAttributes","cause","fields","attrs","captureConsole","telemetry","target","origError","origWarn","inside","make","orig","args"],"mappings":"AAKO,SAASA,EACdC,GACAC,IAAuE,IAClD;AACrB,QAAMC,IAA6B;AAAA,IACjC,eAAeF;AAAA,IACf,iBAAiBC,EAAO,WAAW;AAAA,IACnC,oBAAoBA,EAAO,cAAc;AAAA,EAAA;AAE3C,SAAIA,EAAO,UAAU,WAAWC,EAAM,aAAa,IAAID,EAAO,QACvDC;AACT;AAOO,SAASC,EACdC,GACAC,IAA0C,SAC9B;AACZ,QAAMC,IAAYD,EAAO,MAAM,KAAKA,CAAM,GACpCE,IAAWF,EAAO,KAAK,KAAKA,CAAM;AACxC,MAAIG,IAAS;AAEb,QAAMC,IAAO,CAACT,GAAmBU,MAC/B,IAAIC,MAAgB;AAClB,QAAI,CAACH,GAAQ;AACX,MAAAA,IAAS;AACT,UAAI;AACF,QAAAJ,EAAU,IAAI,aAAaL,EAAqBC,GAAO,EAAE,SAASW,EAAK,IAAI,MAAM,EAAE,KAAK,GAAG,EAAA,CAAG,CAAC;AAAA,MACjG,UAAA;AACE,QAAAH,IAAS;AAAA,MACX;AAAA,IACF;AACA,IAAAE,EAAK,GAAGC,CAAI;AAAA,EACd;AAEF,SAAAN,EAAO,QAAQI,EAAK,gBAAgBH,CAAS,GAC7CD,EAAO,OAAOI,EAAK,eAAeF,CAAQ,GAEnC,MAAM;AAAE,IAAAF,EAAO,QAAQC,GAAWD,EAAO,OAAOE;AAAA,EAAU;AACnE;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./crashCapture-BYTM4FLC.cjs");class c{constructor(t){this.telemetry=t}attach(t={}){const{captureConsole:a=!0}=t;return new Promise((o,n)=>{try{window.onerror=(e,i,h,u,s)=>{this.telemetry.log("app.crash",r.buildCrashAttributes("Error",{message:s?.message??e,stacktrace:s?.stack}))},window.onunhandledrejection=e=>{this.telemetry.log("app.crash",r.buildCrashAttributes("UnhandledRejection",{message:e.reason?.message??"Unhandled Promise Rejection",stacktrace:e.reason?.stack}))},a&&r.captureConsole(this.telemetry),o()}catch(e){n(e)}})}}exports.CrashHandler=c;
2
+ //# sourceMappingURL=crashHandler.web-BSxDpFTo.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashHandler.web-BSxDpFTo.cjs","sources":["../src/adapters/web/crashHandler.web.ts"],"sourcesContent":["import { Telemetry } from \"../../core/telemetry\";\nimport { buildCrashAttributes, captureConsole } from \"../crashCapture\";\n\nexport type CrashHandlerOptions = { captureConsole?: boolean };\n\nexport class CrashHandler {\n constructor(private telemetry: Telemetry) { }\n\n // Lockstep with native: funnels JS errors, unhandled rejections and (opt-out)\n // console.error/warn into one `app.crash` stream keyed by `crash.cause`. #28\n attach(options: CrashHandlerOptions = {}): Promise<void> {\n const { captureConsole: consoleEnabled = true } = options;\n return new Promise((resolve, reject) => {\n try {\n window.onerror = (msg, _url, _line, _col, error) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"Error\", {\n message: error?.message ?? msg,\n stacktrace: error?.stack,\n }));\n };\n\n window.onunhandledrejection = (event) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"UnhandledRejection\", {\n message: event.reason?.message ?? \"Unhandled Promise Rejection\",\n stacktrace: event.reason?.stack,\n }));\n };\n\n if (consoleEnabled) captureConsole(this.telemetry);\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n}\n"],"names":["CrashHandler","telemetry","options","consoleEnabled","resolve","reject","msg","_url","_line","_col","error","buildCrashAttributes","event","captureConsole"],"mappings":"+HAKO,MAAMA,CAAa,CACtB,YAAoBC,EAAsB,CAAtB,KAAA,UAAAA,CAAwB,CAI5C,OAAOC,EAA+B,GAAmB,CACrD,KAAM,CAAE,eAAgBC,EAAiB,EAAA,EAASD,EAClD,OAAO,IAAI,QAAQ,CAACE,EAASC,IAAW,CACpC,GAAI,CACA,OAAO,QAAU,CAACC,EAAKC,EAAMC,EAAOC,EAAMC,IAAU,CAChD,KAAK,UAAU,IAAI,YAAaC,EAAAA,qBAAqB,QAAS,CAC1D,QAASD,GAAO,SAAWJ,EAC3B,WAAYI,GAAO,KAAA,CACtB,CAAC,CACN,EAEA,OAAO,qBAAwBE,GAAU,CACrC,KAAK,UAAU,IAAI,YAAaD,EAAAA,qBAAqB,qBAAsB,CACvE,QAASC,EAAM,QAAQ,SAAW,8BAClC,WAAYA,EAAM,QAAQ,KAAA,CAC7B,CAAC,CACN,EAEIT,GAAgBU,EAAAA,eAAe,KAAK,SAAS,EAEjDT,EAAA,CACJ,OAASM,EAAO,CACZL,EAAOK,CAAK,CAChB,CACJ,CAAC,CACL,CACJ"}
@@ -0,0 +1,32 @@
1
+ import { b as s, c } from "./crashCapture-D_rkkBVa.js";
2
+ class u {
3
+ constructor(t) {
4
+ this.telemetry = t;
5
+ }
6
+ // Lockstep with native: funnels JS errors, unhandled rejections and (opt-out)
7
+ // console.error/warn into one `app.crash` stream keyed by `crash.cause`. #28
8
+ attach(t = {}) {
9
+ const { captureConsole: a = !0 } = t;
10
+ return new Promise((o, n) => {
11
+ try {
12
+ window.onerror = (e, i, h, m, r) => {
13
+ this.telemetry.log("app.crash", s("Error", {
14
+ message: r?.message ?? e,
15
+ stacktrace: r?.stack
16
+ }));
17
+ }, window.onunhandledrejection = (e) => {
18
+ this.telemetry.log("app.crash", s("UnhandledRejection", {
19
+ message: e.reason?.message ?? "Unhandled Promise Rejection",
20
+ stacktrace: e.reason?.stack
21
+ }));
22
+ }, a && c(this.telemetry), o();
23
+ } catch (e) {
24
+ n(e);
25
+ }
26
+ });
27
+ }
28
+ }
29
+ export {
30
+ u as CrashHandler
31
+ };
32
+ //# sourceMappingURL=crashHandler.web-D59bmhg9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashHandler.web-D59bmhg9.js","sources":["../src/adapters/web/crashHandler.web.ts"],"sourcesContent":["import { Telemetry } from \"../../core/telemetry\";\nimport { buildCrashAttributes, captureConsole } from \"../crashCapture\";\n\nexport type CrashHandlerOptions = { captureConsole?: boolean };\n\nexport class CrashHandler {\n constructor(private telemetry: Telemetry) { }\n\n // Lockstep with native: funnels JS errors, unhandled rejections and (opt-out)\n // console.error/warn into one `app.crash` stream keyed by `crash.cause`. #28\n attach(options: CrashHandlerOptions = {}): Promise<void> {\n const { captureConsole: consoleEnabled = true } = options;\n return new Promise((resolve, reject) => {\n try {\n window.onerror = (msg, _url, _line, _col, error) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"Error\", {\n message: error?.message ?? msg,\n stacktrace: error?.stack,\n }));\n };\n\n window.onunhandledrejection = (event) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"UnhandledRejection\", {\n message: event.reason?.message ?? \"Unhandled Promise Rejection\",\n stacktrace: event.reason?.stack,\n }));\n };\n\n if (consoleEnabled) captureConsole(this.telemetry);\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n}\n"],"names":["CrashHandler","telemetry","options","consoleEnabled","resolve","reject","msg","_url","_line","_col","error","buildCrashAttributes","event","captureConsole"],"mappings":";AAKO,MAAMA,EAAa;AAAA,EACtB,YAAoBC,GAAsB;AAAtB,SAAA,YAAAA;AAAA,EAAwB;AAAA;AAAA;AAAA,EAI5C,OAAOC,IAA+B,IAAmB;AACrD,UAAM,EAAE,gBAAgBC,IAAiB,GAAA,IAASD;AAClD,WAAO,IAAI,QAAQ,CAACE,GAASC,MAAW;AACpC,UAAI;AACA,eAAO,UAAU,CAACC,GAAKC,GAAMC,GAAOC,GAAMC,MAAU;AAChD,eAAK,UAAU,IAAI,aAAaC,EAAqB,SAAS;AAAA,YAC1D,SAASD,GAAO,WAAWJ;AAAA,YAC3B,YAAYI,GAAO;AAAA,UAAA,CACtB,CAAC;AAAA,QACN,GAEA,OAAO,uBAAuB,CAACE,MAAU;AACrC,eAAK,UAAU,IAAI,aAAaD,EAAqB,sBAAsB;AAAA,YACvE,SAASC,EAAM,QAAQ,WAAW;AAAA,YAClC,YAAYA,EAAM,QAAQ;AAAA,UAAA,CAC7B,CAAC;AAAA,QACN,GAEIT,KAAgBU,EAAe,KAAK,SAAS,GAEjDT,EAAA;AAAA,MACJ,SAASM,GAAO;AACZ,QAAAL,EAAOK,CAAK;AAAA,MAChB;AAAA,IACJ,CAAC;AAAA,EACL;AACJ;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("./crashCapture-BYTM4FLC.cjs");class c{constructor(s){this.telemetry=s}attach(s={}){const{captureConsole:l=!0}=s;return new Promise((o,i)=>{try{if(typeof ErrorUtils<"u"&&ErrorUtils.setGlobalHandler){const e=ErrorUtils.getGlobalHandler?.();ErrorUtils.setGlobalHandler((r,a)=>{this.telemetry.log("app.crash",n.buildCrashAttributes("Error",{message:r?.message,stacktrace:r?.stack,fatal:a})),e&&e(r,a)})}const t=e=>{this.telemetry.log("app.crash",n.buildCrashAttributes("UnhandledRejection",{message:e?.reason?.message??"Unhandled Promise Rejection",stacktrace:e?.reason?.stack}))};globalThis.addEventListener?globalThis.addEventListener("unhandledrejection",t):require("promise/setimmediate/rejection-tracking").enable({allRejections:!0,onUnhandled:(r,a)=>t({reason:a})}),l&&n.captureConsole(this.telemetry),o()}catch(t){i(t)}})}}exports.CrashHandlerNative=c;
2
+ //# sourceMappingURL=crashHandlerNative.native-DeAFze4E.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashHandlerNative.native-DeAFze4E.cjs","sources":["../src/adapters/native/crashHandlerNative.native.ts"],"sourcesContent":["import { Telemetry } from \"../../core/telemetry\";\nimport { buildCrashAttributes, captureConsole } from \"../crashCapture\";\n\nexport type CrashHandlerOptions = { captureConsole?: boolean };\n\nexport class CrashHandlerNative {\n constructor(private telemetry: Telemetry) { }\n\n // Funnels JS errors, unhandled rejections and (opt-out) console.error/warn into one\n // `app.crash` stream keyed by `crash.cause`. Console capture defaults on (opt-out). #28\n attach(options: CrashHandlerOptions = {}): Promise<void> {\n const { captureConsole: consoleEnabled = true } = options;\n return new Promise((resolve, reject) => {\n try {\n if (typeof ErrorUtils !== \"undefined\" && ErrorUtils.setGlobalHandler) {\n const defaultHandler = ErrorUtils.getGlobalHandler?.();\n ErrorUtils.setGlobalHandler((error: any, isFatal?: boolean) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"Error\", {\n message: error?.message,\n stacktrace: error?.stack,\n fatal: isFatal,\n }));\n if (defaultHandler) defaultHandler(error, isFatal); // keep RN red screen in dev\n });\n }\n\n const onRejection = (event: any) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"UnhandledRejection\", {\n message: event?.reason?.message ?? \"Unhandled Promise Rejection\",\n stacktrace: event?.reason?.stack,\n }));\n };\n\n if (globalThis.addEventListener) {\n globalThis.addEventListener(\"unhandledrejection\", onRejection);\n } else {\n const tracking = require(\"promise/setimmediate/rejection-tracking\");\n tracking.enable({\n allRejections: true,\n onUnhandled: (_id: any, error: any) =>\n onRejection({ reason: error }),\n });\n }\n\n if (consoleEnabled) captureConsole(this.telemetry);\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n}\n"],"names":["CrashHandlerNative","telemetry","options","consoleEnabled","resolve","reject","defaultHandler","error","isFatal","buildCrashAttributes","onRejection","event","_id","captureConsole"],"mappings":"+HAKO,MAAMA,CAAmB,CAC5B,YAAoBC,EAAsB,CAAtB,KAAA,UAAAA,CAAwB,CAI5C,OAAOC,EAA+B,GAAmB,CACrD,KAAM,CAAE,eAAgBC,EAAiB,EAAA,EAASD,EAClD,OAAO,IAAI,QAAQ,CAACE,EAASC,IAAW,CACpC,GAAI,CACA,GAAI,OAAO,WAAe,KAAe,WAAW,iBAAkB,CAClE,MAAMC,EAAiB,WAAW,mBAAA,EAClC,WAAW,iBAAiB,CAACC,EAAYC,IAAsB,CAC3D,KAAK,UAAU,IAAI,YAAaC,EAAAA,qBAAqB,QAAS,CAC1D,QAASF,GAAO,QAChB,WAAYA,GAAO,MACnB,MAAOC,CAAA,CACV,CAAC,EACEF,GAAgBA,EAAeC,EAAOC,CAAO,CACrD,CAAC,CACL,CAEA,MAAME,EAAeC,GAAe,CAChC,KAAK,UAAU,IAAI,YAAaF,EAAAA,qBAAqB,qBAAsB,CACvE,QAASE,GAAO,QAAQ,SAAW,8BACnC,WAAYA,GAAO,QAAQ,KAAA,CAC9B,CAAC,CACN,EAEI,WAAW,iBACX,WAAW,iBAAiB,qBAAsBD,CAAW,EAE5C,QAAQ,yCAAyC,EACzD,OAAO,CACZ,cAAe,GACf,YAAa,CAACE,EAAUL,IACpBG,EAAY,CAAE,OAAQH,EAAO,CAAA,CACpC,EAGDJ,GAAgBU,EAAAA,eAAe,KAAK,SAAS,EAEjDT,EAAA,CACJ,OAASG,EAAO,CACZF,EAAOE,CAAK,CAChB,CACJ,CAAC,CACL,CACJ"}
@@ -0,0 +1,41 @@
1
+ import { b as n, c } from "./crashCapture-D_rkkBVa.js";
2
+ class m {
3
+ constructor(s) {
4
+ this.telemetry = s;
5
+ }
6
+ // Funnels JS errors, unhandled rejections and (opt-out) console.error/warn into one
7
+ // `app.crash` stream keyed by `crash.cause`. Console capture defaults on (opt-out). #28
8
+ attach(s = {}) {
9
+ const { captureConsole: l = !0 } = s;
10
+ return new Promise((o, i) => {
11
+ try {
12
+ if (typeof ErrorUtils < "u" && ErrorUtils.setGlobalHandler) {
13
+ const e = ErrorUtils.getGlobalHandler?.();
14
+ ErrorUtils.setGlobalHandler((r, a) => {
15
+ this.telemetry.log("app.crash", n("Error", {
16
+ message: r?.message,
17
+ stacktrace: r?.stack,
18
+ fatal: a
19
+ })), e && e(r, a);
20
+ });
21
+ }
22
+ const t = (e) => {
23
+ this.telemetry.log("app.crash", n("UnhandledRejection", {
24
+ message: e?.reason?.message ?? "Unhandled Promise Rejection",
25
+ stacktrace: e?.reason?.stack
26
+ }));
27
+ };
28
+ globalThis.addEventListener ? globalThis.addEventListener("unhandledrejection", t) : require("promise/setimmediate/rejection-tracking").enable({
29
+ allRejections: !0,
30
+ onUnhandled: (r, a) => t({ reason: a })
31
+ }), l && c(this.telemetry), o();
32
+ } catch (t) {
33
+ i(t);
34
+ }
35
+ });
36
+ }
37
+ }
38
+ export {
39
+ m as CrashHandlerNative
40
+ };
41
+ //# sourceMappingURL=crashHandlerNative.native-d7qJkzA6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crashHandlerNative.native-d7qJkzA6.js","sources":["../src/adapters/native/crashHandlerNative.native.ts"],"sourcesContent":["import { Telemetry } from \"../../core/telemetry\";\nimport { buildCrashAttributes, captureConsole } from \"../crashCapture\";\n\nexport type CrashHandlerOptions = { captureConsole?: boolean };\n\nexport class CrashHandlerNative {\n constructor(private telemetry: Telemetry) { }\n\n // Funnels JS errors, unhandled rejections and (opt-out) console.error/warn into one\n // `app.crash` stream keyed by `crash.cause`. Console capture defaults on (opt-out). #28\n attach(options: CrashHandlerOptions = {}): Promise<void> {\n const { captureConsole: consoleEnabled = true } = options;\n return new Promise((resolve, reject) => {\n try {\n if (typeof ErrorUtils !== \"undefined\" && ErrorUtils.setGlobalHandler) {\n const defaultHandler = ErrorUtils.getGlobalHandler?.();\n ErrorUtils.setGlobalHandler((error: any, isFatal?: boolean) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"Error\", {\n message: error?.message,\n stacktrace: error?.stack,\n fatal: isFatal,\n }));\n if (defaultHandler) defaultHandler(error, isFatal); // keep RN red screen in dev\n });\n }\n\n const onRejection = (event: any) => {\n this.telemetry.log(\"app.crash\", buildCrashAttributes(\"UnhandledRejection\", {\n message: event?.reason?.message ?? \"Unhandled Promise Rejection\",\n stacktrace: event?.reason?.stack,\n }));\n };\n\n if (globalThis.addEventListener) {\n globalThis.addEventListener(\"unhandledrejection\", onRejection);\n } else {\n const tracking = require(\"promise/setimmediate/rejection-tracking\");\n tracking.enable({\n allRejections: true,\n onUnhandled: (_id: any, error: any) =>\n onRejection({ reason: error }),\n });\n }\n\n if (consoleEnabled) captureConsole(this.telemetry);\n\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n}\n"],"names":["CrashHandlerNative","telemetry","options","consoleEnabled","resolve","reject","defaultHandler","error","isFatal","buildCrashAttributes","onRejection","event","_id","captureConsole"],"mappings":";AAKO,MAAMA,EAAmB;AAAA,EAC5B,YAAoBC,GAAsB;AAAtB,SAAA,YAAAA;AAAA,EAAwB;AAAA;AAAA;AAAA,EAI5C,OAAOC,IAA+B,IAAmB;AACrD,UAAM,EAAE,gBAAgBC,IAAiB,GAAA,IAASD;AAClD,WAAO,IAAI,QAAQ,CAACE,GAASC,MAAW;AACpC,UAAI;AACA,YAAI,OAAO,aAAe,OAAe,WAAW,kBAAkB;AAClE,gBAAMC,IAAiB,WAAW,mBAAA;AAClC,qBAAW,iBAAiB,CAACC,GAAYC,MAAsB;AAC3D,iBAAK,UAAU,IAAI,aAAaC,EAAqB,SAAS;AAAA,cAC1D,SAASF,GAAO;AAAA,cAChB,YAAYA,GAAO;AAAA,cACnB,OAAOC;AAAA,YAAA,CACV,CAAC,GACEF,KAAgBA,EAAeC,GAAOC,CAAO;AAAA,UACrD,CAAC;AAAA,QACL;AAEA,cAAME,IAAc,CAACC,MAAe;AAChC,eAAK,UAAU,IAAI,aAAaF,EAAqB,sBAAsB;AAAA,YACvE,SAASE,GAAO,QAAQ,WAAW;AAAA,YACnC,YAAYA,GAAO,QAAQ;AAAA,UAAA,CAC9B,CAAC;AAAA,QACN;AAEA,QAAI,WAAW,mBACX,WAAW,iBAAiB,sBAAsBD,CAAW,IAE5C,QAAQ,yCAAyC,EACzD,OAAO;AAAA,UACZ,eAAe;AAAA,UACf,aAAa,CAACE,GAAUL,MACpBG,EAAY,EAAE,QAAQH,GAAO;AAAA,QAAA,CACpC,GAGDJ,KAAgBU,EAAe,KAAK,SAAS,GAEjDT,EAAA;AAAA,MACJ,SAASG,GAAO;AACZ,QAAAF,EAAOE,CAAK;AAAA,MAChB;AAAA,IACJ,CAAC;AAAA,EACL;AACJ;"}
@@ -0,0 +1,68 @@
1
+ class r {
2
+ async log(s, t) {
3
+ return (await this.instancePromise).log(s, t);
4
+ }
5
+ async flush() {
6
+ return (await this.instancePromise).flush();
7
+ }
8
+ async shutdown() {
9
+ return (await this.instancePromise).shutdown();
10
+ }
11
+ async trackErrors(s) {
12
+ const { CrashHandlerNative: t } = await import("./crashHandlerNative.native-d7qJkzA6.js"), e = await this.instancePromise, a = new t(e);
13
+ return e.trackErrors(a, s);
14
+ }
15
+ // ---------- User Profile Management ----------
16
+ async setUserId(s) {
17
+ (await this.instancePromise).setUserId(s);
18
+ }
19
+ async generateUserId() {
20
+ return (await this.instancePromise).generateUserId();
21
+ }
22
+ async setUserProfile(s) {
23
+ (await this.instancePromise).setUserProfile(s);
24
+ }
25
+ async setUserDetails(s) {
26
+ (await this.instancePromise).setUserDetails(s);
27
+ }
28
+ async updateUserProfile(s) {
29
+ (await this.instancePromise).updateUserProfile(s);
30
+ }
31
+ async getUserProfile() {
32
+ return (await this.instancePromise).getUserProfile();
33
+ }
34
+ async clearUserProfile() {
35
+ (await this.instancePromise).clearUserProfile();
36
+ }
37
+ async setUserName(s, t, e) {
38
+ (await this.instancePromise).setUserName(s, t, e);
39
+ }
40
+ async setUserContact(s, t) {
41
+ (await this.instancePromise).setUserContact(s, t);
42
+ }
43
+ // EdgeRum-style identify(): emits user.profile.update, preserves the anonymous user.id (#31)
44
+ async identify(s) {
45
+ return (await this.instancePromise).identify(s);
46
+ }
47
+ }
48
+ let i = !1;
49
+ function o(n) {
50
+ i = n;
51
+ }
52
+ const c = {
53
+ log: (...n) => {
54
+ i && console.log(...n);
55
+ },
56
+ warn: (...n) => {
57
+ i && console.warn(...n);
58
+ },
59
+ error: (...n) => {
60
+ i && console.error(...n);
61
+ }
62
+ };
63
+ export {
64
+ r as T,
65
+ c as d,
66
+ o as s
67
+ };
68
+ //# sourceMappingURL=debug-DsvQ9y3W.js.map