coveo.analytics 2.33.0 → 2.33.1

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.
@@ -342,20 +342,12 @@ const addDefaultValues = (eventType, payload) => {
342
342
 
343
343
  class Cookie {
344
344
  static set(name, value, expire) {
345
- var domain, expirationDate, domainParts, host;
345
+ let expirationDate;
346
346
  if (expire) {
347
347
  expirationDate = new Date();
348
348
  expirationDate.setTime(expirationDate.getTime() + expire);
349
349
  }
350
- host = window.location.hostname;
351
- if (host.indexOf('.') === -1) {
352
- writeCookie(name, value, expirationDate);
353
- }
354
- else {
355
- domainParts = host.split('.');
356
- domain = domainParts[domainParts.length - 2] + '.' + domainParts[domainParts.length - 1];
357
- writeCookie(name, value, expirationDate, domain);
358
- }
350
+ writeCookie(name, value, expirationDate, getCookieDomain(window.location.hostname));
359
351
  }
360
352
  static get(name) {
361
353
  var cookiePrefix = name + '=';
@@ -373,6 +365,35 @@ class Cookie {
373
365
  Cookie.set(name, '', -1);
374
366
  }
375
367
  }
368
+ function getCookieDomain(host) {
369
+ if (host.indexOf('.') === -1) {
370
+ return undefined;
371
+ }
372
+ const domainParts = host.split('.');
373
+ for (let domainLength = 2; domainLength <= domainParts.length; domainLength++) {
374
+ const domain = domainParts.slice(-domainLength).join('.');
375
+ if (supportsCookieDomain(domain)) {
376
+ return domain;
377
+ }
378
+ }
379
+ return undefined;
380
+ }
381
+ function supportsCookieDomain(domain) {
382
+ const name = `__coveo_cookie_domain_test_${Math.random().toString(36).substring(2)}`;
383
+ try {
384
+ writeCookie(name, '1', undefined, domain);
385
+ return Cookie.get(name) === '1';
386
+ }
387
+ catch (_a) {
388
+ return false;
389
+ }
390
+ finally {
391
+ try {
392
+ writeCookie(name, '', new Date(0), domain);
393
+ }
394
+ catch (_b) { }
395
+ }
396
+ }
376
397
  function writeCookie(name, value, expirationDate, domain) {
377
398
  document.cookie =
378
399
  `${name}=${value}` +
@@ -596,7 +617,7 @@ const addPageViewToHistory = (pageViewValue) => __awaiter(void 0, void 0, void 0
596
617
  yield store.addElementAsync(historyElement);
597
618
  });
598
619
 
599
- const libVersion = "2.33.0";
620
+ const libVersion = "2.33.1";
600
621
 
601
622
  const getFormattedLocation = (location) => `${location.protocol}//${location.hostname}${location.pathname.indexOf('/') === 0 ? location.pathname : `/${location.pathname}`}${location.search}`;
602
623
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coveo.analytics",
3
- "version": "2.33.0",
3
+ "version": "2.33.1",
4
4
  "description": "📈 Coveo analytics client (node and browser compatible) ",
5
5
  "license": "MIT",
6
6
  "author": "Coveo",
@@ -28,8 +28,8 @@
28
28
  "browser": "dist/coveoua.browser.js",
29
29
  "types": "dist/definitions/coveoua/library.d.ts",
30
30
  "dependencies": {
31
- "cross-fetch": "3.2.0",
32
- "uuid": "14.0.1"
31
+ "cross-fetch": "4.1.0",
32
+ "uuid": "14.0.2"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@rollup/plugin-alias": "5.1.1",
@@ -39,18 +39,18 @@
39
39
  "@rollup/plugin-replace": "6.0.3",
40
40
  "@rollup/plugin-terser": "1.0.0",
41
41
  "@rollup/plugin-typescript": "12.3.0",
42
- "@types/node": "24.13.3",
42
+ "@types/node": "24.13.6",
43
43
  "fetch-mock": "9.11.0",
44
- "jsdom": "28.1.0",
44
+ "jsdom": "30.1.1",
45
45
  "node-fetch": "2.7.0",
46
- "publint": "0.3.22",
46
+ "publint": "0.3.24",
47
47
  "react-native-get-random-values": "1.11.0",
48
- "rollup": "4.62.4",
48
+ "rollup": "4.63.4",
49
49
  "rollup-plugin-copy": "3.5.0",
50
50
  "rollup-plugin-serve": "1.1.1",
51
51
  "tslib": "2.8.1",
52
52
  "typescript": "6.0.3",
53
- "vitest": "4.1.10"
53
+ "vitest": "4.1.11"
54
54
  },
55
55
  "engines": {
56
56
  "node": "^22.11.0 || ^24.11.0"
@@ -4,18 +4,48 @@ import {Cookie} from './cookieutils';
4
4
  describe('Cookie', () => {
5
5
  const originalLocation = window.location;
6
6
 
7
- const captureCookieWrite = (protocol: string, hostname: string) => {
7
+ const captureCookieWrite = (
8
+ protocol: string,
9
+ hostname: string,
10
+ validDomains = ['example.com'],
11
+ throwingDomains: string[] = []
12
+ ) => {
8
13
  Object.defineProperty(window, 'location', {
9
14
  configurable: true,
10
15
  value: {...originalLocation, protocol, hostname},
11
16
  });
17
+ const cookies = new Map<string, string>();
12
18
  const writes: string[] = [];
13
- vi.spyOn(document, 'cookie', 'set').mockImplementation((value: string) => {
14
- writes.push(value);
19
+ vi.spyOn(document, 'cookie', 'get').mockImplementation(() =>
20
+ [...cookies.entries()].map(([name, value]) => `${name}=${value}`).join('; ')
21
+ );
22
+ vi.spyOn(document, 'cookie', 'set').mockImplementation((cookie: string) => {
23
+ writes.push(cookie);
24
+ const [nameValue, ...attributes] = cookie.split(';');
25
+ const [name, value] = nameValue.split('=');
26
+ const domain = attributes
27
+ .map((attribute) => attribute.trim())
28
+ .find((attribute) => attribute.startsWith('domain='))
29
+ ?.substring('domain='.length);
30
+
31
+ if (domain && throwingDomains.includes(domain)) {
32
+ throw new DOMException('Cookie domain is forbidden', 'SecurityError');
33
+ }
34
+
35
+ if (!domain || validDomains.includes(domain)) {
36
+ if (value) {
37
+ cookies.set(name, value);
38
+ } else {
39
+ cookies.delete(name);
40
+ }
41
+ }
15
42
  });
16
43
  return writes;
17
44
  };
18
45
 
46
+ const getCookieWrite = (writes: string[], name: string) =>
47
+ writes.find((write) => write.startsWith(`${name}=`));
48
+
19
49
  afterEach(() => {
20
50
  vi.restoreAllMocks();
21
51
  Object.defineProperty(window, 'location', {
@@ -29,7 +59,9 @@ describe('Cookie', () => {
29
59
 
30
60
  Cookie.set('testCookie', 'testValue');
31
61
 
32
- expect(writes[0]).toBe('testCookie=testValue;path=/;SameSite=Lax;Secure');
62
+ expect(getCookieWrite(writes, 'testCookie')).toBe(
63
+ 'testCookie=testValue;path=/;SameSite=Lax;Secure'
64
+ );
33
65
  });
34
66
 
35
67
  it('omits the Secure attribute when the page is served over http', () => {
@@ -37,7 +69,7 @@ describe('Cookie', () => {
37
69
 
38
70
  Cookie.set('testCookie', 'testValue');
39
71
 
40
- expect(writes[0]).toBe('testCookie=testValue;path=/;SameSite=Lax');
72
+ expect(getCookieWrite(writes, 'testCookie')).toBe('testCookie=testValue;path=/;SameSite=Lax');
41
73
  });
42
74
 
43
75
  it('keeps the domain attribute alongside Secure over https', () => {
@@ -45,7 +77,29 @@ describe('Cookie', () => {
45
77
 
46
78
  Cookie.set('testCookie', 'testValue');
47
79
 
48
- expect(writes[0]).toBe('testCookie=testValue;domain=example.com;path=/;SameSite=Lax;Secure');
80
+ expect(getCookieWrite(writes, 'testCookie')).toBe(
81
+ 'testCookie=testValue;domain=example.com;path=/;SameSite=Lax;Secure'
82
+ );
83
+ });
84
+
85
+ it('uses the first browser-accepted domain after a multi-label public suffix', () => {
86
+ const writes = captureCookieWrite('https:', 'www.example.co.uk', ['example.co.uk']);
87
+
88
+ Cookie.set('testCookie', 'testValue');
89
+
90
+ expect(writes).toEqual(expect.arrayContaining([expect.stringContaining('domain=co.uk')]));
91
+ expect(getCookieWrite(writes, 'testCookie')).toBe(
92
+ 'testCookie=testValue;domain=example.co.uk;path=/;SameSite=Lax;Secure'
93
+ );
94
+ });
95
+
96
+ it('continues after a public-suffix cookie write throws', () => {
97
+ const writes = captureCookieWrite('https:', 'www.example.co.uk', ['example.co.uk'], ['co.uk']);
98
+
99
+ expect(() => Cookie.set('testCookie', 'testValue')).not.toThrow();
100
+ expect(getCookieWrite(writes, 'testCookie')).toBe(
101
+ 'testCookie=testValue;domain=example.co.uk;path=/;SameSite=Lax;Secure'
102
+ );
49
103
  });
50
104
 
51
105
  it('keeps the expiration attribute alongside Secure over https', () => {
@@ -53,7 +107,8 @@ describe('Cookie', () => {
53
107
 
54
108
  Cookie.set('testCookie', 'testValue', 3600000);
55
109
 
56
- expect(writes[0]).toContain('expires=');
57
- expect(writes[0]).toContain(';path=/;SameSite=Lax;Secure');
110
+ const write = getCookieWrite(writes, 'testCookie');
111
+ expect(write).toContain('expires=');
112
+ expect(write).toContain(';path=/;SameSite=Lax;Secure');
58
113
  });
59
114
  });
@@ -8,21 +8,12 @@ interface CookieDetails {
8
8
  // Code originally modified from : https://developers.livechatinc.com/blog/setting-cookies-to-subdomains-in-javascript/
9
9
  export class Cookie {
10
10
  static set(name: string, value: string, expire?: number) {
11
- var domain: string, expirationDate: Date | undefined, domainParts: string[], host: string;
11
+ let expirationDate: Date | undefined;
12
12
  if (expire) {
13
13
  expirationDate = new Date();
14
14
  expirationDate.setTime(expirationDate.getTime() + expire);
15
15
  }
16
- host = window.location.hostname;
17
- if (host.indexOf('.') === -1) {
18
- // no "." in a domain - single domain name, it's localhost or something similar
19
- writeCookie(name, value, expirationDate);
20
- } else {
21
- domainParts = host.split('.');
22
- // we always have at least 2 domain parts
23
- domain = domainParts[domainParts.length - 2] + '.' + domainParts[domainParts.length - 1];
24
- writeCookie(name, value, expirationDate, domain);
25
- }
16
+ writeCookie(name, value, expirationDate, getCookieDomain(window.location.hostname));
26
17
  }
27
18
 
28
19
  static get(name: string) {
@@ -43,6 +34,36 @@ export class Cookie {
43
34
  }
44
35
  }
45
36
 
37
+ function getCookieDomain(host: string) {
38
+ if (host.indexOf('.') === -1) {
39
+ return undefined;
40
+ }
41
+
42
+ const domainParts = host.split('.');
43
+ for (let domainLength = 2; domainLength <= domainParts.length; domainLength++) {
44
+ const domain = domainParts.slice(-domainLength).join('.');
45
+ if (supportsCookieDomain(domain)) {
46
+ return domain;
47
+ }
48
+ }
49
+
50
+ return undefined;
51
+ }
52
+
53
+ function supportsCookieDomain(domain: string) {
54
+ const name = `__coveo_cookie_domain_test_${Math.random().toString(36).substring(2)}`;
55
+ try {
56
+ writeCookie(name, '1', undefined, domain);
57
+ return Cookie.get(name) === '1';
58
+ } catch {
59
+ return false;
60
+ } finally {
61
+ try {
62
+ writeCookie(name, '', new Date(0), domain);
63
+ } catch {}
64
+ }
65
+ }
66
+
46
67
  function writeCookie(name: string, value: string, expirationDate?: Date, domain?: string) {
47
68
  document.cookie =
48
69
  `${name}=${value}` +