getu-attribution-v2-sdk 0.2.5 → 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.
- package/README.md +6 -0
- package/dist/core/AttributionSDK.d.ts +32 -1
- package/dist/core/AttributionSDK.d.ts.map +1 -1
- package/dist/core/AttributionSDK.js +144 -9
- package/dist/getuai-attribution.min.js +1 -1
- package/dist/index.esm.js +204 -9
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +204 -9
- package/dist/storage/index.d.ts +14 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +48 -0
- package/dist/types/index.d.ts +29 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +12 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -569,6 +569,12 @@ When `autoTrack: true`, the SDK automatically tracks:
|
|
|
569
569
|
- Captures all form field values (with password masking)
|
|
570
570
|
- Includes form metadata (id, action, method)
|
|
571
571
|
- Handles checkboxes, radio buttons, multi-select, file inputs
|
|
572
|
+
- **Fallback field collection**: For form fields without `name` attribute, SDK will use fallback keys:
|
|
573
|
+
- Priority: `name` attribute
|
|
574
|
+
- Fallback 1: `id_{id}` (if field has `id`)
|
|
575
|
+
- Fallback 2: `aria_{aria-label}` (if field has `aria-label`)
|
|
576
|
+
- Fallback 3: `ph_{placeholder}_{index}` (if field has `placeholder`)
|
|
577
|
+
- Fallback 4: `field_{index}` (as last resort)
|
|
572
578
|
|
|
573
579
|
#### External Link Clicks
|
|
574
580
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDKConfig, EventType, AttributionData, Currency, UserSession } from "../types";
|
|
1
|
+
import { SDKConfig, EventType, AttributionData, Currency, UserSession, UserTraits } from "../types";
|
|
2
2
|
export declare class AttributionSDK {
|
|
3
3
|
private config;
|
|
4
4
|
private logger;
|
|
@@ -60,12 +60,43 @@ export declare class AttributionSDK {
|
|
|
60
60
|
setUserId(userId: string): void;
|
|
61
61
|
getUserId(): string | null;
|
|
62
62
|
removeUserId(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Identify user and set user attributes
|
|
65
|
+
* Used to explicitly set user information, e.g., after login
|
|
66
|
+
*
|
|
67
|
+
* @param userId User unique identifier
|
|
68
|
+
* @param traits User attributes
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* sdk.identify('user-123', {
|
|
72
|
+
* email: 'user@example.com',
|
|
73
|
+
* name: 'John Doe',
|
|
74
|
+
* company_name: 'Acme Inc'
|
|
75
|
+
* });
|
|
76
|
+
*/
|
|
77
|
+
identify(userId: string, traits?: UserTraits): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Get current user traits
|
|
80
|
+
*/
|
|
81
|
+
getUserTraits(): UserTraits | null;
|
|
82
|
+
/**
|
|
83
|
+
* Get current session ID
|
|
84
|
+
*/
|
|
85
|
+
getSessionId(): string | null;
|
|
63
86
|
private initializeSession;
|
|
64
87
|
private extractAndStoreUTMData;
|
|
65
88
|
private setupAutoTracking;
|
|
66
89
|
private setupFormTracking;
|
|
67
90
|
private serializeFormFields;
|
|
91
|
+
private getFormFieldKey;
|
|
92
|
+
private normalizeFormFieldKey;
|
|
68
93
|
private serializeFormValue;
|
|
94
|
+
/**
|
|
95
|
+
* Extract standardized lead fields from form data
|
|
96
|
+
* @param formData Serialized form data
|
|
97
|
+
* @returns Extracted user traits
|
|
98
|
+
*/
|
|
99
|
+
private extractLeadFields;
|
|
69
100
|
private setupLinkTracking;
|
|
70
101
|
private handleCrossDomainUTM;
|
|
71
102
|
private setupNetworkHandlers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AttributionSDK.d.ts","sourceRoot":"","sources":["../../src/core/AttributionSDK.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAET,SAAS,EACT,eAAe,EAEf,QAAQ,EACR,WAAW,
|
|
1
|
+
{"version":3,"file":"AttributionSDK.d.ts","sourceRoot":"","sources":["../../src/core/AttributionSDK.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventType, Currency, defaultEndpoint, } from "../types";
|
|
1
|
+
import { EventType, Currency, defaultEndpoint, DEFAULT_FIELD_MAPPINGS, } from "../types";
|
|
2
2
|
import { AttributionStorageManager } from "../storage";
|
|
3
3
|
import { EventQueueManager, EventHttpClient } from "../queue";
|
|
4
4
|
import { generateId, getTimestamp, extractUTMParams, getCurrentUrl, getReferrer, getUserAgent, getPageTitle, generateSessionId, isOnline, ConsoleLogger, addUTMToURL, shouldExcludeDomain, isExternalURL, filterUTMParams, cleanURL, getQueryString, getQueryParams, } from "../utils";
|
|
@@ -412,6 +412,55 @@ export class AttributionSDK {
|
|
|
412
412
|
this.storage.removeUserId();
|
|
413
413
|
this.logger.info("👤 User ID removed");
|
|
414
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* Identify user and set user attributes
|
|
417
|
+
* Used to explicitly set user information, e.g., after login
|
|
418
|
+
*
|
|
419
|
+
* @param userId User unique identifier
|
|
420
|
+
* @param traits User attributes
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* sdk.identify('user-123', {
|
|
424
|
+
* email: 'user@example.com',
|
|
425
|
+
* name: 'John Doe',
|
|
426
|
+
* company_name: 'Acme Inc'
|
|
427
|
+
* });
|
|
428
|
+
*/
|
|
429
|
+
async identify(userId, traits) {
|
|
430
|
+
if (!this.initialized) {
|
|
431
|
+
this.logger.warn("SDK not initialized, identify call queued");
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (!userId || userId.trim() === "") {
|
|
435
|
+
this.logger.warn("Cannot identify with empty user ID");
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
// Set user ID
|
|
439
|
+
this.setUserId(userId);
|
|
440
|
+
// Store user traits
|
|
441
|
+
if (traits) {
|
|
442
|
+
this.storage.setUserTraits(traits);
|
|
443
|
+
this.logger.info(`User identified: ${userId}`, traits);
|
|
444
|
+
}
|
|
445
|
+
// Send identify event to backend
|
|
446
|
+
await this.trackEvent(EventType.FORM_SUBMIT, {
|
|
447
|
+
_identify: true,
|
|
448
|
+
_user_traits: traits,
|
|
449
|
+
tracking_user_id: userId,
|
|
450
|
+
}, userId);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Get current user traits
|
|
454
|
+
*/
|
|
455
|
+
getUserTraits() {
|
|
456
|
+
return this.storage.getUserTraits();
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Get current session ID
|
|
460
|
+
*/
|
|
461
|
+
getSessionId() {
|
|
462
|
+
return this.session?.sessionId || null;
|
|
463
|
+
}
|
|
415
464
|
// Initialize user session
|
|
416
465
|
initializeSession() {
|
|
417
466
|
const existingSession = this.storage.getSession();
|
|
@@ -492,8 +541,17 @@ export class AttributionSDK {
|
|
|
492
541
|
return;
|
|
493
542
|
}
|
|
494
543
|
const fieldValues = this.serializeFormFields(form);
|
|
544
|
+
// Extract standardized lead fields
|
|
545
|
+
const leadFields = this.extractLeadFields(fieldValues);
|
|
546
|
+
// If email is extracted, automatically store user traits
|
|
547
|
+
if (leadFields.email) {
|
|
548
|
+
this.storage.setUserTraits(leadFields);
|
|
549
|
+
this.logger.debug("Lead fields extracted from form:", leadFields);
|
|
550
|
+
}
|
|
495
551
|
this.trackEvent(EventType.FORM_SUBMIT, {
|
|
496
552
|
...fieldValues,
|
|
553
|
+
// Add standardized lead fields
|
|
554
|
+
_lead_fields: leadFields,
|
|
497
555
|
form_id: form.id || form.name,
|
|
498
556
|
form_action: form.action,
|
|
499
557
|
form_method: form.method,
|
|
@@ -526,17 +584,29 @@ export class AttributionSDK {
|
|
|
526
584
|
result[name] = serializedValue;
|
|
527
585
|
}
|
|
528
586
|
}
|
|
529
|
-
// Ensure all
|
|
587
|
+
// Ensure all fields are represented, including unchecked radios/checkboxes.
|
|
588
|
+
// For fields without name attribute, use a stable fallback key (id/aria-label/placeholder/index).
|
|
530
589
|
const elements = Array.from(form.elements);
|
|
531
|
-
// Group elements by
|
|
590
|
+
// Group elements by key
|
|
532
591
|
const nameToElements = new Map();
|
|
533
|
-
for (
|
|
534
|
-
const
|
|
535
|
-
if (
|
|
592
|
+
for (let index = 0; index < elements.length; index++) {
|
|
593
|
+
const el = elements[index];
|
|
594
|
+
if (el.disabled)
|
|
595
|
+
continue;
|
|
596
|
+
const tagName = el.tagName.toLowerCase();
|
|
597
|
+
const inputType = el.type?.toLowerCase();
|
|
598
|
+
if (tagName === "button" ||
|
|
599
|
+
inputType === "submit" ||
|
|
600
|
+
inputType === "reset") {
|
|
536
601
|
continue;
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
602
|
+
}
|
|
603
|
+
const fieldKey = this.getFormFieldKey(el, index);
|
|
604
|
+
if (!fieldKey) {
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
if (!nameToElements.has(fieldKey))
|
|
608
|
+
nameToElements.set(fieldKey, []);
|
|
609
|
+
nameToElements.get(fieldKey).push(el);
|
|
540
610
|
}
|
|
541
611
|
nameToElements.forEach((els, name) => {
|
|
542
612
|
// Determine the dominant type for a group (radio/checkbox take precedence)
|
|
@@ -621,6 +691,34 @@ export class AttributionSDK {
|
|
|
621
691
|
}
|
|
622
692
|
return result;
|
|
623
693
|
}
|
|
694
|
+
getFormFieldKey(el, index) {
|
|
695
|
+
const name = el.name;
|
|
696
|
+
if (name) {
|
|
697
|
+
return name;
|
|
698
|
+
}
|
|
699
|
+
if (el.id) {
|
|
700
|
+
return `id_${el.id}`;
|
|
701
|
+
}
|
|
702
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
703
|
+
if (ariaLabel && ariaLabel.trim()) {
|
|
704
|
+
return `aria_${this.normalizeFormFieldKey(ariaLabel)}`;
|
|
705
|
+
}
|
|
706
|
+
const placeholder = el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement
|
|
707
|
+
? el.placeholder
|
|
708
|
+
: "";
|
|
709
|
+
if (placeholder && placeholder.trim()) {
|
|
710
|
+
return `ph_${this.normalizeFormFieldKey(placeholder)}_${index}`;
|
|
711
|
+
}
|
|
712
|
+
return `field_${index}`;
|
|
713
|
+
}
|
|
714
|
+
normalizeFormFieldKey(raw) {
|
|
715
|
+
return raw
|
|
716
|
+
.trim()
|
|
717
|
+
.toLowerCase()
|
|
718
|
+
.replace(/\s+/g, "_")
|
|
719
|
+
.replace(/[^a-z0-9_]/g, "")
|
|
720
|
+
.slice(0, 40);
|
|
721
|
+
}
|
|
624
722
|
// Convert FormData value to a serializable value
|
|
625
723
|
serializeFormValue(value) {
|
|
626
724
|
if (value instanceof File) {
|
|
@@ -632,6 +730,43 @@ export class AttributionSDK {
|
|
|
632
730
|
}
|
|
633
731
|
return value;
|
|
634
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Extract standardized lead fields from form data
|
|
735
|
+
* @param formData Serialized form data
|
|
736
|
+
* @returns Extracted user traits
|
|
737
|
+
*/
|
|
738
|
+
extractLeadFields(formData) {
|
|
739
|
+
const result = {};
|
|
740
|
+
// Iterate through all standard field mappings
|
|
741
|
+
for (const [standardField, aliases] of Object.entries(DEFAULT_FIELD_MAPPINGS)) {
|
|
742
|
+
if (result[standardField])
|
|
743
|
+
continue; // Already found, skip
|
|
744
|
+
// Look for matching field
|
|
745
|
+
for (const alias of aliases || []) {
|
|
746
|
+
const lowerAlias = alias.toLowerCase();
|
|
747
|
+
// Search for matching key in formData
|
|
748
|
+
for (const [key, value] of Object.entries(formData)) {
|
|
749
|
+
if (key.toLowerCase() === lowerAlias ||
|
|
750
|
+
key.toLowerCase().includes(lowerAlias)) {
|
|
751
|
+
if (value && typeof value === "string" && value.trim()) {
|
|
752
|
+
result[standardField] = value.trim();
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (result[standardField])
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// Combine first_name and last_name into name (if name is empty)
|
|
762
|
+
if (!result.name && (result.first_name || result.last_name)) {
|
|
763
|
+
result.name = [result.first_name, result.last_name]
|
|
764
|
+
.filter(Boolean)
|
|
765
|
+
.join(" ")
|
|
766
|
+
.trim();
|
|
767
|
+
}
|
|
768
|
+
return result;
|
|
769
|
+
}
|
|
635
770
|
// Setup link tracking
|
|
636
771
|
setupLinkTracking() {
|
|
637
772
|
document.addEventListener("click", (event) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.GetuAIAttribution=e():t.GetuAIAttribution=e()}(this,()=>(()=>{"use strict";var t,e,i={d:(t,e)=>{for(var r in e)i.o(e,r)&&!i.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},r={};i.d(r,{default:()=>X}),function(t){t.PAGE_VIEW="page_view",t.PAGE_CLICK="page_click",t.VIDEO_PLAY="video_play",t.FORM_SUBMIT="form_submit",t.EMAIL_VERIFICATION="email_verification",t.LOGIN="login",t.SIGNUP="signup",t.PRODUCT_VIEW="product_view",t.ADD_TO_CART="add_to_cart",t.PURCHASE="purchase",t.AUDIT_APPROVED="audit_approved"}(t||(t={})),function(t){t.USD="USD"}(e||(e={}));const n="https://attribution.getu.ai/attribution/api",s=[t.PURCHASE,t.LOGIN,t.SIGNUP,t.FORM_SUBMIT,t.EMAIL_VERIFICATION,t.AUDIT_APPROVED];function a(){return Math.floor(Date.now()/1e3)}function o(){try{const t="__localStorage_test__";return localStorage.setItem(t,t),localStorage.removeItem(t),!0}catch{return!1}}class c{constructor(t=!0){this.enabled=t}debug(t,...e){this.enabled&&console.debug&&console.debug(`[GetuAI Debug] ${t}`,...e)}info(t,...e){this.enabled&&console.info&&console.info(`[GetuAI Info] ${t}`,...e)}warn(t,...e){this.enabled&&console.warn&&console.warn(`[GetuAI Warn] ${t}`,...e)}error(t,...e){this.enabled&&console.error&&console.error(`[GetuAI Error] ${t}`,...e)}}function u(){return document.referrer||""}function l(){return window.location.href}function d(){return document.title||""}function h(t,e){try{const i=new URL(t);return Object.entries(e).forEach(([t,e])=>{e&&!i.searchParams.has(t)&&i.searchParams.set(t,e)}),i.toString()}catch(e){return t}}function g(t,e=["utm_source","utm_medium","utm_campaign"]){const i={};return e.forEach(e=>{t[e]&&(i[e]=t[e])}),i}function m(t){try{const e=t||window.location.href;return new URL(e).search}catch(t){return""}}function p(t){try{const e=t||window.location.href,i=new URL(e),r={};return i.searchParams.forEach((t,e)=>{r[e]=t}),r}catch(t){return{}}}class f{constructor(t){this.logger=t}get(t){try{if(!o())return this.logger.warn("LocalStorage not supported"),null;const e=localStorage.getItem(t);return null===e?null:JSON.parse(e)}catch(t){return this.logger.error("Error reading from localStorage:",t),null}}set(t,e){try{if(!o())return void this.logger.warn("LocalStorage not supported");localStorage.setItem(t,JSON.stringify(e))}catch(t){this.logger.error("Error writing to localStorage:",t),this.handleQuotaExceeded()}}remove(t){try{o()&&localStorage.removeItem(t)}catch(t){this.logger.error("Error removing from localStorage:",t)}}clear(){try{o()&&localStorage.clear()}catch(t){this.logger.error("Error clearing localStorage:",t)}}handleQuotaExceeded(){try{const t=Object.keys(localStorage).filter(t=>t.startsWith("attribution_"));if(t.length>0){t.sort((t,e)=>{const i=this.get(t),r=this.get(e);return(i?.expiresAt||0)-(r?.expiresAt||0)});const e=Math.ceil(.2*t.length);t.slice(0,e).forEach(t=>{this.remove(t)}),this.logger.info(`Cleaned up ${e} old attribution records`)}}catch(t){this.logger.error("Error during quota cleanup:",t)}}}class w{constructor(t){this.dbName="attribution_events",this.dbVersion=1,this.storeName="events",this.db=null,this.logger=t}async init(){if("indexedDB"in window)return new Promise((t,e)=>{const i=indexedDB.open(this.dbName,this.dbVersion);i.onerror=()=>{this.logger.error("Failed to open IndexedDB:",i.error),e(i.error)},i.onsuccess=()=>{this.db=i.result,this.logger.info("IndexedDB initialized successfully"),t()},i.onupgradeneeded=t=>{const e=t.target.result;if(!e.objectStoreNames.contains(this.storeName)){const t=e.createObjectStore(this.storeName,{keyPath:"id",autoIncrement:!0});t.createIndex("timestamp","timestamp",{unique:!1}),t.createIndex("sent","sent",{unique:!1}),t.createIndex("queued_at","queued_at",{unique:!1})}}});this.logger.warn("IndexedDB not supported")}async addEvent(t){if(!this.db)throw new Error("IndexedDB not initialized");return new Promise((e,i)=>{const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName),n={...t,queued_at:Date.now(),sent:!1},s=r.add(n);s.onsuccess=()=>{this.logger.debug("Event added to IndexedDB queue"),e()},s.onerror=()=>{this.logger.error("Failed to add event to IndexedDB:",s.error),i(s.error)}})}async getUnsentEvents(t=100){return this.db?new Promise((e,i)=>{const r=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).index("sent").getAll(IDBKeyRange.only(!1),t);r.onsuccess=()=>{const t=r.result.map(t=>{const{queued_at:e,sent:i,...r}=t;return r});e(t)},r.onerror=()=>{this.logger.error("Failed to get unsent events:",r.error),i(r.error)}}):[]}async markEventsAsSent(t){if(this.db&&0!==t.length)return new Promise((e,i)=>{const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName);let n=0,s=!1;t.forEach(a=>{const o=r.get(a);o.onsuccess=()=>{if(o.result){const a={...o.result,sent:!0},c=r.put(a);c.onsuccess=()=>{n++,n!==t.length||s||e()},c.onerror=()=>{s=!0,this.logger.error("Failed to mark event as sent:",c.error),i(c.error)}}else n++,n!==t.length||s||e()},o.onerror=()=>{s=!0,this.logger.error("Failed to get event for marking as sent:",o.error),i(o.error)}})})}async cleanupOldEvents(t=6048e5){if(!this.db)return;const e=Date.now()-t;return new Promise((t,i)=>{const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).index("queued_at").openCursor(IDBKeyRange.upperBound(e));r.onsuccess=()=>{const e=r.result;e?(e.delete(),e.continue()):(this.logger.info("Old events cleanup completed"),t())},r.onerror=()=>{this.logger.error("Failed to cleanup old events:",r.error),i(r.error)}})}async getQueueSize(){return this.db?new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).count();i.onsuccess=()=>{t(i.result)},i.onerror=()=>{this.logger.error("Failed to get queue size:",i.error),e(i.error)}}):0}async clear(){if(this.db)return new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();i.onsuccess=()=>{this.logger.info("IndexedDB queue cleared"),t()},i.onerror=()=>{this.logger.error("Failed to clear IndexedDB queue:",i.error),e(i.error)}})}}class y{constructor(t){this.UTM_STORAGE_KEY="attribution_utm_data",this.SESSION_STORAGE_KEY="attribution_session",this.USER_ID_KEY="getuai_user_id",this.PENDING_EVENTS_KEY="getuai_pending_events_v1",this.USER_ID_COOKIE_EXPIRES=365,this.logger=t,this.localStorage=new f(t),this.indexedDB=new w(t)}setUserId(t){if(!t||""===t.trim())return void this.logger.warn("Cannot set empty user ID");const e=t.trim();try{this.setCookie(this.USER_ID_KEY,e,this.USER_ID_COOKIE_EXPIRES),this.logger.debug(`👤 User ID stored in cookie: ${e}`)}catch(t){this.logger.error("Failed to store user ID in cookie:",t)}try{"undefined"!=typeof localStorage&&(localStorage.setItem(this.USER_ID_KEY,e),this.logger.debug(`👤 User ID stored in localStorage: ${e}`))}catch(t){this.logger.error("Failed to store user ID in localStorage:",t)}}getUserId(){try{if("undefined"!=typeof localStorage){const t=localStorage.getItem(this.USER_ID_KEY);if(t)return t}}catch(t){this.logger.debug("Failed to get user ID from localStorage:",t)}try{const t=this.getCookie(this.USER_ID_KEY);if(t){try{"undefined"!=typeof localStorage&&localStorage.setItem(this.USER_ID_KEY,t)}catch(t){}return t}}catch(t){this.logger.debug("Failed to get user ID from cookie:",t)}return null}removeUserId(){try{this.deleteCookie(this.USER_ID_KEY),this.logger.debug("👤 User ID removed from cookie")}catch(t){this.logger.error("Failed to remove user ID from cookie:",t)}try{"undefined"!=typeof localStorage&&(localStorage.removeItem(this.USER_ID_KEY),this.logger.debug("👤 User ID removed from localStorage"))}catch(t){this.logger.error("Failed to remove user ID from localStorage:",t)}}setCookie(t,e,i){try{const r=new Date;r.setTime(r.getTime()+24*i*60*60*1e3);const n=`${t}=${encodeURIComponent(e)};expires=${r.toUTCString()};path=/;SameSite=Lax`;document.cookie=n}catch(t){this.logger.error("Failed to set cookie:",t)}}getCookie(t){try{const e=t+"=",i=document.cookie.split(";");for(let t=0;t<i.length;t++){let r=i[t];for(;" "===r.charAt(0);)r=r.substring(1,r.length);if(0===r.indexOf(e))return decodeURIComponent(r.substring(e.length,r.length))}return null}catch(t){return this.logger.error("Failed to get cookie:",t),null}}deleteCookie(t){try{document.cookie=`${t}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;`}catch(t){this.logger.error("Failed to delete cookie:",t)}}async init(){await this.indexedDB.init()}getPendingEvents(){try{const t=this.localStorage.get(this.PENDING_EVENTS_KEY);return Array.isArray(t)?t:[]}catch(t){return this.logger.debug("Failed to read pending events:",t),[]}}appendPendingEvents(t){if(t&&0!==t.length)try{const e=[...this.getPendingEvents(),...t].slice(-500);this.localStorage.set(this.PENDING_EVENTS_KEY,e)}catch(t){this.logger.debug("Failed to append pending events:",t)}}removePendingEventsByIds(t){if(t&&0!==t.length)try{const e=this.getPendingEvents();if(0===e.length)return;const i=new Set(t),r=e.filter(t=>!i.has(t.event_id));0===r.length?this.localStorage.remove(this.PENDING_EVENTS_KEY):this.localStorage.set(this.PENDING_EVENTS_KEY,r)}catch(t){this.logger.debug("Failed to remove pending events:",t)}}clearPendingEvents(){try{this.localStorage.remove(this.PENDING_EVENTS_KEY)}catch(t){this.logger.debug("Failed to clear pending events:",t)}}storeUTMData(t){try{const e=this.getUTMData(),i={utm_source:"",utm_medium:"",utm_campaign:"",utm_term:"",utm_content:"",timestamp:Date.now()},r={firstTouch:e?.firstTouch||i,lastTouch:e?.lastTouch||i,touchpoints:e?.touchpoints||[],...t,expiresAt:Date.now()+2592e6};this.localStorage.set(this.UTM_STORAGE_KEY,r),this.logger.debug("UTM data stored successfully:",{firstTouch:r.firstTouch,lastTouch:r.lastTouch,touchpointsCount:r.touchpoints.length,expiresAt:new Date(r.expiresAt).toISOString()})}catch(t){this.logger.error("Failed to store UTM data:",t)}}getUTMData(){const t=this.localStorage.get(this.UTM_STORAGE_KEY);return t&&t.expiresAt&&t.expiresAt>Date.now()?t:(t&&this.localStorage.remove(this.UTM_STORAGE_KEY),null)}storeSession(t){this.localStorage.set(this.SESSION_STORAGE_KEY,t)}getSession(){return this.localStorage.get(this.SESSION_STORAGE_KEY)}async queueEvent(t){try{await this.indexedDB.addEvent(t)}catch(t){throw this.logger.error("Failed to queue event:",t),t}}async getUnsentEvents(t=100){return await this.indexedDB.getUnsentEvents(t)}async markEventsAsSent(t){await this.indexedDB.markEventsAsSent(t)}async getQueueSize(){return await this.indexedDB.getQueueSize()}async cleanupOldEvents(){await this.indexedDB.cleanupOldEvents()}async clearQueue(){await this.indexedDB.clear()}cleanupExpiredData(){this.getUTMData()}}const _="0.2.5";class v{constructor(t,e,i,r=100,n=2e3,s=3,a=1e3,o){this.queue=[],this.processing=!1,this.batchTimer=null,this.retryCounts=new Map,this.logger=t,this.apiKey=e,this.apiEndpoint=i,this.batchSize=r,this.batchInterval=n,this.maxRetries=s,this.retryDelay=a,this.sendEvents=o,this.debouncedProcess=function(t){let e;return(...i)=>{clearTimeout(e),e=setTimeout(()=>t(...i),100)}}(this.process.bind(this))}add(t){if(s.includes(t.event_type))return this.logger.debug(`Immediate event detected: ${t.event_type}, sending immediately`),void this.processImmediate(t);this.queue.push(t),this.logger.debug(`Event added to queue: ${t.event_type}`),this.scheduleBatchProcessing()}async process(){if(this.processing||0===this.queue.length)return;this.processing=!0;const t=this.queue.splice(0,this.batchSize);try{this.logger.debug(`Processing ${t.length} events from queue`),await this.sendEvents(t),this.resetRetryCounts(t),this.logger.info(`Successfully processed ${t.length} events`)}catch(e){return this.logger.error("Failed to process events:",e),this.enqueueBatchForRetry(t),void setTimeout(()=>{this.processing=!1,this.debouncedProcess()},this.retryDelay)}this.processing=!1,this.queue.length>0&&this.debouncedProcess()}async processImmediate(t){try{this.logger.debug(`Processing immediate event: ${t.event_type}`),await this.sendEvents([t]),this.resetRetryCounts([t]),this.logger.info(`Immediate event processed successfully: ${t.event_type}`)}catch(e){this.logger.error(`Failed to process immediate event: ${t.event_type}`,e),this.enqueueBatchForRetry([t])}}scheduleBatchProcessing(){this.batchTimer&&clearTimeout(this.batchTimer),this.batchTimer=setTimeout(()=>{this.debouncedProcess()},this.batchInterval)}clear(){this.queue=[],this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null),this.processing=!1,this.logger.info("Event queue cleared")}size(){return this.queue.length}getStats(){return{size:this.queue.length,processing:this.processing}}async flush(){for(this.logger.info("Flushing event queue");this.queue.length>0;)await this.process()}drainAll(){const t=this.queue.splice(0,this.queue.length);return this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null),this.processing=!1,t}enqueueBatchForRetry(t){const e=[];for(const i of t){const t=(this.retryCounts.get(i.event_id)||0)+1;this.retryCounts.set(i.event_id,t),t>this.maxRetries?(this.logger.warn(`Dropping event after max retries (${this.maxRetries}): ${i.event_type} (${i.event_id})`),this.retryCounts.delete(i.event_id)):e.push(i)}e.length>0&&this.queue.unshift(...e)}resetRetryCounts(t){for(const e of t)this.retryCounts.delete(e.event_id)}}class S{constructor(t,e,i,r=3,n=1e3){this.logger=t,this.apiKey=e,this.apiEndpoint=i,this.maxRetries=r,this.retryDelay=n}async sendEvents(t){if(0===t.length)return;const e={events:t.map(t=>({event_id:t.event_id,event_type:t.event_type,tracking_user_id:t.tracking_user_id,utm_source:t.utm_source||null,utm_medium:t.utm_medium||null,utm_campaign:t.utm_campaign||null,utm_term:t.utm_term||null,utm_content:t.utm_content||null,revenue:t.revenue||null,currency:t.currency||null,event_data:t.event_data||null,context:t.context||null,timestamp:t.timestamp||a()})),sdk_version:_};await async function(t,e=3,i=1e3){let r;for(let n=0;n<=e;n++)try{return await t()}catch(t){if(r=t,n===e)throw r;const s=i*Math.pow(2,n);await new Promise(t=>setTimeout(t,s))}throw r}(async()=>{const i=await fetch(`${this.apiEndpoint}/attribution/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(e)});if(!i.ok){const t=await i.text();throw new Error(`HTTP ${i.status}: ${t}`)}const r=await i.json();return this.logger.debug("Events sent successfully:",r),{result:r,sentEvents:t}},this.maxRetries,this.retryDelay)}async sendEventsKeepalive(t){if(0===t.length)return;const e={events:t.map(t=>({event_id:t.event_id,event_type:t.event_type,tracking_user_id:t.tracking_user_id,utm_source:t.utm_source||null,utm_medium:t.utm_medium||null,utm_campaign:t.utm_campaign||null,utm_term:t.utm_term||null,utm_content:t.utm_content||null,revenue:t.revenue||null,currency:t.currency||null,event_data:t.event_data||null,context:t.context||null,timestamp:t.timestamp||a()})),sdk_version:_},i=await fetch(`${this.apiEndpoint}/attribution/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(e),keepalive:!0});if(!i.ok)throw new Error(`HTTP ${i.status}`)}sendEventsBeacon(t){if(0===t.length)return!0;if("undefined"==typeof navigator||"function"!=typeof navigator.sendBeacon)return!1;const e={events:t.map(t=>({event_id:t.event_id,event_type:t.event_type,tracking_user_id:t.tracking_user_id,utm_source:t.utm_source||null,utm_medium:t.utm_medium||null,utm_campaign:t.utm_campaign||null,utm_term:t.utm_term||null,utm_content:t.utm_content||null,revenue:t.revenue||null,currency:t.currency||null,event_data:t.event_data||null,context:t.context||null,timestamp:t.timestamp||a()})),sdk_version:_},i=`${this.apiEndpoint}/attribution/events_beacon?api_key=${encodeURIComponent(this.apiKey)}`,r=new Blob([JSON.stringify(e)],{type:"text/plain"});return navigator.sendBeacon(i,r)}async sendSingleEvent(t){await this.sendEvents([t])}async testConnection(){try{return(await fetch(`${this.apiEndpoint}/health`,{method:"GET",headers:{Authorization:`Bearer ${this.apiKey}`}})).ok}catch(t){return this.logger.error("Connection test failed:",t),!1}}}class k{constructor(t){this.session=null,this.initialized=!1,this.autoTrackEnabled=!1,this.pageViewTrackTimes=new Map,this.cachedPublicIP=null,this.publicIPFetchPromise=null,this.initialPageViewTriggered=!1,this.spaTrackingEnabled=!1,this.lastTrackedPath="",this.originalPushState=null,this.originalReplaceState=null,this.popstateHandler=null,this.config={apiEndpoint:n,batchSize:100,batchInterval:2e3,maxRetries:3,retryDelay:1e3,enableDebug:!1,autoTrack:!1,autoTrackPageView:!1,sessionTimeout:18e5,enableCrossDomainUTM:!0,crossDomainUTMParams:["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],excludeDomains:[],autoCleanUTM:!0,pageViewDebounceInterval:5e3,...t},this.logger=new c(this.config.enableDebug),this.storage=new y(this.logger),this.httpClient=new S(this.logger,this.config.apiKey,this.config.apiEndpoint||n,this.config.maxRetries,this.config.retryDelay),this.queue=new v(this.logger,this.config.apiKey,this.config.apiEndpoint||n,this.config.batchSize,this.config.batchInterval,this.config.maxRetries,this.config.retryDelay,t=>this.httpClient.sendEvents(t))}async init(){if(this.initialized)this.logger.warn("SDK already initialized");else try{this.logger.info("Initializing GetuAI Attribution SDK"),this.storage.init().catch(t=>{this.logger.warn("Storage initialization failed (IndexedDB may be unavailable), continuing with basic features:",t)}),this.initializeUserId(),this.initializeSession(),this.extractAndStoreUTMData(),this.config.autoTrack&&this.setupAutoTracking(),this.setupNetworkHandlers(),this.setupVisibilityHandlers(),this.setupBeforeUnloadHandler(),this.initialized=!0,this.logger.info("🚀 GetuAI Attribution SDK initialized successfully"),this.logger.info("📄 Auto track page view = "+this.config.autoTrackPageView),this.retryPendingEvents().catch(t=>{this.logger.warn("⚠️ Pending events retry failed",t)}),this.config.autoTrackPageView&&(this.logger.info("📄 Auto track page view enabled (including SPA route tracking)"),this.lastTrackedPath=this.getCurrentPath(),this.setupSPATracking(),this.initialPageViewTriggered||(this.initialPageViewTriggered=!0,Promise.resolve().then(()=>this.trackPageView()).then(()=>this.queue.process()).then(()=>{this.logger.info("✅ Auto track page view completed")}).catch(t=>this.logger.error("❌ Auto track page view failed:",t))))}catch(t){throw this.logger.error("Failed to initialize SDK:",t),t}}async trackEvent(t,i,r,n,s=e.USD){if(this.initialized)try{const e=l(),o=this.cachedPublicIP;this.ensurePublicIPFetched();const c={domain:"undefined"!=typeof window?window.location.hostname:null,path:"undefined"!=typeof window?window.location.pathname:null,title:d(),referrer:u(),url:e.split("?")[0],querystring:m(e),query_params:p(e),ip_address:o},h={session_id:this.session?.sessionId,start_time:this.session?.startTime,last_activity:this.session?.lastActivity,page_views:this.session?.pageViews},g=r||this.getUserId(),f={event_id:"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)}),event_type:t,tracking_user_id:g||void 0,timestamp:a(),event_data:i,context:{page:c,session:h},revenue:n,currency:s,...this.getUTMParams()};this.logger.debug(`Tracking event: ${t}`,f),this.queue.add(f)}catch(e){this.logger.error(`Failed to track event ${t}:`,e)}else this.logger.warn("SDK not initialized, event not tracked")}async trackPageView(e,i){const r=l(),n=r.split("?")[0],s=Date.now(),a=this.config.pageViewDebounceInterval||5e3,o=this.pageViewTrackTimes.get(n);if(o&&s-o<a)return void this.logger.debug(`Page view debounced: ${n} (last tracked ${s-o}ms ago)`);const c={url:r,title:d(),referrer:u(),user_agent:navigator.userAgent||"",...e};await this.trackEvent(t.PAGE_VIEW,c,i),this.pageViewTrackTimes.set(n,s),this.cleanupPageViewTrackTimes()}cleanupPageViewTrackTimes(){const t=Date.now()-36e5;for(const[e,i]of this.pageViewTrackTimes.entries())i<t&&this.pageViewTrackTimes.delete(e)}ensurePublicIPFetched(){this.cachedPublicIP||this.publicIPFetchPromise||(this.publicIPFetchPromise=this.fetchPublicIP().then(t=>(t&&(this.cachedPublicIP=t),t)).catch(()=>null).finally(()=>{this.publicIPFetchPromise=null}))}async fetchPublicIP(){try{const t=new AbortController,e=setTimeout(()=>t.abort(),2e3),i=await fetch("https://api.ipify.org?format=json",{signal:t.signal,headers:{Accept:"application/json"}});if(clearTimeout(e),!i.ok)return null;const r=await i.json();return"string"==typeof r?.ip?r.ip:null}catch(t){return this.logger.debug("Public IP fetch failed",t),null}}async trackPurchase(i,r,n=e.USD,s){await this.trackEvent(t.PURCHASE,s,i,r,n)}async trackLogin(e,i){await this.trackEvent(t.LOGIN,i,e)}async trackSignup(e,i){await this.trackEvent(t.SIGNUP,i,e)}async trackFormSubmit(e,i){await this.trackEvent(t.FORM_SUBMIT,i,e)}async trackVideoPlay(e,i){await this.trackEvent(t.VIDEO_PLAY,i,e)}async trackEmailVerification(e,i){await this.trackEvent(t.EMAIL_VERIFICATION,i,e)}async trackAuditApproved(e,i){await this.trackEvent(t.AUDIT_APPROVED,i,e)}async trackPurchaseAuto(i){const r=i.tracking_user_id||this.getUserId();r?await this.trackEvent(t.PURCHASE,i.purchaseData,r,i.revenue,i.currency||e.USD):this.logger.error("❌ trackPurchaseAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackLoginAuto(e){const i=e.tracking_user_id||this.getUserId();i?await this.trackEvent(t.LOGIN,e.loginData,i):this.logger.error("❌ trackLoginAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackSignupAuto(e){const i=e.tracking_user_id||this.getUserId();i?await this.trackEvent(t.SIGNUP,e.signupData,i):this.logger.error("❌ trackSignupAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackEmailVerificationAuto(e){const i=e.tracking_user_id||this.getUserId();i?await this.trackEvent(t.EMAIL_VERIFICATION,e.verificationData,i):this.logger.error("❌ trackEmailVerificationAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackProductView(e,i){await this.trackEvent(t.PRODUCT_VIEW,i,e)}async trackAddToCart(e,i){await this.trackEvent(t.ADD_TO_CART,i,e)}async trackPageClick(e,i){await this.trackEvent(t.PAGE_CLICK,i,e)}getAttributionData(){return this.storage.getUTMData()}addUTMToURL(t){if(!this.config.enableCrossDomainUTM)return t;const e=this.getAttributionData();return e?h(t,g(e.lastTouch,this.config.crossDomainUTMParams)):t}getCurrentUTMParams(){const t=this.getAttributionData();return t?g(t.lastTouch,this.config.crossDomainUTMParams):{}}getUTMParams(){const t=this.getAttributionData();if(!t)return this.logger.debug("No attribution data available for UTM params"),{};const e={utm_source:t.lastTouch.utm_source||null,utm_medium:t.lastTouch.utm_medium||null,utm_campaign:t.lastTouch.utm_campaign||null,utm_term:t.lastTouch.utm_term||null,utm_content:t.lastTouch.utm_content||null},i={};return e.utm_source&&""!==e.utm_source.trim()?i.utm_source=e.utm_source:i.utm_source=null,e.utm_medium&&""!==e.utm_medium.trim()?i.utm_medium=e.utm_medium:i.utm_medium=null,e.utm_campaign&&""!==e.utm_campaign.trim()?i.utm_campaign=e.utm_campaign:i.utm_campaign=null,e.utm_term&&""!==e.utm_term.trim()?i.utm_term=e.utm_term:i.utm_term=null,e.utm_content&&""!==e.utm_content.trim()?i.utm_content=e.utm_content:i.utm_content=null,this.logger.debug("UTM params for event:",i),i}initializeUserId(){if(this.config.userId)this.setUserId(this.config.userId),this.logger.info(`👤 User ID initialized from config: ${this.config.userId}`);else{const t=this.getUserId();t?this.logger.debug(`👤 Existing user ID found: ${t}`):this.logger.debug("👤 No user ID found, will be set when user identifies")}}setUserId(t){t&&""!==t.trim()?(this.storage.setUserId(t),this.logger.info(`👤 User ID set: ${t}`)):this.logger.warn("Cannot set empty user ID")}getUserId(){return this.storage.getUserId()}removeUserId(){this.storage.removeUserId(),this.logger.info("👤 User ID removed")}initializeSession(){const t=this.storage.getSession(),e=Date.now();t&&e-t.lastActivity<this.config.sessionTimeout?this.session={...t,lastActivity:e}:this.session={sessionId:`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,startTime:e,lastActivity:e,pageViews:0},this.storage.storeSession(this.session),this.logger.debug("Session initialized:",this.session)}extractAndStoreUTMData(){const t=l(),e=function(t){const e=function(t){const e={};try{new URL(t).searchParams.forEach((t,i)=>{e[i]=t})}catch(t){}return e}(t),i={};return["utm_source","utm_medium","utm_campaign","utm_term","utm_content"].forEach(t=>{e[t]&&""!==e[t].trim()&&(i[t]=e[t].trim())}),i}(t);if(this.logger.debug("Extracting UTM params from URL:",t),this.logger.debug("Found UTM params:",e),0===Object.keys(e).length)return void this.logger.debug("No UTM parameters found in URL");const i={utm_source:e.utm_source||"",utm_medium:e.utm_medium||"",utm_campaign:e.utm_campaign||"",utm_term:e.utm_term||"",utm_content:e.utm_content||"",timestamp:Date.now()},r=this.getAttributionData(),n={firstTouch:r?.firstTouch||i,lastTouch:i,touchpoints:r?.touchpoints||[],expiresAt:Date.now()+2592e6};r&&r.lastTouch.utm_source===i.utm_source&&r.lastTouch.utm_campaign===i.utm_campaign||n.touchpoints.push(i),this.storage.storeUTMData(n),this.logger.info("UTM data extracted and stored successfully:",i),this.config.autoCleanUTM&&function(){try{const t=new URL(window.location.href);let e=!1;["utm_source","utm_medium","utm_campaign","utm_term","utm_content"].forEach(i=>{t.searchParams.has(i)&&(t.searchParams.delete(i),e=!0)}),e&&window.history.replaceState({},document.title,t.toString())}catch(t){console.warn("Failed to clean URL:",t)}}()}setupAutoTracking(){this.autoTrackEnabled=!0,this.setupFormTracking(),this.setupLinkTracking(),this.logger.info("Auto-tracking enabled")}setupFormTracking(){document.addEventListener("submit",e=>{try{const i=e.target;if(!i)return;const r=this.serializeFormFields(i);this.trackEvent(t.FORM_SUBMIT,{...r,form_id:i.id||i.name,form_action:i.action,form_method:i.method})}catch(t){this.logger.error("Failed to auto-track form submit:",t)}})}serializeFormFields(t){const e={};try{const i=new FormData(t);for(const[t,r]of i.entries()){const i=this.serializeFormValue(r);if(Object.prototype.hasOwnProperty.call(e,t)){const r=e[t];Array.isArray(r)?(r.push(i),e[t]=r):e[t]=[r,i]}else e[t]=i}const r=Array.from(t.elements),n=new Map;for(const t of r){const e=t.name;e&&!t.disabled&&(n.has(e)||n.set(e,[]),n.get(e).push(t))}n.forEach((t,i)=>{const r=t.some(t=>"radio"===t.type),n=t.some(t=>"checkbox"===t.type),s=t.some(t=>"file"===t.type),a=t.some(t=>"SELECT"===t.tagName&&t.multiple),o=t.some(t=>"password"===t.type);if(n){const r=t.filter(t=>"checkbox"===t.type).filter(t=>t.checked).map(t=>t.value||"on");return void(Object.prototype.hasOwnProperty.call(e,i)?Array.isArray(e[i])||(e[i]=[e[i],...r]):e[i]=r)}if(r){const r=t.filter(t=>"radio"===t.type).find(t=>t.checked);return void(Object.prototype.hasOwnProperty.call(e,i)||(e[i]=r?r.value:null))}if(a){const r=t.find(t=>"SELECT"===t.tagName&&t.multiple);if(r){const t=Array.from(r.selectedOptions).map(t=>t.value);return void(Object.prototype.hasOwnProperty.call(e,i)||(e[i]=t))}}if(s){const r=t.find(t=>"file"===t.type);if(r){const t=r.files?Array.from(r.files):[];return void(Object.prototype.hasOwnProperty.call(e,i)||(e[i]=t.map(t=>this.serializeFormValue(t))))}}if(o)Object.prototype.hasOwnProperty.call(e,i)?e[i]="string"==typeof e[i]?"*****":e[i]:e[i]="*****";else if(!Object.prototype.hasOwnProperty.call(e,i)){const r=t[0];if("SELECT"===r.tagName){const t=r;e[i]=t.multiple?Array.from(t.selectedOptions).map(t=>t.value):t.value}else r.type,e[i]=r.value??""}})}catch(t){this.logger.error("Failed to serialize form fields:",t)}return e}serializeFormValue(t){return t instanceof File?{file_name:t.name,file_size:t.size,file_type:t.type}:t}setupLinkTracking(){document.addEventListener("click",t=>{const e=t.target.closest("a");e&&function(t){try{const e=new URL(t),i=window.location.hostname;return e.hostname!==i}catch(t){return!1}}(e.href)&&this.handleCrossDomainUTM(e,t)})}handleCrossDomainUTM(t,e){if(!this.config.enableCrossDomainUTM)return;const i=t.href;if(function(t,e=[]){try{const i=new URL(t).hostname.toLowerCase();return e.some(t=>{const e=t.toLowerCase();return i===e||i.endsWith(`.${e}`)})}catch(t){return!1}}(i,this.config.excludeDomains))return void this.logger.debug(`Domain excluded from UTM passing: ${i}`);const r=this.getAttributionData();if(!r)return void this.logger.debug("No UTM data available for cross-domain passing");const n=g(r.lastTouch,this.config.crossDomainUTMParams);if(0===Object.keys(n).length)return void this.logger.debug("No UTM parameters to pass");const s=h(i,n);s!==i&&(t.href=s,this.logger.debug("UTM parameters added to external link:",{original:i,enhanced:s,utmParams:n}),this.logger.debug("Cross-domain UTM passed:",{link_url:s,original_url:i,utm_params_passed:n}))}setupNetworkHandlers(){window.addEventListener("online",()=>{this.logger.info("Network connection restored"),this.queue.flush()}),window.addEventListener("offline",()=>{this.logger.warn("Network connection lost")})}setupVisibilityHandlers(){document.addEventListener("visibilitychange",()=>{"hidden"!==document.visibilityState?"visible"===document.visibilityState&&this.updateSessionActivity():this.flushOnUnload("visibilitychange:hidden")})}setupBeforeUnloadHandler(){window.addEventListener("beforeunload",()=>{this.flushOnUnload("beforeunload")}),window.addEventListener("pagehide",()=>{this.flushOnUnload("pagehide")})}flushOnUnload(t){try{this.updateSessionActivity();const e=this.queue.drainAll();if(0===e.length)return;if(this.storage.appendPendingEvents(e),this.logger.debug(`🚚 Unload flush triggered: ${t}`,{count:e.length}),this.httpClient.sendEventsBeacon(e))return void this.storage.removePendingEventsByIds(e.map(t=>t.event_id));const i=20;for(let t=0;t<e.length;t+=i){const r=e.slice(t,t+i);this.httpClient.sendEventsKeepalive(r).then(()=>{this.storage.removePendingEventsByIds(r.map(t=>t.event_id))}).catch(t=>{this.logger.debug("Unload keepalive send failed",t)})}}catch(t){this.logger.debug("flushOnUnload failed",t)}}async retryPendingEvents(){const t=this.storage.getPendingEvents();if(0!==t.length){this.logger.info(`📦 Retrying pending events: ${t.length}`);try{await this.httpClient.sendEvents(t),this.storage.removePendingEventsByIds(t.map(t=>t.event_id)),this.logger.info(`✅ Pending events sent: ${t.length}`)}catch(t){this.logger.warn("⚠️ Pending events retry failed",t)}}}getCurrentPath(){return"undefined"==typeof window?"":window.location.pathname+window.location.search}setupSPATracking(){if("undefined"==typeof window||"undefined"==typeof history)return void this.logger.warn("⚠️ SPA tracking not available in this environment");if(this.spaTrackingEnabled)return void this.logger.warn("⚠️ SPA tracking already enabled");this.spaTrackingEnabled=!0,this.lastTrackedPath=this.getCurrentPath(),this.originalPushState=history.pushState.bind(history),this.originalReplaceState=history.replaceState.bind(history);const t=t=>{const e=this.getCurrentPath();e!==this.lastTrackedPath?(this.logger.debug(`🔄 [SPA] Route change detected (${t}): ${this.lastTrackedPath} -> ${e}`),this.lastTrackedPath=e,setTimeout(()=>{this.trackPageView().then(()=>this.queue.process()).then(()=>{this.logger.debug(`✅ [SPA] Page view tracked for: ${e}`)}).catch(t=>{this.logger.error("❌ [SPA] Failed to track page view:",t)})},100)):this.logger.debug(`🔄 [SPA] Route change detected (${t}) but path unchanged: ${e}`)};history.pushState=(e,i,r)=>{const n=this.originalPushState(e,i,r);return t("pushState"),n},history.replaceState=(e,i,r)=>{const n=this.originalReplaceState(e,i,r);return t("replaceState"),n},this.popstateHandler=()=>{t("popstate")},window.addEventListener("popstate",this.popstateHandler),this.logger.info("🔄 SPA tracking setup completed")}cleanupSPATracking(){this.spaTrackingEnabled&&(this.originalPushState&&(history.pushState=this.originalPushState,this.originalPushState=null),this.originalReplaceState&&(history.replaceState=this.originalReplaceState,this.originalReplaceState=null),this.popstateHandler&&(window.removeEventListener("popstate",this.popstateHandler),this.popstateHandler=null),this.spaTrackingEnabled=!1,this.logger.info("🔄 SPA tracking cleaned up"))}updateSessionActivity(){this.session&&(this.session.lastActivity=Date.now(),this.storage.storeSession(this.session))}async flush(){await this.queue.flush()}getStatus(){return{initialized:this.initialized,session:this.session,queueSize:this.queue.size(),online:navigator.onLine,crossDomainUTM:{enabled:this.config.enableCrossDomainUTM||!0,currentParams:this.getCurrentUTMParams()},spaTracking:{enabled:this.spaTrackingEnabled,currentPath:this.lastTrackedPath}}}destroy(){this.queue.clear(),this.autoTrackEnabled=!1,this.cleanupSPATracking(),this.initialized=!1,this.logger.info("🗑️ SDK destroyed")}}let E=null;async function b(t){if(E)return console.warn("GetuAI SDK: Already initialized"),E;try{if(E=new k(t),await E.init(),t.enableDebug&&(window.GetuAISDK=E),console.log("GetuAI Attribution SDK initialized successfully"),"undefined"!=typeof window){const t=new CustomEvent("getuaiSDKReady",{detail:{sdk:E}});window.dispatchEvent(t)}return E}catch(t){if(console.error("GetuAI SDK: Failed to initialize:",t),"undefined"!=typeof window){const e=new CustomEvent("getuaiSDKError",{detail:{error:t}});window.dispatchEvent(e)}throw t}}function I(){return E}function T(){return new Promise((t,e)=>{if(E)return void t(E);const i=e=>{window.removeEventListener("getuaiSDKReady",i),window.removeEventListener("getuaiSDKError",r),t(e.detail.sdk)},r=t=>{window.removeEventListener("getuaiSDKReady",i),window.removeEventListener("getuaiSDKError",r),e(t.detail.error)};window.addEventListener("getuaiSDKReady",i),window.addEventListener("getuaiSDKError",r),setTimeout(()=>{window.removeEventListener("getuaiSDKReady",i),window.removeEventListener("getuaiSDKError",r),e(new Error("SDK initialization timeout"))},1e4)})}async function P(t,i,r,n,s=e.USD){const a=I();a?await a.trackEvent(t,i,r,n,s):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function D(t,e){const i=I();i?await i.trackPageView(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function A(t,i,r=e.USD,n){const s=I();s?await s.trackPurchase(t,i,r,n):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function U(t,e){const i=I();i?await i.trackLogin(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function C(t,e){const i=I();i?await i.trackSignup(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function x(t,e){const i=I();i?await i.trackFormSubmit(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function K(t,e){const i=I();i?await i.trackVideoPlay(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function N(t,e){const i=I();i?await i.trackEmailVerification(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function R(t){const e=I();e?await e.trackPurchaseAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function O(t){const e=I();e?await e.trackLoginAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function V(t){const e=I();e?await e.trackSignupAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function M(t){const e=I();e?await e.trackEmailVerificationAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function z(t,e){const i=I();i?await i.trackProductView(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function F(t,e){const i=I();i?await i.trackAddToCart(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function L(t,e){const i=I();i?await i.trackPageClick(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}function G(){const t=I();return t?t.getAttributionData():null}async function $(){const t=I();t?await t.flush():console.warn("GetuAI SDK: Not initialized. Call init() first.")}function q(){const t=I();return t?t.getStatus():null}function B(t){const e=I();return e?e.addUTMToURL(t):(console.warn("GetuAI SDK: Not initialized. Call init() first."),t)}function j(){const t=I();return t?t.getCurrentUTMParams():{}}function Y(t){const e=I();e?e.setUserId(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}function H(){const t=I();return t?t.getUserId():(console.warn("GetuAI SDK: Not initialized. Call init() first."),null)}function W(){const t=I();t?t.removeUserId():console.warn("GetuAI SDK: Not initialized. Call init() first.")}function J(){E&&(E.destroy(),E=null,console.log("GetuAI SDK destroyed"))}class Q extends k{static async init(t){return await b(t)}static async trackEvent(t,i,r,n,s=e.USD){return await P(t,i,r,n,s)}static async trackPageView(t,e){return await D(t,e)}static async trackPurchase(t,i,r=e.USD,n){return await A(t,i,r,n)}static async trackLogin(t,e){return await U(t,e)}static async trackSignup(t,e){return await C(t,e)}static async trackFormSubmit(t,e){return await x(t,e)}static async trackVideoPlay(t,e){return await K(t,e)}static async trackEmailVerification(t,e){return await N(t,e)}static async trackPurchaseAuto(t){return await R(t)}static async trackLoginAuto(t){return await O(t)}static async trackSignupAuto(t){return await V(t)}static async trackEmailVerificationAuto(t){return await M(t)}static async trackProductView(t,e){return await z(t,e)}static async trackAddToCart(t,e){return await F(t,e)}static async trackPageClick(t,e){return await L(t,e)}static getAttributionData(){return G()}static async flush(){return await $()}static getStatus(){return q()}static addUTMToURL(t){return B(t)}static getCurrentUTMParams(){return j()}static setUserId(t){Y(t)}static getUserId(){return H()}static removeUserId(){W()}static destroy(){J()}static getSDK(){return I()}static waitForSDK(){return T()}}"undefined"!=typeof document&&function(){if(E)return;const t=document.currentScript;if(!t)return void console.warn("GetuAI SDK: Could not find script tag for auto-initialization");const e=t.getAttribute("data-api-key");e?b({apiKey:e,apiEndpoint:t.getAttribute("data-api-endpoint")||n,enableDebug:"true"===t.getAttribute("data-debug"),autoTrack:"true"===t.getAttribute("data-auto-track"),autoTrackPageView:"true"===t.getAttribute("data-auto-track-page-view"),autoCleanUTM:"false"!==t.getAttribute("data-auto-clean-utm"),batchSize:parseInt(t.getAttribute("data-batch-size")||"100"),batchInterval:parseInt(t.getAttribute("data-batch-interval")||"2000"),userId:t.getAttribute("data-user-id")||void 0}):console.warn("GetuAI SDK: No API key provided. Please add data-api-key attribute to script tag.")}(),"undefined"!=typeof window&&(window.getuaiSDK={init:b,getSDK:I,waitForSDK:T,trackEvent:P,trackPageView:D,trackPageClick:L,trackPurchase:A,trackLogin:U,trackSignup:C,trackFormSubmit:x,trackVideoPlay:K,trackEmailVerification:N,trackAuditApproved:async function(t,e){const i=I();i?await i.trackAuditApproved(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")},trackProductView:z,trackAddToCart:F,trackPurchaseAuto:R,trackLoginAuto:O,trackSignupAuto:V,trackEmailVerificationAuto:M,getAttributionData:G,flush:$,getStatus:q,addUTMToURL:B,getCurrentUTMParams:j,setUserId:Y,getUserId:H,removeUserId:W,destroy:J,EventType:t,Currency:e,AttributionSDK:Q},window.init=b,window.waitForSDK=T,window.trackEvent=P,window.trackPageView=D,window.trackPageClick=L,window.trackPurchase=A,window.trackLogin=U,window.trackSignup=C,window.trackFormSubmit=x,window.trackVideoPlay=K,window.trackEmailVerification=N,window.trackProductView=z,window.trackAddToCart=F,window.trackPurchaseAuto=R,window.trackLoginAuto=O,window.trackSignupAuto=V,window.trackEmailVerificationAuto=M,window.getAttributionData=G,window.flush=$,window.getStatus=q,window.addUTMToURL=B,window.getCurrentUTMParams=j,window.setUserId=Y,window.getUserId=H,window.removeUserId=W,window.destroy=J,window.AttributionSDK=Q);const X={init:b,getSDK:I,waitForSDK:T,trackEvent:P,trackPageView:D,trackPageClick:L,trackPurchase:A,trackLogin:U,trackSignup:C,trackFormSubmit:x,trackVideoPlay:K,trackEmailVerification:N,trackProductView:z,trackAddToCart:F,trackPurchaseAuto:R,trackLoginAuto:O,trackSignupAuto:V,trackEmailVerificationAuto:M,getAttributionData:G,flush:$,getStatus:q,addUTMToURL:B,getCurrentUTMParams:j,setUserId:Y,getUserId:H,removeUserId:W,destroy:J,EventType:t,Currency:e,AttributionSDK:Q};return r.default})());
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.GetuAIAttribution=e():t.GetuAIAttribution=e()}(this,()=>(()=>{"use strict";var t,e,i={d:(t,e)=>{for(var r in e)i.o(e,r)&&!i.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},r={};i.d(r,{default:()=>Z}),function(t){t.PAGE_VIEW="page_view",t.PAGE_CLICK="page_click",t.VIDEO_PLAY="video_play",t.FORM_SUBMIT="form_submit",t.EMAIL_VERIFICATION="email_verification",t.LOGIN="login",t.SIGNUP="signup",t.PRODUCT_VIEW="product_view",t.ADD_TO_CART="add_to_cart",t.PURCHASE="purchase",t.AUDIT_APPROVED="audit_approved"}(t||(t={})),function(t){t.USD="USD"}(e||(e={}));const n="https://attribution.getu.ai/attribution/api",s=[t.PURCHASE,t.LOGIN,t.SIGNUP,t.FORM_SUBMIT,t.EMAIL_VERIFICATION,t.AUDIT_APPROVED],a={email:["email","e-mail","mail","user_email","email_address"],name:["name","full_name","fullname","username","display_name"],first_name:["first_name","firstname","fname","given_name"],last_name:["last_name","lastname","lname","surname","family_name"],phone:["phone","telephone","mobile","phone_number","tel"],company_name:["company","company_name","organization","org","business"],title:["title","job_title","position","role","job"]};function o(){return Math.floor(Date.now()/1e3)}function c(){try{const t="__localStorage_test__";return localStorage.setItem(t,t),localStorage.removeItem(t),!0}catch{return!1}}class u{constructor(t=!0){this.enabled=t}debug(t,...e){this.enabled&&console.debug&&console.debug(`[GetuAI Debug] ${t}`,...e)}info(t,...e){this.enabled&&console.info&&console.info(`[GetuAI Info] ${t}`,...e)}warn(t,...e){this.enabled&&console.warn&&console.warn(`[GetuAI Warn] ${t}`,...e)}error(t,...e){this.enabled&&console.error&&console.error(`[GetuAI Error] ${t}`,...e)}}function l(){return document.referrer||""}function d(){return window.location.href}function h(){return document.title||""}function g(t,e){try{const i=new URL(t);return Object.entries(e).forEach(([t,e])=>{e&&!i.searchParams.has(t)&&i.searchParams.set(t,e)}),i.toString()}catch(e){return t}}function m(t,e=["utm_source","utm_medium","utm_campaign"]){const i={};return e.forEach(e=>{t[e]&&(i[e]=t[e])}),i}function p(t){try{const e=t||window.location.href;return new URL(e).search}catch(t){return""}}function f(t){try{const e=t||window.location.href,i=new URL(e),r={};return i.searchParams.forEach((t,e)=>{r[e]=t}),r}catch(t){return{}}}class w{constructor(t){this.logger=t}get(t){try{if(!c())return this.logger.warn("LocalStorage not supported"),null;const e=localStorage.getItem(t);return null===e?null:JSON.parse(e)}catch(t){return this.logger.error("Error reading from localStorage:",t),null}}set(t,e){try{if(!c())return void this.logger.warn("LocalStorage not supported");localStorage.setItem(t,JSON.stringify(e))}catch(t){this.logger.error("Error writing to localStorage:",t),this.handleQuotaExceeded()}}remove(t){try{c()&&localStorage.removeItem(t)}catch(t){this.logger.error("Error removing from localStorage:",t)}}clear(){try{c()&&localStorage.clear()}catch(t){this.logger.error("Error clearing localStorage:",t)}}handleQuotaExceeded(){try{const t=Object.keys(localStorage).filter(t=>t.startsWith("attribution_"));if(t.length>0){t.sort((t,e)=>{const i=this.get(t),r=this.get(e);return(i?.expiresAt||0)-(r?.expiresAt||0)});const e=Math.ceil(.2*t.length);t.slice(0,e).forEach(t=>{this.remove(t)}),this.logger.info(`Cleaned up ${e} old attribution records`)}}catch(t){this.logger.error("Error during quota cleanup:",t)}}}class y{constructor(t){this.dbName="attribution_events",this.dbVersion=1,this.storeName="events",this.db=null,this.logger=t}async init(){if("indexedDB"in window)return new Promise((t,e)=>{const i=indexedDB.open(this.dbName,this.dbVersion);i.onerror=()=>{this.logger.error("Failed to open IndexedDB:",i.error),e(i.error)},i.onsuccess=()=>{this.db=i.result,this.logger.info("IndexedDB initialized successfully"),t()},i.onupgradeneeded=t=>{const e=t.target.result;if(!e.objectStoreNames.contains(this.storeName)){const t=e.createObjectStore(this.storeName,{keyPath:"id",autoIncrement:!0});t.createIndex("timestamp","timestamp",{unique:!1}),t.createIndex("sent","sent",{unique:!1}),t.createIndex("queued_at","queued_at",{unique:!1})}}});this.logger.warn("IndexedDB not supported")}async addEvent(t){if(!this.db)throw new Error("IndexedDB not initialized");return new Promise((e,i)=>{const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName),n={...t,queued_at:Date.now(),sent:!1},s=r.add(n);s.onsuccess=()=>{this.logger.debug("Event added to IndexedDB queue"),e()},s.onerror=()=>{this.logger.error("Failed to add event to IndexedDB:",s.error),i(s.error)}})}async getUnsentEvents(t=100){return this.db?new Promise((e,i)=>{const r=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).index("sent").getAll(IDBKeyRange.only(!1),t);r.onsuccess=()=>{const t=r.result.map(t=>{const{queued_at:e,sent:i,...r}=t;return r});e(t)},r.onerror=()=>{this.logger.error("Failed to get unsent events:",r.error),i(r.error)}}):[]}async markEventsAsSent(t){if(this.db&&0!==t.length)return new Promise((e,i)=>{const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName);let n=0,s=!1;t.forEach(a=>{const o=r.get(a);o.onsuccess=()=>{if(o.result){const a={...o.result,sent:!0},c=r.put(a);c.onsuccess=()=>{n++,n!==t.length||s||e()},c.onerror=()=>{s=!0,this.logger.error("Failed to mark event as sent:",c.error),i(c.error)}}else n++,n!==t.length||s||e()},o.onerror=()=>{s=!0,this.logger.error("Failed to get event for marking as sent:",o.error),i(o.error)}})})}async cleanupOldEvents(t=6048e5){if(!this.db)return;const e=Date.now()-t;return new Promise((t,i)=>{const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).index("queued_at").openCursor(IDBKeyRange.upperBound(e));r.onsuccess=()=>{const e=r.result;e?(e.delete(),e.continue()):(this.logger.info("Old events cleanup completed"),t())},r.onerror=()=>{this.logger.error("Failed to cleanup old events:",r.error),i(r.error)}})}async getQueueSize(){return this.db?new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).count();i.onsuccess=()=>{t(i.result)},i.onerror=()=>{this.logger.error("Failed to get queue size:",i.error),e(i.error)}}):0}async clear(){if(this.db)return new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();i.onsuccess=()=>{this.logger.info("IndexedDB queue cleared"),t()},i.onerror=()=>{this.logger.error("Failed to clear IndexedDB queue:",i.error),e(i.error)}})}}class _{constructor(t){this.UTM_STORAGE_KEY="attribution_utm_data",this.SESSION_STORAGE_KEY="attribution_session",this.USER_ID_KEY="getuai_user_id",this.PENDING_EVENTS_KEY="getuai_pending_events_v1",this.USER_TRAITS_KEY="getuai_user_traits",this.USER_ID_COOKIE_EXPIRES=365,this.logger=t,this.localStorage=new w(t),this.indexedDB=new y(t)}setUserId(t){if(!t||""===t.trim())return void this.logger.warn("Cannot set empty user ID");const e=t.trim();try{this.setCookie(this.USER_ID_KEY,e,this.USER_ID_COOKIE_EXPIRES),this.logger.debug(`👤 User ID stored in cookie: ${e}`)}catch(t){this.logger.error("Failed to store user ID in cookie:",t)}try{"undefined"!=typeof localStorage&&(localStorage.setItem(this.USER_ID_KEY,e),this.logger.debug(`👤 User ID stored in localStorage: ${e}`))}catch(t){this.logger.error("Failed to store user ID in localStorage:",t)}}getUserId(){try{if("undefined"!=typeof localStorage){const t=localStorage.getItem(this.USER_ID_KEY);if(t)return t}}catch(t){this.logger.debug("Failed to get user ID from localStorage:",t)}try{const t=this.getCookie(this.USER_ID_KEY);if(t){try{"undefined"!=typeof localStorage&&localStorage.setItem(this.USER_ID_KEY,t)}catch(t){}return t}}catch(t){this.logger.debug("Failed to get user ID from cookie:",t)}return null}removeUserId(){try{this.deleteCookie(this.USER_ID_KEY),this.logger.debug("👤 User ID removed from cookie")}catch(t){this.logger.error("Failed to remove user ID from cookie:",t)}try{"undefined"!=typeof localStorage&&(localStorage.removeItem(this.USER_ID_KEY),this.logger.debug("👤 User ID removed from localStorage"))}catch(t){this.logger.error("Failed to remove user ID from localStorage:",t)}}setCookie(t,e,i){try{const r=new Date;r.setTime(r.getTime()+24*i*60*60*1e3);const n=`${t}=${encodeURIComponent(e)};expires=${r.toUTCString()};path=/;SameSite=Lax`;document.cookie=n}catch(t){this.logger.error("Failed to set cookie:",t)}}getCookie(t){try{const e=t+"=",i=document.cookie.split(";");for(let t=0;t<i.length;t++){let r=i[t];for(;" "===r.charAt(0);)r=r.substring(1,r.length);if(0===r.indexOf(e))return decodeURIComponent(r.substring(e.length,r.length))}return null}catch(t){return this.logger.error("Failed to get cookie:",t),null}}deleteCookie(t){try{document.cookie=`${t}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;`}catch(t){this.logger.error("Failed to delete cookie:",t)}}async init(){await this.indexedDB.init()}getPendingEvents(){try{const t=this.localStorage.get(this.PENDING_EVENTS_KEY);return Array.isArray(t)?t:[]}catch(t){return this.logger.debug("Failed to read pending events:",t),[]}}appendPendingEvents(t){if(t&&0!==t.length)try{const e=[...this.getPendingEvents(),...t].slice(-500);this.localStorage.set(this.PENDING_EVENTS_KEY,e)}catch(t){this.logger.debug("Failed to append pending events:",t)}}removePendingEventsByIds(t){if(t&&0!==t.length)try{const e=this.getPendingEvents();if(0===e.length)return;const i=new Set(t),r=e.filter(t=>!i.has(t.event_id));0===r.length?this.localStorage.remove(this.PENDING_EVENTS_KEY):this.localStorage.set(this.PENDING_EVENTS_KEY,r)}catch(t){this.logger.debug("Failed to remove pending events:",t)}}clearPendingEvents(){try{this.localStorage.remove(this.PENDING_EVENTS_KEY)}catch(t){this.logger.debug("Failed to clear pending events:",t)}}storeUTMData(t){try{const e=this.getUTMData(),i={utm_source:"",utm_medium:"",utm_campaign:"",utm_term:"",utm_content:"",timestamp:Date.now()},r={firstTouch:e?.firstTouch||i,lastTouch:e?.lastTouch||i,touchpoints:e?.touchpoints||[],...t,expiresAt:Date.now()+2592e6};this.localStorage.set(this.UTM_STORAGE_KEY,r),this.logger.debug("UTM data stored successfully:",{firstTouch:r.firstTouch,lastTouch:r.lastTouch,touchpointsCount:r.touchpoints.length,expiresAt:new Date(r.expiresAt).toISOString()})}catch(t){this.logger.error("Failed to store UTM data:",t)}}getUTMData(){const t=this.localStorage.get(this.UTM_STORAGE_KEY);return t&&t.expiresAt&&t.expiresAt>Date.now()?t:(t&&this.localStorage.remove(this.UTM_STORAGE_KEY),null)}storeSession(t){this.localStorage.set(this.SESSION_STORAGE_KEY,t)}getSession(){return this.localStorage.get(this.SESSION_STORAGE_KEY)}async queueEvent(t){try{await this.indexedDB.addEvent(t)}catch(t){throw this.logger.error("Failed to queue event:",t),t}}async getUnsentEvents(t=100){return await this.indexedDB.getUnsentEvents(t)}async markEventsAsSent(t){await this.indexedDB.markEventsAsSent(t)}async getQueueSize(){return await this.indexedDB.getQueueSize()}async cleanupOldEvents(){await this.indexedDB.cleanupOldEvents()}async clearQueue(){await this.indexedDB.clear()}cleanupExpiredData(){this.getUTMData()}setUserTraits(t){try{const e={...this.getUserTraits()||{},...t};"undefined"!=typeof localStorage&&(localStorage.setItem(this.USER_TRAITS_KEY,JSON.stringify(e)),this.logger.debug("User traits stored:",e))}catch(t){this.logger.error("Failed to store user traits:",t)}}getUserTraits(){try{if("undefined"!=typeof localStorage){const t=localStorage.getItem(this.USER_TRAITS_KEY);return t?JSON.parse(t):null}return null}catch(t){return this.logger.error("Failed to get user traits:",t),null}}clearUserTraits(){try{"undefined"!=typeof localStorage&&(localStorage.removeItem(this.USER_TRAITS_KEY),this.logger.debug("User traits cleared"))}catch(t){this.logger.error("Failed to clear user traits:",t)}}}const v="0.3.0";class S{constructor(t,e,i,r=100,n=2e3,s=3,a=1e3,o){this.queue=[],this.processing=!1,this.batchTimer=null,this.retryCounts=new Map,this.logger=t,this.apiKey=e,this.apiEndpoint=i,this.batchSize=r,this.batchInterval=n,this.maxRetries=s,this.retryDelay=a,this.sendEvents=o,this.debouncedProcess=function(t){let e;return(...i)=>{clearTimeout(e),e=setTimeout(()=>t(...i),100)}}(this.process.bind(this))}add(t){if(s.includes(t.event_type))return this.logger.debug(`Immediate event detected: ${t.event_type}, sending immediately`),void this.processImmediate(t);this.queue.push(t),this.logger.debug(`Event added to queue: ${t.event_type}`),this.scheduleBatchProcessing()}async process(){if(this.processing||0===this.queue.length)return;this.processing=!0;const t=this.queue.splice(0,this.batchSize);try{this.logger.debug(`Processing ${t.length} events from queue`),await this.sendEvents(t),this.resetRetryCounts(t),this.logger.info(`Successfully processed ${t.length} events`)}catch(e){return this.logger.error("Failed to process events:",e),this.enqueueBatchForRetry(t),void setTimeout(()=>{this.processing=!1,this.debouncedProcess()},this.retryDelay)}this.processing=!1,this.queue.length>0&&this.debouncedProcess()}async processImmediate(t){try{this.logger.debug(`Processing immediate event: ${t.event_type}`),await this.sendEvents([t]),this.resetRetryCounts([t]),this.logger.info(`Immediate event processed successfully: ${t.event_type}`)}catch(e){this.logger.error(`Failed to process immediate event: ${t.event_type}`,e),this.enqueueBatchForRetry([t])}}scheduleBatchProcessing(){this.batchTimer&&clearTimeout(this.batchTimer),this.batchTimer=setTimeout(()=>{this.debouncedProcess()},this.batchInterval)}clear(){this.queue=[],this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null),this.processing=!1,this.logger.info("Event queue cleared")}size(){return this.queue.length}getStats(){return{size:this.queue.length,processing:this.processing}}async flush(){for(this.logger.info("Flushing event queue");this.queue.length>0;)await this.process()}drainAll(){const t=this.queue.splice(0,this.queue.length);return this.batchTimer&&(clearTimeout(this.batchTimer),this.batchTimer=null),this.processing=!1,t}enqueueBatchForRetry(t){const e=[];for(const i of t){const t=(this.retryCounts.get(i.event_id)||0)+1;this.retryCounts.set(i.event_id,t),t>this.maxRetries?(this.logger.warn(`Dropping event after max retries (${this.maxRetries}): ${i.event_type} (${i.event_id})`),this.retryCounts.delete(i.event_id)):e.push(i)}e.length>0&&this.queue.unshift(...e)}resetRetryCounts(t){for(const e of t)this.retryCounts.delete(e.event_id)}}class k{constructor(t,e,i,r=3,n=1e3){this.logger=t,this.apiKey=e,this.apiEndpoint=i,this.maxRetries=r,this.retryDelay=n}async sendEvents(t){if(0===t.length)return;const e={events:t.map(t=>({event_id:t.event_id,event_type:t.event_type,tracking_user_id:t.tracking_user_id,utm_source:t.utm_source||null,utm_medium:t.utm_medium||null,utm_campaign:t.utm_campaign||null,utm_term:t.utm_term||null,utm_content:t.utm_content||null,revenue:t.revenue||null,currency:t.currency||null,event_data:t.event_data||null,context:t.context||null,timestamp:t.timestamp||o()})),sdk_version:v};await async function(t,e=3,i=1e3){let r;for(let n=0;n<=e;n++)try{return await t()}catch(t){if(r=t,n===e)throw r;const s=i*Math.pow(2,n);await new Promise(t=>setTimeout(t,s))}throw r}(async()=>{const i=await fetch(`${this.apiEndpoint}/attribution/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(e)});if(!i.ok){const t=await i.text();throw new Error(`HTTP ${i.status}: ${t}`)}const r=await i.json();return this.logger.debug("Events sent successfully:",r),{result:r,sentEvents:t}},this.maxRetries,this.retryDelay)}async sendEventsKeepalive(t){if(0===t.length)return;const e={events:t.map(t=>({event_id:t.event_id,event_type:t.event_type,tracking_user_id:t.tracking_user_id,utm_source:t.utm_source||null,utm_medium:t.utm_medium||null,utm_campaign:t.utm_campaign||null,utm_term:t.utm_term||null,utm_content:t.utm_content||null,revenue:t.revenue||null,currency:t.currency||null,event_data:t.event_data||null,context:t.context||null,timestamp:t.timestamp||o()})),sdk_version:v},i=await fetch(`${this.apiEndpoint}/attribution/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify(e),keepalive:!0});if(!i.ok)throw new Error(`HTTP ${i.status}`)}sendEventsBeacon(t){if(0===t.length)return!0;if("undefined"==typeof navigator||"function"!=typeof navigator.sendBeacon)return!1;const e={events:t.map(t=>({event_id:t.event_id,event_type:t.event_type,tracking_user_id:t.tracking_user_id,utm_source:t.utm_source||null,utm_medium:t.utm_medium||null,utm_campaign:t.utm_campaign||null,utm_term:t.utm_term||null,utm_content:t.utm_content||null,revenue:t.revenue||null,currency:t.currency||null,event_data:t.event_data||null,context:t.context||null,timestamp:t.timestamp||o()})),sdk_version:v},i=`${this.apiEndpoint}/attribution/events_beacon?api_key=${encodeURIComponent(this.apiKey)}`,r=new Blob([JSON.stringify(e)],{type:"text/plain"});return navigator.sendBeacon(i,r)}async sendSingleEvent(t){await this.sendEvents([t])}async testConnection(){try{return(await fetch(`${this.apiEndpoint}/health`,{method:"GET",headers:{Authorization:`Bearer ${this.apiKey}`}})).ok}catch(t){return this.logger.error("Connection test failed:",t),!1}}}class b{constructor(t){this.session=null,this.initialized=!1,this.autoTrackEnabled=!1,this.pageViewTrackTimes=new Map,this.cachedPublicIP=null,this.publicIPFetchPromise=null,this.initialPageViewTriggered=!1,this.spaTrackingEnabled=!1,this.lastTrackedPath="",this.originalPushState=null,this.originalReplaceState=null,this.popstateHandler=null,this.config={apiEndpoint:n,batchSize:100,batchInterval:2e3,maxRetries:3,retryDelay:1e3,enableDebug:!1,autoTrack:!1,autoTrackPageView:!1,sessionTimeout:18e5,enableCrossDomainUTM:!0,crossDomainUTMParams:["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],excludeDomains:[],autoCleanUTM:!0,pageViewDebounceInterval:5e3,...t},this.logger=new u(this.config.enableDebug),this.storage=new _(this.logger),this.httpClient=new k(this.logger,this.config.apiKey,this.config.apiEndpoint||n,this.config.maxRetries,this.config.retryDelay),this.queue=new S(this.logger,this.config.apiKey,this.config.apiEndpoint||n,this.config.batchSize,this.config.batchInterval,this.config.maxRetries,this.config.retryDelay,t=>this.httpClient.sendEvents(t))}async init(){if(this.initialized)this.logger.warn("SDK already initialized");else try{this.logger.info("Initializing GetuAI Attribution SDK"),this.storage.init().catch(t=>{this.logger.warn("Storage initialization failed (IndexedDB may be unavailable), continuing with basic features:",t)}),this.initializeUserId(),this.initializeSession(),this.extractAndStoreUTMData(),this.config.autoTrack&&this.setupAutoTracking(),this.setupNetworkHandlers(),this.setupVisibilityHandlers(),this.setupBeforeUnloadHandler(),this.initialized=!0,this.logger.info("🚀 GetuAI Attribution SDK initialized successfully"),this.logger.info("📄 Auto track page view = "+this.config.autoTrackPageView),this.retryPendingEvents().catch(t=>{this.logger.warn("⚠️ Pending events retry failed",t)}),this.config.autoTrackPageView&&(this.logger.info("📄 Auto track page view enabled (including SPA route tracking)"),this.lastTrackedPath=this.getCurrentPath(),this.setupSPATracking(),this.initialPageViewTriggered||(this.initialPageViewTriggered=!0,Promise.resolve().then(()=>this.trackPageView()).then(()=>this.queue.process()).then(()=>{this.logger.info("✅ Auto track page view completed")}).catch(t=>this.logger.error("❌ Auto track page view failed:",t))))}catch(t){throw this.logger.error("Failed to initialize SDK:",t),t}}async trackEvent(t,i,r,n,s=e.USD){if(this.initialized)try{const e=d(),a=this.cachedPublicIP;this.ensurePublicIPFetched();const c={domain:"undefined"!=typeof window?window.location.hostname:null,path:"undefined"!=typeof window?window.location.pathname:null,title:h(),referrer:l(),url:e.split("?")[0],querystring:p(e),query_params:f(e),ip_address:a},u={session_id:this.session?.sessionId,start_time:this.session?.startTime,last_activity:this.session?.lastActivity,page_views:this.session?.pageViews},g=r||this.getUserId(),m={event_id:"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)}),event_type:t,tracking_user_id:g||void 0,timestamp:o(),event_data:i,context:{page:c,session:u},revenue:n,currency:s,...this.getUTMParams()};this.logger.debug(`Tracking event: ${t}`,m),this.queue.add(m)}catch(e){this.logger.error(`Failed to track event ${t}:`,e)}else this.logger.warn("SDK not initialized, event not tracked")}async trackPageView(e,i){const r=d(),n=r.split("?")[0],s=Date.now(),a=this.config.pageViewDebounceInterval||5e3,o=this.pageViewTrackTimes.get(n);if(o&&s-o<a)return void this.logger.debug(`Page view debounced: ${n} (last tracked ${s-o}ms ago)`);const c={url:r,title:h(),referrer:l(),user_agent:navigator.userAgent||"",...e};await this.trackEvent(t.PAGE_VIEW,c,i),this.pageViewTrackTimes.set(n,s),this.cleanupPageViewTrackTimes()}cleanupPageViewTrackTimes(){const t=Date.now()-36e5;for(const[e,i]of this.pageViewTrackTimes.entries())i<t&&this.pageViewTrackTimes.delete(e)}ensurePublicIPFetched(){this.cachedPublicIP||this.publicIPFetchPromise||(this.publicIPFetchPromise=this.fetchPublicIP().then(t=>(t&&(this.cachedPublicIP=t),t)).catch(()=>null).finally(()=>{this.publicIPFetchPromise=null}))}async fetchPublicIP(){try{const t=new AbortController,e=setTimeout(()=>t.abort(),2e3),i=await fetch("https://api.ipify.org?format=json",{signal:t.signal,headers:{Accept:"application/json"}});if(clearTimeout(e),!i.ok)return null;const r=await i.json();return"string"==typeof r?.ip?r.ip:null}catch(t){return this.logger.debug("Public IP fetch failed",t),null}}async trackPurchase(i,r,n=e.USD,s){await this.trackEvent(t.PURCHASE,s,i,r,n)}async trackLogin(e,i){await this.trackEvent(t.LOGIN,i,e)}async trackSignup(e,i){await this.trackEvent(t.SIGNUP,i,e)}async trackFormSubmit(e,i){await this.trackEvent(t.FORM_SUBMIT,i,e)}async trackVideoPlay(e,i){await this.trackEvent(t.VIDEO_PLAY,i,e)}async trackEmailVerification(e,i){await this.trackEvent(t.EMAIL_VERIFICATION,i,e)}async trackAuditApproved(e,i){await this.trackEvent(t.AUDIT_APPROVED,i,e)}async trackPurchaseAuto(i){const r=i.tracking_user_id||this.getUserId();r?await this.trackEvent(t.PURCHASE,i.purchaseData,r,i.revenue,i.currency||e.USD):this.logger.error("❌ trackPurchaseAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackLoginAuto(e){const i=e.tracking_user_id||this.getUserId();i?await this.trackEvent(t.LOGIN,e.loginData,i):this.logger.error("❌ trackLoginAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackSignupAuto(e){const i=e.tracking_user_id||this.getUserId();i?await this.trackEvent(t.SIGNUP,e.signupData,i):this.logger.error("❌ trackSignupAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackEmailVerificationAuto(e){const i=e.tracking_user_id||this.getUserId();i?await this.trackEvent(t.EMAIL_VERIFICATION,e.verificationData,i):this.logger.error("❌ trackEmailVerificationAuto requires tracking_user_id. Please set user ID using setUserId() or pass it in options.tracking_user_id.")}async trackProductView(e,i){await this.trackEvent(t.PRODUCT_VIEW,i,e)}async trackAddToCart(e,i){await this.trackEvent(t.ADD_TO_CART,i,e)}async trackPageClick(e,i){await this.trackEvent(t.PAGE_CLICK,i,e)}getAttributionData(){return this.storage.getUTMData()}addUTMToURL(t){if(!this.config.enableCrossDomainUTM)return t;const e=this.getAttributionData();return e?g(t,m(e.lastTouch,this.config.crossDomainUTMParams)):t}getCurrentUTMParams(){const t=this.getAttributionData();return t?m(t.lastTouch,this.config.crossDomainUTMParams):{}}getUTMParams(){const t=this.getAttributionData();if(!t)return this.logger.debug("No attribution data available for UTM params"),{};const e={utm_source:t.lastTouch.utm_source||null,utm_medium:t.lastTouch.utm_medium||null,utm_campaign:t.lastTouch.utm_campaign||null,utm_term:t.lastTouch.utm_term||null,utm_content:t.lastTouch.utm_content||null},i={};return e.utm_source&&""!==e.utm_source.trim()?i.utm_source=e.utm_source:i.utm_source=null,e.utm_medium&&""!==e.utm_medium.trim()?i.utm_medium=e.utm_medium:i.utm_medium=null,e.utm_campaign&&""!==e.utm_campaign.trim()?i.utm_campaign=e.utm_campaign:i.utm_campaign=null,e.utm_term&&""!==e.utm_term.trim()?i.utm_term=e.utm_term:i.utm_term=null,e.utm_content&&""!==e.utm_content.trim()?i.utm_content=e.utm_content:i.utm_content=null,this.logger.debug("UTM params for event:",i),i}initializeUserId(){if(this.config.userId)this.setUserId(this.config.userId),this.logger.info(`👤 User ID initialized from config: ${this.config.userId}`);else{const t=this.getUserId();t?this.logger.debug(`👤 Existing user ID found: ${t}`):this.logger.debug("👤 No user ID found, will be set when user identifies")}}setUserId(t){t&&""!==t.trim()?(this.storage.setUserId(t),this.logger.info(`👤 User ID set: ${t}`)):this.logger.warn("Cannot set empty user ID")}getUserId(){return this.storage.getUserId()}removeUserId(){this.storage.removeUserId(),this.logger.info("👤 User ID removed")}async identify(e,i){this.initialized?e&&""!==e.trim()?(this.setUserId(e),i&&(this.storage.setUserTraits(i),this.logger.info(`User identified: ${e}`,i)),await this.trackEvent(t.FORM_SUBMIT,{_identify:!0,_user_traits:i,tracking_user_id:e},e)):this.logger.warn("Cannot identify with empty user ID"):this.logger.warn("SDK not initialized, identify call queued")}getUserTraits(){return this.storage.getUserTraits()}getSessionId(){return this.session?.sessionId||null}initializeSession(){const t=this.storage.getSession(),e=Date.now();t&&e-t.lastActivity<this.config.sessionTimeout?this.session={...t,lastActivity:e}:this.session={sessionId:`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,startTime:e,lastActivity:e,pageViews:0},this.storage.storeSession(this.session),this.logger.debug("Session initialized:",this.session)}extractAndStoreUTMData(){const t=d(),e=function(t){const e=function(t){const e={};try{new URL(t).searchParams.forEach((t,i)=>{e[i]=t})}catch(t){}return e}(t),i={};return["utm_source","utm_medium","utm_campaign","utm_term","utm_content"].forEach(t=>{e[t]&&""!==e[t].trim()&&(i[t]=e[t].trim())}),i}(t);if(this.logger.debug("Extracting UTM params from URL:",t),this.logger.debug("Found UTM params:",e),0===Object.keys(e).length)return void this.logger.debug("No UTM parameters found in URL");const i={utm_source:e.utm_source||"",utm_medium:e.utm_medium||"",utm_campaign:e.utm_campaign||"",utm_term:e.utm_term||"",utm_content:e.utm_content||"",timestamp:Date.now()},r=this.getAttributionData(),n={firstTouch:r?.firstTouch||i,lastTouch:i,touchpoints:r?.touchpoints||[],expiresAt:Date.now()+2592e6};r&&r.lastTouch.utm_source===i.utm_source&&r.lastTouch.utm_campaign===i.utm_campaign||n.touchpoints.push(i),this.storage.storeUTMData(n),this.logger.info("UTM data extracted and stored successfully:",i),this.config.autoCleanUTM&&function(){try{const t=new URL(window.location.href);let e=!1;["utm_source","utm_medium","utm_campaign","utm_term","utm_content"].forEach(i=>{t.searchParams.has(i)&&(t.searchParams.delete(i),e=!0)}),e&&window.history.replaceState({},document.title,t.toString())}catch(t){console.warn("Failed to clean URL:",t)}}()}setupAutoTracking(){this.autoTrackEnabled=!0,this.setupFormTracking(),this.setupLinkTracking(),this.logger.info("Auto-tracking enabled")}setupFormTracking(){document.addEventListener("submit",e=>{try{const i=e.target;if(!i)return;const r=this.serializeFormFields(i),n=this.extractLeadFields(r);n.email&&(this.storage.setUserTraits(n),this.logger.debug("Lead fields extracted from form:",n)),this.trackEvent(t.FORM_SUBMIT,{...r,_lead_fields:n,form_id:i.id||i.name,form_action:i.action,form_method:i.method})}catch(t){this.logger.error("Failed to auto-track form submit:",t)}})}serializeFormFields(t){const e={};try{const i=new FormData(t);for(const[t,r]of i.entries()){const i=this.serializeFormValue(r);if(Object.prototype.hasOwnProperty.call(e,t)){const r=e[t];Array.isArray(r)?(r.push(i),e[t]=r):e[t]=[r,i]}else e[t]=i}const r=Array.from(t.elements),n=new Map;for(let t=0;t<r.length;t++){const e=r[t];if(e.disabled)continue;const i=e.tagName.toLowerCase(),s=e.type?.toLowerCase();if("button"===i||"submit"===s||"reset"===s)continue;const a=this.getFormFieldKey(e,t);a&&(n.has(a)||n.set(a,[]),n.get(a).push(e))}n.forEach((t,i)=>{const r=t.some(t=>"radio"===t.type),n=t.some(t=>"checkbox"===t.type),s=t.some(t=>"file"===t.type),a=t.some(t=>"SELECT"===t.tagName&&t.multiple),o=t.some(t=>"password"===t.type);if(n){const r=t.filter(t=>"checkbox"===t.type).filter(t=>t.checked).map(t=>t.value||"on");return void(Object.prototype.hasOwnProperty.call(e,i)?Array.isArray(e[i])||(e[i]=[e[i],...r]):e[i]=r)}if(r){const r=t.filter(t=>"radio"===t.type).find(t=>t.checked);return void(Object.prototype.hasOwnProperty.call(e,i)||(e[i]=r?r.value:null))}if(a){const r=t.find(t=>"SELECT"===t.tagName&&t.multiple);if(r){const t=Array.from(r.selectedOptions).map(t=>t.value);return void(Object.prototype.hasOwnProperty.call(e,i)||(e[i]=t))}}if(s){const r=t.find(t=>"file"===t.type);if(r){const t=r.files?Array.from(r.files):[];return void(Object.prototype.hasOwnProperty.call(e,i)||(e[i]=t.map(t=>this.serializeFormValue(t))))}}if(o)Object.prototype.hasOwnProperty.call(e,i)?e[i]="string"==typeof e[i]?"*****":e[i]:e[i]="*****";else if(!Object.prototype.hasOwnProperty.call(e,i)){const r=t[0];if("SELECT"===r.tagName){const t=r;e[i]=t.multiple?Array.from(t.selectedOptions).map(t=>t.value):t.value}else r.type,e[i]=r.value??""}})}catch(t){this.logger.error("Failed to serialize form fields:",t)}return e}getFormFieldKey(t,e){const i=t.name;if(i)return i;if(t.id)return`id_${t.id}`;const r=t.getAttribute("aria-label");if(r&&r.trim())return`aria_${this.normalizeFormFieldKey(r)}`;const n=t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement?t.placeholder:"";return n&&n.trim()?`ph_${this.normalizeFormFieldKey(n)}_${e}`:`field_${e}`}normalizeFormFieldKey(t){return t.trim().toLowerCase().replace(/\s+/g,"_").replace(/[^a-z0-9_]/g,"").slice(0,40)}serializeFormValue(t){return t instanceof File?{file_name:t.name,file_size:t.size,file_type:t.type}:t}extractLeadFields(t){const e={};for(const[i,r]of Object.entries(a))if(!e[i])for(const n of r||[]){const r=n.toLowerCase();for(const[n,s]of Object.entries(t))if((n.toLowerCase()===r||n.toLowerCase().includes(r))&&s&&"string"==typeof s&&s.trim()){e[i]=s.trim();break}if(e[i])break}return e.name||!e.first_name&&!e.last_name||(e.name=[e.first_name,e.last_name].filter(Boolean).join(" ").trim()),e}setupLinkTracking(){document.addEventListener("click",t=>{const e=t.target.closest("a");e&&function(t){try{const e=new URL(t),i=window.location.hostname;return e.hostname!==i}catch(t){return!1}}(e.href)&&this.handleCrossDomainUTM(e,t)})}handleCrossDomainUTM(t,e){if(!this.config.enableCrossDomainUTM)return;const i=t.href;if(function(t,e=[]){try{const i=new URL(t).hostname.toLowerCase();return e.some(t=>{const e=t.toLowerCase();return i===e||i.endsWith(`.${e}`)})}catch(t){return!1}}(i,this.config.excludeDomains))return void this.logger.debug(`Domain excluded from UTM passing: ${i}`);const r=this.getAttributionData();if(!r)return void this.logger.debug("No UTM data available for cross-domain passing");const n=m(r.lastTouch,this.config.crossDomainUTMParams);if(0===Object.keys(n).length)return void this.logger.debug("No UTM parameters to pass");const s=g(i,n);s!==i&&(t.href=s,this.logger.debug("UTM parameters added to external link:",{original:i,enhanced:s,utmParams:n}),this.logger.debug("Cross-domain UTM passed:",{link_url:s,original_url:i,utm_params_passed:n}))}setupNetworkHandlers(){window.addEventListener("online",()=>{this.logger.info("Network connection restored"),this.queue.flush()}),window.addEventListener("offline",()=>{this.logger.warn("Network connection lost")})}setupVisibilityHandlers(){document.addEventListener("visibilitychange",()=>{"hidden"!==document.visibilityState?"visible"===document.visibilityState&&this.updateSessionActivity():this.flushOnUnload("visibilitychange:hidden")})}setupBeforeUnloadHandler(){window.addEventListener("beforeunload",()=>{this.flushOnUnload("beforeunload")}),window.addEventListener("pagehide",()=>{this.flushOnUnload("pagehide")})}flushOnUnload(t){try{this.updateSessionActivity();const e=this.queue.drainAll();if(0===e.length)return;if(this.storage.appendPendingEvents(e),this.logger.debug(`🚚 Unload flush triggered: ${t}`,{count:e.length}),this.httpClient.sendEventsBeacon(e))return void this.storage.removePendingEventsByIds(e.map(t=>t.event_id));const i=20;for(let t=0;t<e.length;t+=i){const r=e.slice(t,t+i);this.httpClient.sendEventsKeepalive(r).then(()=>{this.storage.removePendingEventsByIds(r.map(t=>t.event_id))}).catch(t=>{this.logger.debug("Unload keepalive send failed",t)})}}catch(t){this.logger.debug("flushOnUnload failed",t)}}async retryPendingEvents(){const t=this.storage.getPendingEvents();if(0!==t.length){this.logger.info(`📦 Retrying pending events: ${t.length}`);try{await this.httpClient.sendEvents(t),this.storage.removePendingEventsByIds(t.map(t=>t.event_id)),this.logger.info(`✅ Pending events sent: ${t.length}`)}catch(t){this.logger.warn("⚠️ Pending events retry failed",t)}}}getCurrentPath(){return"undefined"==typeof window?"":window.location.pathname+window.location.search}setupSPATracking(){if("undefined"==typeof window||"undefined"==typeof history)return void this.logger.warn("⚠️ SPA tracking not available in this environment");if(this.spaTrackingEnabled)return void this.logger.warn("⚠️ SPA tracking already enabled");this.spaTrackingEnabled=!0,this.lastTrackedPath=this.getCurrentPath(),this.originalPushState=history.pushState.bind(history),this.originalReplaceState=history.replaceState.bind(history);const t=t=>{const e=this.getCurrentPath();e!==this.lastTrackedPath?(this.logger.debug(`🔄 [SPA] Route change detected (${t}): ${this.lastTrackedPath} -> ${e}`),this.lastTrackedPath=e,setTimeout(()=>{this.trackPageView().then(()=>this.queue.process()).then(()=>{this.logger.debug(`✅ [SPA] Page view tracked for: ${e}`)}).catch(t=>{this.logger.error("❌ [SPA] Failed to track page view:",t)})},100)):this.logger.debug(`🔄 [SPA] Route change detected (${t}) but path unchanged: ${e}`)};history.pushState=(e,i,r)=>{const n=this.originalPushState(e,i,r);return t("pushState"),n},history.replaceState=(e,i,r)=>{const n=this.originalReplaceState(e,i,r);return t("replaceState"),n},this.popstateHandler=()=>{t("popstate")},window.addEventListener("popstate",this.popstateHandler),this.logger.info("🔄 SPA tracking setup completed")}cleanupSPATracking(){this.spaTrackingEnabled&&(this.originalPushState&&(history.pushState=this.originalPushState,this.originalPushState=null),this.originalReplaceState&&(history.replaceState=this.originalReplaceState,this.originalReplaceState=null),this.popstateHandler&&(window.removeEventListener("popstate",this.popstateHandler),this.popstateHandler=null),this.spaTrackingEnabled=!1,this.logger.info("🔄 SPA tracking cleaned up"))}updateSessionActivity(){this.session&&(this.session.lastActivity=Date.now(),this.storage.storeSession(this.session))}async flush(){await this.queue.flush()}getStatus(){return{initialized:this.initialized,session:this.session,queueSize:this.queue.size(),online:navigator.onLine,crossDomainUTM:{enabled:this.config.enableCrossDomainUTM||!0,currentParams:this.getCurrentUTMParams()},spaTracking:{enabled:this.spaTrackingEnabled,currentPath:this.lastTrackedPath}}}destroy(){this.queue.clear(),this.autoTrackEnabled=!1,this.cleanupSPATracking(),this.initialized=!1,this.logger.info("🗑️ SDK destroyed")}}let E=null;async function I(t){if(E)return console.warn("GetuAI SDK: Already initialized"),E;try{if(E=new b(t),await E.init(),t.enableDebug&&(window.GetuAISDK=E),console.log("GetuAI Attribution SDK initialized successfully"),"undefined"!=typeof window){const t=new CustomEvent("getuaiSDKReady",{detail:{sdk:E}});window.dispatchEvent(t)}return E}catch(t){if(console.error("GetuAI SDK: Failed to initialize:",t),"undefined"!=typeof window){const e=new CustomEvent("getuaiSDKError",{detail:{error:t}});window.dispatchEvent(e)}throw t}}function T(){return E}function P(){return new Promise((t,e)=>{if(E)return void t(E);const i=e=>{window.removeEventListener("getuaiSDKReady",i),window.removeEventListener("getuaiSDKError",r),t(e.detail.sdk)},r=t=>{window.removeEventListener("getuaiSDKReady",i),window.removeEventListener("getuaiSDKError",r),e(t.detail.error)};window.addEventListener("getuaiSDKReady",i),window.addEventListener("getuaiSDKError",r),setTimeout(()=>{window.removeEventListener("getuaiSDKReady",i),window.removeEventListener("getuaiSDKError",r),e(new Error("SDK initialization timeout"))},1e4)})}async function A(t,i,r,n,s=e.USD){const a=T();a?await a.trackEvent(t,i,r,n,s):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function D(t,e){const i=T();i?await i.trackPageView(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function U(t,i,r=e.USD,n){const s=T();s?await s.trackPurchase(t,i,r,n):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function C(t,e){const i=T();i?await i.trackLogin(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function x(t,e){const i=T();i?await i.trackSignup(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function K(t,e){const i=T();i?await i.trackFormSubmit(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function R(t,e){const i=T();i?await i.trackVideoPlay(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function N(t,e){const i=T();i?await i.trackEmailVerification(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function F(t){const e=T();e?await e.trackPurchaseAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function O(t){const e=T();e?await e.trackLoginAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function L(t){const e=T();e?await e.trackSignupAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function z(t){const e=T();e?await e.trackEmailVerificationAuto(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function M(t,e){const i=T();i?await i.trackProductView(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function V(t,e){const i=T();i?await i.trackAddToCart(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}async function G(t,e){const i=T();i?await i.trackPageClick(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")}function $(){const t=T();return t?t.getAttributionData():null}async function q(){const t=T();t?await t.flush():console.warn("GetuAI SDK: Not initialized. Call init() first.")}function B(){const t=T();return t?t.getStatus():null}function j(t){const e=T();return e?e.addUTMToURL(t):(console.warn("GetuAI SDK: Not initialized. Call init() first."),t)}function Y(){const t=T();return t?t.getCurrentUTMParams():{}}function H(t){const e=T();e?e.setUserId(t):console.warn("GetuAI SDK: Not initialized. Call init() first.")}function J(){const t=T();return t?t.getUserId():(console.warn("GetuAI SDK: Not initialized. Call init() first."),null)}function W(){const t=T();t?t.removeUserId():console.warn("GetuAI SDK: Not initialized. Call init() first.")}function Q(){E&&(E.destroy(),E=null,console.log("GetuAI SDK destroyed"))}class X extends b{static async init(t){return await I(t)}static async trackEvent(t,i,r,n,s=e.USD){return await A(t,i,r,n,s)}static async trackPageView(t,e){return await D(t,e)}static async trackPurchase(t,i,r=e.USD,n){return await U(t,i,r,n)}static async trackLogin(t,e){return await C(t,e)}static async trackSignup(t,e){return await x(t,e)}static async trackFormSubmit(t,e){return await K(t,e)}static async trackVideoPlay(t,e){return await R(t,e)}static async trackEmailVerification(t,e){return await N(t,e)}static async trackPurchaseAuto(t){return await F(t)}static async trackLoginAuto(t){return await O(t)}static async trackSignupAuto(t){return await L(t)}static async trackEmailVerificationAuto(t){return await z(t)}static async trackProductView(t,e){return await M(t,e)}static async trackAddToCart(t,e){return await V(t,e)}static async trackPageClick(t,e){return await G(t,e)}static getAttributionData(){return $()}static async flush(){return await q()}static getStatus(){return B()}static addUTMToURL(t){return j(t)}static getCurrentUTMParams(){return Y()}static setUserId(t){H(t)}static getUserId(){return J()}static removeUserId(){W()}static destroy(){Q()}static getSDK(){return T()}static waitForSDK(){return P()}}"undefined"!=typeof document&&function(){if(E)return;const t=document.currentScript;if(!t)return void console.warn("GetuAI SDK: Could not find script tag for auto-initialization");const e=t.getAttribute("data-api-key");e?I({apiKey:e,apiEndpoint:t.getAttribute("data-api-endpoint")||n,enableDebug:"true"===t.getAttribute("data-debug"),autoTrack:"true"===t.getAttribute("data-auto-track"),autoTrackPageView:"true"===t.getAttribute("data-auto-track-page-view"),autoCleanUTM:"false"!==t.getAttribute("data-auto-clean-utm"),batchSize:parseInt(t.getAttribute("data-batch-size")||"100"),batchInterval:parseInt(t.getAttribute("data-batch-interval")||"2000"),userId:t.getAttribute("data-user-id")||void 0}):console.warn("GetuAI SDK: No API key provided. Please add data-api-key attribute to script tag.")}(),"undefined"!=typeof window&&(window.getuaiSDK={init:I,getSDK:T,waitForSDK:P,trackEvent:A,trackPageView:D,trackPageClick:G,trackPurchase:U,trackLogin:C,trackSignup:x,trackFormSubmit:K,trackVideoPlay:R,trackEmailVerification:N,trackAuditApproved:async function(t,e){const i=T();i?await i.trackAuditApproved(t,e):console.warn("GetuAI SDK: Not initialized. Call init() first.")},trackProductView:M,trackAddToCart:V,trackPurchaseAuto:F,trackLoginAuto:O,trackSignupAuto:L,trackEmailVerificationAuto:z,getAttributionData:$,flush:q,getStatus:B,addUTMToURL:j,getCurrentUTMParams:Y,setUserId:H,getUserId:J,removeUserId:W,destroy:Q,EventType:t,Currency:e,AttributionSDK:X},window.init=I,window.waitForSDK=P,window.trackEvent=A,window.trackPageView=D,window.trackPageClick=G,window.trackPurchase=U,window.trackLogin=C,window.trackSignup=x,window.trackFormSubmit=K,window.trackVideoPlay=R,window.trackEmailVerification=N,window.trackProductView=M,window.trackAddToCart=V,window.trackPurchaseAuto=F,window.trackLoginAuto=O,window.trackSignupAuto=L,window.trackEmailVerificationAuto=z,window.getAttributionData=$,window.flush=q,window.getStatus=B,window.addUTMToURL=j,window.getCurrentUTMParams=Y,window.setUserId=H,window.getUserId=J,window.removeUserId=W,window.destroy=Q,window.AttributionSDK=X);const Z={init:I,getSDK:T,waitForSDK:P,trackEvent:A,trackPageView:D,trackPageClick:G,trackPurchase:U,trackLogin:C,trackSignup:x,trackFormSubmit:K,trackVideoPlay:R,trackEmailVerification:N,trackProductView:M,trackAddToCart:V,trackPurchaseAuto:F,trackLoginAuto:O,trackSignupAuto:L,trackEmailVerificationAuto:z,getAttributionData:$,flush:q,getStatus:B,addUTMToURL:j,getCurrentUTMParams:Y,setUserId:H,getUserId:J,removeUserId:W,destroy:Q,EventType:t,Currency:e,AttributionSDK:X};return r.default})());
|