|
1 | 1 | (function () { |
| 2 | + // Store script reference for extensions |
| 3 | + const script = document.currentScript; |
| 4 | + |
2 | 5 | const DUB_ID_VAR = 'dub_id'; |
3 | 6 | const COOKIE_EXPIRES = 90 * 24 * 60 * 60 * 1000; // 90 days |
4 | 7 | const HOSTNAME = window.location.hostname; |
5 | | - let clientClickTracked = false; |
6 | 8 |
|
7 | | - // Store script reference for extensions |
8 | | - const script = document.currentScript; |
| 9 | + // Common script attributes |
| 10 | + const API_HOST = script.getAttribute('data-api-host') || 'https://api.dub.co'; |
| 11 | + const COOKIE_OPTIONS = (() => { |
| 12 | + const defaultOptions = { |
| 13 | + domain: |
| 14 | + HOSTNAME === 'localhost' |
| 15 | + ? undefined |
| 16 | + : `.${HOSTNAME.replace(/^www\./, '')}`, |
| 17 | + path: '/', |
| 18 | + sameSite: 'Lax', |
| 19 | + expires: new Date(Date.now() + COOKIE_EXPIRES).toUTCString(), |
| 20 | + }; |
| 21 | + |
| 22 | + const opts = script.getAttribute('data-cookie-options'); |
| 23 | + if (!opts) return defaultOptions; |
| 24 | + |
| 25 | + const parsedOpts = JSON.parse(opts); |
| 26 | + if (parsedOpts.expiresInDays) { |
| 27 | + parsedOpts.expires = new Date( |
| 28 | + Date.now() + parsedOpts.expiresInDays * 24 * 60 * 60 * 1000, |
| 29 | + ).toUTCString(); |
| 30 | + delete parsedOpts.expiresInDays; |
| 31 | + } |
| 32 | + |
| 33 | + return { ...defaultOptions, ...parsedOpts }; |
| 34 | + })(); |
| 35 | + const SHORT_DOMAIN = |
| 36 | + script.getAttribute('data-short-domain') || |
| 37 | + script.getAttribute('data-domain'); |
| 38 | + const ATTRIBUTION_MODEL = |
| 39 | + script.getAttribute('data-attribution-model') || 'last-click'; |
9 | 40 |
|
10 | 41 | // Cookie management |
11 | | - const cookie = { |
| 42 | + const cookieManager = { |
12 | 43 | get(key) { |
13 | 44 | return document.cookie |
14 | 45 | .split(';') |
15 | 46 | .map((c) => c.trim().split('=')) |
16 | 47 | .find(([k]) => k === key)?.[1]; |
17 | 48 | }, |
18 | 49 |
|
19 | | - set(key, value, options = {}) { |
20 | | - const defaultOptions = { |
21 | | - domain: |
22 | | - HOSTNAME === 'localhost' |
23 | | - ? undefined |
24 | | - : `.${HOSTNAME.replace(/^www\./, '')}`, |
25 | | - path: '/', |
26 | | - sameSite: 'Lax', |
27 | | - expires: new Date(Date.now() + COOKIE_EXPIRES).toUTCString(), |
28 | | - }; |
29 | | - |
30 | | - const opts = { ...defaultOptions, ...options }; |
31 | | - const cookieString = Object.entries(opts) |
| 50 | + set(key, value) { |
| 51 | + const cookieString = Object.entries(COOKIE_OPTIONS) |
32 | 52 | .filter(([, v]) => v) |
33 | 53 | .map(([k, v]) => `${k}=${v}`) |
34 | 54 | .join('; '); |
|
37 | 57 | }, |
38 | 58 | }; |
39 | 59 |
|
| 60 | + let clientClickTracked = false; |
40 | 61 | // Track click and set cookie |
41 | 62 | function trackClick(identifier) { |
42 | 63 | if (clientClickTracked) return; |
43 | 64 | clientClickTracked = true; |
44 | 65 |
|
45 | | - const apiHost = |
46 | | - script.getAttribute('data-api-host') || 'https://api.dub.co'; |
47 | | - const shortDomain = |
48 | | - script.getAttribute('data-short-domain') || |
49 | | - script.getAttribute('data-domain'); |
50 | | - |
51 | | - fetch(`${apiHost}/track/click`, { |
| 66 | + fetch(`${API_HOST}/track/click`, { |
52 | 67 | method: 'POST', |
53 | 68 | headers: { 'Content-Type': 'application/json' }, |
54 | 69 | body: JSON.stringify({ |
55 | | - domain: shortDomain, |
| 70 | + domain: SHORT_DOMAIN, |
56 | 71 | key: identifier, |
57 | 72 | url: window.location.href, |
58 | 73 | referrer: document.referrer, |
|
61 | 76 | .then((res) => res.ok && res.json()) |
62 | 77 | .then((data) => { |
63 | 78 | if (data) { |
64 | | - const cookieOptions = script.getAttribute('data-cookie-options'); |
65 | | - cookie.set( |
66 | | - DUB_ID_VAR, |
67 | | - data.clickId, |
68 | | - cookieOptions ? JSON.parse(cookieOptions) : null, |
69 | | - ); |
| 79 | + cookieManager.set(DUB_ID_VAR, data.clickId); |
70 | 80 | } |
71 | 81 | }); |
72 | 82 | } |
73 | 83 |
|
74 | 84 | // Initialize tracking |
75 | 85 | function init() { |
76 | 86 | const params = new URLSearchParams(window.location.search); |
77 | | - const shortDomain = |
78 | | - script.getAttribute('data-short-domain') || |
79 | | - script.getAttribute('data-domain'); |
80 | 87 | const queryParam = script.getAttribute('data-query-param') || 'via'; |
81 | | - const attributionModel = |
82 | | - script.getAttribute('data-attribution-model') || 'last-click'; |
83 | 88 |
|
84 | 89 | // Direct click ID in URL |
85 | 90 | const clickId = params.get(DUB_ID_VAR); |
86 | 91 | if (clickId) { |
87 | | - const cookieOptions = script.getAttribute('data-cookie-options'); |
88 | | - cookie.set( |
89 | | - DUB_ID_VAR, |
90 | | - clickId, |
91 | | - cookieOptions ? JSON.parse(cookieOptions) : null, |
92 | | - ); |
| 92 | + cookieManager.set(DUB_ID_VAR, clickId); |
93 | 93 | return; |
94 | 94 | } |
95 | 95 |
|
96 | 96 | // Track via query param |
97 | 97 | const identifier = params.get(queryParam); |
98 | | - if (identifier && shortDomain) { |
99 | | - const existingCookie = cookie.get(DUB_ID_VAR); |
100 | | - if (!existingCookie || attributionModel !== 'first-click') { |
| 98 | + if (identifier && SHORT_DOMAIN) { |
| 99 | + const existingCookie = cookieManager.get(DUB_ID_VAR); |
| 100 | + if (!existingCookie || ATTRIBUTION_MODEL !== 'first-click') { |
101 | 101 | trackClick(identifier); |
102 | 102 | } |
103 | 103 | } |
104 | 104 | } |
105 | 105 |
|
106 | 106 | // Export core functionality |
107 | 107 | window._dubAnalytics = { |
| 108 | + script, |
| 109 | + cookieManager, |
108 | 110 | DUB_ID_VAR, |
109 | 111 | HOSTNAME, |
110 | | - cookie, |
111 | | - script, // Export script reference |
| 112 | + API_HOST, |
| 113 | + COOKIE_OPTIONS, |
| 114 | + SHORT_DOMAIN, |
| 115 | + ATTRIBUTION_MODEL, |
112 | 116 | }; |
113 | 117 |
|
114 | 118 | // Initialize |
|
0 commit comments