@aranova/tracking-browser 0.2.2 → 0.3.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.
|
@@ -180,6 +180,282 @@ var AranovaTracking = (() => {
|
|
|
180
180
|
return getTrackingParamsFromCookieReader(getCookieValueFromDocument);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
// ../tracking-core/src/session.ts
|
|
184
|
+
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
185
|
+
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
186
|
+
var SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
187
|
+
function safeUuid() {
|
|
188
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function")
|
|
189
|
+
return crypto.randomUUID();
|
|
190
|
+
return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
|
|
191
|
+
}
|
|
192
|
+
function readLocalStorage(key) {
|
|
193
|
+
try {
|
|
194
|
+
return window.localStorage.getItem(key);
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function writeLocalStorage(key, value) {
|
|
200
|
+
try {
|
|
201
|
+
window.localStorage.setItem(key, value);
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function getVisitorId() {
|
|
206
|
+
if (typeof window === "undefined")
|
|
207
|
+
return safeUuid();
|
|
208
|
+
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
209
|
+
if (existing && existing.length > 0)
|
|
210
|
+
return existing;
|
|
211
|
+
const fresh = safeUuid();
|
|
212
|
+
writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
|
|
213
|
+
return fresh;
|
|
214
|
+
}
|
|
215
|
+
function getOrRotateSessionId(now = Date.now()) {
|
|
216
|
+
if (typeof window === "undefined")
|
|
217
|
+
return safeUuid();
|
|
218
|
+
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
219
|
+
if (raw) {
|
|
220
|
+
try {
|
|
221
|
+
const parsed = JSON.parse(raw);
|
|
222
|
+
if (typeof parsed.id === "string" && typeof parsed.last_event_at === "number") {
|
|
223
|
+
if (now - parsed.last_event_at <= SESSION_IDLE_MS) {
|
|
224
|
+
const refreshed = { id: parsed.id, last_event_at: now };
|
|
225
|
+
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));
|
|
226
|
+
return parsed.id;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
} catch {
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const fresh = { id: safeUuid(), last_event_at: now };
|
|
233
|
+
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
|
|
234
|
+
return fresh.id;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ../tracking-core/src/ingest.ts
|
|
238
|
+
var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
|
|
239
|
+
var DEFAULT_MAX_QUEUE_SIZE = 10;
|
|
240
|
+
var HARD_MAX_BATCH = 50;
|
|
241
|
+
var API_KEY_HEADER = "X-Aranova-Api-Key";
|
|
242
|
+
function buildContext(surface, sdkVersion, packageName) {
|
|
243
|
+
return {
|
|
244
|
+
surface,
|
|
245
|
+
sdk_version: sdkVersion,
|
|
246
|
+
package_name: packageName,
|
|
247
|
+
site_origin: typeof window === "undefined" ? null : window.location.origin,
|
|
248
|
+
page_title: typeof document === "undefined" ? null : document.title || null,
|
|
249
|
+
referrer: typeof document === "undefined" ? null : document.referrer || null
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function readTrackingParams() {
|
|
253
|
+
if (typeof window === "undefined")
|
|
254
|
+
return createEmptyTrackingParams();
|
|
255
|
+
try {
|
|
256
|
+
captureTrackingParamsFromLocation();
|
|
257
|
+
} catch {
|
|
258
|
+
}
|
|
259
|
+
return getTrackingParamsFromCookieReader(getCookieValueFromDocument);
|
|
260
|
+
}
|
|
261
|
+
function consentSnapshot() {
|
|
262
|
+
try {
|
|
263
|
+
return { state: getConsentState() };
|
|
264
|
+
} catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async function postWithFetch(url, body, apiKey, keepalive) {
|
|
269
|
+
if (typeof fetch !== "function")
|
|
270
|
+
return;
|
|
271
|
+
try {
|
|
272
|
+
await fetch(url, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: {
|
|
275
|
+
"Content-Type": "application/json",
|
|
276
|
+
[API_KEY_HEADER]: apiKey
|
|
277
|
+
},
|
|
278
|
+
body,
|
|
279
|
+
keepalive,
|
|
280
|
+
// CORS is open on the tracking endpoint; never send cookies.
|
|
281
|
+
credentials: "omit",
|
|
282
|
+
mode: "cors"
|
|
283
|
+
});
|
|
284
|
+
} catch {
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function createTrackingClient(config) {
|
|
288
|
+
const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
289
|
+
const maxQueueSize = Math.min(config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE, HARD_MAX_BATCH);
|
|
290
|
+
const sdkVersion = config.sdkVersion ?? null;
|
|
291
|
+
const packageName = config.packageName ?? null;
|
|
292
|
+
const endpointBase = config.endpoint.replace(/\/$/, "");
|
|
293
|
+
const eventsUrl = `${endpointBase}/events`;
|
|
294
|
+
let queue = [];
|
|
295
|
+
let flushTimer = null;
|
|
296
|
+
let firstPage = null;
|
|
297
|
+
let destroyed = false;
|
|
298
|
+
const visitorId = getVisitorId();
|
|
299
|
+
let sessionId = getOrRotateSessionId();
|
|
300
|
+
if (typeof window !== "undefined")
|
|
301
|
+
firstPage = window.location.href;
|
|
302
|
+
function buildSessionPayload() {
|
|
303
|
+
sessionId = getOrRotateSessionId();
|
|
304
|
+
const params = readTrackingParams();
|
|
305
|
+
const context = buildContext(config.surface, sdkVersion, packageName);
|
|
306
|
+
return {
|
|
307
|
+
session_id: sessionId,
|
|
308
|
+
visitor_id: visitorId,
|
|
309
|
+
gclid: params.gclid,
|
|
310
|
+
fbclid: params.fbclid,
|
|
311
|
+
utm_source: params.utm_source,
|
|
312
|
+
utm_medium: params.utm_medium,
|
|
313
|
+
utm_campaign: params.utm_campaign,
|
|
314
|
+
utm_term: params.utm_term,
|
|
315
|
+
utm_content: params.utm_content,
|
|
316
|
+
first_page: firstPage,
|
|
317
|
+
consent_state: consentSnapshot(),
|
|
318
|
+
context
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function scheduleFlush() {
|
|
322
|
+
if (flushTimer !== null || destroyed)
|
|
323
|
+
return;
|
|
324
|
+
flushTimer = setTimeout(() => {
|
|
325
|
+
flushTimer = null;
|
|
326
|
+
void flush();
|
|
327
|
+
}, flushIntervalMs);
|
|
328
|
+
}
|
|
329
|
+
function clearScheduledFlush() {
|
|
330
|
+
if (flushTimer !== null) {
|
|
331
|
+
clearTimeout(flushTimer);
|
|
332
|
+
flushTimer = null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async function flush() {
|
|
336
|
+
if (queue.length === 0)
|
|
337
|
+
return;
|
|
338
|
+
const events = queue.slice(0, HARD_MAX_BATCH);
|
|
339
|
+
queue = queue.slice(events.length);
|
|
340
|
+
clearScheduledFlush();
|
|
341
|
+
const body = {
|
|
342
|
+
session: buildSessionPayload(),
|
|
343
|
+
events
|
|
344
|
+
};
|
|
345
|
+
const serialized = JSON.stringify(body);
|
|
346
|
+
await postWithFetch(eventsUrl, serialized, config.apiKey, false);
|
|
347
|
+
}
|
|
348
|
+
function trackEvent2(input) {
|
|
349
|
+
if (destroyed)
|
|
350
|
+
return;
|
|
351
|
+
if (!input || typeof input.eventType !== "string" || input.eventType.length === 0)
|
|
352
|
+
return;
|
|
353
|
+
const occurredAt = input.occurredAt instanceof Date ? input.occurredAt.toISOString() : typeof input.occurredAt === "string" ? input.occurredAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
354
|
+
queue.push({
|
|
355
|
+
event_type: input.eventType,
|
|
356
|
+
page_url: input.pageUrl ?? (typeof window === "undefined" ? null : window.location.href),
|
|
357
|
+
metadata: input.metadata ?? null,
|
|
358
|
+
occurred_at: occurredAt
|
|
359
|
+
});
|
|
360
|
+
if (queue.length >= maxQueueSize) {
|
|
361
|
+
void flush();
|
|
362
|
+
} else {
|
|
363
|
+
scheduleFlush();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function flushOnUnload() {
|
|
367
|
+
if (queue.length === 0)
|
|
368
|
+
return;
|
|
369
|
+
const events = queue.slice(0, HARD_MAX_BATCH);
|
|
370
|
+
queue = queue.slice(events.length);
|
|
371
|
+
clearScheduledFlush();
|
|
372
|
+
const body = {
|
|
373
|
+
session: buildSessionPayload(),
|
|
374
|
+
events
|
|
375
|
+
};
|
|
376
|
+
const serialized = JSON.stringify(body);
|
|
377
|
+
void postWithFetch(eventsUrl, serialized, config.apiKey, true);
|
|
378
|
+
}
|
|
379
|
+
if (typeof window !== "undefined") {
|
|
380
|
+
window.addEventListener("pagehide", flushOnUnload);
|
|
381
|
+
window.addEventListener("visibilitychange", () => {
|
|
382
|
+
if (document.visibilityState === "hidden") flushOnUnload();
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
trackEvent: trackEvent2,
|
|
387
|
+
flush,
|
|
388
|
+
getSessionId: () => sessionId,
|
|
389
|
+
getVisitorId: () => visitorId,
|
|
390
|
+
destroy: () => {
|
|
391
|
+
destroyed = true;
|
|
392
|
+
clearScheduledFlush();
|
|
393
|
+
queue = [];
|
|
394
|
+
if (typeof window !== "undefined") {
|
|
395
|
+
window.removeEventListener("pagehide", flushOnUnload);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// ../tracking-core/src/page-view.ts
|
|
402
|
+
function buildPageViewMetadata() {
|
|
403
|
+
if (typeof window === "undefined" || typeof document === "undefined")
|
|
404
|
+
return null;
|
|
405
|
+
return {
|
|
406
|
+
page: {
|
|
407
|
+
title: document.title || null,
|
|
408
|
+
path: window.location.pathname,
|
|
409
|
+
search: window.location.search,
|
|
410
|
+
hash: window.location.hash
|
|
411
|
+
},
|
|
412
|
+
referrer: document.referrer || null,
|
|
413
|
+
viewport: { w: window.innerWidth, h: window.innerHeight }
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function fireManualPageView(client) {
|
|
417
|
+
const metadata = buildPageViewMetadata();
|
|
418
|
+
client.trackEvent({
|
|
419
|
+
eventType: "page_view",
|
|
420
|
+
pageUrl: typeof window === "undefined" ? null : window.location.href,
|
|
421
|
+
metadata
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
function attachAutoPageView(client, options = {}) {
|
|
425
|
+
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
426
|
+
return () => {
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
let lastPath = window.location.pathname + window.location.search;
|
|
430
|
+
function maybeFire() {
|
|
431
|
+
const current = window.location.pathname + window.location.search;
|
|
432
|
+
if (current === lastPath)
|
|
433
|
+
return;
|
|
434
|
+
lastPath = current;
|
|
435
|
+
fireManualPageView(client);
|
|
436
|
+
}
|
|
437
|
+
const originalPushState = history.pushState.bind(history);
|
|
438
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
439
|
+
function patchedPushState(...args) {
|
|
440
|
+
originalPushState(...args);
|
|
441
|
+
setTimeout(maybeFire, 0);
|
|
442
|
+
}
|
|
443
|
+
function patchedReplaceState(...args) {
|
|
444
|
+
originalReplaceState(...args);
|
|
445
|
+
setTimeout(maybeFire, 0);
|
|
446
|
+
}
|
|
447
|
+
history.pushState = patchedPushState;
|
|
448
|
+
history.replaceState = patchedReplaceState;
|
|
449
|
+
window.addEventListener("popstate", maybeFire);
|
|
450
|
+
if (!options.skipInitial)
|
|
451
|
+
fireManualPageView(client);
|
|
452
|
+
return () => {
|
|
453
|
+
history.pushState = originalPushState;
|
|
454
|
+
history.replaceState = originalReplaceState;
|
|
455
|
+
window.removeEventListener("popstate", maybeFire);
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
183
459
|
// src/index.ts
|
|
184
460
|
var BANNER_ID = "aranova-tracking-consent-banner";
|
|
185
461
|
function getTrackingParams() {
|
|
@@ -263,10 +539,15 @@ var AranovaTracking = (() => {
|
|
|
263
539
|
banner.appendChild(container);
|
|
264
540
|
document.body.appendChild(banner);
|
|
265
541
|
}
|
|
542
|
+
var activeClient = null;
|
|
543
|
+
var detachAutoPageView = null;
|
|
266
544
|
function init(config = {}) {
|
|
267
545
|
if (typeof window === "undefined")
|
|
268
546
|
return;
|
|
547
|
+
window.AranovaTracking = trackingScriptApi;
|
|
269
548
|
const {
|
|
549
|
+
apiKey,
|
|
550
|
+
endpoint,
|
|
270
551
|
autoCaptureTrackingParams = true,
|
|
271
552
|
cookieMaxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,
|
|
272
553
|
gtagId,
|
|
@@ -278,13 +559,40 @@ var AranovaTracking = (() => {
|
|
|
278
559
|
bootstrapGoogleAdsTracking(gtagId);
|
|
279
560
|
if (renderConsentBanner)
|
|
280
561
|
mountConsentBanner();
|
|
562
|
+
if (activeClient !== null) {
|
|
563
|
+
detachAutoPageView?.();
|
|
564
|
+
activeClient.destroy();
|
|
565
|
+
activeClient = null;
|
|
566
|
+
detachAutoPageView = null;
|
|
567
|
+
}
|
|
568
|
+
if (apiKey && endpoint) {
|
|
569
|
+
activeClient = createTrackingClient({
|
|
570
|
+
apiKey,
|
|
571
|
+
endpoint,
|
|
572
|
+
surface: "script",
|
|
573
|
+
packageName: "@aranova/tracking-browser"
|
|
574
|
+
});
|
|
575
|
+
detachAutoPageView = attachAutoPageView(activeClient);
|
|
576
|
+
} else if (apiKey || endpoint) {
|
|
577
|
+
console.warn(
|
|
578
|
+
"[AranovaTracking] init() requires both `apiKey` and `endpoint` to enable first-party event ingest. Page-view events will not be sent."
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function trackEvent(input) {
|
|
583
|
+
if (activeClient === null) {
|
|
584
|
+
console.warn("[AranovaTracking] trackEvent called before init({ apiKey, endpoint })");
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
activeClient.trackEvent(input);
|
|
281
588
|
}
|
|
282
589
|
var trackingScriptApi = {
|
|
283
590
|
init,
|
|
284
591
|
captureTrackingParams: () => captureTrackingParamsFromLocation(),
|
|
285
592
|
getTrackingParams,
|
|
286
593
|
getConsentState,
|
|
287
|
-
setConsentState
|
|
594
|
+
setConsentState,
|
|
595
|
+
trackEvent
|
|
288
596
|
};
|
|
289
597
|
if (typeof window !== "undefined")
|
|
290
598
|
window.AranovaTracking = trackingScriptApi;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../../tracking-core/src/consent.ts","../../../tracking-core/src/gtag.ts","../../../tracking-core/src/tracking.ts"],"sourcesContent":["import { getConsentState, setConsentState } from '../../tracking-core/src/index';\nimport { bootstrapGoogleAdsTracking } from '../../tracking-core/src/index';\nimport {\n captureTrackingParamsFromLocation,\n getCookieValueFromDocument,\n getTrackingParamsFromCookieReader,\n TRACKING_COOKIE_MAX_AGE_SECONDS,\n type TrackingInitConfig,\n type TrackingParams,\n} from '../../tracking-core/src/index';\n\nconst BANNER_ID = 'aranova-tracking-consent-banner';\n\nfunction getTrackingParams(): TrackingParams {\n return getTrackingParamsFromCookieReader(getCookieValueFromDocument);\n}\n\nfunction removeConsentBanner(): void {\n document.getElementById(BANNER_ID)?.remove();\n}\n\nfunction createConsentButton(label: string, onClick: () => void, style: Partial<CSSStyleDeclaration>): HTMLButtonElement {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = label;\n Object.assign(button.style, {\n borderRadius: '6px',\n padding: '10px 16px',\n fontSize: '14px',\n fontWeight: '600',\n cursor: 'pointer',\n border: '1px solid #d1d5db',\n background: '#ffffff',\n color: '#374151',\n }, style);\n button.addEventListener('click', onClick);\n return button;\n}\n\nfunction mountConsentBanner(): void {\n if (typeof document === 'undefined' || getConsentState() !== 'pending' || document.getElementById(BANNER_ID))\n return;\n\n const banner = document.createElement('div');\n banner.id = BANNER_ID;\n Object.assign(banner.style, {\n position: 'fixed',\n left: '0',\n right: '0',\n bottom: '0',\n zIndex: '2147483647',\n background: '#ffffff',\n borderTop: '1px solid #e5e7eb',\n boxShadow: '0 -4px 20px rgba(0, 0, 0, 0.12)',\n padding: '16px',\n fontFamily: 'Inter, system-ui, sans-serif',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const container = document.createElement('div');\n Object.assign(container.style, {\n maxWidth: '960px',\n margin: '0 auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '12px',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const message = document.createElement('p');\n message.textContent = 'We use cookies to understand ad performance and improve how our marketing works across visits. You can accept or decline this tracking.';\n Object.assign(message.style, {\n margin: '0',\n color: '#374151',\n fontSize: '14px',\n lineHeight: '1.5',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const actions = document.createElement('div');\n Object.assign(actions.style, {\n display: 'flex',\n gap: '8px',\n flexWrap: 'wrap',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const declineButton = createConsentButton('Decline', () => {\n setConsentState('denied');\n removeConsentBanner();\n }, {});\n\n const acceptButton = createConsentButton('Accept', () => {\n setConsentState('granted');\n removeConsentBanner();\n }, {\n background: '#111827',\n color: '#ffffff',\n border: '1px solid #111827',\n });\n\n actions.appendChild(declineButton);\n actions.appendChild(acceptButton);\n container.appendChild(message);\n container.appendChild(actions);\n banner.appendChild(container);\n document.body.appendChild(banner);\n}\n\nexport function init(config: TrackingInitConfig = {}): void {\n if (typeof window === 'undefined')\n return;\n\n const {\n autoCaptureTrackingParams = true,\n cookieMaxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n gtagId,\n renderConsentBanner = true,\n } = config;\n\n if (autoCaptureTrackingParams)\n captureTrackingParamsFromLocation(window.location.href, cookieMaxAgeSeconds);\n\n if (gtagId)\n bootstrapGoogleAdsTracking(gtagId);\n\n if (renderConsentBanner)\n mountConsentBanner();\n}\n\n// Keep the script surface small so browser installs stay easy to document.\nconst trackingScriptApi = {\n init,\n captureTrackingParams: (): TrackingParams => captureTrackingParamsFromLocation(),\n getTrackingParams,\n getConsentState,\n setConsentState,\n};\n\nif (typeof window !== 'undefined')\n window.AranovaTracking = trackingScriptApi;\n\nexport default trackingScriptApi;\n","import type { ConsentState } from './types';\n\nexport const CONSENT_STATE_KEY = 'consent_state';\nexport const CONSENT_TIMESTAMP_KEY = 'consent_timestamp';\n\nexport type GtagConsentValue = 'granted' | 'denied';\n\nexport interface ConsentUpdatePayload {\n ad_storage: GtagConsentValue;\n ad_user_data: GtagConsentValue;\n ad_personalization: GtagConsentValue;\n analytics_storage: GtagConsentValue;\n}\n\nexport function buildConsentPayload(state: GtagConsentValue): ConsentUpdatePayload {\n return {\n ad_storage: state,\n ad_user_data: state,\n ad_personalization: state,\n analytics_storage: state,\n };\n}\n\nexport function getConsentState(): ConsentState {\n if (typeof window === 'undefined')\n return 'pending';\n\n const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);\n\n if (storedState === 'granted' || storedState === 'denied')\n return storedState;\n\n return 'pending';\n}\n\nexport function setConsentState(state: GtagConsentValue): void {\n if (typeof window === 'undefined')\n return;\n\n window.localStorage.setItem(CONSENT_STATE_KEY, state);\n window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, new Date().toISOString());\n\n if (typeof window.gtag === 'function')\n window.gtag('consent', 'update', buildConsentPayload(state));\n}\n\nexport function restoreStoredConsent(): ConsentState {\n const consentState = getConsentState();\n\n if (consentState === 'granted' || consentState === 'denied')\n setConsentState(consentState);\n\n return consentState;\n}\n","import { buildConsentPayload, getConsentState, restoreStoredConsent } from './consent';\n\nexport const GTAG_SCRIPT_HOST = 'https://www.googletagmanager.com/gtag/js';\nexport const TRACKING_SCRIPT_ATTRIBUTE = 'data-aranova-tracking';\n\nfunction getScriptMarker(id: string): string {\n return `aranova-${id}`;\n}\n\nexport function createConsentDefaultScript(): string {\n return `\nwindow.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\nwindow.gtag = gtag;\ngtag('consent', 'default', {\n ad_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n analytics_storage: 'denied',\n wait_for_update: 500,\n});\n`.trim();\n}\n\nexport function createGtagInitScript(gtagId: string): string {\n return `\nwindow.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\nwindow.gtag = gtag;\ngtag('js', new Date());\ngtag('config', '${gtagId}');\n`.trim();\n}\n\nexport function createConsentRestoreScript(): string {\n return `\nconst consentState = window.localStorage.getItem('consent_state');\nif (window.gtag && (consentState === 'granted' || consentState === 'denied')) {\n window.gtag('consent', 'update', {\n ad_storage: consentState,\n ad_user_data: consentState,\n ad_personalization: consentState,\n analytics_storage: consentState,\n });\n}\n`.trim();\n}\n\nexport function ensureGtagFunction(): NonNullable<Window['gtag']> {\n window.dataLayer = window.dataLayer || [];\n\n if (typeof window.gtag === 'function')\n return window.gtag;\n\n window.gtag = (...args: unknown[]) => {\n window.dataLayer?.push(args);\n };\n\n return window.gtag;\n}\n\nexport function applyDefaultConsentState(): void {\n const gtag = ensureGtagFunction();\n gtag('consent', 'default', {\n ad_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n analytics_storage: 'denied',\n wait_for_update: 500,\n });\n}\n\nexport function loadGtagScript(gtagId: string): void {\n if (typeof document === 'undefined')\n return;\n\n const marker = getScriptMarker('gtag-loader');\n const existingScript = document.querySelector<HTMLScriptElement>(`script[${TRACKING_SCRIPT_ATTRIBUTE}=\"${marker}\"]`);\n if (existingScript)\n return;\n\n const script = document.createElement('script');\n script.async = true;\n script.src = `${GTAG_SCRIPT_HOST}?id=${encodeURIComponent(gtagId)}`;\n script.setAttribute(TRACKING_SCRIPT_ATTRIBUTE, marker);\n document.head.appendChild(script);\n}\n\nexport function initializeGtag(gtagId: string): void {\n const gtag = ensureGtagFunction();\n gtag('js', new Date());\n gtag('config', gtagId);\n}\n\nexport function restoreConsentState(): void {\n if (typeof window === 'undefined')\n return;\n\n const consentState = getConsentState();\n if (consentState === 'granted' || consentState === 'denied')\n window.gtag?.('consent', 'update', buildConsentPayload(consentState));\n}\n\nexport function bootstrapGoogleAdsTracking(gtagId: string): void {\n if (typeof window === 'undefined' || typeof document === 'undefined')\n return;\n\n applyDefaultConsentState();\n loadGtagScript(gtagId);\n initializeGtag(gtagId);\n restoreStoredConsent();\n}\n","import type { TrackingParams } from './types';\n\nexport const TRACKING_COOKIE_MAX_AGE_SECONDS = 7_776_000;\n\nexport const TRACKING_PARAM_KEYS = [\n 'gclid',\n 'fbclid',\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_term',\n 'utm_content',\n] as const;\n\nexport type TrackingParamKey = (typeof TRACKING_PARAM_KEYS)[number];\n\nexport function createEmptyTrackingParams(): TrackingParams {\n return {\n gclid: null,\n fbclid: null,\n utm_source: null,\n utm_medium: null,\n utm_campaign: null,\n utm_term: null,\n utm_content: null,\n };\n}\n\nexport function normalizeTrackingCookieValue(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nexport function getTrackingParamsFromCookieReader(\n readCookie: (key: TrackingParamKey) => unknown,\n): TrackingParams {\n return TRACKING_PARAM_KEYS.reduce<TrackingParams>((params, key) => {\n params[key] = normalizeTrackingCookieValue(readCookie(key));\n return params;\n }, createEmptyTrackingParams());\n}\n\nexport function getTrackingQueryValues(\n searchParams: Pick<URLSearchParams, 'get'>,\n): Partial<Record<TrackingParamKey, string>> {\n return TRACKING_PARAM_KEYS.reduce<Partial<Record<TrackingParamKey, string>>>((params, key) => {\n const value = searchParams.get(key);\n\n if (typeof value === 'string' && value.trim().length > 0) {\n params[key] = value;\n }\n\n return params;\n }, {});\n}\n\nexport function getCookieValueFromDocument(key: TrackingParamKey): string | null {\n if (typeof document === 'undefined')\n return null;\n\n const cookies = document.cookie ? document.cookie.split('; ') : [];\n const match = cookies.find((cookie) => cookie.startsWith(`${key}=`));\n\n if (!match)\n return null;\n\n const [, rawValue = ''] = match.split('=');\n return normalizeTrackingCookieValue(decodeURIComponent(rawValue));\n}\n\nexport function setTrackingCookie(\n key: TrackingParamKey,\n value: string,\n maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n): void {\n if (typeof document === 'undefined')\n return;\n\n const encodedValue = encodeURIComponent(value);\n document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;\n}\n\nexport function persistTrackingParamsFromSearchParams(\n searchParams: Pick<URLSearchParams, 'get'>,\n maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n): Partial<Record<TrackingParamKey, string>> {\n const trackingValues = getTrackingQueryValues(searchParams);\n\n Object.entries(trackingValues).forEach(([key, value]) => {\n setTrackingCookie(key as TrackingParamKey, value, maxAgeSeconds);\n });\n\n return trackingValues;\n}\n\nexport function captureTrackingParamsFromLocation(\n url = typeof window === 'undefined' ? '' : window.location.href,\n maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n): TrackingParams {\n const resolvedUrl = typeof window === 'undefined'\n ? new URL(url || 'https://example.invalid')\n : new URL(url, window.location.origin);\n persistTrackingParamsFromSearchParams(resolvedUrl.searchParams, maxAgeSeconds);\n return getTrackingParamsFromCookieReader(getCookieValueFromDocument);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../../tracking-core/src/consent.ts","../../../tracking-core/src/gtag.ts","../../../tracking-core/src/tracking.ts","../../../tracking-core/src/session.ts","../../../tracking-core/src/ingest.ts","../../../tracking-core/src/page-view.ts"],"sourcesContent":["// Public entry for @aranova/tracking-browser. Served via jsDelivr for <script> installs:\n// https://cdn.jsdelivr.net/npm/@aranova/tracking-browser@<version>/dist/browser/aranova-tracking.global.js\nimport { getConsentState, setConsentState } from '../../tracking-core/src/index';\nimport { bootstrapGoogleAdsTracking } from '../../tracking-core/src/index';\nimport {\n attachAutoPageView,\n captureTrackingParamsFromLocation,\n createTrackingClient,\n getCookieValueFromDocument,\n getTrackingParamsFromCookieReader,\n TRACKING_COOKIE_MAX_AGE_SECONDS,\n type TrackEventInput,\n type TrackingClient,\n type TrackingInitConfig,\n type TrackingParams,\n} from '../../tracking-core/src/index';\n\nconst BANNER_ID = 'aranova-tracking-consent-banner';\n\nfunction getTrackingParams(): TrackingParams {\n return getTrackingParamsFromCookieReader(getCookieValueFromDocument);\n}\n\nfunction removeConsentBanner(): void {\n document.getElementById(BANNER_ID)?.remove();\n}\n\nfunction createConsentButton(label: string, onClick: () => void, style: Partial<CSSStyleDeclaration>): HTMLButtonElement {\n const button = document.createElement('button');\n button.type = 'button';\n button.textContent = label;\n Object.assign(button.style, {\n borderRadius: '6px',\n padding: '10px 16px',\n fontSize: '14px',\n fontWeight: '600',\n cursor: 'pointer',\n border: '1px solid #d1d5db',\n background: '#ffffff',\n color: '#374151',\n }, style);\n button.addEventListener('click', onClick);\n return button;\n}\n\nfunction mountConsentBanner(): void {\n if (typeof document === 'undefined' || getConsentState() !== 'pending' || document.getElementById(BANNER_ID))\n return;\n\n const banner = document.createElement('div');\n banner.id = BANNER_ID;\n Object.assign(banner.style, {\n position: 'fixed',\n left: '0',\n right: '0',\n bottom: '0',\n zIndex: '2147483647',\n background: '#ffffff',\n borderTop: '1px solid #e5e7eb',\n boxShadow: '0 -4px 20px rgba(0, 0, 0, 0.12)',\n padding: '16px',\n fontFamily: 'Inter, system-ui, sans-serif',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const container = document.createElement('div');\n Object.assign(container.style, {\n maxWidth: '960px',\n margin: '0 auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '12px',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const message = document.createElement('p');\n message.textContent = 'We use cookies to understand ad performance and improve how our marketing works across visits. You can accept or decline this tracking.';\n Object.assign(message.style, {\n margin: '0',\n color: '#374151',\n fontSize: '14px',\n lineHeight: '1.5',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const actions = document.createElement('div');\n Object.assign(actions.style, {\n display: 'flex',\n gap: '8px',\n flexWrap: 'wrap',\n } satisfies Partial<CSSStyleDeclaration>);\n\n const declineButton = createConsentButton('Decline', () => {\n setConsentState('denied');\n removeConsentBanner();\n }, {});\n\n const acceptButton = createConsentButton('Accept', () => {\n setConsentState('granted');\n removeConsentBanner();\n }, {\n background: '#111827',\n color: '#ffffff',\n border: '1px solid #111827',\n });\n\n actions.appendChild(declineButton);\n actions.appendChild(acceptButton);\n container.appendChild(message);\n container.appendChild(actions);\n banner.appendChild(container);\n document.body.appendChild(banner);\n}\n\nlet activeClient: TrackingClient | null = null;\nlet detachAutoPageView: (() => void) | null = null;\n\nexport function init(config: TrackingInitConfig = {}): void {\n if (typeof window === 'undefined')\n return;\n\n // Re-assert the global in case it was deleted between init() calls.\n window.AranovaTracking = trackingScriptApi;\n\n const {\n apiKey,\n endpoint,\n autoCaptureTrackingParams = true,\n cookieMaxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n gtagId,\n renderConsentBanner = true,\n } = config;\n\n if (autoCaptureTrackingParams)\n captureTrackingParamsFromLocation(window.location.href, cookieMaxAgeSeconds);\n\n if (gtagId)\n bootstrapGoogleAdsTracking(gtagId);\n\n if (renderConsentBanner)\n mountConsentBanner();\n\n // Tear down any previous client first so a re-init call is idempotent and\n // re-initializing without creds fully resets the ingest surface.\n if (activeClient !== null) {\n detachAutoPageView?.();\n activeClient.destroy();\n activeClient = null;\n detachAutoPageView = null;\n }\n\n if (apiKey && endpoint) {\n activeClient = createTrackingClient({\n apiKey,\n endpoint,\n surface: 'script',\n packageName: '@aranova/tracking-browser',\n });\n detachAutoPageView = attachAutoPageView(activeClient);\n } else if (apiKey || endpoint) {\n // eslint-disable-next-line no-console\n console.warn(\n '[AranovaTracking] init() requires both `apiKey` and `endpoint` to enable first-party event ingest. ' +\n 'Page-view events will not be sent.',\n );\n }\n}\n\nfunction trackEvent(input: TrackEventInput): void {\n if (activeClient === null) {\n // eslint-disable-next-line no-console\n console.warn('[AranovaTracking] trackEvent called before init({ apiKey, endpoint })');\n return;\n }\n activeClient.trackEvent(input);\n}\n\n// Keep the script surface small so browser installs stay easy to document.\nconst trackingScriptApi = {\n init,\n captureTrackingParams: (): TrackingParams => captureTrackingParamsFromLocation(),\n getTrackingParams,\n getConsentState,\n setConsentState,\n trackEvent,\n};\n\nif (typeof window !== 'undefined')\n window.AranovaTracking = trackingScriptApi;\n\nexport default trackingScriptApi;\n","import type { ConsentState } from './types';\n\nexport const CONSENT_STATE_KEY = 'consent_state';\nexport const CONSENT_TIMESTAMP_KEY = 'consent_timestamp';\n\nexport type GtagConsentValue = 'granted' | 'denied';\n\nexport interface ConsentUpdatePayload {\n ad_storage: GtagConsentValue;\n ad_user_data: GtagConsentValue;\n ad_personalization: GtagConsentValue;\n analytics_storage: GtagConsentValue;\n}\n\nexport function buildConsentPayload(state: GtagConsentValue): ConsentUpdatePayload {\n return {\n ad_storage: state,\n ad_user_data: state,\n ad_personalization: state,\n analytics_storage: state,\n };\n}\n\nexport function getConsentState(): ConsentState {\n if (typeof window === 'undefined')\n return 'pending';\n\n const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);\n\n if (storedState === 'granted' || storedState === 'denied')\n return storedState;\n\n return 'pending';\n}\n\nexport function setConsentState(state: GtagConsentValue): void {\n if (typeof window === 'undefined')\n return;\n\n window.localStorage.setItem(CONSENT_STATE_KEY, state);\n window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, new Date().toISOString());\n\n if (typeof window.gtag === 'function')\n window.gtag('consent', 'update', buildConsentPayload(state));\n}\n\nexport function restoreStoredConsent(): ConsentState {\n const consentState = getConsentState();\n\n if (consentState === 'granted' || consentState === 'denied')\n setConsentState(consentState);\n\n return consentState;\n}\n","import { buildConsentPayload, getConsentState, restoreStoredConsent } from './consent';\n\nexport const GTAG_SCRIPT_HOST = 'https://www.googletagmanager.com/gtag/js';\nexport const TRACKING_SCRIPT_ATTRIBUTE = 'data-aranova-tracking';\n\nfunction getScriptMarker(id: string): string {\n return `aranova-${id}`;\n}\n\nexport function createConsentDefaultScript(): string {\n return `\nwindow.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\nwindow.gtag = gtag;\ngtag('consent', 'default', {\n ad_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n analytics_storage: 'denied',\n wait_for_update: 500,\n});\n`.trim();\n}\n\nexport function createGtagInitScript(gtagId: string): string {\n return `\nwindow.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\nwindow.gtag = gtag;\ngtag('js', new Date());\ngtag('config', '${gtagId}');\n`.trim();\n}\n\nexport function createConsentRestoreScript(): string {\n return `\nconst consentState = window.localStorage.getItem('consent_state');\nif (window.gtag && (consentState === 'granted' || consentState === 'denied')) {\n window.gtag('consent', 'update', {\n ad_storage: consentState,\n ad_user_data: consentState,\n ad_personalization: consentState,\n analytics_storage: consentState,\n });\n}\n`.trim();\n}\n\nexport function ensureGtagFunction(): NonNullable<Window['gtag']> {\n window.dataLayer = window.dataLayer || [];\n\n if (typeof window.gtag === 'function')\n return window.gtag;\n\n window.gtag = (...args: unknown[]) => {\n window.dataLayer?.push(args);\n };\n\n return window.gtag;\n}\n\nexport function applyDefaultConsentState(): void {\n const gtag = ensureGtagFunction();\n gtag('consent', 'default', {\n ad_storage: 'denied',\n ad_user_data: 'denied',\n ad_personalization: 'denied',\n analytics_storage: 'denied',\n wait_for_update: 500,\n });\n}\n\nexport function loadGtagScript(gtagId: string): void {\n if (typeof document === 'undefined')\n return;\n\n const marker = getScriptMarker('gtag-loader');\n const existingScript = document.querySelector<HTMLScriptElement>(`script[${TRACKING_SCRIPT_ATTRIBUTE}=\"${marker}\"]`);\n if (existingScript)\n return;\n\n const script = document.createElement('script');\n script.async = true;\n script.src = `${GTAG_SCRIPT_HOST}?id=${encodeURIComponent(gtagId)}`;\n script.setAttribute(TRACKING_SCRIPT_ATTRIBUTE, marker);\n document.head.appendChild(script);\n}\n\nexport function initializeGtag(gtagId: string): void {\n const gtag = ensureGtagFunction();\n gtag('js', new Date());\n gtag('config', gtagId);\n}\n\nexport function restoreConsentState(): void {\n if (typeof window === 'undefined')\n return;\n\n const consentState = getConsentState();\n if (consentState === 'granted' || consentState === 'denied')\n window.gtag?.('consent', 'update', buildConsentPayload(consentState));\n}\n\nexport function bootstrapGoogleAdsTracking(gtagId: string): void {\n if (typeof window === 'undefined' || typeof document === 'undefined')\n return;\n\n applyDefaultConsentState();\n loadGtagScript(gtagId);\n initializeGtag(gtagId);\n restoreStoredConsent();\n}\n","import type { TrackingParams } from './types';\n\nexport const TRACKING_COOKIE_MAX_AGE_SECONDS = 7_776_000;\n\nexport const TRACKING_PARAM_KEYS = [\n 'gclid',\n 'fbclid',\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_term',\n 'utm_content',\n] as const;\n\nexport type TrackingParamKey = (typeof TRACKING_PARAM_KEYS)[number];\n\nexport function createEmptyTrackingParams(): TrackingParams {\n return {\n gclid: null,\n fbclid: null,\n utm_source: null,\n utm_medium: null,\n utm_campaign: null,\n utm_term: null,\n utm_content: null,\n };\n}\n\nexport function normalizeTrackingCookieValue(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null;\n}\n\nexport function getTrackingParamsFromCookieReader(\n readCookie: (key: TrackingParamKey) => unknown,\n): TrackingParams {\n return TRACKING_PARAM_KEYS.reduce<TrackingParams>((params, key) => {\n params[key] = normalizeTrackingCookieValue(readCookie(key));\n return params;\n }, createEmptyTrackingParams());\n}\n\nexport function getTrackingQueryValues(\n searchParams: Pick<URLSearchParams, 'get'>,\n): Partial<Record<TrackingParamKey, string>> {\n return TRACKING_PARAM_KEYS.reduce<Partial<Record<TrackingParamKey, string>>>((params, key) => {\n const value = searchParams.get(key);\n\n if (typeof value === 'string' && value.trim().length > 0) {\n params[key] = value;\n }\n\n return params;\n }, {});\n}\n\nexport function getCookieValueFromDocument(key: TrackingParamKey): string | null {\n if (typeof document === 'undefined')\n return null;\n\n const cookies = document.cookie ? document.cookie.split('; ') : [];\n const match = cookies.find((cookie) => cookie.startsWith(`${key}=`));\n\n if (!match)\n return null;\n\n const [, rawValue = ''] = match.split('=');\n return normalizeTrackingCookieValue(decodeURIComponent(rawValue));\n}\n\nexport function setTrackingCookie(\n key: TrackingParamKey,\n value: string,\n maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n): void {\n if (typeof document === 'undefined')\n return;\n\n const encodedValue = encodeURIComponent(value);\n document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;\n}\n\nexport function persistTrackingParamsFromSearchParams(\n searchParams: Pick<URLSearchParams, 'get'>,\n maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n): Partial<Record<TrackingParamKey, string>> {\n const trackingValues = getTrackingQueryValues(searchParams);\n\n Object.entries(trackingValues).forEach(([key, value]) => {\n setTrackingCookie(key as TrackingParamKey, value, maxAgeSeconds);\n });\n\n return trackingValues;\n}\n\nexport function captureTrackingParamsFromLocation(\n url = typeof window === 'undefined' ? '' : window.location.href,\n maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS,\n): TrackingParams {\n const resolvedUrl = typeof window === 'undefined'\n ? new URL(url || 'https://example.invalid')\n : new URL(url, window.location.origin);\n persistTrackingParamsFromSearchParams(resolvedUrl.searchParams, maxAgeSeconds);\n return getTrackingParamsFromCookieReader(getCookieValueFromDocument);\n}\n","// Visitor + session identity for the tracking SDK.\n//\n// Visitor: persistent localStorage UUID, never expires until the user clears\n// browser storage. Used for cross-session correlation.\n//\n// Session: rolling 30-minute idle window. Regenerated when more than\n// SESSION_IDLE_MS has passed since the last event. Matches the behavior of\n// GA4, PostHog, Mixpanel, etc., so analytics is comparable.\n\nexport const VISITOR_STORAGE_KEY = 'aranova_tracking_visitor';\nexport const SESSION_STORAGE_KEY = 'aranova_tracking_session';\nexport const SESSION_IDLE_MS = 30 * 60 * 1000;\n\nexport interface StoredSession {\n id: string;\n last_event_at: number;\n}\n\nfunction safeUuid(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n return crypto.randomUUID();\n // Fallback for ancient browsers — not cryptographically perfect but unique enough.\n return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;\n}\n\nfunction readLocalStorage(key: string): string | null {\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n}\n\nfunction writeLocalStorage(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value);\n } catch {\n // Storage may be denied (private mode, blocked cookies, quota). Caller is\n // responsible for degrading gracefully.\n }\n}\n\nexport function getVisitorId(): string {\n if (typeof window === 'undefined')\n return safeUuid();\n\n const existing = readLocalStorage(VISITOR_STORAGE_KEY);\n if (existing && existing.length > 0)\n return existing;\n\n const fresh = safeUuid();\n writeLocalStorage(VISITOR_STORAGE_KEY, fresh);\n return fresh;\n}\n\nexport function getOrRotateSessionId(now: number = Date.now()): string {\n if (typeof window === 'undefined')\n return safeUuid();\n\n const raw = readLocalStorage(SESSION_STORAGE_KEY);\n if (raw) {\n try {\n const parsed = JSON.parse(raw) as Partial<StoredSession>;\n if (typeof parsed.id === 'string' && typeof parsed.last_event_at === 'number') {\n if (now - parsed.last_event_at <= SESSION_IDLE_MS) {\n const refreshed: StoredSession = { id: parsed.id, last_event_at: now };\n writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(refreshed));\n return parsed.id;\n }\n }\n } catch {\n // Fall through to a fresh session.\n }\n }\n\n const fresh: StoredSession = { id: safeUuid(), last_event_at: now };\n writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));\n return fresh.id;\n}\n\n/** Test/debug helper — wipes both ids. */\nexport function resetTrackingIdentity(): void {\n if (typeof window === 'undefined')\n return;\n try {\n window.localStorage.removeItem(VISITOR_STORAGE_KEY);\n window.localStorage.removeItem(SESSION_STORAGE_KEY);\n } catch {\n // ignored\n }\n}\n","// Tracking ingest client. Queues events, debounce-flushes them to the\n// /tracking/events endpoint, and degrades silently on errors so a broken\n// network never breaks the host site.\n\nimport { getConsentState } from './consent';\nimport {\n captureTrackingParamsFromLocation,\n createEmptyTrackingParams,\n getCookieValueFromDocument,\n getTrackingParamsFromCookieReader,\n} from './tracking';\nimport { getOrRotateSessionId, getVisitorId } from './session';\nimport type {\n TrackingClientContext,\n TrackingEventCreatePayload,\n TrackingInstallSurface,\n TrackingParams,\n TrackingSessionUpsertPayload,\n} from './types';\n\nexport const DEFAULT_FLUSH_INTERVAL_MS = 2000;\nexport const DEFAULT_MAX_QUEUE_SIZE = 10;\nexport const HARD_MAX_BATCH = 50;\nexport const API_KEY_HEADER = 'X-Aranova-Api-Key';\n\nexport interface TrackingClientConfig {\n apiKey: string;\n endpoint: string;\n surface: TrackingInstallSurface;\n sdkVersion?: string;\n packageName?: string;\n /** Override the default 2s debounce window. */\n flushIntervalMs?: number;\n /** Override the default 10-event batch trigger. */\n maxQueueSize?: number;\n /** When true, swallow nothing — useful for tests. */\n debug?: boolean;\n}\n\nexport interface TrackEventInput {\n eventType: string;\n pageUrl?: string | null;\n metadata?: Record<string, unknown> | null;\n occurredAt?: Date | string | null;\n}\n\ninterface QueuedEvent {\n event_type: string;\n page_url: string | null;\n metadata: Record<string, unknown> | null;\n occurred_at: string | null;\n}\n\nexport interface TrackingClient {\n trackEvent: (input: TrackEventInput) => void;\n flush: () => Promise<void>;\n getSessionId: () => string;\n getVisitorId: () => string;\n destroy: () => void;\n}\n\ninterface IngestRequestBody {\n session: TrackingSessionUpsertPayload;\n events: Array<{\n event_type: string;\n page_url: string | null;\n metadata: Record<string, unknown> | null;\n occurred_at: string | null;\n }>;\n}\n\nfunction buildContext(\n surface: TrackingInstallSurface,\n sdkVersion: string | null,\n packageName: string | null,\n): TrackingClientContext {\n return {\n surface,\n sdk_version: sdkVersion,\n package_name: packageName,\n site_origin: typeof window === 'undefined' ? null : window.location.origin,\n page_title: typeof document === 'undefined' ? null : document.title || null,\n referrer: typeof document === 'undefined' ? null : document.referrer || null,\n };\n}\n\nfunction readTrackingParams(): TrackingParams {\n if (typeof window === 'undefined')\n return createEmptyTrackingParams();\n // Capture from URL on every read so the first event in a session reflects the\n // landing-page params even if the cookie helper hasn't run yet.\n try {\n captureTrackingParamsFromLocation();\n } catch {\n // ignore\n }\n return getTrackingParamsFromCookieReader(getCookieValueFromDocument);\n}\n\nfunction consentSnapshot(): Record<string, unknown> | null {\n try {\n return { state: getConsentState() };\n } catch {\n return null;\n }\n}\n\nasync function postWithFetch(url: string, body: string, apiKey: string, keepalive: boolean): Promise<void> {\n if (typeof fetch !== 'function')\n return;\n try {\n await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n [API_KEY_HEADER]: apiKey,\n },\n body,\n keepalive,\n // CORS is open on the tracking endpoint; never send cookies.\n credentials: 'omit',\n mode: 'cors',\n });\n } catch {\n // fire-and-forget — never throw to the host site\n }\n}\n\nexport function createTrackingClient(config: TrackingClientConfig): TrackingClient {\n const flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n const maxQueueSize = Math.min(config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE, HARD_MAX_BATCH);\n const sdkVersion = config.sdkVersion ?? null;\n const packageName = config.packageName ?? null;\n const endpointBase = config.endpoint.replace(/\\/$/, '');\n const eventsUrl = `${endpointBase}/events`;\n\n let queue: QueuedEvent[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n let firstPage: string | null = null;\n let destroyed = false;\n\n // Initialize identity early so the first POST has stable values.\n const visitorId = getVisitorId();\n let sessionId = getOrRotateSessionId();\n\n if (typeof window !== 'undefined')\n firstPage = window.location.href;\n\n function buildSessionPayload(): TrackingSessionUpsertPayload {\n sessionId = getOrRotateSessionId();\n const params = readTrackingParams();\n const context = buildContext(config.surface, sdkVersion, packageName);\n return {\n session_id: sessionId,\n visitor_id: visitorId,\n gclid: params.gclid,\n fbclid: params.fbclid,\n utm_source: params.utm_source,\n utm_medium: params.utm_medium,\n utm_campaign: params.utm_campaign,\n utm_term: params.utm_term,\n utm_content: params.utm_content,\n first_page: firstPage,\n consent_state: consentSnapshot(),\n context,\n };\n }\n\n function scheduleFlush(): void {\n if (flushTimer !== null || destroyed)\n return;\n flushTimer = setTimeout(() => {\n flushTimer = null;\n void flush();\n }, flushIntervalMs);\n }\n\n function clearScheduledFlush(): void {\n if (flushTimer !== null) {\n clearTimeout(flushTimer);\n flushTimer = null;\n }\n }\n\n async function flush(): Promise<void> {\n if (queue.length === 0)\n return;\n\n const events = queue.slice(0, HARD_MAX_BATCH);\n queue = queue.slice(events.length);\n clearScheduledFlush();\n\n const body: IngestRequestBody = {\n session: buildSessionPayload(),\n events,\n };\n\n const serialized = JSON.stringify(body);\n\n // Prefer fetch + keepalive for better error visibility. sendBeacon is the\n // pagehide fallback path because it survives navigation away.\n await postWithFetch(eventsUrl, serialized, config.apiKey, false);\n }\n\n function trackEvent(input: TrackEventInput): void {\n if (destroyed)\n return;\n if (!input || typeof input.eventType !== 'string' || input.eventType.length === 0)\n return;\n\n const occurredAt =\n input.occurredAt instanceof Date\n ? input.occurredAt.toISOString()\n : typeof input.occurredAt === 'string'\n ? input.occurredAt\n : new Date().toISOString();\n\n queue.push({\n event_type: input.eventType,\n page_url:\n input.pageUrl ?? (typeof window === 'undefined' ? null : window.location.href),\n metadata: input.metadata ?? null,\n occurred_at: occurredAt,\n });\n\n if (queue.length >= maxQueueSize) {\n void flush();\n } else {\n scheduleFlush();\n }\n }\n\n function flushOnUnload(): void {\n if (queue.length === 0)\n return;\n const events = queue.slice(0, HARD_MAX_BATCH);\n queue = queue.slice(events.length);\n clearScheduledFlush();\n\n const body: IngestRequestBody = {\n session: buildSessionPayload(),\n events,\n };\n const serialized = JSON.stringify(body);\n void postWithFetch(eventsUrl, serialized, config.apiKey, true);\n }\n\n if (typeof window !== 'undefined') {\n window.addEventListener('pagehide', flushOnUnload);\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') flushOnUnload();\n });\n }\n\n return {\n trackEvent,\n flush,\n getSessionId: () => sessionId,\n getVisitorId: () => visitorId,\n destroy: () => {\n destroyed = true;\n clearScheduledFlush();\n queue = [];\n if (typeof window !== 'undefined') {\n window.removeEventListener('pagehide', flushOnUnload);\n }\n },\n };\n}\n","// Auto page_view emission. Fires once on attach, then again on every SPA\n// navigation. Detects navigation via three signals:\n// - history.pushState (patched)\n// - history.replaceState (patched)\n// - popstate event (back/forward buttons)\n//\n// The Next.js provider can opt out of this and use `usePathname` instead so\n// it picks up App Router transitions reliably without monkey-patching globals.\n\nimport type { TrackingClient } from './ingest';\n\nexport interface PageViewMetadata {\n page: {\n title: string | null;\n path: string;\n search: string;\n hash: string;\n };\n referrer: string | null;\n viewport?: { w: number; h: number };\n}\n\nexport function buildPageViewMetadata(): PageViewMetadata | null {\n if (typeof window === 'undefined' || typeof document === 'undefined')\n return null;\n return {\n page: {\n title: document.title || null,\n path: window.location.pathname,\n search: window.location.search,\n hash: window.location.hash,\n },\n referrer: document.referrer || null,\n viewport: { w: window.innerWidth, h: window.innerHeight },\n };\n}\n\nexport function fireManualPageView(client: TrackingClient): void {\n const metadata = buildPageViewMetadata();\n client.trackEvent({\n eventType: 'page_view',\n pageUrl: typeof window === 'undefined' ? null : window.location.href,\n metadata: metadata as unknown as Record<string, unknown> | null,\n });\n}\n\nexport interface AttachAutoPageViewOptions {\n /** Skip the initial fire on attach (useful when the host already fired one). */\n skipInitial?: boolean;\n}\n\nexport function attachAutoPageView(\n client: TrackingClient,\n options: AttachAutoPageViewOptions = {},\n): () => void {\n if (typeof window === 'undefined' || typeof history === 'undefined') {\n return () => {};\n }\n\n let lastPath = window.location.pathname + window.location.search;\n\n function maybeFire(): void {\n const current = window.location.pathname + window.location.search;\n if (current === lastPath)\n return;\n lastPath = current;\n fireManualPageView(client);\n }\n\n const originalPushState = history.pushState.bind(history);\n const originalReplaceState = history.replaceState.bind(history);\n\n function patchedPushState(this: History, ...args: Parameters<History['pushState']>): void {\n originalPushState(...args);\n // Defer one tick so the URL is settled before we read it.\n setTimeout(maybeFire, 0);\n }\n function patchedReplaceState(this: History, ...args: Parameters<History['replaceState']>): void {\n originalReplaceState(...args);\n setTimeout(maybeFire, 0);\n }\n\n history.pushState = patchedPushState as History['pushState'];\n history.replaceState = patchedReplaceState as History['replaceState'];\n window.addEventListener('popstate', maybeFire);\n\n if (!options.skipInitial)\n fireManualPageView(client);\n\n return () => {\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n window.removeEventListener('popstate', maybeFire);\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,MAAM,oBAAoB;AAC1B,MAAM,wBAAwB;AAW9B,WAAS,oBAAoB,OAA+C;AACjF,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,mBAAmB;AAAA,IACrB;AAAA,EACF;AAEO,WAAS,kBAAgC;AAC9C,QAAI,OAAO,WAAW;AACpB,aAAO;AAET,UAAM,cAAc,OAAO,aAAa,QAAQ,iBAAiB;AAEjE,QAAI,gBAAgB,aAAa,gBAAgB;AAC/C,aAAO;AAET,WAAO;AAAA,EACT;AAEO,WAAS,gBAAgB,OAA+B;AAC7D,QAAI,OAAO,WAAW;AACpB;AAEF,WAAO,aAAa,QAAQ,mBAAmB,KAAK;AACpD,WAAO,aAAa,QAAQ,wBAAuB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAE3E,QAAI,OAAO,OAAO,SAAS;AACzB,aAAO,KAAK,WAAW,UAAU,oBAAoB,KAAK,CAAC;AAAA,EAC/D;AAEO,WAAS,uBAAqC;AACnD,UAAM,eAAe,gBAAgB;AAErC,QAAI,iBAAiB,aAAa,iBAAiB;AACjD,sBAAgB,YAAY;AAE9B,WAAO;AAAA,EACT;;;ACnDO,MAAM,mBAAmB;AACzB,MAAM,4BAA4B;AAEzC,WAAS,gBAAgB,IAAoB;AAC3C,WAAO,WAAW,EAAE;AAAA,EACtB;AAyCO,WAAS,qBAAkD;AAChE,WAAO,YAAY,OAAO,aAAa,CAAC;AAExC,QAAI,OAAO,OAAO,SAAS;AACzB,aAAO,OAAO;AAEhB,WAAO,OAAO,IAAI,SAAoB;AACpC,aAAO,WAAW,KAAK,IAAI;AAAA,IAC7B;AAEA,WAAO,OAAO;AAAA,EAChB;AAEO,WAAS,2BAAiC;AAC/C,UAAM,OAAO,mBAAmB;AAChC,SAAK,WAAW,WAAW;AAAA,MACzB,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,mBAAmB;AAAA,MACnB,iBAAiB;AAAA,IACnB,CAAC;AAAA,EACH;AAEO,WAAS,eAAe,QAAsB;AACnD,QAAI,OAAO,aAAa;AACtB;AAEF,UAAM,SAAS,gBAAgB,aAAa;AAC5C,UAAM,iBAAiB,SAAS,cAAiC,UAAU,yBAAyB,KAAK,MAAM,IAAI;AACnH,QAAI;AACF;AAEF,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ;AACf,WAAO,MAAM,GAAG,gBAAgB,OAAO,mBAAmB,MAAM,CAAC;AACjE,WAAO,aAAa,2BAA2B,MAAM;AACrD,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC;AAEO,WAAS,eAAe,QAAsB;AACnD,UAAM,OAAO,mBAAmB;AAChC,SAAK,MAAM,oBAAI,KAAK,CAAC;AACrB,SAAK,UAAU,MAAM;AAAA,EACvB;AAWO,WAAS,2BAA2B,QAAsB;AAC/D,QAAI,OAAO,WAAW,eAAe,OAAO,aAAa;AACvD;AAEF,6BAAyB;AACzB,mBAAe,MAAM;AACrB,mBAAe,MAAM;AACrB,yBAAqB;AAAA,EACvB;;;AC7GO,MAAM,kCAAkC;AAExC,MAAM,sBAAsB;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAIO,WAAS,4BAA4C;AAC1D,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,EACF;AAEO,WAAS,6BAA6B,OAA+B;AAC1E,WAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AAAA,EACjE;AAEO,WAAS,kCACd,YACgB;AAChB,WAAO,oBAAoB,OAAuB,CAAC,QAAQ,QAAQ;AACjE,aAAO,GAAG,IAAI,6BAA6B,WAAW,GAAG,CAAC;AAC1D,aAAO;AAAA,IACT,GAAG,0BAA0B,CAAC;AAAA,EAChC;AAEO,WAAS,uBACd,cAC2C;AAC3C,WAAO,oBAAoB,OAAkD,CAAC,QAAQ,QAAQ;AAC5F,YAAM,QAAQ,aAAa,IAAI,GAAG;AAElC,UAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG;AACxD,eAAO,GAAG,IAAI;AAAA,MAChB;AAEA,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAAA,EACP;AAEO,WAAS,2BAA2B,KAAsC;AAC/E,QAAI,OAAO,aAAa;AACtB,aAAO;AAET,UAAM,UAAU,SAAS,SAAS,SAAS,OAAO,MAAM,IAAI,IAAI,CAAC;AACjE,UAAM,QAAQ,QAAQ,KAAK,CAAC,WAAW,OAAO,WAAW,GAAG,GAAG,GAAG,CAAC;AAEnE,QAAI,CAAC;AACH,aAAO;AAET,UAAM,CAAC,EAAE,WAAW,EAAE,IAAI,MAAM,MAAM,GAAG;AACzC,WAAO,6BAA6B,mBAAmB,QAAQ,CAAC;AAAA,EAClE;AAEO,WAAS,kBACd,KACA,OACA,gBAAgB,iCACV;AACN,QAAI,OAAO,aAAa;AACtB;AAEF,UAAM,eAAe,mBAAmB,KAAK;AAC7C,aAAS,SAAS,GAAG,GAAG,IAAI,YAAY,aAAa,aAAa;AAAA,EACpE;AAEO,WAAS,sCACd,cACA,gBAAgB,iCAC2B;AAC3C,UAAM,iBAAiB,uBAAuB,YAAY;AAE1D,WAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACvD,wBAAkB,KAAyB,OAAO,aAAa;AAAA,IACjE,CAAC;AAED,WAAO;AAAA,EACT;AAEO,WAAS,kCACd,MAAM,OAAO,WAAW,cAAc,KAAK,OAAO,SAAS,MAC3D,gBAAgB,iCACA;AAChB,UAAM,cAAc,OAAO,WAAW,cAClC,IAAI,IAAI,OAAO,yBAAyB,IACxC,IAAI,IAAI,KAAK,OAAO,SAAS,MAAM;AACvC,0CAAsC,YAAY,cAAc,aAAa;AAC7E,WAAO,kCAAkC,0BAA0B;AAAA,EACrE;;;AC9FO,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB,KAAK,KAAK;AAOzC,WAAS,WAAmB;AAC1B,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe;AAChE,aAAO,OAAO,WAAW;AAE3B,WAAO,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,EACjH;AAEA,WAAS,iBAAiB,KAA4B;AACpD,QAAI;AACF,aAAO,OAAO,aAAa,QAAQ,GAAG;AAAA,IACxC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,kBAAkB,KAAa,OAAqB;AAC3D,QAAI;AACF,aAAO,aAAa,QAAQ,KAAK,KAAK;AAAA,IACxC,QAAQ;AAAA,IAGR;AAAA,EACF;AAEO,WAAS,eAAuB;AACrC,QAAI,OAAO,WAAW;AACpB,aAAO,SAAS;AAElB,UAAM,WAAW,iBAAiB,mBAAmB;AACrD,QAAI,YAAY,SAAS,SAAS;AAChC,aAAO;AAET,UAAM,QAAQ,SAAS;AACvB,sBAAkB,qBAAqB,KAAK;AAC5C,WAAO;AAAA,EACT;AAEO,WAAS,qBAAqB,MAAc,KAAK,IAAI,GAAW;AACrE,QAAI,OAAO,WAAW;AACpB,aAAO,SAAS;AAElB,UAAM,MAAM,iBAAiB,mBAAmB;AAChD,QAAI,KAAK;AACP,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,YAAI,OAAO,OAAO,OAAO,YAAY,OAAO,OAAO,kBAAkB,UAAU;AAC7E,cAAI,MAAM,OAAO,iBAAiB,iBAAiB;AACjD,kBAAM,YAA2B,EAAE,IAAI,OAAO,IAAI,eAAe,IAAI;AACrE,8BAAkB,qBAAqB,KAAK,UAAU,SAAS,CAAC;AAChE,mBAAO,OAAO;AAAA,UAChB;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,QAAuB,EAAE,IAAI,SAAS,GAAG,eAAe,IAAI;AAClE,sBAAkB,qBAAqB,KAAK,UAAU,KAAK,CAAC;AAC5D,WAAO,MAAM;AAAA,EACf;;;AC1DO,MAAM,4BAA4B;AAClC,MAAM,yBAAyB;AAC/B,MAAM,iBAAiB;AACvB,MAAM,iBAAiB;AAgD9B,WAAS,aACP,SACA,YACA,aACuB;AACvB,WAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,MACb,cAAc;AAAA,MACd,aAAa,OAAO,WAAW,cAAc,OAAO,OAAO,SAAS;AAAA,MACpE,YAAY,OAAO,aAAa,cAAc,OAAO,SAAS,SAAS;AAAA,MACvE,UAAU,OAAO,aAAa,cAAc,OAAO,SAAS,YAAY;AAAA,IAC1E;AAAA,EACF;AAEA,WAAS,qBAAqC;AAC5C,QAAI,OAAO,WAAW;AACpB,aAAO,0BAA0B;AAGnC,QAAI;AACF,wCAAkC;AAAA,IACpC,QAAQ;AAAA,IAER;AACA,WAAO,kCAAkC,0BAA0B;AAAA,EACrE;AAEA,WAAS,kBAAkD;AACzD,QAAI;AACF,aAAO,EAAE,OAAO,gBAAgB,EAAE;AAAA,IACpC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,iBAAe,cAAc,KAAa,MAAc,QAAgB,WAAmC;AACzG,QAAI,OAAO,UAAU;AACnB;AACF,QAAI;AACF,YAAM,MAAM,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,CAAC,cAAc,GAAG;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QAEA,aAAa;AAAA,QACb,MAAM;AAAA,MACR,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AAEO,WAAS,qBAAqB,QAA8C;AACjF,UAAM,kBAAkB,OAAO,mBAAmB;AAClD,UAAM,eAAe,KAAK,IAAI,OAAO,gBAAgB,wBAAwB,cAAc;AAC3F,UAAM,aAAa,OAAO,cAAc;AACxC,UAAM,cAAc,OAAO,eAAe;AAC1C,UAAM,eAAe,OAAO,SAAS,QAAQ,OAAO,EAAE;AACtD,UAAM,YAAY,GAAG,YAAY;AAEjC,QAAI,QAAuB,CAAC;AAC5B,QAAI,aAAmD;AACvD,QAAI,YAA2B;AAC/B,QAAI,YAAY;AAGhB,UAAM,YAAY,aAAa;AAC/B,QAAI,YAAY,qBAAqB;AAErC,QAAI,OAAO,WAAW;AACpB,kBAAY,OAAO,SAAS;AAE9B,aAAS,sBAAoD;AAC3D,kBAAY,qBAAqB;AACjC,YAAM,SAAS,mBAAmB;AAClC,YAAM,UAAU,aAAa,OAAO,SAAS,YAAY,WAAW;AACpE,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO;AAAA,QACf,YAAY,OAAO;AAAA,QACnB,YAAY,OAAO;AAAA,QACnB,cAAc,OAAO;AAAA,QACrB,UAAU,OAAO;AAAA,QACjB,aAAa,OAAO;AAAA,QACpB,YAAY;AAAA,QACZ,eAAe,gBAAgB;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAEA,aAAS,gBAAsB;AAC7B,UAAI,eAAe,QAAQ;AACzB;AACF,mBAAa,WAAW,MAAM;AAC5B,qBAAa;AACb,aAAK,MAAM;AAAA,MACb,GAAG,eAAe;AAAA,IACpB;AAEA,aAAS,sBAA4B;AACnC,UAAI,eAAe,MAAM;AACvB,qBAAa,UAAU;AACvB,qBAAa;AAAA,MACf;AAAA,IACF;AAEA,mBAAe,QAAuB;AACpC,UAAI,MAAM,WAAW;AACnB;AAEF,YAAM,SAAS,MAAM,MAAM,GAAG,cAAc;AAC5C,cAAQ,MAAM,MAAM,OAAO,MAAM;AACjC,0BAAoB;AAEpB,YAAM,OAA0B;AAAA,QAC9B,SAAS,oBAAoB;AAAA,QAC7B;AAAA,MACF;AAEA,YAAM,aAAa,KAAK,UAAU,IAAI;AAItC,YAAM,cAAc,WAAW,YAAY,OAAO,QAAQ,KAAK;AAAA,IACjE;AAEA,aAASA,YAAW,OAA8B;AAChD,UAAI;AACF;AACF,UAAI,CAAC,SAAS,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,WAAW;AAC9E;AAEF,YAAM,aACJ,MAAM,sBAAsB,OACxB,MAAM,WAAW,YAAY,IAC7B,OAAO,MAAM,eAAe,WAC1B,MAAM,cACN,oBAAI,KAAK,GAAE,YAAY;AAE/B,YAAM,KAAK;AAAA,QACT,YAAY,MAAM;AAAA,QAClB,UACE,MAAM,YAAY,OAAO,WAAW,cAAc,OAAO,OAAO,SAAS;AAAA,QAC3E,UAAU,MAAM,YAAY;AAAA,QAC5B,aAAa;AAAA,MACf,CAAC;AAED,UAAI,MAAM,UAAU,cAAc;AAChC,aAAK,MAAM;AAAA,MACb,OAAO;AACL,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,aAAS,gBAAsB;AAC7B,UAAI,MAAM,WAAW;AACnB;AACF,YAAM,SAAS,MAAM,MAAM,GAAG,cAAc;AAC5C,cAAQ,MAAM,MAAM,OAAO,MAAM;AACjC,0BAAoB;AAEpB,YAAM,OAA0B;AAAA,QAC9B,SAAS,oBAAoB;AAAA,QAC7B;AAAA,MACF;AACA,YAAM,aAAa,KAAK,UAAU,IAAI;AACtC,WAAK,cAAc,WAAW,YAAY,OAAO,QAAQ,IAAI;AAAA,IAC/D;AAEA,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,iBAAiB,YAAY,aAAa;AACjD,aAAO,iBAAiB,oBAAoB,MAAM;AAChD,YAAI,SAAS,oBAAoB,SAAU,eAAc;AAAA,MAC3D,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,YAAAA;AAAA,MACA;AAAA,MACA,cAAc,MAAM;AAAA,MACpB,cAAc,MAAM;AAAA,MACpB,SAAS,MAAM;AACb,oBAAY;AACZ,4BAAoB;AACpB,gBAAQ,CAAC;AACT,YAAI,OAAO,WAAW,aAAa;AACjC,iBAAO,oBAAoB,YAAY,aAAa;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;;;ACtPO,WAAS,wBAAiD;AAC/D,QAAI,OAAO,WAAW,eAAe,OAAO,aAAa;AACvD,aAAO;AACT,WAAO;AAAA,MACL,MAAM;AAAA,QACJ,OAAO,SAAS,SAAS;AAAA,QACzB,MAAM,OAAO,SAAS;AAAA,QACtB,QAAQ,OAAO,SAAS;AAAA,QACxB,MAAM,OAAO,SAAS;AAAA,MACxB;AAAA,MACA,UAAU,SAAS,YAAY;AAAA,MAC/B,UAAU,EAAE,GAAG,OAAO,YAAY,GAAG,OAAO,YAAY;AAAA,IAC1D;AAAA,EACF;AAEO,WAAS,mBAAmB,QAA8B;AAC/D,UAAM,WAAW,sBAAsB;AACvC,WAAO,WAAW;AAAA,MAChB,WAAW;AAAA,MACX,SAAS,OAAO,WAAW,cAAc,OAAO,OAAO,SAAS;AAAA,MAChE;AAAA,IACF,CAAC;AAAA,EACH;AAOO,WAAS,mBACd,QACA,UAAqC,CAAC,GAC1B;AACZ,QAAI,OAAO,WAAW,eAAe,OAAO,YAAY,aAAa;AACnE,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,QAAI,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS;AAE1D,aAAS,YAAkB;AACzB,YAAM,UAAU,OAAO,SAAS,WAAW,OAAO,SAAS;AAC3D,UAAI,YAAY;AACd;AACF,iBAAW;AACX,yBAAmB,MAAM;AAAA,IAC3B;AAEA,UAAM,oBAAoB,QAAQ,UAAU,KAAK,OAAO;AACxD,UAAM,uBAAuB,QAAQ,aAAa,KAAK,OAAO;AAE9D,aAAS,oBAAmC,MAA8C;AACxF,wBAAkB,GAAG,IAAI;AAEzB,iBAAW,WAAW,CAAC;AAAA,IACzB;AACA,aAAS,uBAAsC,MAAiD;AAC9F,2BAAqB,GAAG,IAAI;AAC5B,iBAAW,WAAW,CAAC;AAAA,IACzB;AAEA,YAAQ,YAAY;AACpB,YAAQ,eAAe;AACvB,WAAO,iBAAiB,YAAY,SAAS;AAE7C,QAAI,CAAC,QAAQ;AACX,yBAAmB,MAAM;AAE3B,WAAO,MAAM;AACX,cAAQ,YAAY;AACpB,cAAQ,eAAe;AACvB,aAAO,oBAAoB,YAAY,SAAS;AAAA,IAClD;AAAA,EACF;;;AN7EA,MAAM,YAAY;AAElB,WAAS,oBAAoC;AAC3C,WAAO,kCAAkC,0BAA0B;AAAA,EACrE;AAEA,WAAS,sBAA4B;AACnC,aAAS,eAAe,SAAS,GAAG,OAAO;AAAA,EAC7C;AAEA,WAAS,oBAAoB,OAAe,SAAqB,OAAwD;AACvH,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,OAAO;AACd,WAAO,cAAc;AACrB,WAAO,OAAO,OAAO,OAAO;AAAA,MAC1B,cAAc;AAAA,MACd,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,OAAO;AAAA,IACT,GAAG,KAAK;AACR,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO;AAAA,EACT;AAEA,WAAS,qBAA2B;AAClC,QAAI,OAAO,aAAa,eAAe,gBAAgB,MAAM,aAAa,SAAS,eAAe,SAAS;AACzG;AAEF,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,KAAK;AACZ,WAAO,OAAO,OAAO,OAAO;AAAA,MAC1B,UAAU;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,IACd,CAAwC;AAExC,UAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,WAAO,OAAO,UAAU,OAAO;AAAA,MAC7B,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,eAAe;AAAA,MACf,KAAK;AAAA,IACP,CAAwC;AAExC,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,WAAO,OAAO,QAAQ,OAAO;AAAA,MAC3B,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,UAAU;AAAA,MACV,YAAY;AAAA,IACd,CAAwC;AAExC,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,WAAO,OAAO,QAAQ,OAAO;AAAA,MAC3B,SAAS;AAAA,MACT,KAAK;AAAA,MACL,UAAU;AAAA,IACZ,CAAwC;AAExC,UAAM,gBAAgB,oBAAoB,WAAW,MAAM;AACzD,sBAAgB,QAAQ;AACxB,0BAAoB;AAAA,IACtB,GAAG,CAAC,CAAC;AAEL,UAAM,eAAe,oBAAoB,UAAU,MAAM;AACvD,sBAAgB,SAAS;AACzB,0BAAoB;AAAA,IACtB,GAAG;AAAA,MACD,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,IACV,CAAC;AAED,YAAQ,YAAY,aAAa;AACjC,YAAQ,YAAY,YAAY;AAChC,cAAU,YAAY,OAAO;AAC7B,cAAU,YAAY,OAAO;AAC7B,WAAO,YAAY,SAAS;AAC5B,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC;AAEA,MAAI,eAAsC;AAC1C,MAAI,qBAA0C;AAEvC,WAAS,KAAK,SAA6B,CAAC,GAAS;AAC1D,QAAI,OAAO,WAAW;AACpB;AAGF,WAAO,kBAAkB;AAEzB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,4BAA4B;AAAA,MAC5B,sBAAsB;AAAA,MACtB;AAAA,MACA,sBAAsB;AAAA,IACxB,IAAI;AAEJ,QAAI;AACF,wCAAkC,OAAO,SAAS,MAAM,mBAAmB;AAE7E,QAAI;AACF,iCAA2B,MAAM;AAEnC,QAAI;AACF,yBAAmB;AAIrB,QAAI,iBAAiB,MAAM;AACzB,2BAAqB;AACrB,mBAAa,QAAQ;AACrB,qBAAe;AACf,2BAAqB;AAAA,IACvB;AAEA,QAAI,UAAU,UAAU;AACtB,qBAAe,qBAAqB;AAAA,QAClC;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,aAAa;AAAA,MACf,CAAC;AACD,2BAAqB,mBAAmB,YAAY;AAAA,IACtD,WAAW,UAAU,UAAU;AAE7B,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AAAA,EACF;AAEA,WAAS,WAAW,OAA8B;AAChD,QAAI,iBAAiB,MAAM;AAEzB,cAAQ,KAAK,uEAAuE;AACpF;AAAA,IACF;AACA,iBAAa,WAAW,KAAK;AAAA,EAC/B;AAGA,MAAM,oBAAoB;AAAA,IACxB;AAAA,IACA,uBAAuB,MAAsB,kCAAkC;AAAA,IAC/E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,OAAO,WAAW;AACpB,WAAO,kBAAkB;AAE3B,MAAO,cAAQ;","names":["trackEvent"]}
|
package/package.json
CHANGED