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