onerway-analytics 1.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/dist/bundle/index.js +1361 -0
- package/dist/bundle/index.js.map +7 -0
- package/dist/core/analytics.d.ts +45 -0
- package/dist/core/analytics.d.ts.map +1 -0
- package/dist/core/analytics.js +369 -0
- package/dist/core/analytics.test.d.ts +2 -0
- package/dist/core/analytics.test.d.ts.map +1 -0
- package/dist/core/analytics.test.js +169 -0
- package/dist/core/auto-track.d.ts +6 -0
- package/dist/core/auto-track.d.ts.map +1 -0
- package/dist/core/auto-track.js +126 -0
- package/dist/core/context-collector.d.ts +4 -0
- package/dist/core/context-collector.d.ts.map +1 -0
- package/dist/core/context-collector.js +42 -0
- package/dist/core/error-monitor.d.ts +5 -0
- package/dist/core/error-monitor.d.ts.map +1 -0
- package/dist/core/error-monitor.js +61 -0
- package/dist/core/ga-adapter.d.ts +12 -0
- package/dist/core/ga-adapter.d.ts.map +1 -0
- package/dist/core/ga-adapter.js +35 -0
- package/dist/core/ga-loader.d.ts +10 -0
- package/dist/core/ga-loader.d.ts.map +1 -0
- package/dist/core/ga-loader.js +30 -0
- package/dist/core/ga-manager.d.ts +24 -0
- package/dist/core/ga-manager.d.ts.map +1 -0
- package/dist/core/ga-manager.js +64 -0
- package/dist/core/performance-monitor.d.ts +5 -0
- package/dist/core/performance-monitor.d.ts.map +1 -0
- package/dist/core/performance-monitor.js +43 -0
- package/dist/core/sender.d.ts +10 -0
- package/dist/core/sender.d.ts.map +1 -0
- package/dist/core/sender.js +65 -0
- package/dist/core/session-manager.d.ts +13 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +54 -0
- package/dist/core/storage.d.ts +9 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +48 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/types/index.d.ts +162 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +28 -0
- package/dist/utils/index.d.ts +30 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +216 -0
- package/package.json +47 -0
|
@@ -0,0 +1,1361 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var OnrwayAnalytics = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
API_KEY_MAP: () => API_KEY_MAP,
|
|
25
|
+
Analytics: () => Analytics,
|
|
26
|
+
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
27
|
+
GAManager: () => GAManager,
|
|
28
|
+
SDK_VERSION: () => SDK_VERSION,
|
|
29
|
+
STORAGE_KEYS: () => STORAGE_KEYS,
|
|
30
|
+
Sender: () => Sender,
|
|
31
|
+
SessionManager: () => SessionManager,
|
|
32
|
+
StorageQueue: () => StorageQueue,
|
|
33
|
+
collectContext: () => collectContext,
|
|
34
|
+
collectMarketing: () => collectMarketing,
|
|
35
|
+
createAnalytics: () => createAnalytics,
|
|
36
|
+
detectBrowser: () => detectBrowser,
|
|
37
|
+
detectOS: () => detectOS,
|
|
38
|
+
generateId: () => generateId,
|
|
39
|
+
generateUUID: () => generateUUID,
|
|
40
|
+
getCountryFromLanguage: () => getCountryFromLanguage,
|
|
41
|
+
getDeviceType: () => getDeviceType,
|
|
42
|
+
getHostname: () => getHostname,
|
|
43
|
+
getLanguage: () => getLanguage,
|
|
44
|
+
getPageUrl: () => getPageUrl,
|
|
45
|
+
getReferrer: () => getReferrer,
|
|
46
|
+
getScreenSize: () => getScreenSize,
|
|
47
|
+
getTimestamp: () => getTimestamp,
|
|
48
|
+
getTimezone: () => getTimezone,
|
|
49
|
+
initAutoTrack: () => initAutoTrack,
|
|
50
|
+
initErrorMonitor: () => initErrorMonitor,
|
|
51
|
+
initPerformanceMonitor: () => initPerformanceMonitor,
|
|
52
|
+
isBrowser: () => isBrowser,
|
|
53
|
+
isObject: () => isObject,
|
|
54
|
+
merge: () => merge,
|
|
55
|
+
parseUTMParams: () => parseUTMParams,
|
|
56
|
+
truncateText: () => truncateText
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// src/types/index.ts
|
|
60
|
+
var API_KEY_MAP = {
|
|
61
|
+
beta: "5skbadERCne5HKSS9a1EXz5RetUiEfpP",
|
|
62
|
+
development: "5skbadERCne5HKSS9a1EXz5RetUiEfpP",
|
|
63
|
+
test: "Dguh5yxNDEwyQlqDmikmd7ImruaOp8c8",
|
|
64
|
+
testing: "Dguh5yxNDEwyQlqDmikmd7ImruaOp8c8",
|
|
65
|
+
sit: "Dguh5yxNDEwyQlqDmikmd7ImruaOp8c8",
|
|
66
|
+
uat: "W565QolX6clTuL1Kqgpp0JmUqBkWKY6i",
|
|
67
|
+
prod: "HUk5Kogyuv9zH5qDA2qSCjVEnhanSkf8",
|
|
68
|
+
production: "HUk5Kogyuv9zH5qDA2qSCjVEnhanSkf8"
|
|
69
|
+
};
|
|
70
|
+
var SDK_VERSION = "1.0.0";
|
|
71
|
+
var DEFAULT_CONFIG = {
|
|
72
|
+
debug: false,
|
|
73
|
+
autoTrack: true,
|
|
74
|
+
bufferFlushInterval: 5e3,
|
|
75
|
+
bufferMaxSize: 25,
|
|
76
|
+
maxRetryCount: 3,
|
|
77
|
+
sessionTimeout: 30 * 60 * 1e3,
|
|
78
|
+
clientType: "WEB",
|
|
79
|
+
merchantLanguage: "en"
|
|
80
|
+
};
|
|
81
|
+
var STORAGE_KEYS = {
|
|
82
|
+
FAILED_QUEUE: "__analytics_failed_queue__",
|
|
83
|
+
CLIENT_ID: "__analytics_client_id__",
|
|
84
|
+
LANDING_PAGE: "__analytics_landing_page__",
|
|
85
|
+
REFERRER_URL: "__analytics_referrer_url__"
|
|
86
|
+
};
|
|
87
|
+
var MAX_STORAGE_ITEMS = 500;
|
|
88
|
+
|
|
89
|
+
// src/utils/index.ts
|
|
90
|
+
function generateId() {
|
|
91
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
92
|
+
}
|
|
93
|
+
function getTimestamp() {
|
|
94
|
+
return Date.now();
|
|
95
|
+
}
|
|
96
|
+
function isObject(value) {
|
|
97
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
98
|
+
}
|
|
99
|
+
function merge(target, source) {
|
|
100
|
+
const result = { ...target };
|
|
101
|
+
for (const key in source) {
|
|
102
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
103
|
+
result[key] = source[key];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
function generateUUID() {
|
|
109
|
+
const hex = "0123456789abcdef";
|
|
110
|
+
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
|
|
111
|
+
return template.replace(/[xy]/g, (c2) => {
|
|
112
|
+
const r2 = Math.random() * 16 | 0;
|
|
113
|
+
const v2 = c2 === "x" ? r2 : r2 & 3 | 8;
|
|
114
|
+
return hex[v2];
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function detectBrowser() {
|
|
118
|
+
if (typeof navigator === "undefined") return { name: "Unknown", version: "0" };
|
|
119
|
+
const ua = navigator.userAgent;
|
|
120
|
+
const edgeMatch = ua.match(/Edg\/(\d+)/);
|
|
121
|
+
if (edgeMatch) return { name: "Edge", version: edgeMatch[1] };
|
|
122
|
+
const chromeMatch = ua.match(/Chrome\/(\d+)/);
|
|
123
|
+
const safariMatch = ua.match(/Safari\/(\d+)/);
|
|
124
|
+
if (chromeMatch && !ua.includes("Edg") && !ua.includes("OPR")) {
|
|
125
|
+
return { name: "Chrome", version: chromeMatch[1] };
|
|
126
|
+
}
|
|
127
|
+
const firefoxMatch = ua.match(/Firefox\/(\d+)/);
|
|
128
|
+
if (firefoxMatch) return { name: "Firefox", version: firefoxMatch[1] };
|
|
129
|
+
const opMatch = ua.match(/OPR\/(\d+)/);
|
|
130
|
+
if (opMatch) return { name: "Opera", version: opMatch[1] };
|
|
131
|
+
if (safariMatch && !ua.includes("Chrome")) {
|
|
132
|
+
const versionMatch = ua.match(/Version\/(\d+)/);
|
|
133
|
+
return { name: "Safari", version: versionMatch ? versionMatch[1] : safariMatch[1] };
|
|
134
|
+
}
|
|
135
|
+
const ieMatch = ua.match(/(?:MSIE |Trident\/.*; rv:)(\d+)/);
|
|
136
|
+
if (ieMatch) return { name: "IE", version: ieMatch[1] };
|
|
137
|
+
return { name: "Unknown", version: "0" };
|
|
138
|
+
}
|
|
139
|
+
function detectOS() {
|
|
140
|
+
if (typeof navigator === "undefined") return { name: "Unknown", version: "0" };
|
|
141
|
+
const ua = navigator.userAgent;
|
|
142
|
+
const platform = navigator.platform || "";
|
|
143
|
+
if (ua.includes("Windows NT 10")) return { name: "Windows", version: "10" };
|
|
144
|
+
if (ua.includes("Windows NT 6.3")) return { name: "Windows", version: "8.1" };
|
|
145
|
+
if (ua.includes("Windows NT 6.2")) return { name: "Windows", version: "8" };
|
|
146
|
+
if (ua.includes("Windows NT 6.1")) return { name: "Windows", version: "7" };
|
|
147
|
+
if (/Windows NT \d/.test(ua)) return { name: "Windows", version: ua.match(/Windows NT (\d+\.?\d*)/)?.[1] || "0" };
|
|
148
|
+
const macMatch = ua.match(/Mac OS X (\d+[._]\d+)/);
|
|
149
|
+
if (macMatch) return { name: "macOS", version: macMatch[1].replace("_", ".") };
|
|
150
|
+
if (platform.startsWith("Mac")) return { name: "macOS", version: "0" };
|
|
151
|
+
if (/Android (\d+\.?\d*)/.test(ua)) return { name: "Android", version: ua.match(/Android (\d+\.?\d*)/)?.[1] || "0" };
|
|
152
|
+
if (/iPhone|iPad|iPod/.test(ua)) {
|
|
153
|
+
const iosMatch = ua.match(/OS (\d+[._]\d+)/);
|
|
154
|
+
return { name: "iOS", version: iosMatch ? iosMatch[1].replace("_", ".") : "0" };
|
|
155
|
+
}
|
|
156
|
+
if (/Linux/.test(ua) || platform.includes("Linux")) return { name: "Linux", version: "0" };
|
|
157
|
+
return { name: "Unknown", version: "0" };
|
|
158
|
+
}
|
|
159
|
+
function getDeviceType() {
|
|
160
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") return "desktop";
|
|
161
|
+
const width = window.screen.width;
|
|
162
|
+
const hasTouch = navigator.maxTouchPoints > 0;
|
|
163
|
+
if (width < 768 && hasTouch) return "mobile";
|
|
164
|
+
if (width >= 768 && width <= 1024 && hasTouch) return "tablet";
|
|
165
|
+
return "desktop";
|
|
166
|
+
}
|
|
167
|
+
function getScreenSize() {
|
|
168
|
+
if (typeof window === "undefined") return { width: 0, height: 0 };
|
|
169
|
+
return {
|
|
170
|
+
width: window.screen.width,
|
|
171
|
+
height: window.screen.height
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function getPageUrl() {
|
|
175
|
+
if (typeof window === "undefined") return "";
|
|
176
|
+
return window.location.href;
|
|
177
|
+
}
|
|
178
|
+
function getReferrer() {
|
|
179
|
+
if (typeof document === "undefined") return "";
|
|
180
|
+
return document.referrer || "";
|
|
181
|
+
}
|
|
182
|
+
function getHostname() {
|
|
183
|
+
if (typeof window === "undefined") return "";
|
|
184
|
+
return window.location.host.split(":")[0];
|
|
185
|
+
}
|
|
186
|
+
function getTimezone() {
|
|
187
|
+
try {
|
|
188
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
189
|
+
} catch {
|
|
190
|
+
return "UTC";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function getLanguage() {
|
|
194
|
+
if (typeof navigator === "undefined") return "en-US";
|
|
195
|
+
return navigator.language || "en-US";
|
|
196
|
+
}
|
|
197
|
+
function getCountryFromLanguage(language) {
|
|
198
|
+
const parts = language.split("-");
|
|
199
|
+
if (parts.length > 1) return parts[1].toUpperCase();
|
|
200
|
+
const langMap = {
|
|
201
|
+
zh: "CN",
|
|
202
|
+
en: "US",
|
|
203
|
+
ja: "JP",
|
|
204
|
+
ko: "KR",
|
|
205
|
+
fr: "FR",
|
|
206
|
+
de: "DE",
|
|
207
|
+
es: "ES",
|
|
208
|
+
pt: "BR",
|
|
209
|
+
ru: "RU",
|
|
210
|
+
ar: "SA"
|
|
211
|
+
};
|
|
212
|
+
return langMap[parts[0]] || parts[0].toUpperCase();
|
|
213
|
+
}
|
|
214
|
+
function parseUTMParams() {
|
|
215
|
+
if (typeof window === "undefined") return {};
|
|
216
|
+
const params = {};
|
|
217
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
218
|
+
const utmKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
|
|
219
|
+
for (const key of utmKeys) {
|
|
220
|
+
const value = searchParams.get(key);
|
|
221
|
+
if (value) params[key] = value;
|
|
222
|
+
}
|
|
223
|
+
return params;
|
|
224
|
+
}
|
|
225
|
+
function isBrowser() {
|
|
226
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
227
|
+
}
|
|
228
|
+
function safeLocalStorageGet(key) {
|
|
229
|
+
try {
|
|
230
|
+
return localStorage.getItem(key);
|
|
231
|
+
} catch {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function safeLocalStorageSet(key, value) {
|
|
236
|
+
try {
|
|
237
|
+
localStorage.setItem(key, value);
|
|
238
|
+
return true;
|
|
239
|
+
} catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function safeLocalStorageRemove(key) {
|
|
244
|
+
try {
|
|
245
|
+
localStorage.removeItem(key);
|
|
246
|
+
} catch {
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function safeSessionStorageGet(key) {
|
|
250
|
+
try {
|
|
251
|
+
return sessionStorage.getItem(key);
|
|
252
|
+
} catch {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function safeSessionStorageSet(key, value) {
|
|
257
|
+
try {
|
|
258
|
+
sessionStorage.setItem(key, value);
|
|
259
|
+
return true;
|
|
260
|
+
} catch {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function truncateText(text, maxLength) {
|
|
265
|
+
if (!text) return "";
|
|
266
|
+
const trimmed = text.trim().replace(/\s+/g, " ");
|
|
267
|
+
return trimmed.length > maxLength ? trimmed.substring(0, maxLength) + "..." : trimmed;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/core/session-manager.ts
|
|
271
|
+
var SESSION_KEY = "__analytics_session__";
|
|
272
|
+
var SESSION_DEFAULT_TIMEOUT = 30 * 60 * 1e3;
|
|
273
|
+
var SessionManager = class {
|
|
274
|
+
constructor(timeout = SESSION_DEFAULT_TIMEOUT) {
|
|
275
|
+
this.createdAt = 0;
|
|
276
|
+
this.timeout = timeout;
|
|
277
|
+
const existing = this.loadSession();
|
|
278
|
+
if (existing && !this.isExpired(existing)) {
|
|
279
|
+
this.sessionId = existing.sessionId;
|
|
280
|
+
this.createdAt = existing.createdAt;
|
|
281
|
+
} else {
|
|
282
|
+
this.sessionId = this.createNewSession();
|
|
283
|
+
this.createdAt = Date.now();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
getSessionId() {
|
|
287
|
+
if (this.isExpired({ sessionId: this.sessionId, createdAt: this.createdAt })) {
|
|
288
|
+
this.sessionId = this.createNewSession();
|
|
289
|
+
}
|
|
290
|
+
return this.sessionId;
|
|
291
|
+
}
|
|
292
|
+
refresh() {
|
|
293
|
+
this.sessionId = this.createNewSession();
|
|
294
|
+
}
|
|
295
|
+
loadSession() {
|
|
296
|
+
try {
|
|
297
|
+
const raw = safeSessionStorageGet(SESSION_KEY);
|
|
298
|
+
if (!raw) return null;
|
|
299
|
+
return JSON.parse(raw);
|
|
300
|
+
} catch {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
saveSession() {
|
|
305
|
+
const data = {
|
|
306
|
+
sessionId: this.sessionId,
|
|
307
|
+
createdAt: this.createdAt
|
|
308
|
+
};
|
|
309
|
+
safeSessionStorageSet(SESSION_KEY, JSON.stringify(data));
|
|
310
|
+
}
|
|
311
|
+
isExpired(data) {
|
|
312
|
+
return Date.now() - data.createdAt > this.timeout;
|
|
313
|
+
}
|
|
314
|
+
createNewSession() {
|
|
315
|
+
const id = generateUUID();
|
|
316
|
+
this.createdAt = Date.now();
|
|
317
|
+
this.saveSession();
|
|
318
|
+
return id;
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
// src/core/sender.ts
|
|
323
|
+
var Sender = class _Sender {
|
|
324
|
+
static async send(payload, serverUrl, apiKey) {
|
|
325
|
+
if (_Sender.supportsKeepalive()) {
|
|
326
|
+
return _Sender.fetchSend(payload, serverUrl, apiKey);
|
|
327
|
+
}
|
|
328
|
+
return _Sender.xhrSend(payload, serverUrl, apiKey);
|
|
329
|
+
}
|
|
330
|
+
static async sendBeacon(payload, serverUrl, apiKey) {
|
|
331
|
+
if (typeof navigator === "undefined" || !navigator.sendBeacon) {
|
|
332
|
+
throw new Error("sendBeacon not available");
|
|
333
|
+
}
|
|
334
|
+
const url = _Sender.buildBeaconUrl(serverUrl, apiKey);
|
|
335
|
+
const blob = new Blob([JSON.stringify(payload)], { type: "application/json" });
|
|
336
|
+
const success = navigator.sendBeacon(url, blob);
|
|
337
|
+
if (!success) {
|
|
338
|
+
throw new Error("sendBeacon rejected payload");
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
static async fetchSend(payload, serverUrl, apiKey) {
|
|
342
|
+
const response = await fetch(serverUrl, {
|
|
343
|
+
method: "POST",
|
|
344
|
+
headers: {
|
|
345
|
+
"Content-Type": "application/json",
|
|
346
|
+
apiKey
|
|
347
|
+
},
|
|
348
|
+
body: JSON.stringify(payload),
|
|
349
|
+
keepalive: true
|
|
350
|
+
});
|
|
351
|
+
if (!response.ok) {
|
|
352
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
static async xhrSend(payload, serverUrl, apiKey) {
|
|
356
|
+
return new Promise((resolve, reject) => {
|
|
357
|
+
const xhr = new XMLHttpRequest();
|
|
358
|
+
xhr.open("POST", serverUrl);
|
|
359
|
+
xhr.setRequestHeader("Content-Type", "application/json");
|
|
360
|
+
xhr.setRequestHeader("apiKey", apiKey);
|
|
361
|
+
xhr.timeout = 1e4;
|
|
362
|
+
xhr.onload = () => {
|
|
363
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
364
|
+
resolve();
|
|
365
|
+
} else {
|
|
366
|
+
reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
xhr.onerror = () => reject(new Error("XHR network error"));
|
|
370
|
+
xhr.ontimeout = () => reject(new Error("XHR timeout"));
|
|
371
|
+
xhr.send(JSON.stringify(payload));
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
static supportsKeepalive() {
|
|
375
|
+
try {
|
|
376
|
+
return typeof Request !== "undefined" && "keepalive" in Request.prototype;
|
|
377
|
+
} catch {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
static buildBeaconUrl(serverUrl, apiKey) {
|
|
382
|
+
const separator = serverUrl.includes("?") ? "&" : "?";
|
|
383
|
+
return `${serverUrl}${separator}apiKey=${encodeURIComponent(apiKey)}`;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/core/storage.ts
|
|
388
|
+
var StorageQueue = class _StorageQueue {
|
|
389
|
+
static enqueue(event) {
|
|
390
|
+
try {
|
|
391
|
+
const queue = _StorageQueue.readQueue();
|
|
392
|
+
queue.push({ event, storedAt: Date.now() });
|
|
393
|
+
while (queue.length > MAX_STORAGE_ITEMS) {
|
|
394
|
+
queue.shift();
|
|
395
|
+
}
|
|
396
|
+
safeLocalStorageSet(STORAGE_KEYS.FAILED_QUEUE, JSON.stringify(queue));
|
|
397
|
+
} catch {
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
static recover() {
|
|
401
|
+
try {
|
|
402
|
+
const queue = _StorageQueue.readQueue();
|
|
403
|
+
_StorageQueue.clear();
|
|
404
|
+
const events = queue.map((item) => item.event);
|
|
405
|
+
return events;
|
|
406
|
+
} catch {
|
|
407
|
+
return [];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
static clear() {
|
|
411
|
+
safeLocalStorageRemove(STORAGE_KEYS.FAILED_QUEUE);
|
|
412
|
+
}
|
|
413
|
+
static getQueueSize() {
|
|
414
|
+
return _StorageQueue.readQueue().length;
|
|
415
|
+
}
|
|
416
|
+
static readQueue() {
|
|
417
|
+
try {
|
|
418
|
+
const raw = safeLocalStorageGet(STORAGE_KEYS.FAILED_QUEUE);
|
|
419
|
+
if (!raw) return [];
|
|
420
|
+
const parsed = JSON.parse(raw);
|
|
421
|
+
if (!Array.isArray(parsed)) return [];
|
|
422
|
+
return parsed;
|
|
423
|
+
} catch {
|
|
424
|
+
return [];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
// src/core/context-collector.ts
|
|
430
|
+
function collectContext(appKey, merchantLanguage, clientType) {
|
|
431
|
+
const screen = getScreenSize();
|
|
432
|
+
return {
|
|
433
|
+
sdk_version: SDK_VERSION,
|
|
434
|
+
app_key: appKey,
|
|
435
|
+
screen_width: screen.width,
|
|
436
|
+
screen_height: screen.height,
|
|
437
|
+
user_agent: isBrowser() ? navigator.userAgent : "",
|
|
438
|
+
referrer: getReferrer(),
|
|
439
|
+
hostname: getHostname(),
|
|
440
|
+
browser: detectBrowser(),
|
|
441
|
+
operating_system: detectOS(),
|
|
442
|
+
device_type: getDeviceType(),
|
|
443
|
+
country: getCountryFromLanguage(getLanguage()),
|
|
444
|
+
language: getLanguage(),
|
|
445
|
+
merchant_language: merchantLanguage,
|
|
446
|
+
timezone: getTimezone(),
|
|
447
|
+
client_type: clientType
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function collectMarketing() {
|
|
451
|
+
if (!isBrowser()) return {};
|
|
452
|
+
const utm = parseUTMParams();
|
|
453
|
+
let landingPage = safeLocalStorageGet(STORAGE_KEYS.LANDING_PAGE);
|
|
454
|
+
if (!landingPage) {
|
|
455
|
+
landingPage = window.location.href;
|
|
456
|
+
safeLocalStorageSet(STORAGE_KEYS.LANDING_PAGE, landingPage);
|
|
457
|
+
}
|
|
458
|
+
let referrerUrl = safeLocalStorageGet(STORAGE_KEYS.REFERRER_URL);
|
|
459
|
+
if (referrerUrl === null && document.referrer) {
|
|
460
|
+
referrerUrl = document.referrer;
|
|
461
|
+
safeLocalStorageSet(STORAGE_KEYS.REFERRER_URL, referrerUrl);
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
...utm,
|
|
465
|
+
landing_page: landingPage || window.location.href,
|
|
466
|
+
referrer_url: referrerUrl || ""
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/core/auto-track.ts
|
|
471
|
+
var TRACK_ATTR_PREFIX = "data-track-";
|
|
472
|
+
var IGNORE_ATTR = "data-track-ignore";
|
|
473
|
+
var NAME_ATTR = "data-track-name";
|
|
474
|
+
var PROPS_ATTR = "data-track-properties";
|
|
475
|
+
function initAutoTrack(api, selector) {
|
|
476
|
+
if (typeof document === "undefined") return;
|
|
477
|
+
const handler = (e2) => {
|
|
478
|
+
try {
|
|
479
|
+
const target = e2.target;
|
|
480
|
+
if (!target) return;
|
|
481
|
+
if (shouldIgnoreElement(target)) return;
|
|
482
|
+
if (selector) {
|
|
483
|
+
const scope = document.querySelector(selector);
|
|
484
|
+
if (scope && !scope.contains(target)) return;
|
|
485
|
+
}
|
|
486
|
+
const eventName = getTrackName(target);
|
|
487
|
+
const properties = collectElementProperties(target);
|
|
488
|
+
api.track(eventName, properties);
|
|
489
|
+
} catch {
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
document.addEventListener("click", handler, true);
|
|
493
|
+
}
|
|
494
|
+
function shouldIgnoreElement(element) {
|
|
495
|
+
let current = element;
|
|
496
|
+
while (current) {
|
|
497
|
+
if (current.hasAttribute(IGNORE_ATTR)) return true;
|
|
498
|
+
current = current.parentElement;
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
function getTrackName(element) {
|
|
503
|
+
const name = element.getAttribute(NAME_ATTR);
|
|
504
|
+
if (name) return name;
|
|
505
|
+
const id = element.id ? `_${element.id}` : "";
|
|
506
|
+
const tag = element.tagName.toLowerCase();
|
|
507
|
+
return `click_${tag}${id}`;
|
|
508
|
+
}
|
|
509
|
+
function collectElementProperties(element) {
|
|
510
|
+
const props = {
|
|
511
|
+
action: "click",
|
|
512
|
+
target_type: inferTargetType(element),
|
|
513
|
+
target_id: getTargetId(element),
|
|
514
|
+
target_tag: element.tagName.toLowerCase(),
|
|
515
|
+
target_class: getTruncatedClassName(element),
|
|
516
|
+
target_text: truncateText(element.innerText || "", 50)
|
|
517
|
+
};
|
|
518
|
+
if (element.hasAttribute("href") || element.closest("a")) {
|
|
519
|
+
const anchor = element.closest("a");
|
|
520
|
+
if (anchor) {
|
|
521
|
+
props.target_href = anchor.getAttribute("href") || "";
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
const customProps = collectDataTrackProps(element);
|
|
525
|
+
Object.assign(props, customProps);
|
|
526
|
+
return props;
|
|
527
|
+
}
|
|
528
|
+
function inferTargetType(element) {
|
|
529
|
+
const tag = element.tagName.toLowerCase();
|
|
530
|
+
if (tag === "a" || tag === "button") return "button";
|
|
531
|
+
if (tag === "input") {
|
|
532
|
+
const type = element.type;
|
|
533
|
+
if (type === "submit" || type === "button" || type === "reset") return "button";
|
|
534
|
+
if (type === "checkbox" || type === "radio") return "checkbox";
|
|
535
|
+
return "input";
|
|
536
|
+
}
|
|
537
|
+
if (tag === "select") return "select";
|
|
538
|
+
if (tag === "img") return "image";
|
|
539
|
+
if (tag === "form") return "form";
|
|
540
|
+
if (tag === "textarea") return "input";
|
|
541
|
+
return "element";
|
|
542
|
+
}
|
|
543
|
+
function getTargetId(element) {
|
|
544
|
+
if (element.id) return element.id;
|
|
545
|
+
const name = element.getAttribute("name");
|
|
546
|
+
if (name) return name;
|
|
547
|
+
const dataTestId = element.getAttribute("data-testid") || element.getAttribute("data-test-id");
|
|
548
|
+
if (dataTestId) return dataTestId;
|
|
549
|
+
return "";
|
|
550
|
+
}
|
|
551
|
+
function getTruncatedClassName(element) {
|
|
552
|
+
const cls = typeof element.className === "string" ? element.className : "";
|
|
553
|
+
return truncateText(cls, 100);
|
|
554
|
+
}
|
|
555
|
+
function collectDataTrackProps(element) {
|
|
556
|
+
const props = {};
|
|
557
|
+
const trackName = element.getAttribute(NAME_ATTR);
|
|
558
|
+
if (trackName) props.name = trackName;
|
|
559
|
+
const rawProps = element.getAttribute(PROPS_ATTR);
|
|
560
|
+
if (rawProps) {
|
|
561
|
+
try {
|
|
562
|
+
const parsed = JSON.parse(rawProps);
|
|
563
|
+
Object.assign(props, parsed);
|
|
564
|
+
} catch {
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
for (const attr of Array.from(element.attributes)) {
|
|
568
|
+
if (attr.name.startsWith(TRACK_ATTR_PREFIX) && attr.name !== NAME_ATTR && attr.name !== PROPS_ATTR && attr.name !== IGNORE_ATTR) {
|
|
569
|
+
const key = attr.name.replace(TRACK_ATTR_PREFIX, "");
|
|
570
|
+
props[key] = attr.value;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return props;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/core/error-monitor.ts
|
|
577
|
+
function initErrorMonitor(api) {
|
|
578
|
+
if (typeof window === "undefined") return;
|
|
579
|
+
window.addEventListener("error", (event) => {
|
|
580
|
+
try {
|
|
581
|
+
const { message, filename, lineno, colno, error } = event;
|
|
582
|
+
const isResourceError = !message && event.target !== window;
|
|
583
|
+
if (isResourceError) return;
|
|
584
|
+
api.track("error_event", {
|
|
585
|
+
action: "error",
|
|
586
|
+
target_type: "system",
|
|
587
|
+
error_type: "window_error",
|
|
588
|
+
error_message: message || "Unknown error",
|
|
589
|
+
error_filename: filename || "",
|
|
590
|
+
error_lineno: lineno || 0,
|
|
591
|
+
error_colno: colno || 0,
|
|
592
|
+
error_stack: error instanceof Error ? error.stack : "",
|
|
593
|
+
error_name: error instanceof Error ? error.name : ""
|
|
594
|
+
});
|
|
595
|
+
} catch {
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
599
|
+
try {
|
|
600
|
+
const { reason } = event;
|
|
601
|
+
let errorMessage = "Unhandled Promise Rejection";
|
|
602
|
+
let errorStack = "";
|
|
603
|
+
let errorName = "PromiseRejection";
|
|
604
|
+
if (reason instanceof Error) {
|
|
605
|
+
errorMessage = reason.message;
|
|
606
|
+
errorStack = reason.stack || "";
|
|
607
|
+
errorName = reason.name;
|
|
608
|
+
} else if (typeof reason === "string") {
|
|
609
|
+
errorMessage = reason;
|
|
610
|
+
} else {
|
|
611
|
+
try {
|
|
612
|
+
errorMessage = JSON.stringify(reason);
|
|
613
|
+
} catch {
|
|
614
|
+
errorMessage = String(reason);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
api.track("error_event", {
|
|
618
|
+
action: "error",
|
|
619
|
+
target_type: "system",
|
|
620
|
+
error_type: "unhandled_rejection",
|
|
621
|
+
error_message: errorMessage,
|
|
622
|
+
error_stack: errorStack,
|
|
623
|
+
error_name: errorName
|
|
624
|
+
});
|
|
625
|
+
} catch {
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/core/ga-loader.ts
|
|
631
|
+
function loadGtagScript(measurementId) {
|
|
632
|
+
return new Promise((resolve, reject) => {
|
|
633
|
+
if (typeof window !== "undefined" && typeof window.gtag === "function") {
|
|
634
|
+
resolve();
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const script = document.createElement("script");
|
|
638
|
+
script.async = true;
|
|
639
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${measurementId}`;
|
|
640
|
+
script.onload = () => resolve();
|
|
641
|
+
script.onerror = () => reject(new Error("Failed to load gtag.js"));
|
|
642
|
+
document.head.appendChild(script);
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
async function initGA(config) {
|
|
646
|
+
if (!config.enabled || !config.measurementId) return;
|
|
647
|
+
if (typeof window === "undefined") return;
|
|
648
|
+
await loadGtagScript(config.measurementId);
|
|
649
|
+
window.dataLayer = window.dataLayer || [];
|
|
650
|
+
window.gtag = function gtag(...args) {
|
|
651
|
+
window.dataLayer.push(args);
|
|
652
|
+
};
|
|
653
|
+
window.gtag("js", /* @__PURE__ */ new Date());
|
|
654
|
+
window.gtag("config", config.measurementId, {
|
|
655
|
+
send_page_view: config.sendPageView ?? false,
|
|
656
|
+
debug_mode: config.debugMode ?? false
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// node_modules/web-vitals/dist/web-vitals.js
|
|
661
|
+
var e = -1;
|
|
662
|
+
var t = (t2) => {
|
|
663
|
+
addEventListener("pageshow", (n2) => {
|
|
664
|
+
n2.persisted && (e = n2.timeStamp, t2(n2));
|
|
665
|
+
}, true);
|
|
666
|
+
};
|
|
667
|
+
var n = (e2, t2, n2, i2) => {
|
|
668
|
+
let s2, o2;
|
|
669
|
+
return (r2) => {
|
|
670
|
+
t2.value >= 0 && (r2 || i2) && (o2 = t2.value - (s2 ?? 0), (o2 || void 0 === s2) && (s2 = t2.value, t2.delta = o2, t2.rating = ((e3, t3) => e3 > t3[1] ? "poor" : e3 > t3[0] ? "needs-improvement" : "good")(t2.value, n2), e2(t2)));
|
|
671
|
+
};
|
|
672
|
+
};
|
|
673
|
+
var i = (e2) => {
|
|
674
|
+
requestAnimationFrame(() => requestAnimationFrame(e2));
|
|
675
|
+
};
|
|
676
|
+
var s = () => {
|
|
677
|
+
const e2 = performance.getEntriesByType("navigation")[0];
|
|
678
|
+
if (e2 && e2.responseStart > 0 && e2.responseStart < performance.now()) return e2;
|
|
679
|
+
};
|
|
680
|
+
var o = () => s()?.activationStart ?? 0;
|
|
681
|
+
var r = (t2, n2 = -1) => {
|
|
682
|
+
const i2 = s();
|
|
683
|
+
let r2 = "navigate";
|
|
684
|
+
e >= 0 ? r2 = "back-forward-cache" : i2 && (document.prerendering || o() > 0 ? r2 = "prerender" : document.wasDiscarded ? r2 = "restore" : i2.type && (r2 = i2.type.replace(/_/g, "-")));
|
|
685
|
+
return { name: t2, value: n2, rating: "good", delta: 0, entries: [], id: `v5-${Date.now()}-${Math.floor(8999999999999 * Math.random()) + 1e12}`, navigationType: r2 };
|
|
686
|
+
};
|
|
687
|
+
var c = /* @__PURE__ */ new WeakMap();
|
|
688
|
+
function a(e2, t2) {
|
|
689
|
+
return c.get(e2) || c.set(e2, new t2()), c.get(e2);
|
|
690
|
+
}
|
|
691
|
+
var d = class {
|
|
692
|
+
t;
|
|
693
|
+
i = 0;
|
|
694
|
+
o = [];
|
|
695
|
+
h(e2) {
|
|
696
|
+
if (e2.hadRecentInput) return;
|
|
697
|
+
const t2 = this.o[0], n2 = this.o.at(-1);
|
|
698
|
+
this.i && t2 && n2 && e2.startTime - n2.startTime < 1e3 && e2.startTime - t2.startTime < 5e3 ? (this.i += e2.value, this.o.push(e2)) : (this.i = e2.value, this.o = [e2]), this.t?.(e2);
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
var h = (e2, t2, n2 = {}) => {
|
|
702
|
+
try {
|
|
703
|
+
if (PerformanceObserver.supportedEntryTypes.includes(e2)) {
|
|
704
|
+
const i2 = new PerformanceObserver((e3) => {
|
|
705
|
+
queueMicrotask(() => {
|
|
706
|
+
t2(e3.getEntries());
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
return i2.observe({ type: e2, buffered: true, ...n2 }), i2;
|
|
710
|
+
}
|
|
711
|
+
} catch {
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
var f = (e2) => {
|
|
715
|
+
let t2 = false;
|
|
716
|
+
return () => {
|
|
717
|
+
t2 || (e2(), t2 = true);
|
|
718
|
+
};
|
|
719
|
+
};
|
|
720
|
+
var l = -1;
|
|
721
|
+
var u = /* @__PURE__ */ new Set();
|
|
722
|
+
var m = () => "hidden" !== document.visibilityState || document.prerendering ? 1 / 0 : 0;
|
|
723
|
+
var g = (e2) => {
|
|
724
|
+
if ("hidden" === document.visibilityState) {
|
|
725
|
+
if ("visibilitychange" === e2.type) for (const e3 of u) e3();
|
|
726
|
+
isFinite(l) || (l = "visibilitychange" === e2.type ? e2.timeStamp : 0, removeEventListener("prerenderingchange", g, true));
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
var p = () => {
|
|
730
|
+
if (l < 0) {
|
|
731
|
+
const e2 = o(), n2 = document.prerendering ? void 0 : globalThis.performance.getEntriesByType("visibility-state").find((t2) => "hidden" === t2.name && t2.startTime >= e2)?.startTime;
|
|
732
|
+
l = n2 ?? m(), addEventListener("visibilitychange", g, true), addEventListener("prerenderingchange", g, true), t(() => {
|
|
733
|
+
setTimeout(() => {
|
|
734
|
+
l = m();
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
return { get firstHiddenTime() {
|
|
739
|
+
return l;
|
|
740
|
+
}, onHidden(e2) {
|
|
741
|
+
u.add(e2);
|
|
742
|
+
} };
|
|
743
|
+
};
|
|
744
|
+
var v = (e2) => {
|
|
745
|
+
document.prerendering ? addEventListener("prerenderingchange", e2, true) : e2();
|
|
746
|
+
};
|
|
747
|
+
var y = [1800, 3e3];
|
|
748
|
+
var T = (e2, s2 = {}) => {
|
|
749
|
+
v(() => {
|
|
750
|
+
const c2 = p();
|
|
751
|
+
let a2, d2 = r("FCP");
|
|
752
|
+
const f2 = h("paint", (e3) => {
|
|
753
|
+
for (const t2 of e3) "first-contentful-paint" === t2.name && (f2.disconnect(), t2.startTime < c2.firstHiddenTime && (d2.value = Math.max(t2.startTime - o(), 0), d2.entries.push(t2), a2(true)));
|
|
754
|
+
});
|
|
755
|
+
f2 && (a2 = n(e2, d2, y, s2.reportAllChanges), t((t2) => {
|
|
756
|
+
d2 = r("FCP"), a2 = n(e2, d2, y, s2.reportAllChanges), i(() => {
|
|
757
|
+
d2.value = performance.now() - t2.timeStamp, a2(true);
|
|
758
|
+
});
|
|
759
|
+
}));
|
|
760
|
+
});
|
|
761
|
+
};
|
|
762
|
+
var E = [0.1, 0.25];
|
|
763
|
+
var b = (e2, s2 = {}) => {
|
|
764
|
+
const o2 = p();
|
|
765
|
+
T(f(() => {
|
|
766
|
+
let c2, f2 = r("CLS", 0);
|
|
767
|
+
const l2 = a(s2, d), u2 = (e3) => {
|
|
768
|
+
for (const t2 of e3) l2.h(t2);
|
|
769
|
+
l2.i > f2.value && (f2.value = l2.i, f2.entries = l2.o, c2());
|
|
770
|
+
}, m2 = h("layout-shift", u2);
|
|
771
|
+
m2 && (c2 = n(e2, f2, E, s2.reportAllChanges), o2.onHidden(() => {
|
|
772
|
+
u2(m2.takeRecords()), c2(true);
|
|
773
|
+
}), t(() => {
|
|
774
|
+
l2.i = 0, f2 = r("CLS", 0), c2 = n(e2, f2, E, s2.reportAllChanges), i(c2);
|
|
775
|
+
}), setTimeout(c2));
|
|
776
|
+
}));
|
|
777
|
+
};
|
|
778
|
+
var L = 0;
|
|
779
|
+
var P = 1 / 0;
|
|
780
|
+
var _ = 0;
|
|
781
|
+
var M = (e2) => {
|
|
782
|
+
for (const t2 of e2) t2.interactionId && (P = Math.min(P, t2.interactionId), _ = Math.max(_, t2.interactionId), L = _ ? (_ - P) / 7 + 1 : 0);
|
|
783
|
+
};
|
|
784
|
+
var w;
|
|
785
|
+
var C = () => w ? L : performance.interactionCount ?? 0;
|
|
786
|
+
var I = () => {
|
|
787
|
+
"interactionCount" in performance || w || (w = h("event", M, { durationThreshold: 0 }));
|
|
788
|
+
};
|
|
789
|
+
var F = 0;
|
|
790
|
+
var k = class {
|
|
791
|
+
l = [];
|
|
792
|
+
u = /* @__PURE__ */ new Map();
|
|
793
|
+
m;
|
|
794
|
+
p;
|
|
795
|
+
v() {
|
|
796
|
+
F = C(), this.l.length = 0, this.u.clear();
|
|
797
|
+
}
|
|
798
|
+
T() {
|
|
799
|
+
const e2 = Math.min(this.l.length - 1, Math.floor((C() - F) / 50));
|
|
800
|
+
return this.l[e2];
|
|
801
|
+
}
|
|
802
|
+
h(e2) {
|
|
803
|
+
if (this.m?.(e2), !e2.interactionId && "first-input" !== e2.entryType) return;
|
|
804
|
+
const t2 = this.l.at(-1);
|
|
805
|
+
let n2 = this.u.get(e2.interactionId);
|
|
806
|
+
if (n2 || this.l.length < 10 || e2.duration > t2.L) {
|
|
807
|
+
if (n2 ? e2.duration > n2.L ? (n2.entries = [e2], n2.L = e2.duration) : e2.duration === n2.L && e2.startTime === n2.entries[0].startTime && n2.entries.push(e2) : (n2 = { id: e2.interactionId, entries: [e2], L: e2.duration }, this.u.set(n2.id, n2), this.l.push(n2)), this.l.sort((e3, t3) => t3.L - e3.L), this.l.length > 10) {
|
|
808
|
+
const e3 = this.l.splice(10);
|
|
809
|
+
for (const t3 of e3) this.u.delete(t3.id);
|
|
810
|
+
}
|
|
811
|
+
this.p?.(n2);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
var A = (e2) => {
|
|
816
|
+
const t2 = globalThis.requestIdleCallback || setTimeout, n2 = globalThis.cancelIdleCallback || clearTimeout;
|
|
817
|
+
if ("hidden" === document.visibilityState) e2();
|
|
818
|
+
else {
|
|
819
|
+
const i2 = f(e2);
|
|
820
|
+
let s2 = -1;
|
|
821
|
+
const o2 = () => {
|
|
822
|
+
n2(s2), i2();
|
|
823
|
+
};
|
|
824
|
+
addEventListener("visibilitychange", o2, { once: true, capture: true }), s2 = t2(() => {
|
|
825
|
+
removeEventListener("visibilitychange", o2, { capture: true }), i2();
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
var B = [200, 500];
|
|
830
|
+
var S = (e2, i2 = {}) => {
|
|
831
|
+
if (!globalThis.PerformanceEventTiming || !("interactionId" in PerformanceEventTiming.prototype)) return;
|
|
832
|
+
const s2 = p();
|
|
833
|
+
v(() => {
|
|
834
|
+
I();
|
|
835
|
+
let o2, c2 = r("INP");
|
|
836
|
+
const d2 = a(i2, k), f2 = (e3) => {
|
|
837
|
+
A(() => {
|
|
838
|
+
for (const t3 of e3) d2.h(t3);
|
|
839
|
+
const t2 = d2.T();
|
|
840
|
+
t2 && t2.L !== c2.value && (c2.value = t2.L, c2.entries = t2.entries, o2());
|
|
841
|
+
});
|
|
842
|
+
}, l2 = h("event", f2, { durationThreshold: i2.durationThreshold ?? 40 });
|
|
843
|
+
o2 = n(e2, c2, B, i2.reportAllChanges), l2 && (l2.observe({ type: "first-input", buffered: true }), s2.onHidden(() => {
|
|
844
|
+
f2(l2.takeRecords()), o2(true);
|
|
845
|
+
}), t(() => {
|
|
846
|
+
d2.v(), c2 = r("INP"), o2 = n(e2, c2, B, i2.reportAllChanges);
|
|
847
|
+
}));
|
|
848
|
+
});
|
|
849
|
+
};
|
|
850
|
+
var q = class {
|
|
851
|
+
m;
|
|
852
|
+
h(e2) {
|
|
853
|
+
this.m?.(e2);
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
var N = [2500, 4e3];
|
|
857
|
+
var x = (e2, s2 = {}) => {
|
|
858
|
+
v(() => {
|
|
859
|
+
const c2 = p();
|
|
860
|
+
let d2, l2 = r("LCP");
|
|
861
|
+
const u2 = a(s2, q), m2 = (e3) => {
|
|
862
|
+
s2.reportAllChanges || (e3 = e3.slice(-1));
|
|
863
|
+
for (const t2 of e3) u2.h(t2), t2.startTime < c2.firstHiddenTime && (l2.value = Math.max(t2.startTime - o(), 0), l2.entries = [t2], d2());
|
|
864
|
+
}, g2 = h("largest-contentful-paint", m2);
|
|
865
|
+
if (g2) {
|
|
866
|
+
d2 = n(e2, l2, N, s2.reportAllChanges);
|
|
867
|
+
const o2 = f(() => {
|
|
868
|
+
m2(g2.takeRecords()), g2.disconnect(), d2(true);
|
|
869
|
+
}), c3 = (e3) => {
|
|
870
|
+
e3.isTrusted && (A(o2), removeEventListener(e3.type, c3, { capture: true }));
|
|
871
|
+
};
|
|
872
|
+
for (const e3 of ["keydown", "click", "visibilitychange"]) addEventListener(e3, c3, { capture: true });
|
|
873
|
+
t((t2) => {
|
|
874
|
+
l2 = r("LCP"), d2 = n(e2, l2, N, s2.reportAllChanges), i(() => {
|
|
875
|
+
l2.value = performance.now() - t2.timeStamp, d2(true);
|
|
876
|
+
});
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
});
|
|
880
|
+
};
|
|
881
|
+
var H = [800, 1800];
|
|
882
|
+
var O = (e2) => {
|
|
883
|
+
document.prerendering ? v(() => O(e2)) : "complete" !== document.readyState ? addEventListener("load", () => O(e2), true) : setTimeout(e2);
|
|
884
|
+
};
|
|
885
|
+
var $ = (e2, i2 = {}) => {
|
|
886
|
+
let c2 = r("TTFB"), a2 = n(e2, c2, H, i2.reportAllChanges);
|
|
887
|
+
O(() => {
|
|
888
|
+
const d2 = s();
|
|
889
|
+
d2 && (c2.value = Math.max(d2.responseStart - o(), 0), c2.entries = [d2], a2(true), t(() => {
|
|
890
|
+
c2 = r("TTFB", 0), a2 = n(e2, c2, H, i2.reportAllChanges), a2(true);
|
|
891
|
+
}));
|
|
892
|
+
});
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
// src/core/performance-monitor.ts
|
|
896
|
+
function normalize(value, isCLS) {
|
|
897
|
+
if (isCLS) {
|
|
898
|
+
return Math.round(value * 1e4) / 1e4;
|
|
899
|
+
}
|
|
900
|
+
return Math.round(value);
|
|
901
|
+
}
|
|
902
|
+
function reportMetric(api, metric) {
|
|
903
|
+
const isCLS = metric.name === "CLS";
|
|
904
|
+
const properties = {
|
|
905
|
+
action: "metric",
|
|
906
|
+
target_type: "performance",
|
|
907
|
+
metric_name: metric.name,
|
|
908
|
+
metric_value: normalize(metric.value, isCLS),
|
|
909
|
+
metric_rating: metric.rating,
|
|
910
|
+
delta: normalize(metric.delta, isCLS),
|
|
911
|
+
metric_id: metric.id,
|
|
912
|
+
navigation_type: metric.navigationType
|
|
913
|
+
};
|
|
914
|
+
if (metric.name === "LCP") {
|
|
915
|
+
const entry = metric.entries[metric.entries.length - 1];
|
|
916
|
+
if (entry) {
|
|
917
|
+
properties.lcp_element = entry.element?.tagName?.toLowerCase() || "";
|
|
918
|
+
properties.lcp_url = entry.url || "";
|
|
919
|
+
properties.lcp_size = entry.size;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
api.track("web_vital", properties);
|
|
923
|
+
}
|
|
924
|
+
function initPerformanceMonitor(api, config = {}) {
|
|
925
|
+
if (config.enabled === false) return;
|
|
926
|
+
try {
|
|
927
|
+
x((metric) => reportMetric(api, metric));
|
|
928
|
+
T((metric) => reportMetric(api, metric));
|
|
929
|
+
b((metric) => reportMetric(api, metric));
|
|
930
|
+
S((metric) => reportMetric(api, metric));
|
|
931
|
+
$((metric) => reportMetric(api, metric));
|
|
932
|
+
} catch {
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// src/core/ga-adapter.ts
|
|
937
|
+
function trackToGA(eventName, properties, options) {
|
|
938
|
+
if (typeof window === "undefined" || !window.gtag) return;
|
|
939
|
+
const params = {
|
|
940
|
+
session_id: options.sessionId,
|
|
941
|
+
engagement_time_msec: 100,
|
|
942
|
+
page_location: options.pageUrl,
|
|
943
|
+
page_referrer: options.referrer
|
|
944
|
+
};
|
|
945
|
+
const { marketing, userId } = options;
|
|
946
|
+
if (marketing.utm_source) params.utm_source = marketing.utm_source;
|
|
947
|
+
if (marketing.utm_medium) params.utm_medium = marketing.utm_medium;
|
|
948
|
+
if (marketing.utm_campaign) params.utm_campaign = marketing.utm_campaign;
|
|
949
|
+
if (marketing.utm_term) params.utm_term = marketing.utm_term;
|
|
950
|
+
if (marketing.utm_content) params.utm_content = marketing.utm_content;
|
|
951
|
+
if (userId) params.user_id = userId;
|
|
952
|
+
Object.assign(params, properties);
|
|
953
|
+
window.gtag("event", eventName, params);
|
|
954
|
+
}
|
|
955
|
+
function setGAUserId(userId) {
|
|
956
|
+
if (typeof window === "undefined" || !window.gtag) return;
|
|
957
|
+
window.gtag("set", { user_id: userId ?? void 0 });
|
|
958
|
+
}
|
|
959
|
+
function setGAUserProperties(properties) {
|
|
960
|
+
if (typeof window === "undefined" || !window.gtag) return;
|
|
961
|
+
window.gtag("set", "user_properties", properties);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// src/core/ga-manager.ts
|
|
965
|
+
var GAManager = class {
|
|
966
|
+
constructor() {
|
|
967
|
+
this._initialized = false;
|
|
968
|
+
}
|
|
969
|
+
get ready() {
|
|
970
|
+
return this._initialized && typeof window !== "undefined" && typeof window.gtag === "function";
|
|
971
|
+
}
|
|
972
|
+
get measurementId() {
|
|
973
|
+
return this._measurementId;
|
|
974
|
+
}
|
|
975
|
+
track(eventName, properties) {
|
|
976
|
+
if (!this.ready) return;
|
|
977
|
+
window.gtag("event", eventName, properties ?? {});
|
|
978
|
+
}
|
|
979
|
+
setUserId(userId) {
|
|
980
|
+
if (!this.ready) return;
|
|
981
|
+
window.gtag("set", { user_id: userId ?? void 0 });
|
|
982
|
+
}
|
|
983
|
+
setUserProperties(properties) {
|
|
984
|
+
if (!this.ready) return;
|
|
985
|
+
window.gtag("set", "user_properties", properties);
|
|
986
|
+
}
|
|
987
|
+
set(keyOrParams, value) {
|
|
988
|
+
if (!this.ready) return;
|
|
989
|
+
if (typeof keyOrParams === "string") {
|
|
990
|
+
window.gtag("set", keyOrParams, value);
|
|
991
|
+
} else {
|
|
992
|
+
window.gtag("set", keyOrParams);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
config(params) {
|
|
996
|
+
if (!this.ready || !this._measurementId) return;
|
|
997
|
+
window.gtag("config", this._measurementId, params ?? {});
|
|
998
|
+
}
|
|
999
|
+
consent(mode, params) {
|
|
1000
|
+
if (!this.ready) return;
|
|
1001
|
+
window.gtag("consent", mode, params);
|
|
1002
|
+
}
|
|
1003
|
+
get(key, callback) {
|
|
1004
|
+
if (!this.ready || !this._measurementId) return;
|
|
1005
|
+
window.gtag("get", this._measurementId, key, callback);
|
|
1006
|
+
}
|
|
1007
|
+
gtag(...args) {
|
|
1008
|
+
if (typeof window === "undefined" || !window.gtag) return;
|
|
1009
|
+
window.gtag(...args);
|
|
1010
|
+
}
|
|
1011
|
+
_init(measurementId) {
|
|
1012
|
+
this._measurementId = measurementId;
|
|
1013
|
+
this._initialized = true;
|
|
1014
|
+
}
|
|
1015
|
+
_destroy() {
|
|
1016
|
+
this._initialized = false;
|
|
1017
|
+
this._measurementId = void 0;
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
// src/core/analytics.ts
|
|
1022
|
+
var globalBatchCounter = 0;
|
|
1023
|
+
var Analytics = class {
|
|
1024
|
+
constructor(config) {
|
|
1025
|
+
this.buffer = [];
|
|
1026
|
+
this.bufferTimer = null;
|
|
1027
|
+
this.userId = null;
|
|
1028
|
+
this.userProps = {};
|
|
1029
|
+
this.initialized = false;
|
|
1030
|
+
this.retrying = 0;
|
|
1031
|
+
this.gaInitialized = false;
|
|
1032
|
+
this.ga = new GAManager();
|
|
1033
|
+
this.config = {
|
|
1034
|
+
debug: false,
|
|
1035
|
+
autoTrack: true,
|
|
1036
|
+
bufferFlushInterval: DEFAULT_CONFIG.bufferFlushInterval,
|
|
1037
|
+
bufferMaxSize: DEFAULT_CONFIG.bufferMaxSize,
|
|
1038
|
+
maxRetryCount: DEFAULT_CONFIG.maxRetryCount,
|
|
1039
|
+
...config
|
|
1040
|
+
};
|
|
1041
|
+
const appKey = this.config.appKey || this.config.appId || "unknown";
|
|
1042
|
+
if (this.config.appId) this.config.appKey = appKey;
|
|
1043
|
+
this.clientId = this.getOrCreateClientId();
|
|
1044
|
+
this.merchantLang = DEFAULT_CONFIG.merchantLanguage;
|
|
1045
|
+
this.clientType = DEFAULT_CONFIG.clientType;
|
|
1046
|
+
this.batchPageId = this.generateBatchPageId();
|
|
1047
|
+
this.sessionManager = new SessionManager(this.config.sessionTimeout);
|
|
1048
|
+
if (isBrowser()) {
|
|
1049
|
+
this.recoverFailedEvents();
|
|
1050
|
+
}
|
|
1051
|
+
this.registerBeforeUnload();
|
|
1052
|
+
if (this.config.autoTrack && isBrowser()) {
|
|
1053
|
+
initAutoTrack(this, this.config.autoTrackSelector);
|
|
1054
|
+
}
|
|
1055
|
+
if (isBrowser()) {
|
|
1056
|
+
initErrorMonitor(this);
|
|
1057
|
+
}
|
|
1058
|
+
if (isBrowser() && this.config.performance?.enabled !== false) {
|
|
1059
|
+
initPerformanceMonitor(this, this.config.performance);
|
|
1060
|
+
}
|
|
1061
|
+
if (isBrowser() && this.config.ga?.enabled) {
|
|
1062
|
+
this.ga._init(this.config.ga.measurementId);
|
|
1063
|
+
initGA(this.config.ga).then(() => {
|
|
1064
|
+
this.gaInitialized = true;
|
|
1065
|
+
this.log("GA4 initialized with measurementId:", this.config.ga?.measurementId);
|
|
1066
|
+
}).catch((error) => {
|
|
1067
|
+
this.ga._destroy();
|
|
1068
|
+
this.log("Failed to initialize GA4:", error);
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
this.initialized = true;
|
|
1072
|
+
this.log("Analytics SDK initialized", {
|
|
1073
|
+
appKey: this.config.appKey,
|
|
1074
|
+
clientId: this.clientId,
|
|
1075
|
+
sessionId: this.sessionManager.getSessionId()
|
|
1076
|
+
});
|
|
1077
|
+
if (isBrowser()) {
|
|
1078
|
+
this.trackPageView();
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
track(eventName, properties, options) {
|
|
1082
|
+
if (!eventName || typeof eventName !== "string") {
|
|
1083
|
+
this.log("Invalid event name");
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const normalizedProps = properties && isObject(properties) ? properties : {};
|
|
1087
|
+
const isKeyEvent = options?.keyEvent === true || this.isKeyEvent(eventName);
|
|
1088
|
+
if (this.gaInitialized) {
|
|
1089
|
+
trackToGA(eventName, normalizedProps, {
|
|
1090
|
+
sessionId: this.sessionManager.getSessionId(),
|
|
1091
|
+
pageUrl: isBrowser() ? getPageUrl() : "",
|
|
1092
|
+
referrer: isBrowser() ? document.referrer : "",
|
|
1093
|
+
marketing: collectMarketing(),
|
|
1094
|
+
userId: this.userId
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
const event = {
|
|
1098
|
+
event_id: generateUUID(),
|
|
1099
|
+
event_name: eventName,
|
|
1100
|
+
batch_event_index: 0,
|
|
1101
|
+
batch_ordering_id: this.generateBatchOrderingId(),
|
|
1102
|
+
batch_page_id: this.batchPageId,
|
|
1103
|
+
timestamp: getTimestamp(),
|
|
1104
|
+
key_event: isKeyEvent,
|
|
1105
|
+
event_properties: this.buildEventProperties(normalizedProps)
|
|
1106
|
+
};
|
|
1107
|
+
if (isKeyEvent) {
|
|
1108
|
+
this.flushKeyEvent(event);
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
this.buffer.push(event);
|
|
1112
|
+
this.scheduleBufferFlush();
|
|
1113
|
+
if (this.buffer.length >= this.config.bufferMaxSize) {
|
|
1114
|
+
this.flushBuffer();
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
identify(userId, attributes) {
|
|
1118
|
+
const wasAnonymous = !this.userId;
|
|
1119
|
+
this.userId = userId;
|
|
1120
|
+
if (attributes && isObject(attributes)) {
|
|
1121
|
+
this.userProps = attributes;
|
|
1122
|
+
}
|
|
1123
|
+
if (this.gaInitialized) {
|
|
1124
|
+
setGAUserId(userId);
|
|
1125
|
+
if (attributes && isObject(attributes)) {
|
|
1126
|
+
setGAUserProperties(attributes);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
this.log("User identified:", { userId, attributes });
|
|
1130
|
+
if (wasAnonymous && this.buffer.length > 0) {
|
|
1131
|
+
this.flushBuffer();
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
setMerchantLanguage(language) {
|
|
1135
|
+
this.merchantLang = language;
|
|
1136
|
+
}
|
|
1137
|
+
setClientType(clientType) {
|
|
1138
|
+
this.clientType = clientType;
|
|
1139
|
+
}
|
|
1140
|
+
reset() {
|
|
1141
|
+
this.userId = null;
|
|
1142
|
+
this.userProps = {};
|
|
1143
|
+
this.buffer = [];
|
|
1144
|
+
if (this.bufferTimer) {
|
|
1145
|
+
clearTimeout(this.bufferTimer);
|
|
1146
|
+
this.bufferTimer = null;
|
|
1147
|
+
}
|
|
1148
|
+
if (this.gaInitialized) {
|
|
1149
|
+
setGAUserId(null);
|
|
1150
|
+
}
|
|
1151
|
+
this.log("Analytics reset");
|
|
1152
|
+
}
|
|
1153
|
+
getUserProfile() {
|
|
1154
|
+
return {
|
|
1155
|
+
userId: this.userId ?? void 0,
|
|
1156
|
+
anonymousId: this.clientId,
|
|
1157
|
+
attributes: this.userProps
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
getSessionId() {
|
|
1161
|
+
return this.sessionManager.getSessionId();
|
|
1162
|
+
}
|
|
1163
|
+
getClientId() {
|
|
1164
|
+
return this.clientId;
|
|
1165
|
+
}
|
|
1166
|
+
flush() {
|
|
1167
|
+
this.flushBuffer();
|
|
1168
|
+
}
|
|
1169
|
+
log(...args) {
|
|
1170
|
+
if (this.config.debug) {
|
|
1171
|
+
console.log("[Analytics]", ...args);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
getOrCreateClientId() {
|
|
1175
|
+
if (!isBrowser()) return generateUUID();
|
|
1176
|
+
let clientId = safeLocalStorageGet(STORAGE_KEYS.CLIENT_ID);
|
|
1177
|
+
if (!clientId) {
|
|
1178
|
+
clientId = generateUUID();
|
|
1179
|
+
safeLocalStorageSet(STORAGE_KEYS.CLIENT_ID, clientId);
|
|
1180
|
+
}
|
|
1181
|
+
return clientId;
|
|
1182
|
+
}
|
|
1183
|
+
resolveApiKey() {
|
|
1184
|
+
if (this.config.apiKey) return this.config.apiKey;
|
|
1185
|
+
if (this.config.env) {
|
|
1186
|
+
const key = API_KEY_MAP[this.config.env];
|
|
1187
|
+
if (key) return key;
|
|
1188
|
+
}
|
|
1189
|
+
return "";
|
|
1190
|
+
}
|
|
1191
|
+
isKeyEvent(eventName) {
|
|
1192
|
+
if (!this.config.keyEvents || this.config.keyEvents.length === 0) return false;
|
|
1193
|
+
return this.config.keyEvents.includes(eventName);
|
|
1194
|
+
}
|
|
1195
|
+
generateBatchPageId() {
|
|
1196
|
+
return `${getTimestamp().toString(36)}-${generateId().split("-")[1] || Math.random().toString(36).slice(2, 9)}`;
|
|
1197
|
+
}
|
|
1198
|
+
generateBatchOrderingId() {
|
|
1199
|
+
globalBatchCounter += 1;
|
|
1200
|
+
return `${getTimestamp()}-${globalBatchCounter}`;
|
|
1201
|
+
}
|
|
1202
|
+
buildEventProperties(properties) {
|
|
1203
|
+
const defaults = {
|
|
1204
|
+
system: this.config.system || "",
|
|
1205
|
+
domain: this.config.domain || "",
|
|
1206
|
+
scene: "",
|
|
1207
|
+
action: "",
|
|
1208
|
+
target_type: "",
|
|
1209
|
+
target_id: "",
|
|
1210
|
+
page_url: isBrowser() ? getPageUrl() : ""
|
|
1211
|
+
};
|
|
1212
|
+
const merged = {};
|
|
1213
|
+
for (const key of Object.keys(defaults)) {
|
|
1214
|
+
const k2 = key;
|
|
1215
|
+
if (defaults[k2] !== void 0) {
|
|
1216
|
+
merged[k2] = defaults[k2];
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
for (const key of Object.keys(properties)) {
|
|
1220
|
+
merged[key] = properties[key];
|
|
1221
|
+
}
|
|
1222
|
+
return merged;
|
|
1223
|
+
}
|
|
1224
|
+
scheduleBufferFlush() {
|
|
1225
|
+
if (this.bufferTimer) return;
|
|
1226
|
+
this.bufferTimer = setTimeout(() => {
|
|
1227
|
+
this.flushBuffer();
|
|
1228
|
+
}, this.config.bufferFlushInterval);
|
|
1229
|
+
}
|
|
1230
|
+
flushBuffer() {
|
|
1231
|
+
if (this.bufferTimer) {
|
|
1232
|
+
clearTimeout(this.bufferTimer);
|
|
1233
|
+
this.bufferTimer = null;
|
|
1234
|
+
}
|
|
1235
|
+
if (this.buffer.length === 0) return;
|
|
1236
|
+
const events = this.buffer.splice(0, this.buffer.length);
|
|
1237
|
+
events.forEach((e2, i2) => {
|
|
1238
|
+
e2.batch_event_index = i2;
|
|
1239
|
+
});
|
|
1240
|
+
this.log(`Flushing ${events.length} events`);
|
|
1241
|
+
this.sendBatch(events, 0);
|
|
1242
|
+
}
|
|
1243
|
+
flushKeyEvent(event) {
|
|
1244
|
+
this.log("Flushing key event:", event.event_name);
|
|
1245
|
+
this.sendBatch([event], 0);
|
|
1246
|
+
}
|
|
1247
|
+
async sendBatch(events, retryCount) {
|
|
1248
|
+
if (events.length === 0) return;
|
|
1249
|
+
const apiKey = this.resolveApiKey();
|
|
1250
|
+
if (!apiKey) {
|
|
1251
|
+
this.log("No API key configured, dropping events");
|
|
1252
|
+
for (const event of events) {
|
|
1253
|
+
StorageQueue.enqueue(event);
|
|
1254
|
+
}
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
const payload = this.buildPayload(events);
|
|
1258
|
+
try {
|
|
1259
|
+
await Sender.send(payload, this.config.serverUrl, apiKey);
|
|
1260
|
+
this.log(`Batch sent successfully: ${events.length} events`);
|
|
1261
|
+
} catch (error) {
|
|
1262
|
+
this.log(`Batch send failed (attempt ${retryCount + 1}/${this.config.maxRetryCount + 1}):`, error);
|
|
1263
|
+
if (retryCount < this.config.maxRetryCount) {
|
|
1264
|
+
const delay = 1e3 * Math.pow(2, retryCount);
|
|
1265
|
+
this.log(`Retrying in ${delay}ms...`);
|
|
1266
|
+
this.retrying += 1;
|
|
1267
|
+
setTimeout(() => {
|
|
1268
|
+
this.retrying -= 1;
|
|
1269
|
+
this.sendBatch(events, retryCount + 1);
|
|
1270
|
+
}, delay);
|
|
1271
|
+
} else {
|
|
1272
|
+
this.log("Max retries reached, persisting events to localStorage");
|
|
1273
|
+
for (const event of events) {
|
|
1274
|
+
StorageQueue.enqueue(event);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
buildPayload(events) {
|
|
1280
|
+
return {
|
|
1281
|
+
client_id: this.clientId,
|
|
1282
|
+
user_id: this.userId || "",
|
|
1283
|
+
session_id: this.sessionManager.getSessionId(),
|
|
1284
|
+
user_properties: Object.keys(this.userProps).length > 0 ? this.userProps : void 0,
|
|
1285
|
+
context: collectContext(this.config.appKey || this.config.appId || "unknown", this.merchantLang, this.clientType),
|
|
1286
|
+
marketing: collectMarketing(),
|
|
1287
|
+
events
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
recoverFailedEvents() {
|
|
1291
|
+
const failedEvents = StorageQueue.recover();
|
|
1292
|
+
if (failedEvents.length > 0) {
|
|
1293
|
+
this.log(`Recovered ${failedEvents.length} failed events from storage`);
|
|
1294
|
+
for (const event of failedEvents) {
|
|
1295
|
+
event.batch_ordering_id = this.generateBatchOrderingId();
|
|
1296
|
+
event.batch_page_id = this.batchPageId;
|
|
1297
|
+
event.batch_event_index = 0;
|
|
1298
|
+
}
|
|
1299
|
+
const batchSize = this.config.bufferMaxSize;
|
|
1300
|
+
for (let i2 = 0; i2 < failedEvents.length; i2 += batchSize) {
|
|
1301
|
+
const batch = failedEvents.slice(i2, i2 + batchSize);
|
|
1302
|
+
batch.forEach((e2, idx) => {
|
|
1303
|
+
e2.batch_event_index = idx;
|
|
1304
|
+
});
|
|
1305
|
+
this.sendBatch(batch, 0);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
registerBeforeUnload() {
|
|
1310
|
+
if (!isBrowser()) return;
|
|
1311
|
+
const handler = () => {
|
|
1312
|
+
if (this.buffer.length === 0) return;
|
|
1313
|
+
const events = this.buffer.splice(0, this.buffer.length);
|
|
1314
|
+
events.forEach((e2, i2) => {
|
|
1315
|
+
e2.batch_event_index = i2;
|
|
1316
|
+
});
|
|
1317
|
+
const apiKey = this.resolveApiKey();
|
|
1318
|
+
if (!apiKey) return;
|
|
1319
|
+
const payload = this.buildPayload(events);
|
|
1320
|
+
try {
|
|
1321
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1322
|
+
const url = `${this.config.serverUrl}${this.config.serverUrl.includes("?") ? "&" : "?"}apiKey=${encodeURIComponent(apiKey)}`;
|
|
1323
|
+
const blob = new Blob([JSON.stringify(payload)], { type: "application/json" });
|
|
1324
|
+
const success = navigator.sendBeacon(url, blob);
|
|
1325
|
+
if (!success) throw new Error("sendBeacon rejected");
|
|
1326
|
+
} else {
|
|
1327
|
+
try {
|
|
1328
|
+
const xhr = new XMLHttpRequest();
|
|
1329
|
+
xhr.open("POST", this.config.serverUrl, false);
|
|
1330
|
+
xhr.setRequestHeader("Content-Type", "application/json");
|
|
1331
|
+
xhr.setRequestHeader("apiKey", apiKey);
|
|
1332
|
+
xhr.timeout = 2e3;
|
|
1333
|
+
xhr.send(JSON.stringify(payload));
|
|
1334
|
+
} catch {
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
} catch {
|
|
1338
|
+
for (const event of events) {
|
|
1339
|
+
StorageQueue.enqueue(event);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
window.addEventListener("beforeunload", handler);
|
|
1344
|
+
window.addEventListener("pagehide", handler);
|
|
1345
|
+
}
|
|
1346
|
+
trackPageView() {
|
|
1347
|
+
if (!isBrowser()) return;
|
|
1348
|
+
this.track("page_view", {
|
|
1349
|
+
action: "view",
|
|
1350
|
+
target_type: "page",
|
|
1351
|
+
page_url: getPageUrl(),
|
|
1352
|
+
referrer: document.referrer || ""
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
function createAnalytics(config) {
|
|
1357
|
+
return new Analytics(config);
|
|
1358
|
+
}
|
|
1359
|
+
return __toCommonJS(index_exports);
|
|
1360
|
+
})();
|
|
1361
|
+
//# sourceMappingURL=index.js.map
|