shopkit-analytics 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +769 -0
  3. package/dist/adapters/index.d.mts +4 -0
  4. package/dist/adapters/index.d.ts +4 -0
  5. package/dist/adapters/index.js +2405 -0
  6. package/dist/adapters/index.js.map +1 -0
  7. package/dist/adapters/index.mjs +23 -0
  8. package/dist/adapters/index.mjs.map +1 -0
  9. package/dist/affiliate/index.d.mts +138 -0
  10. package/dist/affiliate/index.d.ts +138 -0
  11. package/dist/affiliate/index.js +816 -0
  12. package/dist/affiliate/index.js.map +1 -0
  13. package/dist/affiliate/index.mjs +74 -0
  14. package/dist/affiliate/index.mjs.map +1 -0
  15. package/dist/affiliate-tracker-BgHwibPv.d.mts +144 -0
  16. package/dist/affiliate-tracker-BgHwibPv.d.ts +144 -0
  17. package/dist/chunk-3TQR5DOP.mjs +79 -0
  18. package/dist/chunk-3TQR5DOP.mjs.map +1 -0
  19. package/dist/chunk-4MZH5OLR.mjs +2375 -0
  20. package/dist/chunk-4MZH5OLR.mjs.map +1 -0
  21. package/dist/chunk-JVEGG6JV.mjs +213 -0
  22. package/dist/chunk-JVEGG6JV.mjs.map +1 -0
  23. package/dist/chunk-P4OJDCEZ.mjs +57 -0
  24. package/dist/chunk-P4OJDCEZ.mjs.map +1 -0
  25. package/dist/chunk-TNXTKEGS.mjs +758 -0
  26. package/dist/chunk-TNXTKEGS.mjs.map +1 -0
  27. package/dist/events/index.d.mts +112 -0
  28. package/dist/events/index.d.ts +112 -0
  29. package/dist/events/index.js +2131 -0
  30. package/dist/events/index.js.map +1 -0
  31. package/dist/events/index.mjs +30 -0
  32. package/dist/events/index.mjs.map +1 -0
  33. package/dist/index-BnNRgdUv.d.ts +676 -0
  34. package/dist/index-GODWc1s6.d.mts +676 -0
  35. package/dist/index.d.mts +38 -0
  36. package/dist/index.d.ts +38 -0
  37. package/dist/index.js +3269 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/index.mjs +190 -0
  40. package/dist/index.mjs.map +1 -0
  41. package/dist/subscriber-43gnCKWe.d.ts +80 -0
  42. package/dist/subscriber-IFZJU57V.mjs +8 -0
  43. package/dist/subscriber-IFZJU57V.mjs.map +1 -0
  44. package/dist/subscriber-sWesj_5p.d.mts +80 -0
  45. package/dist/types.d.mts +991 -0
  46. package/dist/types.d.ts +991 -0
  47. package/dist/types.js +102 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/types.mjs +8 -0
  50. package/dist/types.mjs.map +1 -0
  51. package/package.json +110 -0
@@ -0,0 +1,758 @@
1
+ "use client";
2
+
3
+ // src/affiliate/AffiliateTracker.tsx
4
+ import { useEffect } from "react";
5
+
6
+ // src/affiliate/constants.ts
7
+ var UTM_PARAMETERS = [
8
+ "utm_source",
9
+ "utm_medium",
10
+ "utm_campaign",
11
+ "utm_term",
12
+ "utm_content"
13
+ ];
14
+ var CLICK_ID_PARAMETERS = [
15
+ "gclid",
16
+ // Google Ads
17
+ "fbclid",
18
+ // Facebook
19
+ "msclkid",
20
+ // Microsoft Ads
21
+ "ttclid",
22
+ // TikTok
23
+ "twclid",
24
+ // Twitter
25
+ "li_fat_id"
26
+ // LinkedIn
27
+ ];
28
+ var AFFILIATE_PARAMETERS = [
29
+ "click_id",
30
+ "affiliate_id",
31
+ "ref",
32
+ "source",
33
+ "referrer"
34
+ ];
35
+ var ALL_AFFILIATE_PARAMETERS = [
36
+ ...UTM_PARAMETERS,
37
+ ...CLICK_ID_PARAMETERS,
38
+ ...AFFILIATE_PARAMETERS
39
+ ];
40
+ var STORAGE_CONFIG = {
41
+ DEFAULT_KEY: "affiliateParams",
42
+ DEFAULT_TTL: 30 * 24 * 60 * 60 * 1e3
43
+ // 30 days in milliseconds
44
+ };
45
+ var ATTRIBUTION_MODELS = {
46
+ FIRST_TOUCH: "first-touch",
47
+ LAST_TOUCH: "last-touch"
48
+ };
49
+ var STORAGE_TYPES = {
50
+ SESSION: "sessionStorage",
51
+ LOCAL: "localStorage"
52
+ };
53
+ var EVENT_TYPES = {
54
+ CAPTURE: "capture",
55
+ CLEAR: "clear",
56
+ EXPIRE: "expire"
57
+ };
58
+ var ATTRIBUTION_CHANNELS = {
59
+ DIRECT: "direct",
60
+ PAID_SEARCH: "paid_search",
61
+ ORGANIC_SEARCH: "organic_search",
62
+ SOCIAL: "social",
63
+ EMAIL: "email",
64
+ AFFILIATE: "affiliate",
65
+ REFERRAL: "referral",
66
+ DISPLAY: "display"
67
+ };
68
+ var SEARCH_ENGINES = [
69
+ "google.com",
70
+ "bing.com",
71
+ "yahoo.com",
72
+ "duckduckgo.com",
73
+ "baidu.com",
74
+ "yandex.com",
75
+ "ask.com"
76
+ ];
77
+ var SOCIAL_PLATFORMS = [
78
+ "facebook",
79
+ "instagram",
80
+ "twitter",
81
+ "linkedin",
82
+ "tiktok",
83
+ "youtube",
84
+ "pinterest",
85
+ "snapchat"
86
+ ];
87
+
88
+ // src/affiliate/affiliate-tracker.ts
89
+ var DEFAULT_CONFIG = {
90
+ storageKey: STORAGE_CONFIG.DEFAULT_KEY,
91
+ storageType: STORAGE_TYPES.SESSION,
92
+ attribution: ATTRIBUTION_MODELS.LAST_TOUCH,
93
+ ttl: STORAGE_CONFIG.DEFAULT_TTL,
94
+ customParams: [],
95
+ enableReferrerCapture: true,
96
+ enableUserAgentCapture: false,
97
+ onCapture: () => {
98
+ },
99
+ onError: () => {
100
+ }
101
+ };
102
+ var currentConfig = { ...DEFAULT_CONFIG };
103
+ var eventListeners = [];
104
+ function configureAffiliateTracker(config = {}) {
105
+ currentConfig = { ...DEFAULT_CONFIG, ...config };
106
+ }
107
+ function generateSessionId() {
108
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
109
+ }
110
+ function getStorage() {
111
+ if (typeof window === "undefined") return null;
112
+ try {
113
+ return currentConfig.storageType === "localStorage" ? window.localStorage : window.sessionStorage;
114
+ } catch (error) {
115
+ currentConfig.onError(new Error(`Storage not available: ${error}`));
116
+ return null;
117
+ }
118
+ }
119
+ function isExpired(timestamp) {
120
+ return Date.now() - timestamp > currentConfig.ttl;
121
+ }
122
+ function emitEvent(event) {
123
+ eventListeners.forEach((listener) => {
124
+ try {
125
+ listener(event);
126
+ } catch (error) {
127
+ currentConfig.onError(new Error(`Event listener error: ${error}`));
128
+ }
129
+ });
130
+ }
131
+ function addEventListener(listener) {
132
+ eventListeners.push(listener);
133
+ return () => {
134
+ const index = eventListeners.indexOf(listener);
135
+ if (index > -1) {
136
+ eventListeners.splice(index, 1);
137
+ }
138
+ };
139
+ }
140
+ function captureAffiliateParams(customConfig) {
141
+ if (typeof window === "undefined") return null;
142
+ const originalConfig = currentConfig;
143
+ if (customConfig) {
144
+ currentConfig = { ...currentConfig, ...customConfig };
145
+ }
146
+ try {
147
+ const storage = getStorage();
148
+ if (!storage) return null;
149
+ const urlParams = new URLSearchParams(window.location.search);
150
+ const allKeys = [
151
+ ...ALL_AFFILIATE_PARAMETERS,
152
+ ...currentConfig.customParams
153
+ ];
154
+ const affiliateParams = {};
155
+ for (const key of allKeys) {
156
+ const value = urlParams.get(key);
157
+ if (value) {
158
+ affiliateParams[key] = value;
159
+ }
160
+ }
161
+ if (currentConfig.enableReferrerCapture && document.referrer) {
162
+ affiliateParams.referrer = document.referrer;
163
+ }
164
+ if (Object.keys(affiliateParams).length === 0) {
165
+ return null;
166
+ }
167
+ const existingData = getAffiliateParams();
168
+ let shouldUpdate = true;
169
+ if (existingData && currentConfig.attribution === "first-touch") {
170
+ shouldUpdate = false;
171
+ }
172
+ if (shouldUpdate) {
173
+ const affiliateData = {
174
+ ...affiliateParams,
175
+ timestamp: Date.now(),
176
+ sessionId: generateSessionId(),
177
+ attribution: currentConfig.attribution,
178
+ url: window.location.href,
179
+ ...currentConfig.enableUserAgentCapture && {
180
+ userAgent: navigator.userAgent
181
+ }
182
+ };
183
+ storage.setItem(currentConfig.storageKey, JSON.stringify(affiliateData));
184
+ emitEvent({
185
+ type: "capture",
186
+ data: affiliateData,
187
+ timestamp: Date.now()
188
+ });
189
+ currentConfig.onCapture(affiliateData);
190
+ return affiliateData;
191
+ }
192
+ return existingData;
193
+ } catch (error) {
194
+ const errorObj = error instanceof Error ? error : new Error(String(error));
195
+ currentConfig.onError(errorObj);
196
+ return null;
197
+ } finally {
198
+ if (customConfig) {
199
+ currentConfig = originalConfig;
200
+ }
201
+ }
202
+ }
203
+ function getAffiliateParams() {
204
+ if (typeof window === "undefined") return null;
205
+ try {
206
+ const storage = getStorage();
207
+ if (!storage) return null;
208
+ const stored = storage.getItem(currentConfig.storageKey);
209
+ if (!stored) return null;
210
+ const data = JSON.parse(stored);
211
+ if (isExpired(data.timestamp)) {
212
+ clearAffiliateParams();
213
+ emitEvent({
214
+ type: "expire",
215
+ data,
216
+ timestamp: Date.now()
217
+ });
218
+ return null;
219
+ }
220
+ return data;
221
+ } catch (error) {
222
+ const errorObj = error instanceof Error ? error : new Error(String(error));
223
+ currentConfig.onError(errorObj);
224
+ return null;
225
+ }
226
+ }
227
+ function clearAffiliateParams() {
228
+ if (typeof window === "undefined") return;
229
+ try {
230
+ const storage = getStorage();
231
+ if (!storage) return;
232
+ const existingData = getAffiliateParams();
233
+ storage.removeItem(currentConfig.storageKey);
234
+ emitEvent({
235
+ type: "clear",
236
+ data: existingData || void 0,
237
+ timestamp: Date.now()
238
+ });
239
+ } catch (error) {
240
+ const errorObj = error instanceof Error ? error : new Error(String(error));
241
+ currentConfig.onError(errorObj);
242
+ }
243
+ }
244
+ function getAffiliateParamsAsUrlString() {
245
+ const data = getAffiliateParams();
246
+ if (!data) return "";
247
+ const params = new URLSearchParams();
248
+ const affiliateKeys = [
249
+ ...ALL_AFFILIATE_PARAMETERS,
250
+ ...currentConfig.customParams
251
+ ];
252
+ for (const key of affiliateKeys) {
253
+ const value = data[key];
254
+ if (typeof value === "string" && value) {
255
+ params.set(key, value);
256
+ }
257
+ }
258
+ return params.toString();
259
+ }
260
+ function appendAffiliateParams(url) {
261
+ const affiliateParams = getAffiliateParamsAsUrlString();
262
+ if (!affiliateParams) return url;
263
+ const separator = url.includes("?") ? "&" : "?";
264
+ return `${url}${separator}${affiliateParams}`;
265
+ }
266
+ function hasAffiliateData() {
267
+ return getAffiliateParams() !== null;
268
+ }
269
+ function getAffiliateSource() {
270
+ const data = getAffiliateParams();
271
+ if (!data) return null;
272
+ if (data.utm_source) return data.utm_source;
273
+ if (data.referrer) {
274
+ try {
275
+ return new URL(data.referrer).hostname;
276
+ } catch {
277
+ return data.referrer;
278
+ }
279
+ }
280
+ return null;
281
+ }
282
+ function getConfig() {
283
+ return { ...currentConfig };
284
+ }
285
+ function resetConfig() {
286
+ currentConfig = { ...DEFAULT_CONFIG };
287
+ }
288
+
289
+ // src/affiliate/AffiliateTracker.tsx
290
+ import { Fragment, jsx } from "react/jsx-runtime";
291
+ var AffiliateTracker = ({
292
+ config,
293
+ autoCapture = true,
294
+ children
295
+ }) => {
296
+ useEffect(() => {
297
+ if (config) {
298
+ configureAffiliateTracker(config);
299
+ }
300
+ if (autoCapture) {
301
+ captureAffiliateParams();
302
+ }
303
+ }, [config, autoCapture]);
304
+ return children ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
305
+ };
306
+ var AffiliateTracker_default = AffiliateTracker;
307
+
308
+ // src/affiliate/hooks.ts
309
+ import { useState, useEffect as useEffect2, useCallback, useRef } from "react";
310
+ function useAffiliateTracker(config) {
311
+ const [affiliateParams, setAffiliateParams] = useState(
312
+ null
313
+ );
314
+ const [isLoading, setIsLoading] = useState(true);
315
+ const [error, setError] = useState(null);
316
+ const configRef = useRef(config);
317
+ useEffect2(() => {
318
+ configRef.current = config;
319
+ }, [config]);
320
+ useEffect2(() => {
321
+ if (configRef.current) {
322
+ configureAffiliateTracker({
323
+ ...configRef.current,
324
+ onError: (err) => {
325
+ setError(err);
326
+ configRef.current?.onError?.(err);
327
+ }
328
+ });
329
+ }
330
+ }, []);
331
+ const refreshParams = useCallback(() => {
332
+ setIsLoading(true);
333
+ setError(null);
334
+ try {
335
+ const params = getAffiliateParams();
336
+ setAffiliateParams(params);
337
+ } catch (err) {
338
+ const error2 = err instanceof Error ? err : new Error(String(err));
339
+ setError(error2);
340
+ } finally {
341
+ setIsLoading(false);
342
+ }
343
+ }, []);
344
+ const captureParams = useCallback(() => {
345
+ setError(null);
346
+ try {
347
+ const params = captureAffiliateParams(configRef.current);
348
+ setAffiliateParams(params);
349
+ } catch (err) {
350
+ const error2 = err instanceof Error ? err : new Error(String(err));
351
+ setError(error2);
352
+ }
353
+ }, []);
354
+ const clearParams = useCallback(() => {
355
+ setError(null);
356
+ try {
357
+ clearAffiliateParams();
358
+ setAffiliateParams(null);
359
+ } catch (err) {
360
+ const error2 = err instanceof Error ? err : new Error(String(err));
361
+ setError(error2);
362
+ }
363
+ }, []);
364
+ useEffect2(() => {
365
+ const unsubscribe = addEventListener((event) => {
366
+ switch (event.type) {
367
+ case "capture":
368
+ setAffiliateParams(event.data || null);
369
+ break;
370
+ case "clear":
371
+ case "expire":
372
+ setAffiliateParams(null);
373
+ break;
374
+ }
375
+ });
376
+ return unsubscribe;
377
+ }, []);
378
+ useEffect2(() => {
379
+ refreshParams();
380
+ }, [refreshParams]);
381
+ return {
382
+ affiliateParams,
383
+ isLoading,
384
+ error,
385
+ captureParams,
386
+ clearParams,
387
+ refreshParams
388
+ };
389
+ }
390
+ function useHasAffiliateData() {
391
+ const [hasData, setHasData] = useState(false);
392
+ useEffect2(() => {
393
+ const checkData = () => {
394
+ setHasData(hasAffiliateData());
395
+ };
396
+ checkData();
397
+ const unsubscribe = addEventListener(() => {
398
+ checkData();
399
+ });
400
+ return unsubscribe;
401
+ }, []);
402
+ return hasData;
403
+ }
404
+ function useAffiliateSource() {
405
+ const [source, setSource] = useState(null);
406
+ useEffect2(() => {
407
+ const updateSource = () => {
408
+ setSource(getAffiliateSource());
409
+ };
410
+ updateSource();
411
+ const unsubscribe = addEventListener(() => {
412
+ updateSource();
413
+ });
414
+ return unsubscribe;
415
+ }, []);
416
+ return source;
417
+ }
418
+ function useAutoCapture(config) {
419
+ const hasRun = useRef(false);
420
+ useEffect2(() => {
421
+ if (hasRun.current) return;
422
+ hasRun.current = true;
423
+ if (config) {
424
+ configureAffiliateTracker(config);
425
+ }
426
+ captureAffiliateParams();
427
+ }, [config]);
428
+ }
429
+ function useAffiliateEvents(callback, eventTypes) {
430
+ const callbackRef = useRef(callback);
431
+ const eventTypesRef = useRef(eventTypes);
432
+ useEffect2(() => {
433
+ callbackRef.current = callback;
434
+ eventTypesRef.current = eventTypes;
435
+ });
436
+ useEffect2(() => {
437
+ const unsubscribe = addEventListener((event) => {
438
+ if (!eventTypesRef.current || eventTypesRef.current.includes(event.type)) {
439
+ callbackRef.current(event);
440
+ }
441
+ });
442
+ return unsubscribe;
443
+ }, []);
444
+ }
445
+
446
+ // src/affiliate/utils.ts
447
+ var AffiliateAnalytics = class {
448
+ /**
449
+ * Send affiliate data to Google Analytics 4
450
+ */
451
+ static sendToGA4(eventName = "affiliate_attribution", customParams) {
452
+ const affiliateData = getAffiliateParams();
453
+ if (!affiliateData || typeof window === "undefined") return;
454
+ if (typeof window.gtag === "function") {
455
+ const eventParams = {
456
+ utm_source: affiliateData.utm_source,
457
+ utm_medium: affiliateData.utm_medium,
458
+ utm_campaign: affiliateData.utm_campaign,
459
+ utm_term: affiliateData.utm_term,
460
+ utm_content: affiliateData.utm_content,
461
+ affiliate_id: affiliateData.affiliate_id,
462
+ attribution_type: affiliateData.attribution,
463
+ session_id: affiliateData.sessionId,
464
+ ...customParams
465
+ };
466
+ Object.keys(eventParams).forEach((key) => {
467
+ if (eventParams[key] === void 0) {
468
+ delete eventParams[key];
469
+ }
470
+ });
471
+ window.gtag("event", eventName, eventParams);
472
+ }
473
+ }
474
+ /**
475
+ * Send affiliate data to Facebook Pixel
476
+ */
477
+ static sendToFacebookPixel(eventName = "AffiliateAttribution", customParams) {
478
+ const affiliateData = getAffiliateParams();
479
+ if (!affiliateData || typeof window === "undefined") return;
480
+ if (typeof window.fbq === "function") {
481
+ const eventParams = {
482
+ utm_source: affiliateData.utm_source,
483
+ utm_medium: affiliateData.utm_medium,
484
+ utm_campaign: affiliateData.utm_campaign,
485
+ fbclid: affiliateData.fbclid,
486
+ ...customParams
487
+ };
488
+ Object.keys(eventParams).forEach((key) => {
489
+ if (eventParams[key] === void 0) {
490
+ delete eventParams[key];
491
+ }
492
+ });
493
+ window.fbq("trackCustom", eventName, eventParams);
494
+ }
495
+ }
496
+ /**
497
+ * Send affiliate data to any custom analytics endpoint
498
+ */
499
+ static async sendToCustomEndpoint(endpoint, options = {}) {
500
+ const affiliateData = getAffiliateParams();
501
+ if (!affiliateData) return;
502
+ const { method = "POST", headers = {}, customData = {} } = options;
503
+ try {
504
+ await fetch(endpoint, {
505
+ method,
506
+ headers: {
507
+ "Content-Type": "application/json",
508
+ ...headers
509
+ },
510
+ body: JSON.stringify({
511
+ ...affiliateData,
512
+ ...customData
513
+ })
514
+ });
515
+ } catch (error) {
516
+ console.error("Failed to send affiliate data to custom endpoint:", error);
517
+ }
518
+ }
519
+ };
520
+ var AffiliateUrlUtils = class {
521
+ /**
522
+ * Create affiliate links with current parameters
523
+ */
524
+ static createAffiliateLink(baseUrl, additionalParams) {
525
+ let url = appendAffiliateParams(baseUrl);
526
+ if (additionalParams) {
527
+ const separator = url.includes("?") ? "&" : "?";
528
+ const params = new URLSearchParams(additionalParams);
529
+ url = `${url}${separator}${params.toString()}`;
530
+ }
531
+ return url;
532
+ }
533
+ /**
534
+ * Extract affiliate parameters from a URL
535
+ */
536
+ static extractFromUrl(url) {
537
+ try {
538
+ const urlObj = new URL(url);
539
+ const params = {};
540
+ const affiliateKeys = ALL_AFFILIATE_PARAMETERS;
541
+ affiliateKeys.forEach((key) => {
542
+ const value = urlObj.searchParams.get(key);
543
+ if (value) {
544
+ params[key] = value;
545
+ }
546
+ });
547
+ return params;
548
+ } catch {
549
+ return {};
550
+ }
551
+ }
552
+ /**
553
+ * Clean URL by removing affiliate parameters
554
+ */
555
+ static cleanUrl(url) {
556
+ try {
557
+ const urlObj = new URL(url);
558
+ const affiliateKeys = ALL_AFFILIATE_PARAMETERS;
559
+ affiliateKeys.forEach((key) => {
560
+ urlObj.searchParams.delete(key);
561
+ });
562
+ return urlObj.toString();
563
+ } catch {
564
+ return url;
565
+ }
566
+ }
567
+ };
568
+ var AffiliateAttribution = class {
569
+ /**
570
+ * Determine the attribution channel based on affiliate data
571
+ */
572
+ static getAttributionChannel(data) {
573
+ const affiliateData = data || getAffiliateParams();
574
+ if (!affiliateData) return ATTRIBUTION_CHANNELS.DIRECT;
575
+ if (affiliateData.gclid || affiliateData.utm_medium === "cpc" || affiliateData.utm_medium === "ppc") {
576
+ return ATTRIBUTION_CHANNELS.PAID_SEARCH;
577
+ }
578
+ if (affiliateData.fbclid || affiliateData.ttclid || affiliateData.twclid || affiliateData.li_fat_id || affiliateData.utm_source && SOCIAL_PLATFORMS.some(
579
+ (platform) => affiliateData.utm_source?.includes(platform)
580
+ )) {
581
+ return ATTRIBUTION_CHANNELS.SOCIAL;
582
+ }
583
+ if (affiliateData.utm_medium === "email" || affiliateData.utm_source === "email") {
584
+ return ATTRIBUTION_CHANNELS.EMAIL;
585
+ }
586
+ if (affiliateData.affiliate_id || affiliateData.utm_medium === "affiliate" || affiliateData.utm_medium === "referral") {
587
+ return ATTRIBUTION_CHANNELS.AFFILIATE;
588
+ }
589
+ if (affiliateData.utm_medium === "organic" || affiliateData.referrer && this.isSearchEngine(affiliateData.referrer)) {
590
+ return ATTRIBUTION_CHANNELS.ORGANIC_SEARCH;
591
+ }
592
+ if (affiliateData.utm_medium === "display" || affiliateData.utm_medium === "banner") {
593
+ return ATTRIBUTION_CHANNELS.DISPLAY;
594
+ }
595
+ if (affiliateData.referrer) {
596
+ return ATTRIBUTION_CHANNELS.REFERRAL;
597
+ }
598
+ return ATTRIBUTION_CHANNELS.DIRECT;
599
+ }
600
+ /**
601
+ * Check if a URL is from a search engine
602
+ */
603
+ static isSearchEngine(url) {
604
+ const searchEngines = SEARCH_ENGINES;
605
+ try {
606
+ const hostname = new URL(url).hostname.toLowerCase();
607
+ return searchEngines.some((engine) => hostname.includes(engine));
608
+ } catch {
609
+ return false;
610
+ }
611
+ }
612
+ /**
613
+ * Get attribution score (0-100) based on data quality
614
+ */
615
+ static getAttributionScore(data) {
616
+ const affiliateData = data || getAffiliateParams();
617
+ if (!affiliateData) return 0;
618
+ let score = 0;
619
+ score += 20;
620
+ if (affiliateData.utm_source) score += 20;
621
+ if (affiliateData.utm_medium) score += 20;
622
+ if (affiliateData.utm_campaign) score += 15;
623
+ if (affiliateData.gclid || affiliateData.fbclid || affiliateData.msclkid)
624
+ score += 25;
625
+ if (affiliateData.referrer) score += 10;
626
+ if (affiliateData.utm_term) score += 5;
627
+ if (affiliateData.utm_content) score += 5;
628
+ return Math.min(score, 100);
629
+ }
630
+ };
631
+ var AffiliateTestUtils = class {
632
+ /**
633
+ * Mock affiliate data for testing
634
+ */
635
+ static mockAffiliateData(params = {}) {
636
+ return {
637
+ utm_source: "test_source",
638
+ utm_medium: "test_medium",
639
+ utm_campaign: "test_campaign",
640
+ timestamp: Date.now(),
641
+ sessionId: "test-session-id",
642
+ attribution: "last-touch",
643
+ url: "https://example.com?utm_source=test_source&utm_medium=test_medium",
644
+ ...params
645
+ };
646
+ }
647
+ /**
648
+ * Create test URL with affiliate parameters
649
+ */
650
+ static createTestUrl(baseUrl = "https://example.com", params = {}) {
651
+ const defaultParams = {
652
+ utm_source: "test_source",
653
+ utm_medium: "test_medium",
654
+ utm_campaign: "test_campaign",
655
+ ...params
656
+ };
657
+ const url = new URL(baseUrl);
658
+ Object.entries(defaultParams).forEach(([key, value]) => {
659
+ if (value) {
660
+ url.searchParams.set(key, value);
661
+ }
662
+ });
663
+ return url.toString();
664
+ }
665
+ /**
666
+ * Simulate URL navigation for testing
667
+ */
668
+ static simulateNavigation(url) {
669
+ if (typeof window !== "undefined") {
670
+ Object.defineProperty(window, "location", {
671
+ value: {
672
+ ...window.location,
673
+ search: new URL(url).search,
674
+ href: url
675
+ },
676
+ writable: true
677
+ });
678
+ }
679
+ }
680
+ };
681
+ var AffiliateValidation = class {
682
+ /**
683
+ * Validate affiliate parameter format
684
+ */
685
+ static validateParams(params) {
686
+ const errors = [];
687
+ if (params.utm_source && params.utm_source.length > 100) {
688
+ errors.push("utm_source is too long (max 100 characters)");
689
+ }
690
+ if (params.utm_medium && params.utm_medium.length > 100) {
691
+ errors.push("utm_medium is too long (max 100 characters)");
692
+ }
693
+ if (params.utm_campaign && params.utm_campaign.length > 100) {
694
+ errors.push("utm_campaign is too long (max 100 characters)");
695
+ }
696
+ if (params.referrer) {
697
+ try {
698
+ new URL(params.referrer);
699
+ } catch {
700
+ errors.push("referrer is not a valid URL");
701
+ }
702
+ }
703
+ return {
704
+ isValid: errors.length === 0,
705
+ errors
706
+ };
707
+ }
708
+ /**
709
+ * Sanitize affiliate parameters
710
+ */
711
+ static sanitizeParams(params) {
712
+ const sanitized = {};
713
+ Object.entries(params).forEach(([key, value]) => {
714
+ if (typeof value === "string" && value.trim()) {
715
+ sanitized[key] = value.trim().replace(/[<>'"]/g, "").substring(0, 200);
716
+ }
717
+ });
718
+ return sanitized;
719
+ }
720
+ };
721
+
722
+ export {
723
+ UTM_PARAMETERS,
724
+ CLICK_ID_PARAMETERS,
725
+ AFFILIATE_PARAMETERS,
726
+ ALL_AFFILIATE_PARAMETERS,
727
+ STORAGE_CONFIG,
728
+ ATTRIBUTION_MODELS,
729
+ STORAGE_TYPES,
730
+ EVENT_TYPES,
731
+ ATTRIBUTION_CHANNELS,
732
+ SEARCH_ENGINES,
733
+ SOCIAL_PLATFORMS,
734
+ DEFAULT_CONFIG,
735
+ configureAffiliateTracker,
736
+ addEventListener,
737
+ captureAffiliateParams,
738
+ getAffiliateParams,
739
+ clearAffiliateParams,
740
+ getAffiliateParamsAsUrlString,
741
+ appendAffiliateParams,
742
+ hasAffiliateData,
743
+ getAffiliateSource,
744
+ getConfig,
745
+ resetConfig,
746
+ AffiliateTracker_default,
747
+ useAffiliateTracker,
748
+ useHasAffiliateData,
749
+ useAffiliateSource,
750
+ useAutoCapture,
751
+ useAffiliateEvents,
752
+ AffiliateAnalytics,
753
+ AffiliateUrlUtils,
754
+ AffiliateAttribution,
755
+ AffiliateTestUtils,
756
+ AffiliateValidation
757
+ };
758
+ //# sourceMappingURL=chunk-TNXTKEGS.mjs.map