@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
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { d as r } from "./debug-DsvQ9y3W.js";
|
|
2
|
+
import { N as u } from "./navigationTracker-Cts68dgG.js";
|
|
3
|
+
class c {
|
|
4
|
+
constructor(e) {
|
|
5
|
+
this.startTimes = /* @__PURE__ */ new Map(), this.telemetry = e;
|
|
6
|
+
}
|
|
7
|
+
// Screen entry → v3 `navigation` (replaces v2 screen_view). Baseline shape follows the
|
|
8
|
+
// reference/Angular keys; iOS reconciliation is OPEN (see additions ledger).
|
|
9
|
+
startScreen(e) {
|
|
10
|
+
this.startTimes.set(e, Date.now()), this.telemetry.currentScreen = e, this.telemetry.log("navigation", {
|
|
11
|
+
"navigation.from_screen": this.lastScreen ?? null,
|
|
12
|
+
"navigation.to_screen": e,
|
|
13
|
+
"navigation.method": "screen_start",
|
|
14
|
+
"navigation.route_type": "screen"
|
|
15
|
+
}), this.lastScreen = e;
|
|
16
|
+
}
|
|
17
|
+
// Screen exit → v3 `screen.duration` with dwell ms (replaces screen_end + performance.screen_duration).
|
|
18
|
+
endScreen(e) {
|
|
19
|
+
const t = this.startTimes.get(e);
|
|
20
|
+
if (!t) return;
|
|
21
|
+
const s = Date.now() - t;
|
|
22
|
+
this.startTimes.delete(e), this.telemetry.log("screen.duration", {
|
|
23
|
+
"screen.name": e,
|
|
24
|
+
"screen.duration_ms": s,
|
|
25
|
+
"screen.exit_method": "navigation"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
class d {
|
|
30
|
+
constructor(e = 20) {
|
|
31
|
+
this.max = e, this.items = [];
|
|
32
|
+
}
|
|
33
|
+
add(e) {
|
|
34
|
+
this.items.push(e), this.items.length > this.max && this.items.shift();
|
|
35
|
+
}
|
|
36
|
+
list() {
|
|
37
|
+
return [...this.items];
|
|
38
|
+
}
|
|
39
|
+
toJSON() {
|
|
40
|
+
return JSON.stringify(this.items);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function l(h = 16) {
|
|
44
|
+
let e = "";
|
|
45
|
+
for (let t = 0; t < h; t++) e += Math.floor(Math.random() * 16).toString(16);
|
|
46
|
+
return e;
|
|
47
|
+
}
|
|
48
|
+
const f = "3.0.0", m = "react-native", v = f, w = 1800 * 1e3, g = /* @__PURE__ */ new Set([
|
|
49
|
+
"session.started",
|
|
50
|
+
"session.finalized",
|
|
51
|
+
"app_lifecycle",
|
|
52
|
+
"page_load",
|
|
53
|
+
"navigation",
|
|
54
|
+
"screen.duration",
|
|
55
|
+
"http.request",
|
|
56
|
+
"user.interaction",
|
|
57
|
+
"network_change",
|
|
58
|
+
"user.profile.update",
|
|
59
|
+
"custom_event",
|
|
60
|
+
"app.crash",
|
|
61
|
+
"resource_timing",
|
|
62
|
+
"frame_render_time",
|
|
63
|
+
"memory_usage",
|
|
64
|
+
"long_task",
|
|
65
|
+
"LCP",
|
|
66
|
+
"FCP",
|
|
67
|
+
"CLS",
|
|
68
|
+
"INP",
|
|
69
|
+
"TTFB"
|
|
70
|
+
]);
|
|
71
|
+
class S {
|
|
72
|
+
// app.crash count this session (sdk.error_count)
|
|
73
|
+
constructor(e) {
|
|
74
|
+
this.queue = [], this.intervalId = null, this.userId = void 0, this.userProfile = void 0, this.eventCount = 0, this.breadcrumbs = new d(20), this.sessionSequence = 0, this.sessionEventCount = 0, this.errorCount = 0, this.sender = e?.sender, this.batchSize = e?.batchSize ?? 2, this.flushIntervalMs = e?.flushIntervalMs ?? 1e4, this.endpoint = e?.endpoint, this.platform = e?.platform, this.sessionId = e?.sessionId ?? this.generateSessionId(), this.userId = e?.userId ?? this.generateUserId(), this.sessionStart = Date.now(), this.sdkVersion = e?.sdkVersion ?? v, this.sender?.replayFailed && this.sender.replayFailed().catch((t) => {
|
|
75
|
+
r.warn("Telemetry replay failed Telemetry class:", t);
|
|
76
|
+
}), this.flushIntervalMs > 0 && (this.intervalId = setInterval(() => this.flush().catch(() => {
|
|
77
|
+
}), this.flushIntervalMs)), this.navigationTracker = new u(this), this.screens = new c(this), this.deviceInfoHandler = e?.deviceInfoHandler ?? {
|
|
78
|
+
start: async () => Promise.resolve(),
|
|
79
|
+
collect: async () => Promise.resolve({
|
|
80
|
+
app: { name: "", version: "" },
|
|
81
|
+
device: { id: "", platform: "" }
|
|
82
|
+
})
|
|
83
|
+
}, this.networkInfoHandler = e?.networkInfoHandler ?? {
|
|
84
|
+
start: async () => Promise.resolve({}),
|
|
85
|
+
collect: async () => Promise.resolve({})
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// ---------- Session & User APIs ----------
|
|
89
|
+
trackErrors(e, t) {
|
|
90
|
+
this.crashHandler = e, e.attach(t).catch((s) => {
|
|
91
|
+
r.warn("Telemetry crashHandler attach failed:", s);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
getDeviceInfo(e) {
|
|
95
|
+
this.deviceInfoHandler = e, e.start(this).catch((t) => {
|
|
96
|
+
r.warn("Telemetry deviceInfo tracking start failed:", t);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
getNetworkInfo(e) {
|
|
100
|
+
this.networkInfoHandler = e, e.start(this).catch((t) => {
|
|
101
|
+
r.warn("Telemetry networkInfoHandler start failed:", t);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
trackFrameDrops(e) {
|
|
105
|
+
this.frameDropsHandler = e, e.start().catch((t) => {
|
|
106
|
+
r.warn("Telemetry frameDropsHandler start failed:", t);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
trackNetworkRequests(e) {
|
|
110
|
+
this.networkHandler = e, e.start().catch((t) => {
|
|
111
|
+
r.warn("Telemetry networkHandler start failed:", t);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
trackMemoryUsage(e) {
|
|
115
|
+
this.memoryHandler = e, e.recordMemoryUsage().catch((t) => {
|
|
116
|
+
r.warn("Telemetry memoryHandler recordMemoryUsage failed:", t);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
autoTrackNavigation(e) {
|
|
120
|
+
this.navigationHandler = e, e?.start().catch((t) => {
|
|
121
|
+
r.warn("Telemetry navigationHandler start failed:", t);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
generateSessionId() {
|
|
125
|
+
const e = `session_${Date.now()}_${l(16)}`;
|
|
126
|
+
return this.platform ? `${e}_${this.platform}` : e;
|
|
127
|
+
}
|
|
128
|
+
setSessionId(e) {
|
|
129
|
+
this.sessionId = e, this.sessionStart = Date.now();
|
|
130
|
+
}
|
|
131
|
+
getSessionId() {
|
|
132
|
+
return this.sessionId;
|
|
133
|
+
}
|
|
134
|
+
/** Collector endpoint, so fetch/XHR adapters can skip self-capturing the SDK's own POST. */
|
|
135
|
+
getEndpoint() {
|
|
136
|
+
return this.endpoint;
|
|
137
|
+
}
|
|
138
|
+
startNewSession() {
|
|
139
|
+
this.sessionId = this.generateSessionId(), this.sessionStart = Date.now();
|
|
140
|
+
}
|
|
141
|
+
// ---------- Session lifecycle (#29) ----------
|
|
142
|
+
/** Emit session.started for the current session (init / resume). */
|
|
143
|
+
async startSession() {
|
|
144
|
+
this.lastActivity = Date.now(), await this.log("session.started", {});
|
|
145
|
+
}
|
|
146
|
+
/** Finalize the current session: journey summary + sdk.error_count, then an immediate flush. */
|
|
147
|
+
async finalizeSession() {
|
|
148
|
+
await this.log("session.finalized", {
|
|
149
|
+
"session.duration_ms": Date.now() - this.sessionStart,
|
|
150
|
+
"session.event_count": this.sessionEventCount,
|
|
151
|
+
"sdk.error_count": this.errorCount
|
|
152
|
+
}), await this.flush();
|
|
153
|
+
}
|
|
154
|
+
/** Begin a fresh session: new id/start, reset per-session counters, emit session.started. */
|
|
155
|
+
async newSession() {
|
|
156
|
+
this.sessionId = this.generateSessionId(), this.sessionStart = Date.now(), this.sessionSequence = 0, this.sessionEventCount = 0, this.errorCount = 0, await this.startSession();
|
|
157
|
+
}
|
|
158
|
+
/** Idle/boundary rotation: finalize the old session then start a fresh one (the pair). */
|
|
159
|
+
async rotateSession() {
|
|
160
|
+
await this.finalizeSession(), await this.newSession();
|
|
161
|
+
}
|
|
162
|
+
setUserId(e) {
|
|
163
|
+
this.userId = e;
|
|
164
|
+
}
|
|
165
|
+
getUserId() {
|
|
166
|
+
return this.userId;
|
|
167
|
+
}
|
|
168
|
+
generateUserId() {
|
|
169
|
+
return `user_${Date.now()}_${l(16)}`;
|
|
170
|
+
}
|
|
171
|
+
// ---------- User Profile Management ----------
|
|
172
|
+
/**
|
|
173
|
+
* Set complete user profile information
|
|
174
|
+
*/
|
|
175
|
+
setUserProfile(e) {
|
|
176
|
+
const t = Date.now(), s = !this.userProfile || e.userId && e.userId !== this.userProfile.userId;
|
|
177
|
+
this.userProfile = {
|
|
178
|
+
...this.userProfile,
|
|
179
|
+
...e,
|
|
180
|
+
updatedAt: t,
|
|
181
|
+
...s && { createdAt: t }
|
|
182
|
+
}, e.userId ? this.userId = e.userId : this.userProfile && !this.userProfile.userId && (this.userProfile.userId = this.userId || void 0), r.log("Telemetry: User profile updated", this.userProfile);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* EdgeRum-style identify(): attach host-app identity (name/email/phone) to subsequent
|
|
186
|
+
* events and emit one `user.profile.update`. The SDK-owned anonymous `user.id` is
|
|
187
|
+
* preserved — identify never changes it. (#31)
|
|
188
|
+
*/
|
|
189
|
+
async identify(e) {
|
|
190
|
+
this.setUserProfile({
|
|
191
|
+
fullName: e.name,
|
|
192
|
+
email: e.email,
|
|
193
|
+
phone: e.phone,
|
|
194
|
+
avatar: e.avatar,
|
|
195
|
+
customAttributes: e.customAttributes
|
|
196
|
+
}), await this.log("user.profile.update", {});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Set user details with individual parameters
|
|
200
|
+
*/
|
|
201
|
+
setUserDetails(e) {
|
|
202
|
+
this.setUserProfile(e);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Update specific user profile fields
|
|
206
|
+
*/
|
|
207
|
+
updateUserProfile(e) {
|
|
208
|
+
if (!this.userProfile) {
|
|
209
|
+
this.setUserProfile(e);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.userProfile = {
|
|
213
|
+
...this.userProfile,
|
|
214
|
+
...e,
|
|
215
|
+
updatedAt: Date.now()
|
|
216
|
+
}, r.log("Telemetry: User profile updated", this.userProfile);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get current user profile
|
|
220
|
+
*/
|
|
221
|
+
getUserProfile() {
|
|
222
|
+
return this.userProfile;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Clear user profile data
|
|
226
|
+
*/
|
|
227
|
+
clearUserProfile() {
|
|
228
|
+
this.userProfile = void 0, r.log("Telemetry: User profile cleared");
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Set user name (convenience method)
|
|
232
|
+
*/
|
|
233
|
+
setUserName(e, t, s) {
|
|
234
|
+
this.setUserProfile({
|
|
235
|
+
fullName: e,
|
|
236
|
+
firstName: t,
|
|
237
|
+
lastName: s
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Set user contact info (convenience method)
|
|
242
|
+
*/
|
|
243
|
+
setUserContact(e, t) {
|
|
244
|
+
this.setUserProfile({
|
|
245
|
+
email: e,
|
|
246
|
+
phone: t
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// ---------- Logging APIs ----------
|
|
250
|
+
/**
|
|
251
|
+
* Log a named event. Keeps existing signature compatibility.
|
|
252
|
+
* Automatically attaches userId and sessionId to every queued event.
|
|
253
|
+
*/
|
|
254
|
+
async log(e, t) {
|
|
255
|
+
if (this.eventCount++, !e.startsWith("session.")) {
|
|
256
|
+
const o = Date.now();
|
|
257
|
+
this.lastActivity !== void 0 && o - this.lastActivity > w && await this.rotateSession(), this.lastActivity = o, this.sessionEventCount++, e === "app.crash" && this.errorCount++;
|
|
258
|
+
}
|
|
259
|
+
const s = g.has(e), n = s ? e : "custom_event", i = await this.collectContext(t);
|
|
260
|
+
s || (i["event.name"] = e), n === "app.crash" ? i["crash.breadcrumbs"] = this.breadcrumbs.toJSON() : this.breadcrumbs.add({ name: n, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
261
|
+
const a = {
|
|
262
|
+
type: "event",
|
|
263
|
+
eventName: n,
|
|
264
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
265
|
+
attributes: i
|
|
266
|
+
};
|
|
267
|
+
this.queue.push(a), r.log("Telemetry queued event:", e, "Queue size:", this.queue.length), r.log("Event attributes:", i), this.queue.length >= this.batchSize && this.flush();
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Build the v3 Context block that rides on every event AND metric: the flattened
|
|
271
|
+
* device/network snapshot, the caller's data, identity + session + sdk fields, and the
|
|
272
|
+
* user profile. Shared by log() and logMetric() so both carry the identical iOS-clean set.
|
|
273
|
+
*/
|
|
274
|
+
async collectContext(e) {
|
|
275
|
+
let t = {}, s = {};
|
|
276
|
+
try {
|
|
277
|
+
t = await this.deviceInfoHandler?.collect() || {};
|
|
278
|
+
} catch (i) {
|
|
279
|
+
r.warn("Telemetry: failed to fetch device info", i);
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
s = await this.networkInfoHandler?.collect() || {};
|
|
283
|
+
} catch (i) {
|
|
284
|
+
r.warn("Telemetry: failed to fetch network info", i);
|
|
285
|
+
}
|
|
286
|
+
const n = {
|
|
287
|
+
// deviceInfo already namespaces its own keys (app.*, device.*) — flatten flat
|
|
288
|
+
...this.flattenWithPrefix("", t),
|
|
289
|
+
...this.flattenWithPrefix("network", s),
|
|
290
|
+
...this.flattenWithPrefix("", e || {}),
|
|
291
|
+
"user.id": this.userId ?? null,
|
|
292
|
+
"session.id": this.sessionId,
|
|
293
|
+
"session.start_time": new Date(this.sessionStart).toISOString(),
|
|
294
|
+
"session.sequence": this.sessionSequence,
|
|
295
|
+
"sdk.platform": m,
|
|
296
|
+
"sdk.version": this.sdkVersion
|
|
297
|
+
};
|
|
298
|
+
if (this.userProfile) {
|
|
299
|
+
const i = {
|
|
300
|
+
"user.name": this.userProfile.fullName,
|
|
301
|
+
// v3 contract key for host identity
|
|
302
|
+
"user.fullName": this.userProfile.fullName,
|
|
303
|
+
"user.firstName": this.userProfile.firstName,
|
|
304
|
+
"user.lastName": this.userProfile.lastName,
|
|
305
|
+
"user.email": this.userProfile.email,
|
|
306
|
+
"user.phone": this.userProfile.phone,
|
|
307
|
+
"user.avatar": this.userProfile.avatar,
|
|
308
|
+
"user.createdAt": this.userProfile.createdAt,
|
|
309
|
+
"user.updatedAt": this.userProfile.updatedAt,
|
|
310
|
+
...this.flattenWithPrefix("user.custom", this.userProfile.customAttributes || {})
|
|
311
|
+
};
|
|
312
|
+
Object.entries(i).forEach(([a, o]) => {
|
|
313
|
+
o !== void 0 && (n[a] = o);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return n;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Emit a metric on the v3 `type:"metric"` path: { type, metricName, value, timestamp, attributes }.
|
|
320
|
+
* Carries the same Context block as events. Metrics are samples, not user actions, so they
|
|
321
|
+
* don't extend the breadcrumb trail and don't count as session activity — a periodic sampler
|
|
322
|
+
* (memory/frames) must not keep a session alive and defeat the 30-min idle rotation.
|
|
323
|
+
*/
|
|
324
|
+
async logMetric(e, t, s) {
|
|
325
|
+
this.eventCount++;
|
|
326
|
+
const n = await this.collectContext(s), i = {
|
|
327
|
+
type: "metric",
|
|
328
|
+
metricName: e,
|
|
329
|
+
value: t,
|
|
330
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
331
|
+
attributes: n
|
|
332
|
+
};
|
|
333
|
+
this.queue.push(i), this.queue.length >= this.batchSize && this.flush();
|
|
334
|
+
}
|
|
335
|
+
flattenWithPrefix(e, t) {
|
|
336
|
+
const s = {};
|
|
337
|
+
for (const n in t) {
|
|
338
|
+
if (!Object.prototype.hasOwnProperty.call(t, n)) continue;
|
|
339
|
+
const i = t[n], a = e ? `${e}.${n}` : n;
|
|
340
|
+
typeof i == "object" && i !== null && !Array.isArray(i) ? Object.assign(s, this.flattenWithPrefix(a, i)) : s[a] = i;
|
|
341
|
+
}
|
|
342
|
+
return s;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Explicit metric helper (optional convenience) — routes through the v3 metric path.
|
|
346
|
+
*/
|
|
347
|
+
recordMetric(e, t, s) {
|
|
348
|
+
return this.logMetric(e, t, s);
|
|
349
|
+
}
|
|
350
|
+
// ---------- Flush / Persistence ----------
|
|
351
|
+
// Retry + backoff live in the Sender (see sendWithRetry in web/native senders),
|
|
352
|
+
// which is also used by the standalone replay paths. flush() does a single send
|
|
353
|
+
// and, on failure, hands the batch to the sender to persist (or requeues it).
|
|
354
|
+
async flush() {
|
|
355
|
+
if (!this.sender || this.queue.length === 0) return;
|
|
356
|
+
const e = this.queue.splice(0, this.batchSize);
|
|
357
|
+
try {
|
|
358
|
+
await this.sender.send(e), this.sessionSequence++;
|
|
359
|
+
} catch (t) {
|
|
360
|
+
if (this.sender.onFailure)
|
|
361
|
+
try {
|
|
362
|
+
await this.sender.onFailure(e);
|
|
363
|
+
} catch (s) {
|
|
364
|
+
this.queue.unshift(...e), r.warn("Sender.onFailure failed, requeued events:", s);
|
|
365
|
+
}
|
|
366
|
+
else
|
|
367
|
+
this.queue.unshift(...e);
|
|
368
|
+
throw r.error("Telemetry flush failed:", t), t;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
getQueue() {
|
|
372
|
+
return [...this.queue];
|
|
373
|
+
}
|
|
374
|
+
async shutdown() {
|
|
375
|
+
this.intervalId && clearInterval(this.intervalId), await this.flush();
|
|
376
|
+
}
|
|
377
|
+
// Screen tracking lives in ScreenTimingTracker (this.screens), the single timed API.
|
|
378
|
+
// Expose some internal counters (optional)
|
|
379
|
+
getEventCount() {
|
|
380
|
+
return this.eventCount;
|
|
381
|
+
}
|
|
382
|
+
recordRouteChange(e, t) {
|
|
383
|
+
return this.currentScreen = t, this.navigationTracker?.recordRouteChange(e, t);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
export {
|
|
387
|
+
S as Telemetry
|
|
388
|
+
};
|
|
389
|
+
//# sourceMappingURL=telemetry-KI0x4gzC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-KI0x4gzC.js","sources":["../src/adapters/screenTiming.ts","../src/core/breadcrumbs.ts","../src/core/utils/uuid.ts","../src/core/telemetry.ts"],"sourcesContent":["import { Telemetry } from \"../core/telemetry\";\n\nexport class ScreenTimingTracker {\n private telemetry: Telemetry;\n private startTimes: Map<string, number> = new Map();\n private lastScreen?: string;\n\n constructor(telemetry: Telemetry) {\n this.telemetry = telemetry;\n }\n\n // Screen entry → v3 `navigation` (replaces v2 screen_view). Baseline shape follows the\n // reference/Angular keys; iOS reconciliation is OPEN (see additions ledger).\n startScreen(screen: string) {\n this.startTimes.set(screen, Date.now());\n this.telemetry.currentScreen = screen; // best-effort screen for user.interaction taps (#33)\n this.telemetry.log(\"navigation\", {\n \"navigation.from_screen\": this.lastScreen ?? null,\n \"navigation.to_screen\": screen,\n \"navigation.method\": \"screen_start\",\n \"navigation.route_type\": \"screen\",\n });\n this.lastScreen = screen;\n }\n\n // Screen exit → v3 `screen.duration` with dwell ms (replaces screen_end + performance.screen_duration).\n endScreen(screen: string) {\n const start = this.startTimes.get(screen);\n if (!start) return;\n\n const duration = Date.now() - start;\n this.startTimes.delete(screen);\n\n this.telemetry.log(\"screen.duration\", {\n \"screen.name\": screen,\n \"screen.duration_ms\": duration,\n \"screen.exit_method\": \"navigation\",\n });\n }\n}\n","/**\n * Fixed-size ring buffer of recent actions, attached to `app.crash` as the\n * JSON-stringified `crash.breadcrumbs` (last N, oldest evicted first). See #28.\n */\nexport class BreadcrumbBuffer {\n private items: any[] = [];\n\n constructor(private max = 20) {}\n\n add(item: any): void {\n this.items.push(item);\n if (this.items.length > this.max) this.items.shift();\n }\n\n list(): any[] {\n return [...this.items];\n }\n\n toJSON(): string {\n return JSON.stringify(this.items);\n }\n}\n","// Platform-agnostic id generator. The web/native split was byte-identical, so it's gone.\n// ponytail: Math.random ids are fine for session/user correlation; swap to crypto/uuid\n// (e.g. react-native-get-random-values + uuid) here if collision-resistance ever matters.\nexport function generateId() {\n return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);\n}\n\n// v3 wire contract: ids carry a 16-hex-char (64-bit) random segment.\n// ponytail: Math.random hex is fine for session/user correlation; swap to\n// crypto/SecRandom here if collision-resistance ever matters.\nexport function randomHex(length = 16): string {\n let out = \"\";\n for (let i = 0; i < length; i++) out += Math.floor(Math.random() * 16).toString(16);\n return out;\n}\n","import { debug } from \"./debug\";\nimport { NavigationTracker } from \"../adapters/navigationTracker\";\nimport { ScreenTimingTracker } from \"../adapters/screenTiming\";\nimport { BreadcrumbBuffer } from \"./breadcrumbs\";\nimport { randomHex } from \"./utils/uuid\";\nimport { version as PKG_VERSION } from \"../../package.json\";\n\n// v3 wire contract constants\nconst SDK_PLATFORM = \"react-native\"; // framework identity; device OS lives in device.platform\nconst SDK_VERSION = PKG_VERSION; // sdk.version follows the published package version\nconst SESSION_IDLE_MS = 30 * 60 * 1000; // rotate the session after 30 min of inactivity (iOS ADR-004)\n\n// Names the backend routes. Anything else is remapped to `custom_event` with the\n// original name carried as `event.name`. Includes metric names so the metric path\n// (slice: native metrics) isn't remapped.\nconst ALLOWED_NAMES = new Set<string>([\n \"session.started\", \"session.finalized\", \"app_lifecycle\", \"page_load\", \"navigation\",\n \"screen.duration\", \"http.request\", \"user.interaction\", \"network_change\",\n \"user.profile.update\", \"custom_event\", \"app.crash\",\n \"resource_timing\", \"frame_render_time\", \"memory_usage\", \"long_task\",\n \"LCP\", \"FCP\", \"CLS\", \"INP\", \"TTFB\",\n]);\n\n// Events carry `eventName`; metrics carry `metricName` + numeric `value` (v3 §\"Event vs Metric\").\n// Kept as one loose shape (not a strict union) so callers can read `.eventName` without narrowing;\n// the emit helpers (log / logMetric) set the right fields, and JSON.stringify drops the undefined ones.\nexport type TelemetryEvent = {\n type: 'event' | 'metric';\n eventName?: string;\n metricName?: string;\n value?: number;\n timestamp: string; // ISO 8601 (v3 wire contract) — never ms epoch\n attributes?: Record<string, any>;\n};\n\nexport interface Sender {\n send(events: TelemetryEvent[]): Promise<void>;\n onFailure?(events: TelemetryEvent[]): Promise<void>;\n replayFailed?(): Promise<void>;\n}\n\n\n\nexport interface CrashHandlerOptions {\n captureConsole?: boolean; // funnel console.error/warn into app.crash (default on, opt-out)\n}\n\nexport interface CrashHandler {\n attach(options?: CrashHandlerOptions): Promise<void>;\n}\nexport interface NetworkInfo {\n type?: string; // \"wifi\", \"cellular\", \"ethernet\", \"unknown\", etc.\n isConnected?: boolean;\n}\n\nexport interface WebExtraNetworkInfo {\n type?: string;\n isConnected?: boolean;\n downlink?: number; // Mbps estimate\n effectiveType?: string; // \"4g\", \"3g\", etc.\n}\n\nexport interface NetworkInfoHandler {\n start(telemetry: Telemetry): Promise<NetworkInfo>;\n collect(): Promise<NetworkInfo>;\n}\n\nexport interface DeviceInfoHandler {\n start(telemetry: Telemetry): Promise<void>;\n collect(): Promise<DeviceInfo>;\n}\nexport interface FrameDropsHandler {\n start(): Promise<void>;\n}\n\nexport interface NetworkHandler {\n start(): Promise<void>;\n}\n\nexport interface MemoryHandler {\n recordMemoryUsage(): Promise<void>;\n}\n\nexport interface NavigationHandler {\n start(): Promise<void>;\n}\n\n\nexport interface DeviceInfo {\n app: {\n name: string;\n version: string;\n buildNumber?: string;\n packageName?: string;\n };\n device: {\n id: string;\n platform: string;\n platformVersion?: string;\n model?: string;\n manufacturer?: string;\n brand?: string;\n androidSdk?: string;\n androidRelease?: string;\n fingerprint?: string;\n hardware?: string;\n product?: string;\n iosSystemName?: string;\n iosDeviceName?: string;\n };\n}\n\nexport interface UserProfile {\n userId?: string;\n fullName?: string;\n firstName?: string;\n lastName?: string;\n email?: string;\n phone?: string;\n avatar?: string;\n customAttributes?: Record<string, any>;\n createdAt?: number;\n updatedAt?: number;\n}\n\n\ntype Opts = {\n sender?: Sender;\n batchSize?: number;\n flushIntervalMs?: number;\n endpoint?: string;\n sessionId?: string;\n userId?: string | null;\n sdkVersion?: string;\n platform?: string; // device OS (ios|android|web); forms the device/session id suffix\n deviceInfoHandler?: DeviceInfoHandler;\n networkInfoHandler?: NetworkInfoHandler;\n};\n\n/**\n * Telemetry core: queueing, batching, retries, auto-replay and session/user management.\n * Keeps the external API you already use: log(name, data?), flush(), shutdown().\n */\nexport class Telemetry {\n private queue: TelemetryEvent[] = [];\n private sender?: Sender;\n private batchSize: number;\n private flushIntervalMs: number;\n private intervalId: any = null;\n private endpoint?: string;\n private crashHandler?: CrashHandler;\n private navigationTracker?: NavigationTracker;\n // single screen-tracking API (timed); used by the native screenStart/screenEnd\n public screens: ScreenTimingTracker;\n // last-known screen; best-effort context for user.interaction taps (#33)\n public currentScreen?: string;\n\n private networkInfoHandler: NetworkInfoHandler;\n private deviceInfoHandler: DeviceInfoHandler;\n\n private frameDropsHandler?: FrameDropsHandler;\n private networkHandler?: NetworkHandler;\n private memoryHandler?: MemoryHandler;\n private navigationHandler?: NavigationHandler;\n\n\n // session / user state\n private userId?: string | null = undefined;\n private userProfile?: UserProfile = undefined;\n private sessionId: string;\n private sessionStart: number;\n private sdkVersion: string;\n private platform?: string;\n private eventCount = 0;\n // last-20 action trail, attached to app.crash as crash.breadcrumbs (#28)\n private breadcrumbs = new BreadcrumbBuffer(20);\n // session lifecycle (#29)\n private lastActivity?: number; // last non-session event time; drives 30-min idle rotation\n private sessionSequence = 0; // increments per acknowledged (2xx) batch\n private sessionEventCount = 0; // events this session (journey summary)\n private errorCount = 0; // app.crash count this session (sdk.error_count)\n\n constructor(opts?: Opts) {\n this.sender = opts?.sender;\n this.batchSize = opts?.batchSize ?? 2;\n this.flushIntervalMs = opts?.flushIntervalMs ?? 10000;\n this.endpoint = opts?.endpoint;\n this.platform = opts?.platform; // set before id generation (suffix source)\n\n // start a session\n this.sessionId = opts?.sessionId ?? this.generateSessionId();\n this.userId = opts?.userId ?? this.generateUserId();\n this.sessionStart = Date.now();\n this.sdkVersion = opts?.sdkVersion ?? SDK_VERSION;\n\n // auto replay if supported\n if (this.sender?.replayFailed) {\n // don't block constructor; best-effort\n this.sender.replayFailed().catch((err: any) => {\n debug.warn(\"Telemetry replay failed Telemetry class:\", err);\n });\n }\n\n if (this.flushIntervalMs > 0) {\n this.intervalId = setInterval(() => this.flush().catch(() => { }), this.flushIntervalMs);\n }\n\n this.navigationTracker = new NavigationTracker(this);\n this.screens = new ScreenTimingTracker(this);\n\n this.deviceInfoHandler = opts?.deviceInfoHandler ?? {\n start: async () => Promise.resolve(),\n collect: async () => Promise.resolve({\n app: { name: '', version: '' },\n device: { id: '', platform: '' }\n })\n };\n this.networkInfoHandler = opts?.networkInfoHandler ?? {\n start: async () => Promise.resolve({}),\n collect: async () => Promise.resolve({})\n };\n\n }\n\n // ---------- Session & User APIs ----------\n\n public trackErrors(crashHandler: CrashHandler, options?: CrashHandlerOptions) {\n this.crashHandler = crashHandler;\n void crashHandler.attach(options).catch((err) => {\n debug.warn(\"Telemetry crashHandler attach failed:\", err);\n });\n }\n\n getDeviceInfo(deviceInfoHandler: DeviceInfoHandler) {\n this.deviceInfoHandler = deviceInfoHandler;\n void deviceInfoHandler.start(this).catch((err) => {\n debug.warn(\"Telemetry deviceInfo tracking start failed:\", err);\n });\n }\n\n getNetworkInfo(networkInfoHandler: NetworkInfoHandler) {\n this.networkInfoHandler = networkInfoHandler;\n void networkInfoHandler.start(this).catch((err) => {\n debug.warn(\"Telemetry networkInfoHandler start failed:\", err);\n });\n }\n\n public trackFrameDrops(frameDropsHandler: FrameDropsHandler) {\n this.frameDropsHandler = frameDropsHandler;\n void frameDropsHandler.start().catch((err) => {\n debug.warn(\"Telemetry frameDropsHandler start failed:\", err);\n });\n }\n\n public trackNetworkRequests(networkHandler: NetworkHandler) {\n this.networkHandler = networkHandler;\n void networkHandler.start().catch((err) => {\n debug.warn(\"Telemetry networkHandler start failed:\", err);\n });\n }\n\n public trackMemoryUsage(memoryHandler: MemoryHandler) {\n this.memoryHandler = memoryHandler;\n void memoryHandler.recordMemoryUsage().catch((err) => {\n debug.warn(\"Telemetry memoryHandler recordMemoryUsage failed:\", err);\n });\n }\n\n public autoTrackNavigation(navigationHandler?: NavigationHandler) {\n this.navigationHandler = navigationHandler;\n void navigationHandler?.start().catch((err) => {\n debug.warn(\"Telemetry navigationHandler start failed:\", err);\n });\n }\n\n\n private generateSessionId(): string {\n const base = `session_${Date.now()}_${randomHex(16)}`;\n return this.platform ? `${base}_${this.platform}` : base;\n }\n\n public setSessionId(id: string) {\n this.sessionId = id;\n this.sessionStart = Date.now();\n }\n\n public getSessionId(): string {\n return this.sessionId;\n }\n\n /** Collector endpoint, so fetch/XHR adapters can skip self-capturing the SDK's own POST. */\n public getEndpoint(): string | undefined {\n return this.endpoint;\n }\n\n public startNewSession() {\n this.sessionId = this.generateSessionId();\n this.sessionStart = Date.now();\n }\n\n // ---------- Session lifecycle (#29) ----------\n\n /** Emit session.started for the current session (init / resume). */\n public async startSession() {\n this.lastActivity = Date.now();\n await this.log(\"session.started\", {});\n }\n\n /** Finalize the current session: journey summary + sdk.error_count, then an immediate flush. */\n public async finalizeSession() {\n await this.log(\"session.finalized\", {\n \"session.duration_ms\": Date.now() - this.sessionStart,\n \"session.event_count\": this.sessionEventCount,\n \"sdk.error_count\": this.errorCount,\n });\n await this.flush();\n }\n\n /** Begin a fresh session: new id/start, reset per-session counters, emit session.started. */\n public async newSession() {\n this.sessionId = this.generateSessionId();\n this.sessionStart = Date.now();\n this.sessionSequence = 0;\n this.sessionEventCount = 0;\n this.errorCount = 0;\n await this.startSession();\n }\n\n /** Idle/boundary rotation: finalize the old session then start a fresh one (the pair). */\n public async rotateSession() {\n await this.finalizeSession();\n await this.newSession();\n }\n\n public setUserId(id: string) {\n this.userId = id;\n }\n\n public getUserId(): string | undefined | null {\n return this.userId;\n }\n\n public generateUserId(): string {\n return `user_${Date.now()}_${randomHex(16)}`;\n }\n\n // ---------- User Profile Management ----------\n\n /**\n * Set complete user profile information\n */\n public setUserProfile(profile: Partial<UserProfile>): void {\n const now = Date.now();\n \n // If this is a new profile or userId changed, set createdAt\n const isNewProfile = !this.userProfile || (profile.userId && profile.userId !== this.userProfile.userId);\n \n this.userProfile = {\n ...this.userProfile,\n ...profile,\n updatedAt: now,\n ...(isNewProfile && { createdAt: now })\n };\n\n // Update userId if provided in profile\n if (profile.userId) {\n this.userId = profile.userId;\n } else if (this.userProfile && !this.userProfile.userId) {\n // Set current userId in profile if not provided\n this.userProfile.userId = this.userId || undefined;\n }\n\n debug.log(\"Telemetry: User profile updated\", this.userProfile);\n }\n\n /**\n * EdgeRum-style identify(): attach host-app identity (name/email/phone) to subsequent\n * events and emit one `user.profile.update`. The SDK-owned anonymous `user.id` is\n * preserved — identify never changes it. (#31)\n */\n public async identify(profile: {\n name?: string;\n email?: string;\n phone?: string;\n avatar?: string;\n customAttributes?: Record<string, any>;\n }) {\n this.setUserProfile({\n fullName: profile.name,\n email: profile.email,\n phone: profile.phone,\n avatar: profile.avatar,\n customAttributes: profile.customAttributes,\n });\n await this.log(\"user.profile.update\", {});\n }\n\n /**\n * Set user details with individual parameters\n */\n public setUserDetails(details: {\n fullName?: string;\n firstName?: string;\n lastName?: string;\n email?: string;\n phone?: string;\n avatar?: string;\n customAttributes?: Record<string, any>;\n }): void {\n this.setUserProfile(details);\n }\n\n /**\n * Update specific user profile fields\n */\n public updateUserProfile(updates: Partial<UserProfile>): void {\n if (!this.userProfile) {\n // If no profile exists, create one\n this.setUserProfile(updates);\n return;\n }\n\n this.userProfile = {\n ...this.userProfile,\n ...updates,\n updatedAt: Date.now()\n };\n\n debug.log(\"Telemetry: User profile updated\", this.userProfile);\n }\n\n /**\n * Get current user profile\n */\n public getUserProfile(): UserProfile | undefined {\n return this.userProfile;\n }\n\n /**\n * Clear user profile data\n */\n public clearUserProfile(): void {\n this.userProfile = undefined;\n debug.log(\"Telemetry: User profile cleared\");\n }\n\n /**\n * Set user name (convenience method)\n */\n public setUserName(fullName: string, firstName?: string, lastName?: string): void {\n this.setUserProfile({\n fullName,\n firstName,\n lastName\n });\n }\n\n /**\n * Set user contact info (convenience method)\n */\n public setUserContact(email?: string, phone?: string): void {\n this.setUserProfile({\n email,\n phone\n });\n }\n\n // ---------- Logging APIs ----------\n\n /**\n * Log a named event. Keeps existing signature compatibility.\n * Automatically attaches userId and sessionId to every queued event.\n */\n async log(name: string, data?: Record<string, any>) {\n this.eventCount++;\n\n // Session activity & 30-min idle rotation. Session events don't count as activity\n // (they're emitted *by* the lifecycle), so they never re-trigger rotation.\n if (!name.startsWith('session.')) {\n const now = Date.now();\n if (this.lastActivity !== undefined && now - this.lastActivity > SESSION_IDLE_MS) {\n await this.rotateSession();\n }\n this.lastActivity = now;\n this.sessionEventCount++;\n if (name === 'app.crash') this.errorCount++;\n }\n\n // v3 allowlist: unknown names ship as custom_event, original kept as event.name\n const isAllowed = ALLOWED_NAMES.has(name);\n const eventName = isAllowed ? name : 'custom_event';\n\n const attributes = await this.collectContext(data);\n if (!isAllowed) attributes['event.name'] = name;\n\n // app.crash carries the trail of prior actions; other events extend the trail.\n if (eventName === 'app.crash') {\n attributes['crash.breadcrumbs'] = this.breadcrumbs.toJSON();\n } else {\n this.breadcrumbs.add({ name: eventName, timestamp: new Date().toISOString() });\n }\n\n const e: TelemetryEvent = {\n type: 'event',\n eventName,\n timestamp: new Date().toISOString(),\n attributes,\n };\n\n this.queue.push(e);\n\n debug.log(\"Telemetry queued event:\", name, \"Queue size:\", this.queue.length);\n debug.log(\"Event attributes:\", attributes);\n\n if (this.queue.length >= this.batchSize) {\n void this.flush();\n }\n\n\n }\n\n /**\n * Build the v3 Context block that rides on every event AND metric: the flattened\n * device/network snapshot, the caller's data, identity + session + sdk fields, and the\n * user profile. Shared by log() and logMetric() so both carry the identical iOS-clean set.\n */\n private async collectContext(data?: Record<string, any>): Promise<Record<string, any>> {\n let deviceInfo: Record<string, any> = {};\n let networkInfo: Record<string, any> = {};\n\n try {\n deviceInfo = (await this.deviceInfoHandler?.collect()) || {};\n } catch (err) {\n debug.warn(\"Telemetry: failed to fetch device info\", err);\n }\n\n try {\n networkInfo = (await this.networkInfoHandler?.collect()) || {};\n } catch (err) {\n debug.warn(\"Telemetry: failed to fetch network info\", err);\n }\n\n const attributes: Record<string, any> = {\n // deviceInfo already namespaces its own keys (app.*, device.*) — flatten flat\n ...this.flattenWithPrefix('', deviceInfo),\n ...this.flattenWithPrefix('network', networkInfo),\n ...this.flattenWithPrefix('', data || {}),\n 'user.id': this.userId ?? null,\n 'session.id': this.sessionId,\n 'session.start_time': new Date(this.sessionStart).toISOString(),\n 'session.sequence': this.sessionSequence,\n 'sdk.platform': SDK_PLATFORM,\n 'sdk.version': this.sdkVersion,\n };\n\n if (this.userProfile) {\n const userProfileData = {\n 'user.name': this.userProfile.fullName, // v3 contract key for host identity\n 'user.fullName': this.userProfile.fullName,\n 'user.firstName': this.userProfile.firstName,\n 'user.lastName': this.userProfile.lastName,\n 'user.email': this.userProfile.email,\n 'user.phone': this.userProfile.phone,\n 'user.avatar': this.userProfile.avatar,\n 'user.createdAt': this.userProfile.createdAt,\n 'user.updatedAt': this.userProfile.updatedAt,\n ...this.flattenWithPrefix('user.custom', this.userProfile.customAttributes || {})\n };\n Object.entries(userProfileData).forEach(([key, value]) => {\n if (value !== undefined) attributes[key] = value;\n });\n }\n\n return attributes;\n }\n\n /**\n * Emit a metric on the v3 `type:\"metric\"` path: { type, metricName, value, timestamp, attributes }.\n * Carries the same Context block as events. Metrics are samples, not user actions, so they\n * don't extend the breadcrumb trail and don't count as session activity — a periodic sampler\n * (memory/frames) must not keep a session alive and defeat the 30-min idle rotation.\n */\n async logMetric(metricName: string, value: number, data?: Record<string, any>) {\n this.eventCount++;\n const attributes = await this.collectContext(data);\n\n const m: TelemetryEvent = {\n type: 'metric',\n metricName,\n value,\n timestamp: new Date().toISOString(),\n attributes,\n };\n\n this.queue.push(m);\n if (this.queue.length >= this.batchSize) {\n void this.flush();\n }\n }\n\n private flattenWithPrefix(prefix: string, obj: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const key in obj) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n\n const value = obj[key];\n const prefixedKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n Object.assign(result, this.flattenWithPrefix(prefixedKey, value));\n } else {\n result[prefixedKey] = value;\n }\n }\n\n return result;\n }\n\n\n\n /**\n * Explicit metric helper (optional convenience) — routes through the v3 metric path.\n */\n recordMetric(name: string, value: number, data?: Record<string, any>) {\n return this.logMetric(name, value, data);\n }\n\n // ---------- Flush / Persistence ----------\n\n // Retry + backoff live in the Sender (see sendWithRetry in web/native senders),\n // which is also used by the standalone replay paths. flush() does a single send\n // and, on failure, hands the batch to the sender to persist (or requeues it).\n async flush() {\n if (!this.sender || this.queue.length === 0) return;\n\n // build a batch of up to batchSize\n const toSend = this.queue.splice(0, this.batchSize);\n\n try {\n await this.sender.send(toSend);\n this.sessionSequence++; // acknowledged (2xx) batch — order a session's batches (#29)\n } catch (lastError) {\n if (this.sender.onFailure) {\n try {\n await this.sender.onFailure(toSend);\n } catch (persistErr) {\n // If persistence fails, requeue to avoid data loss\n this.queue.unshift(...toSend);\n debug.warn(\"Sender.onFailure failed, requeued events:\", persistErr);\n }\n } else {\n this.queue.unshift(...toSend);\n }\n\n debug.error(\"Telemetry flush failed:\", lastError);\n throw lastError;\n }\n }\n\n getQueue() {\n return [...this.queue];\n }\n\n async shutdown() {\n if (this.intervalId) clearInterval(this.intervalId);\n await this.flush();\n }\n\n // Screen tracking lives in ScreenTimingTracker (this.screens), the single timed API.\n\n // Expose some internal counters (optional)\n getEventCount() {\n return this.eventCount;\n }\n\n recordRouteChange(from: string, to: string) {\n this.currentScreen = to; // best-effort screen for subsequent taps (#33)\n return this.navigationTracker?.recordRouteChange(from, to);\n }\n\n\n}\n\n"],"names":["ScreenTimingTracker","telemetry","screen","start","duration","BreadcrumbBuffer","max","item","randomHex","length","out","i","SDK_PLATFORM","SDK_VERSION","PKG_VERSION","SESSION_IDLE_MS","ALLOWED_NAMES","Telemetry","opts","err","debug","NavigationTracker","crashHandler","options","deviceInfoHandler","networkInfoHandler","frameDropsHandler","networkHandler","memoryHandler","navigationHandler","base","id","profile","now","isNewProfile","details","updates","fullName","firstName","lastName","email","phone","name","data","isAllowed","eventName","attributes","e","deviceInfo","networkInfo","userProfileData","key","value","metricName","m","prefix","obj","result","prefixedKey","toSend","lastError","persistErr","from","to"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const e = [];
|
|
2
|
+
for (let n = 0; n < 256; ++n)
|
|
3
|
+
e.push((n + 256).toString(16).slice(1));
|
|
4
|
+
function i(n, t = 0) {
|
|
5
|
+
return (e[n[t + 0]] + e[n[t + 1]] + e[n[t + 2]] + e[n[t + 3]] + "-" + e[n[t + 4]] + e[n[t + 5]] + "-" + e[n[t + 6]] + e[n[t + 7]] + "-" + e[n[t + 8]] + e[n[t + 9]] + "-" + e[n[t + 10]] + e[n[t + 11]] + e[n[t + 12]] + e[n[t + 13]] + e[n[t + 14]] + e[n[t + 15]]).toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
let o;
|
|
8
|
+
const r = new Uint8Array(16);
|
|
9
|
+
function y() {
|
|
10
|
+
if (!o) {
|
|
11
|
+
if (typeof crypto > "u" || !crypto.getRandomValues)
|
|
12
|
+
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
13
|
+
o = crypto.getRandomValues.bind(crypto);
|
|
14
|
+
}
|
|
15
|
+
return o(r);
|
|
16
|
+
}
|
|
17
|
+
const m = typeof crypto < "u" && crypto.randomUUID && crypto.randomUUID.bind(crypto), d = { randomUUID: m };
|
|
18
|
+
function p(n, t, c) {
|
|
19
|
+
n = n || {};
|
|
20
|
+
const u = n.random ?? n.rng?.() ?? y();
|
|
21
|
+
if (u.length < 16)
|
|
22
|
+
throw new Error("Random bytes length must be >= 16");
|
|
23
|
+
return u[6] = u[6] & 15 | 64, u[8] = u[8] & 63 | 128, i(u);
|
|
24
|
+
}
|
|
25
|
+
function g(n, t, c) {
|
|
26
|
+
return d.randomUUID && !n ? d.randomUUID() : p(n);
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
g as v
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=v4-BysszJq8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v4-BysszJq8.js","sources":["../node_modules/uuid/dist/stringify.js","../node_modules/uuid/dist/rng.js","../node_modules/uuid/dist/native.js","../node_modules/uuid/dist/v4.js"],"sourcesContent":["import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","let getRandomValues;\nconst rnds8 = new Uint8Array(16);\nexport default function rng() {\n if (!getRandomValues) {\n if (typeof crypto === 'undefined' || !crypto.getRandomValues) {\n throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n }\n getRandomValues = crypto.getRandomValues.bind(crypto);\n }\n return getRandomValues(rnds8);\n}\n","const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);\nexport default { randomUUID };\n","import native from './native.js';\nimport rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction _v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random ?? options.rng?.() ?? rng();\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return unsafeStringify(rnds);\n}\nfunction v4(options, buf, offset) {\n if (native.randomUUID && !buf && !options) {\n return native.randomUUID();\n }\n return _v4(options, buf, offset);\n}\nexport default v4;\n"],"names":["byteToHex","i","unsafeStringify","arr","offset","getRandomValues","rnds8","rng","randomUUID","native","_v4","options","buf","rnds","v4"],"mappings":"AACA,MAAMA,IAAY,CAAA;AAClB,SAASC,IAAI,GAAGA,IAAI,KAAK,EAAEA;AACvB,EAAAD,EAAU,MAAMC,IAAI,KAAO,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAE7C,SAASC,EAAgBC,GAAKC,IAAS,GAAG;AAC7C,UAAQJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IAC7BJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzBJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzBJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzB,MACAJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzBJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzB,MACAJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzBJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzB,MACAJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzBJ,EAAUG,EAAIC,IAAS,CAAC,CAAC,IACzB,MACAJ,EAAUG,EAAIC,IAAS,EAAE,CAAC,IAC1BJ,EAAUG,EAAIC,IAAS,EAAE,CAAC,IAC1BJ,EAAUG,EAAIC,IAAS,EAAE,CAAC,IAC1BJ,EAAUG,EAAIC,IAAS,EAAE,CAAC,IAC1BJ,EAAUG,EAAIC,IAAS,EAAE,CAAC,IAC1BJ,EAAUG,EAAIC,IAAS,EAAE,CAAC,GAAG,YAAW;AAChD;AC1BA,IAAIC;AACJ,MAAMC,IAAQ,IAAI,WAAW,EAAE;AAChB,SAASC,IAAM;AAC1B,MAAI,CAACF,GAAiB;AAClB,QAAI,OAAO,SAAW,OAAe,CAAC,OAAO;AACzC,YAAM,IAAI,MAAM,0GAA0G;AAE9H,IAAAA,IAAkB,OAAO,gBAAgB,KAAK,MAAM;AAAA,EACxD;AACA,SAAOA,EAAgBC,CAAK;AAChC;ACVA,MAAME,IAAa,OAAO,SAAW,OAAe,OAAO,cAAc,OAAO,WAAW,KAAK,MAAM,GACtGC,IAAe,EAAE,YAAAD,EAAU;ACE3B,SAASE,EAAIC,GAASC,GAAKR,GAAQ;AAC/B,EAAAO,IAAUA,KAAW,CAAA;AACrB,QAAME,IAAOF,EAAQ,UAAUA,EAAQ,MAAG,KAAQJ,EAAG;AACrD,MAAIM,EAAK,SAAS;AACd,UAAM,IAAI,MAAM,mCAAmC;AAEvD,SAAAA,EAAK,CAAC,IAAKA,EAAK,CAAC,IAAI,KAAQ,IAC7BA,EAAK,CAAC,IAAKA,EAAK,CAAC,IAAI,KAAQ,KAWtBX,EAAgBW,CAAI;AAC/B;AACA,SAASC,EAAGH,GAASC,GAAKR,GAAQ;AAC9B,SAAIK,EAAO,cAAsB,CAACE,IACvBF,EAAO,WAAU,IAErBC,EAAIC,CAAoB;AACnC;","x_google_ignoreList":[0,1,2,3]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const e=[];for(let n=0;n<256;++n)e.push((n+256).toString(16).slice(1));function i(n,t=0){return(e[n[t+0]]+e[n[t+1]]+e[n[t+2]]+e[n[t+3]]+"-"+e[n[t+4]]+e[n[t+5]]+"-"+e[n[t+6]]+e[n[t+7]]+"-"+e[n[t+8]]+e[n[t+9]]+"-"+e[n[t+10]]+e[n[t+11]]+e[n[t+12]]+e[n[t+13]]+e[n[t+14]]+e[n[t+15]]).toLowerCase()}let o;const r=new Uint8Array(16);function y(){if(!o){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");o=crypto.getRandomValues.bind(crypto)}return o(r)}const m=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),d={randomUUID:m};function p(n,t,c){n=n||{};const u=n.random??n.rng?.()??y();if(u.length<16)throw new Error("Random bytes length must be >= 16");return u[6]=u[6]&15|64,u[8]=u[8]&63|128,i(u)}function g(n,t,c){return d.randomUUID&&!n?d.randomUUID():p(n)}exports.v4=g;
|
|
2
|
+
//# sourceMappingURL=v4-CqdK_b8Y.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v4-CqdK_b8Y.cjs","sources":["../node_modules/uuid/dist/stringify.js","../node_modules/uuid/dist/rng.js","../node_modules/uuid/dist/native.js","../node_modules/uuid/dist/v4.js"],"sourcesContent":["import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","let getRandomValues;\nconst rnds8 = new Uint8Array(16);\nexport default function rng() {\n if (!getRandomValues) {\n if (typeof crypto === 'undefined' || !crypto.getRandomValues) {\n throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n }\n getRandomValues = crypto.getRandomValues.bind(crypto);\n }\n return getRandomValues(rnds8);\n}\n","const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);\nexport default { randomUUID };\n","import native from './native.js';\nimport rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction _v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random ?? options.rng?.() ?? rng();\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return unsafeStringify(rnds);\n}\nfunction v4(options, buf, offset) {\n if (native.randomUUID && !buf && !options) {\n return native.randomUUID();\n }\n return _v4(options, buf, offset);\n}\nexport default v4;\n"],"names":["byteToHex","i","unsafeStringify","arr","offset","getRandomValues","rnds8","rng","randomUUID","native","_v4","options","buf","rnds","v4"],"mappings":"aACA,MAAMA,EAAY,CAAA,EAClB,QAASC,EAAI,EAAGA,EAAI,IAAK,EAAEA,EACvBD,EAAU,MAAMC,EAAI,KAAO,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,EAE7C,SAASC,EAAgBC,EAAKC,EAAS,EAAG,CAC7C,OAAQJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EAC7BJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzBJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzBJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzB,IACAJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzBJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzB,IACAJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzBJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzB,IACAJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzBJ,EAAUG,EAAIC,EAAS,CAAC,CAAC,EACzB,IACAJ,EAAUG,EAAIC,EAAS,EAAE,CAAC,EAC1BJ,EAAUG,EAAIC,EAAS,EAAE,CAAC,EAC1BJ,EAAUG,EAAIC,EAAS,EAAE,CAAC,EAC1BJ,EAAUG,EAAIC,EAAS,EAAE,CAAC,EAC1BJ,EAAUG,EAAIC,EAAS,EAAE,CAAC,EAC1BJ,EAAUG,EAAIC,EAAS,EAAE,CAAC,GAAG,YAAW,CAChD,CC1BA,IAAIC,EACJ,MAAMC,EAAQ,IAAI,WAAW,EAAE,EAChB,SAASC,GAAM,CAC1B,GAAI,CAACF,EAAiB,CAClB,GAAI,OAAO,OAAW,KAAe,CAAC,OAAO,gBACzC,MAAM,IAAI,MAAM,0GAA0G,EAE9HA,EAAkB,OAAO,gBAAgB,KAAK,MAAM,CACxD,CACA,OAAOA,EAAgBC,CAAK,CAChC,CCVA,MAAME,EAAa,OAAO,OAAW,KAAe,OAAO,YAAc,OAAO,WAAW,KAAK,MAAM,EACtGC,EAAe,CAAE,WAAAD,CAAU,ECE3B,SAASE,EAAIC,EAASC,EAAKR,EAAQ,CAC/BO,EAAUA,GAAW,CAAA,EACrB,MAAME,EAAOF,EAAQ,QAAUA,EAAQ,MAAG,GAAQJ,EAAG,EACrD,GAAIM,EAAK,OAAS,GACd,MAAM,IAAI,MAAM,mCAAmC,EAEvD,OAAAA,EAAK,CAAC,EAAKA,EAAK,CAAC,EAAI,GAAQ,GAC7BA,EAAK,CAAC,EAAKA,EAAK,CAAC,EAAI,GAAQ,IAWtBX,EAAgBW,CAAI,CAC/B,CACA,SAASC,EAAGH,EAASC,EAAKR,EAAQ,CAC9B,OAAIK,EAAO,YAAsB,CAACE,EACvBF,EAAO,WAAU,EAErBC,EAAIC,CAAoB,CACnC","x_google_ignoreList":[0,1,2,3]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { b as c } from "./batch-DLG_gtOm.js";
|
|
2
|
+
const d = "https://your.telemetry.endpoint/collect", s = "telemetry_failed_events";
|
|
3
|
+
function f(r) {
|
|
4
|
+
if (typeof localStorage > "u") return;
|
|
5
|
+
const e = JSON.parse(localStorage.getItem(s) || "[]");
|
|
6
|
+
localStorage.setItem(s, JSON.stringify([...e, ...r]));
|
|
7
|
+
}
|
|
8
|
+
async function u(r, e, a, t = 3) {
|
|
9
|
+
let n = 0, i;
|
|
10
|
+
for (; n < t; )
|
|
11
|
+
try {
|
|
12
|
+
const o = await fetch(r, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
...e ? { "X-API-Key": e } : {}
|
|
17
|
+
},
|
|
18
|
+
body: c(a),
|
|
19
|
+
keepalive: !0
|
|
20
|
+
});
|
|
21
|
+
if (!o.ok)
|
|
22
|
+
throw new Error(`Telemetry send failed: ${o.status}`);
|
|
23
|
+
return;
|
|
24
|
+
} catch (o) {
|
|
25
|
+
i = o, n++, n < t && await new Promise((l) => setTimeout(l, n * 500));
|
|
26
|
+
}
|
|
27
|
+
throw i;
|
|
28
|
+
}
|
|
29
|
+
function m(r = d, e, a = 3) {
|
|
30
|
+
return {
|
|
31
|
+
async send(t) {
|
|
32
|
+
await u(r, e, t, a);
|
|
33
|
+
},
|
|
34
|
+
async onFailure(t) {
|
|
35
|
+
f(t);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
m as webSender
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=webSender-B27tmT1w.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webSender-B27tmT1w.js","sources":["../src/adapters/webSender.ts"],"sourcesContent":["import { debug } from \"../core/debug\";\nimport type { TelemetryEvent, Sender } from \"../core/telemetry\";\nimport { buildBatch } from \"./batch\";\n\nconst DEFAULT_ENDPOINT = \"https://your.telemetry.endpoint/collect\";\nconst STORAGE_KEY = \"telemetry_failed_events\";\n\n// Save failed events in localStorage\nfunction persistFailed(events: TelemetryEvent[]) {\n if (typeof localStorage === \"undefined\") return;\n const existing = JSON.parse(localStorage.getItem(STORAGE_KEY) || \"[]\");\n localStorage.setItem(STORAGE_KEY, JSON.stringify([...existing, ...events]));\n}\n\n// Try sending a batch with retries + backoff.\n// v3 uses fetch({ keepalive: true }) rather than navigator.sendBeacon: the beacon\n// API cannot set the required X-API-Key header. keepalive preserves the\n// survives-page-unload property we relied on sendBeacon for.\nasync function sendWithRetry(endpoint: string, apiKey: string | undefined, events: TelemetryEvent[], retryCount: number = 3) {\n let attempts = 0;\n let lastError: any;\n\n while (attempts < retryCount) {\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey ? { \"X-API-Key\": apiKey } : {}),\n },\n body: buildBatch(events),\n keepalive: true,\n });\n\n if (!res.ok) {\n throw new Error(`Telemetry send failed: ${res.status}`);\n }\n\n return; // ✅ success\n } catch (err) {\n lastError = err;\n attempts++;\n if (attempts < retryCount) {\n await new Promise(res => setTimeout(res, attempts * 500)); // backoff\n }\n }\n }\n\n // ❌ after retries still failed\n throw lastError;\n}\n\nexport function webSender(endpoint: string = DEFAULT_ENDPOINT, apiKey?: string, retryCount: number = 3): Sender {\n return {\n async send(events: TelemetryEvent[]) {\n // Retry + backoff here; persistence on final failure is the core flush()'s\n // job via onFailure() — kept single, so a failed batch isn't persisted twice.\n await sendWithRetry(endpoint, apiKey, events, retryCount);\n },\n async onFailure(events: TelemetryEvent[]) {\n persistFailed(events);\n },\n };\n}\n\n// Replay failed events on startup\nexport function replayFailedWeb(endpoint: string = DEFAULT_ENDPOINT, apiKey?: string, retryCount: number = 3) {\n debug.log(\"Telemetry replayFailedWeb launched\");\n if (typeof localStorage === \"undefined\") return;\n const stored = JSON.parse(localStorage.getItem(STORAGE_KEY) || \"[]\") as TelemetryEvent[];\n if (stored.length > 0) {\n localStorage.removeItem(STORAGE_KEY);\n return sendWithRetry(endpoint, apiKey, stored, retryCount).catch(err => {\n // If replay fails again, re-persist\n persistFailed(stored);\n debug.warn(\"Telemetry replay failed:\", err);\n });\n }\n}\n\n"],"names":["DEFAULT_ENDPOINT","STORAGE_KEY","persistFailed","events","existing","sendWithRetry","endpoint","apiKey","retryCount","attempts","lastError","res","buildBatch","err","webSender"],"mappings":";AAIA,MAAMA,IAAmB,2CACnBC,IAAc;AAGpB,SAASC,EAAcC,GAA0B;AAC7C,MAAI,OAAO,eAAiB,IAAa;AACzC,QAAMC,IAAW,KAAK,MAAM,aAAa,QAAQH,CAAW,KAAK,IAAI;AACrE,eAAa,QAAQA,GAAa,KAAK,UAAU,CAAC,GAAGG,GAAU,GAAGD,CAAM,CAAC,CAAC;AAC9E;AAMA,eAAeE,EAAcC,GAAkBC,GAA4BJ,GAA0BK,IAAqB,GAAG;AACzH,MAAIC,IAAW,GACXC;AAEJ,SAAOD,IAAWD;AACd,QAAI;AACA,YAAMG,IAAM,MAAM,MAAML,GAAU;AAAA,QAC9B,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,gBAAgB;AAAA,UAChB,GAAIC,IAAS,EAAE,aAAaA,MAAW,CAAA;AAAA,QAAC;AAAA,QAE5C,MAAMK,EAAWT,CAAM;AAAA,QACvB,WAAW;AAAA,MAAA,CACd;AAED,UAAI,CAACQ,EAAI;AACL,cAAM,IAAI,MAAM,0BAA0BA,EAAI,MAAM,EAAE;AAG1D;AAAA,IACJ,SAASE,GAAK;AACV,MAAAH,IAAYG,GACZJ,KACIA,IAAWD,KACX,MAAM,IAAI,QAAQ,CAAAG,MAAO,WAAWA,GAAKF,IAAW,GAAG,CAAC;AAAA,IAEhE;AAIJ,QAAMC;AACV;AAEO,SAASI,EAAUR,IAAmBN,GAAkBO,GAAiBC,IAAqB,GAAW;AAC5G,SAAO;AAAA,IACH,MAAM,KAAKL,GAA0B;AAGjC,YAAME,EAAcC,GAAUC,GAAQJ,GAAQK,CAAU;AAAA,IAC5D;AAAA,IACA,MAAM,UAAUL,GAA0B;AACtC,MAAAD,EAAcC,CAAM;AAAA,IACxB;AAAA,EAAA;AAER;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("./batch-CLBFgYPC.cjs"),d="https://your.telemetry.endpoint/collect",s="telemetry_failed_events";function u(r){if(typeof localStorage>"u")return;const e=JSON.parse(localStorage.getItem(s)||"[]");localStorage.setItem(s,JSON.stringify([...e,...r]))}async function y(r,e,a,t=3){let n=0,i;for(;n<t;)try{const o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",...e?{"X-API-Key":e}:{}},body:c.buildBatch(a),keepalive:!0});if(!o.ok)throw new Error(`Telemetry send failed: ${o.status}`);return}catch(o){i=o,n++,n<t&&await new Promise(l=>setTimeout(l,n*500))}throw i}function f(r=d,e,a=3){return{async send(t){await y(r,e,t,a)},async onFailure(t){u(t)}}}exports.webSender=f;
|
|
2
|
+
//# sourceMappingURL=webSender-BWi4x1df.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webSender-BWi4x1df.cjs","sources":["../src/adapters/webSender.ts"],"sourcesContent":["import { debug } from \"../core/debug\";\nimport type { TelemetryEvent, Sender } from \"../core/telemetry\";\nimport { buildBatch } from \"./batch\";\n\nconst DEFAULT_ENDPOINT = \"https://your.telemetry.endpoint/collect\";\nconst STORAGE_KEY = \"telemetry_failed_events\";\n\n// Save failed events in localStorage\nfunction persistFailed(events: TelemetryEvent[]) {\n if (typeof localStorage === \"undefined\") return;\n const existing = JSON.parse(localStorage.getItem(STORAGE_KEY) || \"[]\");\n localStorage.setItem(STORAGE_KEY, JSON.stringify([...existing, ...events]));\n}\n\n// Try sending a batch with retries + backoff.\n// v3 uses fetch({ keepalive: true }) rather than navigator.sendBeacon: the beacon\n// API cannot set the required X-API-Key header. keepalive preserves the\n// survives-page-unload property we relied on sendBeacon for.\nasync function sendWithRetry(endpoint: string, apiKey: string | undefined, events: TelemetryEvent[], retryCount: number = 3) {\n let attempts = 0;\n let lastError: any;\n\n while (attempts < retryCount) {\n try {\n const res = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey ? { \"X-API-Key\": apiKey } : {}),\n },\n body: buildBatch(events),\n keepalive: true,\n });\n\n if (!res.ok) {\n throw new Error(`Telemetry send failed: ${res.status}`);\n }\n\n return; // ✅ success\n } catch (err) {\n lastError = err;\n attempts++;\n if (attempts < retryCount) {\n await new Promise(res => setTimeout(res, attempts * 500)); // backoff\n }\n }\n }\n\n // ❌ after retries still failed\n throw lastError;\n}\n\nexport function webSender(endpoint: string = DEFAULT_ENDPOINT, apiKey?: string, retryCount: number = 3): Sender {\n return {\n async send(events: TelemetryEvent[]) {\n // Retry + backoff here; persistence on final failure is the core flush()'s\n // job via onFailure() — kept single, so a failed batch isn't persisted twice.\n await sendWithRetry(endpoint, apiKey, events, retryCount);\n },\n async onFailure(events: TelemetryEvent[]) {\n persistFailed(events);\n },\n };\n}\n\n// Replay failed events on startup\nexport function replayFailedWeb(endpoint: string = DEFAULT_ENDPOINT, apiKey?: string, retryCount: number = 3) {\n debug.log(\"Telemetry replayFailedWeb launched\");\n if (typeof localStorage === \"undefined\") return;\n const stored = JSON.parse(localStorage.getItem(STORAGE_KEY) || \"[]\") as TelemetryEvent[];\n if (stored.length > 0) {\n localStorage.removeItem(STORAGE_KEY);\n return sendWithRetry(endpoint, apiKey, stored, retryCount).catch(err => {\n // If replay fails again, re-persist\n persistFailed(stored);\n debug.warn(\"Telemetry replay failed:\", err);\n });\n }\n}\n\n"],"names":["DEFAULT_ENDPOINT","STORAGE_KEY","persistFailed","events","existing","sendWithRetry","endpoint","apiKey","retryCount","attempts","lastError","res","buildBatch","err","webSender"],"mappings":"wHAIMA,EAAmB,0CACnBC,EAAc,0BAGpB,SAASC,EAAcC,EAA0B,CAC7C,GAAI,OAAO,aAAiB,IAAa,OACzC,MAAMC,EAAW,KAAK,MAAM,aAAa,QAAQH,CAAW,GAAK,IAAI,EACrE,aAAa,QAAQA,EAAa,KAAK,UAAU,CAAC,GAAGG,EAAU,GAAGD,CAAM,CAAC,CAAC,CAC9E,CAMA,eAAeE,EAAcC,EAAkBC,EAA4BJ,EAA0BK,EAAqB,EAAG,CACzH,IAAIC,EAAW,EACXC,EAEJ,KAAOD,EAAWD,GACd,GAAI,CACA,MAAMG,EAAM,MAAM,MAAML,EAAU,CAC9B,OAAQ,OACR,QAAS,CACL,eAAgB,mBAChB,GAAIC,EAAS,CAAE,YAAaA,GAAW,CAAA,CAAC,EAE5C,KAAMK,EAAAA,WAAWT,CAAM,EACvB,UAAW,EAAA,CACd,EAED,GAAI,CAACQ,EAAI,GACL,MAAM,IAAI,MAAM,0BAA0BA,EAAI,MAAM,EAAE,EAG1D,MACJ,OAASE,EAAK,CACVH,EAAYG,EACZJ,IACIA,EAAWD,GACX,MAAM,IAAI,QAAQG,GAAO,WAAWA,EAAKF,EAAW,GAAG,CAAC,CAEhE,CAIJ,MAAMC,CACV,CAEO,SAASI,EAAUR,EAAmBN,EAAkBO,EAAiBC,EAAqB,EAAW,CAC5G,MAAO,CACH,MAAM,KAAKL,EAA0B,CAGjC,MAAME,EAAcC,EAAUC,EAAQJ,EAAQK,CAAU,CAC5D,EACA,MAAM,UAAUL,EAA0B,CACtCD,EAAcC,CAAM,CACxB,CAAA,CAER"}
|