@windrun-huaiin/third-ui 14.0.1 → 14.0.3

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.
@@ -3,6 +3,27 @@
3
3
  * 客户端专用的指纹生成和管理逻辑
4
4
  * 只能在浏览器环境中使用
5
5
  */
6
+ type FirstTouchData = {
7
+ landingUrl?: string;
8
+ landingPath?: string;
9
+ landingHost?: string;
10
+ externalReferrer?: string;
11
+ capturedAt?: string;
12
+ ref?: string;
13
+ utmSource?: string;
14
+ utmMedium?: string;
15
+ utmCampaign?: string;
16
+ utmTerm?: string;
17
+ utmContent?: string;
18
+ utmId?: string;
19
+ gclid?: string;
20
+ fbclid?: string;
21
+ msclkid?: string;
22
+ ttclid?: string;
23
+ twclid?: string;
24
+ liFatId?: string;
25
+ };
26
+ export declare function getOrCreateFirstTouchData(): FirstTouchData | null;
6
27
  /**
7
28
  * 生成基于真实浏览器特征的fingerprint ID
8
29
  * 使用 FingerprintJS 收集浏览器特征并生成唯一标识
@@ -37,3 +58,4 @@ export declare function useFingerprintHeaders(): () => Promise<Record<string, st
37
58
  * Create a fetch wrapper that automatically includes fingerprint headers
38
59
  */
39
60
  export declare function createFingerprintFetch(): (url: string | URL | Request, init?: RequestInit) => Promise<Response>;
61
+ export {};
@@ -9,6 +9,8 @@ var fingerprintShared = require('./fingerprint-shared.js');
9
9
  * 客户端专用的指纹生成和管理逻辑
10
10
  * 只能在浏览器环境中使用
11
11
  */
12
+ const FIRST_TOUCH_MAX_LENGTH = 2048;
13
+ const FIRST_TOUCH_COOKIE_DAYS = 30;
12
14
  /**
13
15
  * 检查浏览器存储(localStorage 和 cookie)中的指纹 ID
14
16
  * 返回有效的 ID 或 null
@@ -18,7 +20,7 @@ function checkStoredFingerprintId() {
18
20
  return null;
19
21
  }
20
22
  // 优先检查 localStorage
21
- const localStorageId = localStorage.getItem(fingerprintShared.FINGERPRINT_STORAGE_KEY);
23
+ const localStorageId = getLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY);
22
24
  if (localStorageId && fingerprintShared.isValidFingerprintId(localStorageId)) {
23
25
  return localStorageId;
24
26
  }
@@ -26,11 +28,129 @@ function checkStoredFingerprintId() {
26
28
  const cookieId = getCookieValue(fingerprintShared.FINGERPRINT_COOKIE_NAME);
27
29
  if (cookieId && fingerprintShared.isValidFingerprintId(cookieId)) {
28
30
  // 同步到 localStorage
29
- localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, cookieId);
31
+ setLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY, cookieId);
30
32
  return cookieId;
31
33
  }
32
34
  return null;
33
35
  }
36
+ function normalizeString(value, maxLength = FIRST_TOUCH_MAX_LENGTH) {
37
+ if (!value) {
38
+ return undefined;
39
+ }
40
+ const trimmed = value.trim();
41
+ if (!trimmed) {
42
+ return undefined;
43
+ }
44
+ return trimmed.length > maxLength ? trimmed.slice(0, maxLength) : trimmed;
45
+ }
46
+ function readFirstTouchFromStorage() {
47
+ if (typeof window === 'undefined') {
48
+ return null;
49
+ }
50
+ const localStorageValue = getLocalStorageValue(fingerprintShared.FINGERPRINT_FIRST_TOUCH_STORAGE_KEY);
51
+ if (localStorageValue) {
52
+ const parsed = parseFirstTouchValue(localStorageValue);
53
+ if (parsed) {
54
+ syncFirstTouchStorage(parsed);
55
+ return parsed;
56
+ }
57
+ }
58
+ const cookieValue = getCookieValue(fingerprintShared.FINGERPRINT_FIRST_TOUCH_COOKIE_NAME);
59
+ if (cookieValue) {
60
+ const parsed = parseFirstTouchValue(cookieValue);
61
+ if (parsed) {
62
+ syncFirstTouchStorage(parsed);
63
+ return parsed;
64
+ }
65
+ }
66
+ return null;
67
+ }
68
+ function parseFirstTouchValue(value) {
69
+ try {
70
+ const decoded = decodeURIComponent(value);
71
+ const parsed = JSON.parse(decoded);
72
+ return sanitizeFirstTouchData(parsed);
73
+ }
74
+ catch (_a) {
75
+ return null;
76
+ }
77
+ }
78
+ function sanitizeFirstTouchData(data) {
79
+ if (!data) {
80
+ return null;
81
+ }
82
+ const sanitized = {
83
+ landingUrl: normalizeString(data.landingUrl),
84
+ landingPath: normalizeString(data.landingPath, 512),
85
+ landingHost: normalizeString(data.landingHost, 255),
86
+ externalReferrer: normalizeString(data.externalReferrer),
87
+ capturedAt: normalizeString(data.capturedAt, 64),
88
+ ref: normalizeString(data.ref, 512),
89
+ utmSource: normalizeString(data.utmSource, 512),
90
+ utmMedium: normalizeString(data.utmMedium, 512),
91
+ utmCampaign: normalizeString(data.utmCampaign, 512),
92
+ utmTerm: normalizeString(data.utmTerm, 512),
93
+ utmContent: normalizeString(data.utmContent, 512),
94
+ utmId: normalizeString(data.utmId, 512),
95
+ gclid: normalizeString(data.gclid, 512),
96
+ fbclid: normalizeString(data.fbclid, 512),
97
+ msclkid: normalizeString(data.msclkid, 512),
98
+ ttclid: normalizeString(data.ttclid, 512),
99
+ twclid: normalizeString(data.twclid, 512),
100
+ liFatId: normalizeString(data.liFatId, 512),
101
+ };
102
+ return Object.values(sanitized).some(Boolean) ? sanitized : null;
103
+ }
104
+ function serializeFirstTouchData(data) {
105
+ return encodeURIComponent(JSON.stringify(data));
106
+ }
107
+ function syncFirstTouchStorage(data) {
108
+ if (typeof window === 'undefined') {
109
+ return;
110
+ }
111
+ const serialized = serializeFirstTouchData(data);
112
+ setLocalStorageValue(fingerprintShared.FINGERPRINT_FIRST_TOUCH_STORAGE_KEY, serialized);
113
+ setCookie(fingerprintShared.FINGERPRINT_FIRST_TOUCH_COOKIE_NAME, serialized, FIRST_TOUCH_COOKIE_DAYS);
114
+ }
115
+ function buildFirstTouchData() {
116
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
117
+ if (typeof window === 'undefined') {
118
+ return null;
119
+ }
120
+ const url = new URL(window.location.href);
121
+ const data = sanitizeFirstTouchData({
122
+ landingUrl: url.toString(),
123
+ landingPath: url.pathname,
124
+ landingHost: url.host,
125
+ externalReferrer: document.referrer || undefined,
126
+ capturedAt: new Date().toISOString(),
127
+ ref: (_a = url.searchParams.get('ref')) !== null && _a !== void 0 ? _a : undefined,
128
+ utmSource: (_b = url.searchParams.get('utm_source')) !== null && _b !== void 0 ? _b : undefined,
129
+ utmMedium: (_c = url.searchParams.get('utm_medium')) !== null && _c !== void 0 ? _c : undefined,
130
+ utmCampaign: (_d = url.searchParams.get('utm_campaign')) !== null && _d !== void 0 ? _d : undefined,
131
+ utmTerm: (_e = url.searchParams.get('utm_term')) !== null && _e !== void 0 ? _e : undefined,
132
+ utmContent: (_f = url.searchParams.get('utm_content')) !== null && _f !== void 0 ? _f : undefined,
133
+ utmId: (_g = url.searchParams.get('utm_id')) !== null && _g !== void 0 ? _g : undefined,
134
+ gclid: (_h = url.searchParams.get('gclid')) !== null && _h !== void 0 ? _h : undefined,
135
+ fbclid: (_j = url.searchParams.get('fbclid')) !== null && _j !== void 0 ? _j : undefined,
136
+ msclkid: (_k = url.searchParams.get('msclkid')) !== null && _k !== void 0 ? _k : undefined,
137
+ ttclid: (_l = url.searchParams.get('ttclid')) !== null && _l !== void 0 ? _l : undefined,
138
+ twclid: (_m = url.searchParams.get('twclid')) !== null && _m !== void 0 ? _m : undefined,
139
+ liFatId: (_o = url.searchParams.get('li_fat_id')) !== null && _o !== void 0 ? _o : undefined,
140
+ });
141
+ return data;
142
+ }
143
+ function getOrCreateFirstTouchData() {
144
+ const existing = readFirstTouchFromStorage();
145
+ if (existing) {
146
+ return existing;
147
+ }
148
+ const created = buildFirstTouchData();
149
+ if (created) {
150
+ syncFirstTouchStorage(created);
151
+ }
152
+ return created;
153
+ }
34
154
  /**
35
155
  * 生成基于真实浏览器特征的fingerprint ID
36
156
  * 使用 FingerprintJS 收集浏览器特征并生成唯一标识
@@ -52,7 +172,7 @@ function generateFingerprintId() {
52
172
  const result = yield fp.get();
53
173
  const fingerprintId = `fp_${result.visitorId}`;
54
174
  // 存储到 localStorage 和 cookie
55
- localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
175
+ setLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
56
176
  setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
57
177
  console.log('Generated new fingerprint ID:', fingerprintId);
58
178
  return fingerprintId;
@@ -61,7 +181,7 @@ function generateFingerprintId() {
61
181
  console.warn('Failed to generate fingerprint with FingerprintJS:', error);
62
182
  // 降级方案:生成基于时间戳和随机数的 ID
63
183
  const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
64
- localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, fallbackId);
184
+ setLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY, fallbackId);
65
185
  setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fallbackId, 365);
66
186
  console.log('Generated fallback fingerprint ID:', fallbackId);
67
187
  return fallbackId;
@@ -84,7 +204,7 @@ function setFingerprintId(fingerprintId) {
84
204
  if (!fingerprintShared.isValidFingerprintId(fingerprintId)) {
85
205
  throw new Error('Invalid fingerprint ID');
86
206
  }
87
- localStorage.setItem(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
207
+ setLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY, fingerprintId);
88
208
  setCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
89
209
  }
90
210
  /**
@@ -94,7 +214,7 @@ function clearFingerprintId() {
94
214
  if (typeof window === 'undefined') {
95
215
  throw new Error('clearFingerprintId can only be used in browser environment');
96
216
  }
97
- localStorage.removeItem(fingerprintShared.FINGERPRINT_STORAGE_KEY);
217
+ removeLocalStorageValue(fingerprintShared.FINGERPRINT_STORAGE_KEY);
98
218
  deleteCookie(fingerprintShared.FINGERPRINT_COOKIE_NAME);
99
219
  }
100
220
  /**
@@ -117,9 +237,14 @@ function getOrGenerateFingerprintId() {
117
237
  function createFingerprintHeaders() {
118
238
  return tslib_es6.__awaiter(this, void 0, void 0, function* () {
119
239
  const fingerprintId = yield getOrGenerateFingerprintId();
120
- return {
240
+ const headers = {
121
241
  [fingerprintShared.FINGERPRINT_HEADER_NAME]: fingerprintId,
122
242
  };
243
+ const firstTouch = getOrCreateFirstTouchData();
244
+ if (firstTouch) {
245
+ headers[fingerprintShared.FINGERPRINT_FIRST_TOUCH_HEADER] = serializeFirstTouchData(firstTouch);
246
+ }
247
+ return headers;
123
248
  });
124
249
  }
125
250
  /**
@@ -144,26 +269,74 @@ function getCookieValue(name) {
144
269
  if (typeof document === 'undefined') {
145
270
  return null;
146
271
  }
147
- const value = `; ${document.cookie}`;
148
- const parts = value.split(`; ${name}=`);
149
- if (parts.length === 2) {
150
- return ((_a = parts.pop()) === null || _a === void 0 ? void 0 : _a.split(';').shift()) || null;
272
+ try {
273
+ const value = `; ${document.cookie}`;
274
+ const parts = value.split(`; ${name}=`);
275
+ if (parts.length === 2) {
276
+ return ((_a = parts.pop()) === null || _a === void 0 ? void 0 : _a.split(';').shift()) || null;
277
+ }
278
+ return null;
279
+ }
280
+ catch (_b) {
281
+ return null;
151
282
  }
152
- return null;
153
283
  }
154
284
  function setCookie(name, value, days) {
155
285
  if (typeof document === 'undefined') {
156
286
  return;
157
287
  }
158
- const expires = new Date();
159
- expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
160
- document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
288
+ try {
289
+ const expires = new Date();
290
+ expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
291
+ document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
292
+ }
293
+ catch (_a) {
294
+ // Ignore storage failures so attribution never blocks page flow.
295
+ }
161
296
  }
162
297
  function deleteCookie(name) {
163
298
  if (typeof document === 'undefined') {
164
299
  return;
165
300
  }
166
- document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
301
+ try {
302
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
303
+ }
304
+ catch (_a) {
305
+ // Ignore storage failures so attribution never blocks page flow.
306
+ }
307
+ }
308
+ function getLocalStorageValue(key) {
309
+ if (typeof window === 'undefined') {
310
+ return null;
311
+ }
312
+ try {
313
+ return window.localStorage.getItem(key);
314
+ }
315
+ catch (_a) {
316
+ return null;
317
+ }
318
+ }
319
+ function setLocalStorageValue(key, value) {
320
+ if (typeof window === 'undefined') {
321
+ return;
322
+ }
323
+ try {
324
+ window.localStorage.setItem(key, value);
325
+ }
326
+ catch (_a) {
327
+ // Ignore storage failures so attribution never blocks page flow.
328
+ }
329
+ }
330
+ function removeLocalStorageValue(key) {
331
+ if (typeof window === 'undefined') {
332
+ return;
333
+ }
334
+ try {
335
+ window.localStorage.removeItem(key);
336
+ }
337
+ catch (_a) {
338
+ // Ignore storage failures so attribution never blocks page flow.
339
+ }
167
340
  }
168
341
 
169
342
  exports.clearFingerprintId = clearFingerprintId;
@@ -171,6 +344,7 @@ exports.createFingerprintFetch = createFingerprintFetch;
171
344
  exports.createFingerprintHeaders = createFingerprintHeaders;
172
345
  exports.generateFingerprintId = generateFingerprintId;
173
346
  exports.getFingerprintId = getFingerprintId;
347
+ exports.getOrCreateFirstTouchData = getOrCreateFirstTouchData;
174
348
  exports.getOrGenerateFingerprintId = getOrGenerateFingerprintId;
175
349
  exports.setFingerprintId = setFingerprintId;
176
350
  exports.useFingerprintHeaders = useFingerprintHeaders;
@@ -1,12 +1,14 @@
1
1
  import { __awaiter } from '../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
2
2
  import index from '../../node_modules/.pnpm/@fingerprintjs_fingerprintjs@5.1.0/node_modules/@fingerprintjs/fingerprintjs/dist/fp.esm.mjs';
3
- import { isValidFingerprintId, FINGERPRINT_STORAGE_KEY, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER } from './fingerprint-shared.mjs';
3
+ import { isValidFingerprintId, FINGERPRINT_FIRST_TOUCH_STORAGE_KEY, FINGERPRINT_FIRST_TOUCH_COOKIE_NAME, FINGERPRINT_STORAGE_KEY, FINGERPRINT_COOKIE_NAME, FINGERPRINT_FIRST_TOUCH_HEADER, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER } from './fingerprint-shared.mjs';
4
4
 
5
5
  /**
6
6
  * Fingerprint Client Utilities
7
7
  * 客户端专用的指纹生成和管理逻辑
8
8
  * 只能在浏览器环境中使用
9
9
  */
10
+ const FIRST_TOUCH_MAX_LENGTH = 2048;
11
+ const FIRST_TOUCH_COOKIE_DAYS = 30;
10
12
  /**
11
13
  * 检查浏览器存储(localStorage 和 cookie)中的指纹 ID
12
14
  * 返回有效的 ID 或 null
@@ -16,7 +18,7 @@ function checkStoredFingerprintId() {
16
18
  return null;
17
19
  }
18
20
  // 优先检查 localStorage
19
- const localStorageId = localStorage.getItem(FINGERPRINT_STORAGE_KEY);
21
+ const localStorageId = getLocalStorageValue(FINGERPRINT_STORAGE_KEY);
20
22
  if (localStorageId && isValidFingerprintId(localStorageId)) {
21
23
  return localStorageId;
22
24
  }
@@ -24,11 +26,129 @@ function checkStoredFingerprintId() {
24
26
  const cookieId = getCookieValue(FINGERPRINT_COOKIE_NAME);
25
27
  if (cookieId && isValidFingerprintId(cookieId)) {
26
28
  // 同步到 localStorage
27
- localStorage.setItem(FINGERPRINT_STORAGE_KEY, cookieId);
29
+ setLocalStorageValue(FINGERPRINT_STORAGE_KEY, cookieId);
28
30
  return cookieId;
29
31
  }
30
32
  return null;
31
33
  }
34
+ function normalizeString(value, maxLength = FIRST_TOUCH_MAX_LENGTH) {
35
+ if (!value) {
36
+ return undefined;
37
+ }
38
+ const trimmed = value.trim();
39
+ if (!trimmed) {
40
+ return undefined;
41
+ }
42
+ return trimmed.length > maxLength ? trimmed.slice(0, maxLength) : trimmed;
43
+ }
44
+ function readFirstTouchFromStorage() {
45
+ if (typeof window === 'undefined') {
46
+ return null;
47
+ }
48
+ const localStorageValue = getLocalStorageValue(FINGERPRINT_FIRST_TOUCH_STORAGE_KEY);
49
+ if (localStorageValue) {
50
+ const parsed = parseFirstTouchValue(localStorageValue);
51
+ if (parsed) {
52
+ syncFirstTouchStorage(parsed);
53
+ return parsed;
54
+ }
55
+ }
56
+ const cookieValue = getCookieValue(FINGERPRINT_FIRST_TOUCH_COOKIE_NAME);
57
+ if (cookieValue) {
58
+ const parsed = parseFirstTouchValue(cookieValue);
59
+ if (parsed) {
60
+ syncFirstTouchStorage(parsed);
61
+ return parsed;
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+ function parseFirstTouchValue(value) {
67
+ try {
68
+ const decoded = decodeURIComponent(value);
69
+ const parsed = JSON.parse(decoded);
70
+ return sanitizeFirstTouchData(parsed);
71
+ }
72
+ catch (_a) {
73
+ return null;
74
+ }
75
+ }
76
+ function sanitizeFirstTouchData(data) {
77
+ if (!data) {
78
+ return null;
79
+ }
80
+ const sanitized = {
81
+ landingUrl: normalizeString(data.landingUrl),
82
+ landingPath: normalizeString(data.landingPath, 512),
83
+ landingHost: normalizeString(data.landingHost, 255),
84
+ externalReferrer: normalizeString(data.externalReferrer),
85
+ capturedAt: normalizeString(data.capturedAt, 64),
86
+ ref: normalizeString(data.ref, 512),
87
+ utmSource: normalizeString(data.utmSource, 512),
88
+ utmMedium: normalizeString(data.utmMedium, 512),
89
+ utmCampaign: normalizeString(data.utmCampaign, 512),
90
+ utmTerm: normalizeString(data.utmTerm, 512),
91
+ utmContent: normalizeString(data.utmContent, 512),
92
+ utmId: normalizeString(data.utmId, 512),
93
+ gclid: normalizeString(data.gclid, 512),
94
+ fbclid: normalizeString(data.fbclid, 512),
95
+ msclkid: normalizeString(data.msclkid, 512),
96
+ ttclid: normalizeString(data.ttclid, 512),
97
+ twclid: normalizeString(data.twclid, 512),
98
+ liFatId: normalizeString(data.liFatId, 512),
99
+ };
100
+ return Object.values(sanitized).some(Boolean) ? sanitized : null;
101
+ }
102
+ function serializeFirstTouchData(data) {
103
+ return encodeURIComponent(JSON.stringify(data));
104
+ }
105
+ function syncFirstTouchStorage(data) {
106
+ if (typeof window === 'undefined') {
107
+ return;
108
+ }
109
+ const serialized = serializeFirstTouchData(data);
110
+ setLocalStorageValue(FINGERPRINT_FIRST_TOUCH_STORAGE_KEY, serialized);
111
+ setCookie(FINGERPRINT_FIRST_TOUCH_COOKIE_NAME, serialized, FIRST_TOUCH_COOKIE_DAYS);
112
+ }
113
+ function buildFirstTouchData() {
114
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
115
+ if (typeof window === 'undefined') {
116
+ return null;
117
+ }
118
+ const url = new URL(window.location.href);
119
+ const data = sanitizeFirstTouchData({
120
+ landingUrl: url.toString(),
121
+ landingPath: url.pathname,
122
+ landingHost: url.host,
123
+ externalReferrer: document.referrer || undefined,
124
+ capturedAt: new Date().toISOString(),
125
+ ref: (_a = url.searchParams.get('ref')) !== null && _a !== void 0 ? _a : undefined,
126
+ utmSource: (_b = url.searchParams.get('utm_source')) !== null && _b !== void 0 ? _b : undefined,
127
+ utmMedium: (_c = url.searchParams.get('utm_medium')) !== null && _c !== void 0 ? _c : undefined,
128
+ utmCampaign: (_d = url.searchParams.get('utm_campaign')) !== null && _d !== void 0 ? _d : undefined,
129
+ utmTerm: (_e = url.searchParams.get('utm_term')) !== null && _e !== void 0 ? _e : undefined,
130
+ utmContent: (_f = url.searchParams.get('utm_content')) !== null && _f !== void 0 ? _f : undefined,
131
+ utmId: (_g = url.searchParams.get('utm_id')) !== null && _g !== void 0 ? _g : undefined,
132
+ gclid: (_h = url.searchParams.get('gclid')) !== null && _h !== void 0 ? _h : undefined,
133
+ fbclid: (_j = url.searchParams.get('fbclid')) !== null && _j !== void 0 ? _j : undefined,
134
+ msclkid: (_k = url.searchParams.get('msclkid')) !== null && _k !== void 0 ? _k : undefined,
135
+ ttclid: (_l = url.searchParams.get('ttclid')) !== null && _l !== void 0 ? _l : undefined,
136
+ twclid: (_m = url.searchParams.get('twclid')) !== null && _m !== void 0 ? _m : undefined,
137
+ liFatId: (_o = url.searchParams.get('li_fat_id')) !== null && _o !== void 0 ? _o : undefined,
138
+ });
139
+ return data;
140
+ }
141
+ function getOrCreateFirstTouchData() {
142
+ const existing = readFirstTouchFromStorage();
143
+ if (existing) {
144
+ return existing;
145
+ }
146
+ const created = buildFirstTouchData();
147
+ if (created) {
148
+ syncFirstTouchStorage(created);
149
+ }
150
+ return created;
151
+ }
32
152
  /**
33
153
  * 生成基于真实浏览器特征的fingerprint ID
34
154
  * 使用 FingerprintJS 收集浏览器特征并生成唯一标识
@@ -50,7 +170,7 @@ function generateFingerprintId() {
50
170
  const result = yield fp.get();
51
171
  const fingerprintId = `fp_${result.visitorId}`;
52
172
  // 存储到 localStorage 和 cookie
53
- localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
173
+ setLocalStorageValue(FINGERPRINT_STORAGE_KEY, fingerprintId);
54
174
  setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
55
175
  console.log('Generated new fingerprint ID:', fingerprintId);
56
176
  return fingerprintId;
@@ -59,7 +179,7 @@ function generateFingerprintId() {
59
179
  console.warn('Failed to generate fingerprint with FingerprintJS:', error);
60
180
  // 降级方案:生成基于时间戳和随机数的 ID
61
181
  const fallbackId = `fp_fallback_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
62
- localStorage.setItem(FINGERPRINT_STORAGE_KEY, fallbackId);
182
+ setLocalStorageValue(FINGERPRINT_STORAGE_KEY, fallbackId);
63
183
  setCookie(FINGERPRINT_COOKIE_NAME, fallbackId, 365);
64
184
  console.log('Generated fallback fingerprint ID:', fallbackId);
65
185
  return fallbackId;
@@ -82,7 +202,7 @@ function setFingerprintId(fingerprintId) {
82
202
  if (!isValidFingerprintId(fingerprintId)) {
83
203
  throw new Error('Invalid fingerprint ID');
84
204
  }
85
- localStorage.setItem(FINGERPRINT_STORAGE_KEY, fingerprintId);
205
+ setLocalStorageValue(FINGERPRINT_STORAGE_KEY, fingerprintId);
86
206
  setCookie(FINGERPRINT_COOKIE_NAME, fingerprintId, 365);
87
207
  }
88
208
  /**
@@ -92,7 +212,7 @@ function clearFingerprintId() {
92
212
  if (typeof window === 'undefined') {
93
213
  throw new Error('clearFingerprintId can only be used in browser environment');
94
214
  }
95
- localStorage.removeItem(FINGERPRINT_STORAGE_KEY);
215
+ removeLocalStorageValue(FINGERPRINT_STORAGE_KEY);
96
216
  deleteCookie(FINGERPRINT_COOKIE_NAME);
97
217
  }
98
218
  /**
@@ -115,9 +235,14 @@ function getOrGenerateFingerprintId() {
115
235
  function createFingerprintHeaders() {
116
236
  return __awaiter(this, void 0, void 0, function* () {
117
237
  const fingerprintId = yield getOrGenerateFingerprintId();
118
- return {
238
+ const headers = {
119
239
  [FINGERPRINT_HEADER_NAME]: fingerprintId,
120
240
  };
241
+ const firstTouch = getOrCreateFirstTouchData();
242
+ if (firstTouch) {
243
+ headers[FINGERPRINT_FIRST_TOUCH_HEADER] = serializeFirstTouchData(firstTouch);
244
+ }
245
+ return headers;
121
246
  });
122
247
  }
123
248
  /**
@@ -142,26 +267,74 @@ function getCookieValue(name) {
142
267
  if (typeof document === 'undefined') {
143
268
  return null;
144
269
  }
145
- const value = `; ${document.cookie}`;
146
- const parts = value.split(`; ${name}=`);
147
- if (parts.length === 2) {
148
- return ((_a = parts.pop()) === null || _a === void 0 ? void 0 : _a.split(';').shift()) || null;
270
+ try {
271
+ const value = `; ${document.cookie}`;
272
+ const parts = value.split(`; ${name}=`);
273
+ if (parts.length === 2) {
274
+ return ((_a = parts.pop()) === null || _a === void 0 ? void 0 : _a.split(';').shift()) || null;
275
+ }
276
+ return null;
277
+ }
278
+ catch (_b) {
279
+ return null;
149
280
  }
150
- return null;
151
281
  }
152
282
  function setCookie(name, value, days) {
153
283
  if (typeof document === 'undefined') {
154
284
  return;
155
285
  }
156
- const expires = new Date();
157
- expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
158
- document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
286
+ try {
287
+ const expires = new Date();
288
+ expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
289
+ document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
290
+ }
291
+ catch (_a) {
292
+ // Ignore storage failures so attribution never blocks page flow.
293
+ }
159
294
  }
160
295
  function deleteCookie(name) {
161
296
  if (typeof document === 'undefined') {
162
297
  return;
163
298
  }
164
- document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
299
+ try {
300
+ document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
301
+ }
302
+ catch (_a) {
303
+ // Ignore storage failures so attribution never blocks page flow.
304
+ }
305
+ }
306
+ function getLocalStorageValue(key) {
307
+ if (typeof window === 'undefined') {
308
+ return null;
309
+ }
310
+ try {
311
+ return window.localStorage.getItem(key);
312
+ }
313
+ catch (_a) {
314
+ return null;
315
+ }
316
+ }
317
+ function setLocalStorageValue(key, value) {
318
+ if (typeof window === 'undefined') {
319
+ return;
320
+ }
321
+ try {
322
+ window.localStorage.setItem(key, value);
323
+ }
324
+ catch (_a) {
325
+ // Ignore storage failures so attribution never blocks page flow.
326
+ }
327
+ }
328
+ function removeLocalStorageValue(key) {
329
+ if (typeof window === 'undefined') {
330
+ return;
331
+ }
332
+ try {
333
+ window.localStorage.removeItem(key);
334
+ }
335
+ catch (_a) {
336
+ // Ignore storage failures so attribution never blocks page flow.
337
+ }
165
338
  }
166
339
 
167
- export { clearFingerprintId, createFingerprintFetch, createFingerprintHeaders, generateFingerprintId, getFingerprintId, getOrGenerateFingerprintId, setFingerprintId, useFingerprintHeaders };
340
+ export { clearFingerprintId, createFingerprintFetch, createFingerprintHeaders, generateFingerprintId, getFingerprintId, getOrCreateFirstTouchData, getOrGenerateFingerprintId, setFingerprintId, useFingerprintHeaders };
@@ -6,6 +6,9 @@ export declare const FINGERPRINT_STORAGE_KEY = "__x_fingerprint_id";
6
6
  export declare const FINGERPRINT_HEADER_NAME = "x-fingerprint-id-v8";
7
7
  export declare const FINGERPRINT_COOKIE_NAME = "__x_fingerprint_id";
8
8
  export declare const FINGERPRINT_SOURCE_REFER = "x-source-ref";
9
+ export declare const FINGERPRINT_FIRST_TOUCH_STORAGE_KEY = "__x_first_touch";
10
+ export declare const FINGERPRINT_FIRST_TOUCH_COOKIE_NAME = "__x_first_touch";
11
+ export declare const FINGERPRINT_FIRST_TOUCH_HEADER = "x-first-touch";
9
12
  /**
10
13
  * 验证fingerprint ID格式
11
14
  * 可以在客户端和服务端使用
@@ -15,4 +18,7 @@ export declare const FINGERPRINT_CONSTANTS: {
15
18
  readonly STORAGE_KEY: "__x_fingerprint_id";
16
19
  readonly HEADER_NAME: "x-fingerprint-id-v8";
17
20
  readonly COOKIE_NAME: "__x_fingerprint_id";
21
+ readonly FIRST_TOUCH_STORAGE_KEY: "__x_first_touch";
22
+ readonly FIRST_TOUCH_COOKIE_NAME: "__x_first_touch";
23
+ readonly FIRST_TOUCH_HEADER: "x-first-touch";
18
24
  };
@@ -9,6 +9,9 @@ const FINGERPRINT_STORAGE_KEY = '__x_fingerprint_id';
9
9
  const FINGERPRINT_HEADER_NAME = 'x-fingerprint-id-v8';
10
10
  const FINGERPRINT_COOKIE_NAME = '__x_fingerprint_id';
11
11
  const FINGERPRINT_SOURCE_REFER = 'x-source-ref';
12
+ const FINGERPRINT_FIRST_TOUCH_STORAGE_KEY = '__x_first_touch';
13
+ const FINGERPRINT_FIRST_TOUCH_COOKIE_NAME = '__x_first_touch';
14
+ const FINGERPRINT_FIRST_TOUCH_HEADER = 'x-first-touch';
12
15
  /**
13
16
  * 验证fingerprint ID格式
14
17
  * 可以在客户端和服务端使用
@@ -27,10 +30,16 @@ const FINGERPRINT_CONSTANTS = {
27
30
  STORAGE_KEY: FINGERPRINT_STORAGE_KEY,
28
31
  HEADER_NAME: FINGERPRINT_HEADER_NAME,
29
32
  COOKIE_NAME: FINGERPRINT_COOKIE_NAME,
33
+ FIRST_TOUCH_STORAGE_KEY: FINGERPRINT_FIRST_TOUCH_STORAGE_KEY,
34
+ FIRST_TOUCH_COOKIE_NAME: FINGERPRINT_FIRST_TOUCH_COOKIE_NAME,
35
+ FIRST_TOUCH_HEADER: FINGERPRINT_FIRST_TOUCH_HEADER,
30
36
  };
31
37
 
32
38
  exports.FINGERPRINT_CONSTANTS = FINGERPRINT_CONSTANTS;
33
39
  exports.FINGERPRINT_COOKIE_NAME = FINGERPRINT_COOKIE_NAME;
40
+ exports.FINGERPRINT_FIRST_TOUCH_COOKIE_NAME = FINGERPRINT_FIRST_TOUCH_COOKIE_NAME;
41
+ exports.FINGERPRINT_FIRST_TOUCH_HEADER = FINGERPRINT_FIRST_TOUCH_HEADER;
42
+ exports.FINGERPRINT_FIRST_TOUCH_STORAGE_KEY = FINGERPRINT_FIRST_TOUCH_STORAGE_KEY;
34
43
  exports.FINGERPRINT_HEADER_NAME = FINGERPRINT_HEADER_NAME;
35
44
  exports.FINGERPRINT_SOURCE_REFER = FINGERPRINT_SOURCE_REFER;
36
45
  exports.FINGERPRINT_STORAGE_KEY = FINGERPRINT_STORAGE_KEY;
@@ -7,6 +7,9 @@ const FINGERPRINT_STORAGE_KEY = '__x_fingerprint_id';
7
7
  const FINGERPRINT_HEADER_NAME = 'x-fingerprint-id-v8';
8
8
  const FINGERPRINT_COOKIE_NAME = '__x_fingerprint_id';
9
9
  const FINGERPRINT_SOURCE_REFER = 'x-source-ref';
10
+ const FINGERPRINT_FIRST_TOUCH_STORAGE_KEY = '__x_first_touch';
11
+ const FINGERPRINT_FIRST_TOUCH_COOKIE_NAME = '__x_first_touch';
12
+ const FINGERPRINT_FIRST_TOUCH_HEADER = 'x-first-touch';
10
13
  /**
11
14
  * 验证fingerprint ID格式
12
15
  * 可以在客户端和服务端使用
@@ -25,6 +28,9 @@ const FINGERPRINT_CONSTANTS = {
25
28
  STORAGE_KEY: FINGERPRINT_STORAGE_KEY,
26
29
  HEADER_NAME: FINGERPRINT_HEADER_NAME,
27
30
  COOKIE_NAME: FINGERPRINT_COOKIE_NAME,
31
+ FIRST_TOUCH_STORAGE_KEY: FINGERPRINT_FIRST_TOUCH_STORAGE_KEY,
32
+ FIRST_TOUCH_COOKIE_NAME: FINGERPRINT_FIRST_TOUCH_COOKIE_NAME,
33
+ FIRST_TOUCH_HEADER: FINGERPRINT_FIRST_TOUCH_HEADER,
28
34
  };
29
35
 
30
- export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER, FINGERPRINT_STORAGE_KEY, isValidFingerprintId };
36
+ export { FINGERPRINT_CONSTANTS, FINGERPRINT_COOKIE_NAME, FINGERPRINT_FIRST_TOUCH_COOKIE_NAME, FINGERPRINT_FIRST_TOUCH_HEADER, FINGERPRINT_FIRST_TOUCH_STORAGE_KEY, FINGERPRINT_HEADER_NAME, FINGERPRINT_SOURCE_REFER, FINGERPRINT_STORAGE_KEY, isValidFingerprintId };