@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.
- package/README.md +348 -0
- package/dist/appLifecycle-Cynw0kAv.js +14 -0
- package/dist/appLifecycle-Cynw0kAv.js.map +1 -0
- package/dist/appLifecycle-DvJIt7ym.cjs +2 -0
- package/dist/appLifecycle-DvJIt7ym.cjs.map +1 -0
- package/dist/batch-CLBFgYPC.cjs +2 -0
- package/dist/batch-CLBFgYPC.cjs.map +1 -0
- package/dist/batch-DLG_gtOm.js +12 -0
- package/dist/batch-DLG_gtOm.js.map +1 -0
- package/dist/crashCapture-BYTM4FLC.cjs +2 -0
- package/dist/crashCapture-BYTM4FLC.cjs.map +1 -0
- package/dist/crashCapture-D_rkkBVa.js +31 -0
- package/dist/crashCapture-D_rkkBVa.js.map +1 -0
- package/dist/crashHandler.web-BSxDpFTo.cjs +2 -0
- package/dist/crashHandler.web-BSxDpFTo.cjs.map +1 -0
- package/dist/crashHandler.web-D59bmhg9.js +32 -0
- package/dist/crashHandler.web-D59bmhg9.js.map +1 -0
- package/dist/crashHandlerNative.native-DeAFze4E.cjs +2 -0
- package/dist/crashHandlerNative.native-DeAFze4E.cjs.map +1 -0
- package/dist/crashHandlerNative.native-d7qJkzA6.js +41 -0
- package/dist/crashHandlerNative.native-d7qJkzA6.js.map +1 -0
- package/dist/debug-DsvQ9y3W.js +68 -0
- package/dist/debug-DsvQ9y3W.js.map +1 -0
- package/dist/debug-rnOOxFpN.cjs +2 -0
- package/dist/debug-rnOOxFpN.cjs.map +1 -0
- package/dist/deviceInfo.native-7hbRYixR.cjs +2 -0
- package/dist/deviceInfo.native-7hbRYixR.cjs.map +1 -0
- package/dist/deviceInfo.native-D2k0LDhI.js +1171 -0
- package/dist/deviceInfo.native-D2k0LDhI.js.map +1 -0
- package/dist/deviceInfo.web-ByNAlEJh.cjs +2 -0
- package/dist/deviceInfo.web-ByNAlEJh.cjs.map +1 -0
- package/dist/deviceInfo.web-DzQyEku6.js +40 -0
- package/dist/deviceInfo.web-DzQyEku6.js.map +1 -0
- package/dist/frameAggregate-C_HoVFcK.cjs +2 -0
- package/dist/frameAggregate-C_HoVFcK.cjs.map +1 -0
- package/dist/frameAggregate-Cwh1juw1.js +17 -0
- package/dist/frameAggregate-Cwh1juw1.js.map +1 -0
- package/dist/frameDropsNative.native-CP7zrXDf.js +23 -0
- package/dist/frameDropsNative.native-CP7zrXDf.js.map +1 -0
- package/dist/frameDropsNative.native-DKqEDqip.cjs +2 -0
- package/dist/frameDropsNative.native-DKqEDqip.cjs.map +1 -0
- package/dist/frameDropsWeb.web-C9Lt3Fuj.js +22 -0
- package/dist/frameDropsWeb.web-C9Lt3Fuj.js.map +1 -0
- package/dist/frameDropsWeb.web-azpwQCUz.cjs +2 -0
- package/dist/frameDropsWeb.web-azpwQCUz.cjs.map +1 -0
- package/dist/httpAttributes-BV50UKQU.js +19 -0
- package/dist/httpAttributes-BV50UKQU.js.map +1 -0
- package/dist/httpAttributes-xXOD9trQ.cjs +2 -0
- package/dist/httpAttributes-xXOD9trQ.cjs.map +1 -0
- package/dist/index.native.cjs +2 -0
- package/dist/index.native.cjs.map +1 -0
- package/dist/index.native.d.ts +2 -0
- package/dist/index.native.js +109 -0
- package/dist/index.native.js.map +1 -0
- package/dist/index.web.cjs +2 -0
- package/dist/index.web.cjs.map +1 -0
- package/dist/index.web.d.ts +2 -0
- package/dist/index.web.js +80 -0
- package/dist/index.web.js.map +1 -0
- package/dist/interaction-CH8yoY5-.js +23 -0
- package/dist/interaction-CH8yoY5-.js.map +1 -0
- package/dist/interaction-DcNFBW7a.cjs +2 -0
- package/dist/interaction-DcNFBW7a.cjs.map +1 -0
- package/dist/interceptFetchNative.native-VlhtMG-U.js +49 -0
- package/dist/interceptFetchNative.native-VlhtMG-U.js.map +1 -0
- package/dist/interceptFetchNative.native-jEAldH14.cjs +2 -0
- package/dist/interceptFetchNative.native-jEAldH14.cjs.map +1 -0
- package/dist/interceptFetchWeb.web-DFzZliik.cjs +2 -0
- package/dist/interceptFetchWeb.web-DFzZliik.cjs.map +1 -0
- package/dist/interceptFetchWeb.web-DfsMfoRP.js +77 -0
- package/dist/interceptFetchWeb.web-DfsMfoRP.js.map +1 -0
- package/dist/memoryNative.native-BWLh2S9L.js +48 -0
- package/dist/memoryNative.native-BWLh2S9L.js.map +1 -0
- package/dist/memoryNative.native-DCXSOd4Q.cjs +2 -0
- package/dist/memoryNative.native-DCXSOd4Q.cjs.map +1 -0
- package/dist/memoryWeb.web-B3YuV-cB.js +48 -0
- package/dist/memoryWeb.web-B3YuV-cB.js.map +1 -0
- package/dist/memoryWeb.web-CheXAcJn.cjs +2 -0
- package/dist/memoryWeb.web-CheXAcJn.cjs.map +1 -0
- package/dist/nativeSender-BE_mzw_S.js +70 -0
- package/dist/nativeSender-BE_mzw_S.js.map +1 -0
- package/dist/nativeSender-DyAUGY7c.cjs +2 -0
- package/dist/nativeSender-DyAUGY7c.cjs.map +1 -0
- package/dist/navigationNative.native-3tO5JxSd.cjs +2 -0
- package/dist/navigationNative.native-3tO5JxSd.cjs.map +1 -0
- package/dist/navigationNative.native-BUCGPQX2.js +25 -0
- package/dist/navigationNative.native-BUCGPQX2.js.map +1 -0
- package/dist/navigationTracker-B2GMwyKk.cjs +2 -0
- package/dist/navigationTracker-B2GMwyKk.cjs.map +1 -0
- package/dist/navigationTracker-Cts68dgG.js +19 -0
- package/dist/navigationTracker-Cts68dgG.js.map +1 -0
- package/dist/navigationWeb.web-B0necr5j.cjs +2 -0
- package/dist/navigationWeb.web-B0necr5j.cjs.map +1 -0
- package/dist/navigationWeb.web-CORzE_Id.js +46 -0
- package/dist/navigationWeb.web-CORzE_Id.js.map +1 -0
- package/dist/networkChange-CUO1hRLj.cjs +2 -0
- package/dist/networkChange-CUO1hRLj.cjs.map +1 -0
- package/dist/networkChange-D39hdSb0.js +16 -0
- package/dist/networkChange-D39hdSb0.js.map +1 -0
- package/dist/networkInfo.native-BK5fpAOL.js +343 -0
- package/dist/networkInfo.native-BK5fpAOL.js.map +1 -0
- package/dist/networkInfo.native-cxuw93Uy.cjs +2 -0
- package/dist/networkInfo.native-cxuw93Uy.cjs.map +1 -0
- package/dist/networkInfo.web-DJmw1sNK.cjs +2 -0
- package/dist/networkInfo.web-DJmw1sNK.cjs.map +1 -0
- package/dist/networkInfo.web-twcNn_hc.js +32 -0
- package/dist/networkInfo.web-twcNn_hc.js.map +1 -0
- package/dist/src/adapters/appLifecycle.d.ts +15 -0
- package/dist/src/adapters/batch.d.ts +2 -0
- package/dist/src/adapters/crashCapture.d.ts +13 -0
- package/dist/src/adapters/frameAggregate.d.ts +12 -0
- package/dist/src/adapters/httpAttributes.d.ts +9 -0
- package/dist/src/adapters/interaction.d.ts +17 -0
- package/dist/src/adapters/native/crashHandlerNative.native.d.ts +9 -0
- package/dist/src/adapters/native/deviceInfo.native.d.ts +10 -0
- package/dist/src/adapters/native/frameDropsNative.native.d.ts +16 -0
- package/dist/src/adapters/native/interceptFetchNative.native.d.ts +23 -0
- package/dist/src/adapters/native/memoryNative.native.d.ts +25 -0
- package/dist/src/adapters/native/navigationNative.native.d.ts +12 -0
- package/dist/src/adapters/native/networkInfo.native.d.ts +12 -0
- package/dist/src/adapters/nativeSender.d.ts +3 -0
- package/dist/src/adapters/navigationTracker.d.ts +6 -0
- package/dist/src/adapters/networkChange.d.ts +15 -0
- package/dist/src/adapters/screenTiming.d.ts +9 -0
- package/dist/src/adapters/web/crashHandler.web.d.ts +9 -0
- package/dist/src/adapters/web/deviceInfo.web.d.ts +7 -0
- package/dist/src/adapters/web/frameDropsWeb.web.d.ts +16 -0
- package/dist/src/adapters/web/interceptFetchWeb.web.d.ts +29 -0
- package/dist/src/adapters/web/memoryWeb.web.d.ts +26 -0
- package/dist/src/adapters/web/navigationWeb.web.d.ts +29 -0
- package/dist/src/adapters/web/networkInfo.web.d.ts +8 -0
- package/dist/src/adapters/webSender.d.ts +3 -0
- package/dist/src/core/breadcrumbs.d.ts +12 -0
- package/dist/src/core/debug.d.ts +6 -0
- package/dist/src/core/telemetry.d.ts +233 -0
- package/dist/src/core/utils/uuid.d.ts +2 -0
- package/dist/src/createTelemetry.native.d.ts +16 -0
- package/dist/src/createTelemetry.web.d.ts +16 -0
- package/dist/src/index.base.d.ts +36 -0
- package/dist/src/index.native.d.ts +28 -0
- package/dist/src/index.web.d.ts +24 -0
- package/dist/src/shims/react-native-web-shim.d.ts +6 -0
- package/dist/telemetry-Co4MYdwa.cjs +2 -0
- package/dist/telemetry-Co4MYdwa.cjs.map +1 -0
- package/dist/telemetry-KI0x4gzC.js +389 -0
- package/dist/telemetry-KI0x4gzC.js.map +1 -0
- package/dist/v4-BysszJq8.js +31 -0
- package/dist/v4-BysszJq8.js.map +1 -0
- package/dist/v4-CqdK_b8Y.cjs +2 -0
- package/dist/v4-CqdK_b8Y.cjs.map +1 -0
- package/dist/webSender-B27tmT1w.js +42 -0
- package/dist/webSender-B27tmT1w.js.map +1 -0
- package/dist/webSender-BWi4x1df.cjs +2 -0
- package/dist/webSender-BWi4x1df.cjs.map +1 -0
- package/package.json +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# @nathanclaire/edge-telemetry-sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@nathanclaire/edge-telemetry-sdk)
|
|
4
|
+
[](https://reactnative.dev/)
|
|
5
|
+
[](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 @@
|
|
|
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 @@
|
|
|
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
|