coveo.analytics 2.30.56 → 2.32.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.
- package/README.md +37 -43
- package/dist/browser.mjs +513 -357
- package/dist/coveoua.browser.js +1 -1
- package/dist/coveoua.browser.js.map +1 -1
- package/dist/coveoua.debug.js +542 -359
- package/dist/coveoua.debug.js.map +1 -1
- package/dist/coveoua.js +1 -1
- package/dist/coveoua.js.map +1 -1
- package/dist/definitions/client/analytics.d.ts +3 -2
- package/dist/definitions/client/runtimeEnvironment.d.ts +1 -1
- package/dist/definitions/donottrack.d.ts +1 -0
- package/dist/definitions/react-native/index.d.ts +1 -2
- package/dist/definitions/version.d.ts +1 -1
- package/dist/library.cjs +15350 -3699
- package/dist/library.es.js +513 -357
- package/dist/library.js +15350 -3699
- package/dist/library.mjs +15350 -3699
- package/dist/react-native.es.js +634 -460
- package/modules/package.json +9 -9
- package/package.json +60 -91
- package/react-native/package.json +7 -7
- package/src/caseAssist/caseAssistActions.ts +51 -50
- package/src/caseAssist/caseAssistClient.spec.ts +328 -297
- package/src/caseAssist/caseAssistClient.ts +201 -185
- package/src/client/analytics.spec.ts +724 -703
- package/src/client/analytics.ts +677 -602
- package/src/client/analyticsBeaconClient.spec.ts +195 -188
- package/src/client/analyticsBeaconClient.ts +99 -88
- package/src/client/analyticsFetchClient.ts +77 -61
- package/src/client/analyticsRequestClient.ts +17 -17
- package/src/client/location.ts +3 -3
- package/src/client/measurementProtocolMapper.ts +54 -45
- package/src/client/measurementProtocolMapping/baseMeasurementProtocolMapper.ts +48 -44
- package/src/client/measurementProtocolMapping/commerceMeasurementProtocolMapper.ts +133 -121
- package/src/client/measurementProtocolMapping/serviceMeasurementProtocolMapper.ts +17 -17
- package/src/client/noopAnalytics.ts +80 -68
- package/src/client/runtimeEnvironment.ts +50 -41
- package/src/client/utils.spec.ts +112 -97
- package/src/client/utils.ts +39 -39
- package/src/cookieutils.spec.ts +59 -0
- package/src/cookieutils.ts +40 -39
- package/src/coveoua/browser.ts +14 -12
- package/src/coveoua/library.ts +4 -4
- package/src/coveoua/plugins.ts +36 -34
- package/src/coveoua/simpleanalytics.spec.ts +467 -452
- package/src/coveoua/simpleanalytics.ts +146 -140
- package/src/detector.ts +17 -17
- package/src/donottrack.spec.ts +199 -121
- package/src/donottrack.ts +31 -8
- package/src/events.ts +86 -79
- package/src/formatting/format-array-for-coveo-custom-data.spec.ts +13 -12
- package/src/formatting/format-array-for-coveo-custom-data.ts +18 -18
- package/src/formatting/format-omnibox-metadata.ts +16 -12
- package/src/history.spec.ts +197 -195
- package/src/history.ts +143 -133
- package/src/hook/addDefaultValues.ts +13 -8
- package/src/hook/enhanceViewEvent.ts +17 -17
- package/src/insight/insightClient.spec.ts +1848 -1717
- package/src/insight/insightClient.ts +866 -761
- package/src/insight/insightEvents.ts +57 -56
- package/src/plugins/BasePlugin.ts +125 -121
- package/src/plugins/ec.spec.ts +457 -429
- package/src/plugins/ec.ts +202 -199
- package/src/plugins/link.spec.ts +183 -159
- package/src/plugins/link.ts +88 -85
- package/src/plugins/svc.spec.ts +161 -155
- package/src/plugins/svc.ts +93 -91
- package/src/react-native/index.ts +8 -1
- package/src/react-native/react-native-runtime.ts +33 -33
- package/src/react-native/react-native-utils.ts +1 -1
- package/src/react-native/react-native.spec.ts +31 -21
- package/src/searchPage/searchPageClient.spec.ts +1944 -1794
- package/src/searchPage/searchPageClient.ts +1261 -1040
- package/src/searchPage/searchPageEvents.ts +524 -511
- package/src/storage.spec.ts +51 -51
- package/src/storage.ts +47 -47
- package/dist/definitions/bundle/browser-fetch.d.ts +0 -1
- package/dist/definitions/src/coveoua/browser.d.ts +0 -6
- package/dist/definitions/src/coveoua/headless.d.ts +0 -6
- package/dist/definitions/src/coveoua/library.d.ts +0 -17
- package/dist/definitions/src/coveoua/plugins.d.ts +0 -10
- package/dist/definitions/src/coveoua/simpleanalytics.d.ts +0 -33
- package/dist/definitions/src/react-native/index.d.ts +0 -3
- package/dist/definitions/src/react-native/react-native-runtime.d.ts +0 -19
package/src/client/utils.spec.ts
CHANGED
|
@@ -1,113 +1,128 @@
|
|
|
1
1
|
import {truncateUrl} from './utils';
|
|
2
2
|
|
|
3
3
|
describe('utils', () => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
describe('truncateUrl', () => {
|
|
5
|
+
// Note: to obtain a UTF-8 encoded escape sequence, run encodeUriComponent('<value>') in your browser console or NodeJS REPL
|
|
6
|
+
const URL_PLAIN =
|
|
7
|
+
'http://coveo.com/this/is/a/really/long/url/that/will/be/truncated?at=some&arbitrary=point';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
it.each([[8], [16], [32], [64], [128]])(
|
|
10
|
+
`truncateUrl('${URL_PLAIN}', %d) truncates to exactly that length`,
|
|
11
|
+
(limit) => {
|
|
12
|
+
expect(truncateUrl(URL_PLAIN, limit)).toBe(URL_PLAIN.substring(0, limit));
|
|
13
|
+
}
|
|
14
|
+
);
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/** Decoded: `'http://test/ ¿OKツ😅#fine'` */
|
|
17
|
+
const URL_WITH_ESCAPES = 'http://test/%20%C2%BFOK%E3%83%84%F0%9F%98%85#fine';
|
|
18
|
+
// Number of bytes in code-point: <1>< 2 > < 3 >< 4 >
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
it.each([[7], [22], [45], [46], [47], [48], [100]])(
|
|
21
|
+
`truncateUrl('${URL_WITH_ESCAPES}', %d) truncates to the exact limit outside of codepoints`,
|
|
22
|
+
(limit) => {
|
|
23
|
+
expect(truncateUrl(URL_WITH_ESCAPES, limit)).toBe(URL_WITH_ESCAPES.substring(0, limit));
|
|
24
|
+
}
|
|
25
|
+
);
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
it.each([
|
|
28
|
+
[12, 12],
|
|
29
|
+
[13, 12],
|
|
30
|
+
[14, 12],
|
|
31
|
+
[15, 15],
|
|
32
|
+
])(
|
|
33
|
+
`truncateUrl('${URL_WITH_ESCAPES}', %d) does not break up single-byte codepoints`,
|
|
34
|
+
(limit, expectedLength) => {
|
|
35
|
+
expect(truncateUrl(URL_WITH_ESCAPES, limit)).toBe(
|
|
36
|
+
URL_WITH_ESCAPES.substring(0, expectedLength)
|
|
36
37
|
);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
it.each([
|
|
42
|
+
[15, 15],
|
|
43
|
+
[16, 15],
|
|
44
|
+
[17, 15],
|
|
45
|
+
[18, 15],
|
|
46
|
+
[19, 15],
|
|
47
|
+
[20, 15],
|
|
48
|
+
[21, 21],
|
|
49
|
+
])(
|
|
50
|
+
`truncateUrl('${URL_WITH_ESCAPES}', %d) does not break up two-byte codepoints`,
|
|
51
|
+
(limit, expectedLength) => {
|
|
52
|
+
expect(truncateUrl(URL_WITH_ESCAPES, limit)).toBe(
|
|
53
|
+
URL_WITH_ESCAPES.substring(0, expectedLength)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
58
|
+
it.each([
|
|
59
|
+
[23, 23],
|
|
60
|
+
[24, 23],
|
|
61
|
+
[25, 23],
|
|
62
|
+
[26, 23],
|
|
63
|
+
[27, 23],
|
|
64
|
+
[28, 23],
|
|
65
|
+
[29, 23],
|
|
66
|
+
[30, 23],
|
|
67
|
+
[31, 23],
|
|
68
|
+
[32, 32],
|
|
69
|
+
])(
|
|
70
|
+
`truncateUrl('${URL_WITH_ESCAPES}', %d) does not break up three-byte codepoints`,
|
|
71
|
+
(limit, expectedLength) => {
|
|
72
|
+
expect(truncateUrl(URL_WITH_ESCAPES, limit)).toBe(
|
|
73
|
+
URL_WITH_ESCAPES.substring(0, expectedLength)
|
|
66
74
|
);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
67
77
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
it.each([
|
|
79
|
+
[32, 32],
|
|
80
|
+
[33, 32],
|
|
81
|
+
[34, 32],
|
|
82
|
+
[35, 32],
|
|
83
|
+
[36, 32],
|
|
84
|
+
[37, 32],
|
|
85
|
+
[38, 32],
|
|
86
|
+
[39, 32],
|
|
87
|
+
[40, 32],
|
|
88
|
+
[41, 32],
|
|
89
|
+
[42, 32],
|
|
90
|
+
[43, 32],
|
|
91
|
+
[44, 44],
|
|
92
|
+
])(
|
|
93
|
+
`truncateUrl('${URL_WITH_ESCAPES}', %d) does not break up four-byte codepoints`,
|
|
94
|
+
(limit, expectedLength) => {
|
|
95
|
+
expect(truncateUrl(URL_WITH_ESCAPES, limit)).toBe(
|
|
96
|
+
URL_WITH_ESCAPES.substring(0, expectedLength)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
);
|
|
85
100
|
|
|
86
|
-
|
|
101
|
+
const URL_WITH_INVALID_ESCAPES = 'http://test/%this%is%so%invalid';
|
|
87
102
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
);
|
|
110
|
-
},
|
|
103
|
+
it.each([
|
|
104
|
+
[12, 12],
|
|
105
|
+
[13, 12],
|
|
106
|
+
[14, 12],
|
|
107
|
+
[15, 15],
|
|
108
|
+
[16, 16],
|
|
109
|
+
[17, 17],
|
|
110
|
+
[18, 17],
|
|
111
|
+
[19, 17],
|
|
112
|
+
[20, 20],
|
|
113
|
+
[21, 20],
|
|
114
|
+
[22, 20],
|
|
115
|
+
[23, 23],
|
|
116
|
+
[24, 23],
|
|
117
|
+
[25, 23],
|
|
118
|
+
[26, 26],
|
|
119
|
+
])(
|
|
120
|
+
`truncateUrl('${URL_WITH_INVALID_ESCAPES}', %d) only checks for percent with invalid escapes`,
|
|
121
|
+
(limit, expectedLength) => {
|
|
122
|
+
expect(truncateUrl(URL_WITH_INVALID_ESCAPES, limit)).toBe(
|
|
123
|
+
URL_WITH_INVALID_ESCAPES.substring(0, expectedLength)
|
|
111
124
|
);
|
|
112
|
-
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
});
|
|
113
128
|
});
|
package/src/client/utils.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// see https://github.com/microsoft/TypeScript/pull/12253#issuecomment-393954723
|
|
3
3
|
export const keysOf = Object.keys as <T>(o: T) => Extract<keyof T, string>[];
|
|
4
4
|
export function isObject(o: any): boolean {
|
|
5
|
-
|
|
5
|
+
return o !== null && typeof o === 'object' && !Array.isArray(o);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -13,7 +13,7 @@ export function isObject(o: any): boolean {
|
|
|
13
13
|
* @returns The input, possibly coerced to a number.
|
|
14
14
|
*/
|
|
15
15
|
export function coerceToNumber(input: any): any {
|
|
16
|
-
|
|
16
|
+
return typeof input === 'string' && input != '' && !Number.isNaN(+input) ? +input : input;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -29,16 +29,16 @@ const UTF8_HEADER_3 = 0b1110_0000;
|
|
|
29
29
|
const UTF8_HEADER_4 = 0b1111_0000;
|
|
30
30
|
|
|
31
31
|
function utf8ByteCountFromFirstByte(firstByte: number): number {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
if ((firstByte & 0b1111_1000) === UTF8_HEADER_4) {
|
|
33
|
+
return 4;
|
|
34
|
+
}
|
|
35
|
+
if ((firstByte & UTF8_HEADER_4) === UTF8_HEADER_3) {
|
|
36
|
+
return 3;
|
|
37
|
+
}
|
|
38
|
+
if ((firstByte & UTF8_HEADER_3) === UTF8_HEADER_2) {
|
|
39
|
+
return 2;
|
|
40
|
+
}
|
|
41
|
+
return 1;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -49,34 +49,34 @@ function utf8ByteCountFromFirstByte(firstByte: number): number {
|
|
|
49
49
|
* @returns The URL, possibly truncated to a length near limit (at most 11 characters less than limit).
|
|
50
50
|
*/
|
|
51
51
|
export function truncateUrl(input: string, limit: number): string {
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
if (limit < 0 || input.length <= limit) {
|
|
53
|
+
return input;
|
|
54
|
+
}
|
|
55
|
+
// A valid escape sequence is a percent followed by 2 hexadecimal characters; check if we split one up.
|
|
56
|
+
let end = input.indexOf('%', limit - 2);
|
|
57
|
+
if (end < 0 || end > limit) {
|
|
58
|
+
end = limit;
|
|
59
|
+
} else {
|
|
60
|
+
limit = end;
|
|
61
|
+
}
|
|
62
|
+
// Check that truncating at end won't break up an UTF-8 multibyte sequence half-way,
|
|
63
|
+
// by peeking backwards to find the first byte of an UTF-8 sequence (if present).
|
|
64
|
+
while (end > 2 && input.charAt(end - 3) == '%') {
|
|
65
|
+
const peekByte = Number.parseInt(input.substring(end - 2, end), 16);
|
|
66
|
+
// Note: if parsing fails, NaN gets coerced to 0 by the bitwise and.
|
|
67
|
+
if ((peekByte & UTF8_HIGH_BIT) != UTF8_HIGH_BIT) {
|
|
68
|
+
break;
|
|
54
69
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (
|
|
70
|
+
end -= 3;
|
|
71
|
+
// Check if we reached the first byte by checking it is not a "follow byte": 10xx_xxxx.
|
|
72
|
+
if ((peekByte & UTF8_HEADER_2) != UTF8_HIGH_BIT) {
|
|
73
|
+
// If the full code point is there, keep it.
|
|
74
|
+
if (limit - end >= utf8ByteCountFromFirstByte(peekByte) * 3) {
|
|
58
75
|
end = limit;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Check that truncating at end won't break up an UTF-8 multibyte sequence half-way,
|
|
63
|
-
// by peeking backwards to find the first byte of an UTF-8 sequence (if present).
|
|
64
|
-
while (end > 2 && input.charAt(end - 3) == '%') {
|
|
65
|
-
const peekByte = Number.parseInt(input.substring(end - 2, end), 16);
|
|
66
|
-
// Note: if parsing fails, NaN gets coerced to 0 by the bitwise and.
|
|
67
|
-
if ((peekByte & UTF8_HIGH_BIT) != UTF8_HIGH_BIT) {
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
end -= 3;
|
|
71
|
-
// Check if we reached the first byte by checking it is not a "follow byte": 10xx_xxxx.
|
|
72
|
-
if ((peekByte & UTF8_HEADER_2) != UTF8_HIGH_BIT) {
|
|
73
|
-
// If the full code point is there, keep it.
|
|
74
|
-
if (limit - end >= utf8ByteCountFromFirstByte(peekByte) * 3) {
|
|
75
|
-
end = limit;
|
|
76
|
-
}
|
|
77
|
-
// Otherwise, end is already set at the correct point to truncate at (the start of the multibyte sequence).
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
76
|
+
}
|
|
77
|
+
// Otherwise, end is already set at the correct point to truncate at (the start of the multibyte sequence).
|
|
78
|
+
break;
|
|
80
79
|
}
|
|
81
|
-
|
|
80
|
+
}
|
|
81
|
+
return input.substring(0, end);
|
|
82
82
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {vi} from 'vitest';
|
|
2
|
+
import {Cookie} from './cookieutils';
|
|
3
|
+
|
|
4
|
+
describe('Cookie', () => {
|
|
5
|
+
const originalLocation = window.location;
|
|
6
|
+
|
|
7
|
+
const captureCookieWrite = (protocol: string, hostname: string) => {
|
|
8
|
+
Object.defineProperty(window, 'location', {
|
|
9
|
+
configurable: true,
|
|
10
|
+
value: {...originalLocation, protocol, hostname},
|
|
11
|
+
});
|
|
12
|
+
const writes: string[] = [];
|
|
13
|
+
vi.spyOn(document, 'cookie', 'set').mockImplementation((value: string) => {
|
|
14
|
+
writes.push(value);
|
|
15
|
+
});
|
|
16
|
+
return writes;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
vi.restoreAllMocks();
|
|
21
|
+
Object.defineProperty(window, 'location', {
|
|
22
|
+
configurable: true,
|
|
23
|
+
value: originalLocation,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('adds the Secure attribute when the page is served over https', () => {
|
|
28
|
+
const writes = captureCookieWrite('https:', 'localhost');
|
|
29
|
+
|
|
30
|
+
Cookie.set('testCookie', 'testValue');
|
|
31
|
+
|
|
32
|
+
expect(writes[0]).toBe('testCookie=testValue;path=/;SameSite=Lax;Secure');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('omits the Secure attribute when the page is served over http', () => {
|
|
36
|
+
const writes = captureCookieWrite('http:', 'localhost');
|
|
37
|
+
|
|
38
|
+
Cookie.set('testCookie', 'testValue');
|
|
39
|
+
|
|
40
|
+
expect(writes[0]).toBe('testCookie=testValue;path=/;SameSite=Lax');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('keeps the domain attribute alongside Secure over https', () => {
|
|
44
|
+
const writes = captureCookieWrite('https:', 'subdomain.example.com');
|
|
45
|
+
|
|
46
|
+
Cookie.set('testCookie', 'testValue');
|
|
47
|
+
|
|
48
|
+
expect(writes[0]).toBe('testCookie=testValue;domain=example.com;path=/;SameSite=Lax;Secure');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('keeps the expiration attribute alongside Secure over https', () => {
|
|
52
|
+
const writes = captureCookieWrite('https:', 'localhost');
|
|
53
|
+
|
|
54
|
+
Cookie.set('testCookie', 'testValue', 3600000);
|
|
55
|
+
|
|
56
|
+
expect(writes[0]).toContain('expires=');
|
|
57
|
+
expect(writes[0]).toContain(';path=/;SameSite=Lax;Secure');
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/cookieutils.ts
CHANGED
|
@@ -1,52 +1,53 @@
|
|
|
1
1
|
interface CookieDetails {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
name: string;
|
|
3
|
+
value: string;
|
|
4
|
+
expirationDate?: Date;
|
|
5
|
+
domain?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
// Code originally modified from : https://developers.livechatinc.com/blog/setting-cookies-to-subdomains-in-javascript/
|
|
9
9
|
export class Cookie {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
}
|
|
10
|
+
static set(name: string, value: string, expire?: number) {
|
|
11
|
+
var domain: string, expirationDate: Date | undefined, domainParts: string[], host: string;
|
|
12
|
+
if (expire) {
|
|
13
|
+
expirationDate = new Date();
|
|
14
|
+
expirationDate.setTime(expirationDate.getTime() + expire);
|
|
26
15
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
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);
|
|
39
25
|
}
|
|
26
|
+
}
|
|
40
27
|
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
static get(name: string) {
|
|
29
|
+
var cookiePrefix = name + '=';
|
|
30
|
+
var cookieArray = document.cookie.split(';');
|
|
31
|
+
for (var i = 0; i < cookieArray.length; i++) {
|
|
32
|
+
var cookie = cookieArray[i];
|
|
33
|
+
cookie = cookie.replace(/^\s+/, ''); //strip whitespace from front of cookie only
|
|
34
|
+
if (cookie.lastIndexOf(cookiePrefix, 0) === 0) {
|
|
35
|
+
return cookie.substring(cookiePrefix.length, cookie.length);
|
|
36
|
+
}
|
|
43
37
|
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static erase(name: string) {
|
|
42
|
+
Cookie.set(name, '', -1);
|
|
43
|
+
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function writeCookie(name: string, value: string, expirationDate?: Date, domain?: string) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
document.cookie =
|
|
48
|
+
`${name}=${value}` +
|
|
49
|
+
(expirationDate ? `;expires=${expirationDate.toUTCString()}` : '') +
|
|
50
|
+
(domain ? `;domain=${domain}` : '') +
|
|
51
|
+
';path=/;SameSite=Lax' +
|
|
52
|
+
(window.location.protocol === 'https:' ? ';Secure' : '');
|
|
52
53
|
}
|
package/src/coveoua/browser.ts
CHANGED
|
@@ -5,23 +5,23 @@ declare const self: any;
|
|
|
5
5
|
|
|
6
6
|
const promise = (window as any)['Promise'];
|
|
7
7
|
if (!(promise instanceof Function) && !global) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
console.error(
|
|
9
|
+
`This script uses window.Promise which is not supported in your browser. Consider adding a polyfill like "es6-promise".`
|
|
10
|
+
);
|
|
11
11
|
}
|
|
12
12
|
const fetch = (window as any)['fetch'];
|
|
13
13
|
if (!(fetch instanceof Function) && !global) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
console.error(
|
|
15
|
+
`This script uses window.fetch which is not supported in your browser. Consider adding a polyfill like "fetch".`
|
|
16
|
+
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// CoveoUAGlobal is the interface for the global function which also has a
|
|
20
20
|
// queue `q` of unexecuted parameters
|
|
21
21
|
export interface CoveoUAGlobal {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
(action: string, ...params: any[]): void;
|
|
23
|
+
// CoveoAnalytics.q is the queue of last called actions before lib was included
|
|
24
|
+
q?: [string, any[]][];
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// On load of this script we get the global object `coveoua` (which would be)
|
|
@@ -36,9 +36,11 @@ self.coveoanalytics = analytics;
|
|
|
36
36
|
// On normal execution this library should be loaded after the snippet execution
|
|
37
37
|
// so we will execute the actions in the `q` array
|
|
38
38
|
if (coveoua.q) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const initEvents = coveoua.q.filter((args: [string, any[]]) => args[0] === 'init');
|
|
40
|
+
const otherEvents = coveoua.q.filter((args: [string, any[]]) => args[0] !== 'init');
|
|
41
|
+
[...initEvents, ...otherEvents].forEach((args: [string, any[]]) =>
|
|
42
|
+
handleOneAnalyticsEvent.apply(void 0, args)
|
|
43
|
+
);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
export default self.coveoua;
|
package/src/coveoua/library.ts
CHANGED
|
@@ -8,10 +8,10 @@ export {PreprocessAnalyticsRequest} from '../client/analyticsRequestClient';
|
|
|
8
8
|
export {IRuntimeEnvironment} from '../client/runtimeEnvironment';
|
|
9
9
|
export {CoveoUA, getCurrentClient, handleOneAnalyticsEvent} from './simpleanalytics';
|
|
10
10
|
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
CoveoSearchPageClient,
|
|
12
|
+
SearchPageClientProvider,
|
|
13
|
+
EventDescription,
|
|
14
|
+
EventBuilder,
|
|
15
15
|
} from '../searchPage/searchPageClient';
|
|
16
16
|
export {CaseAssistClient, CaseAssistClientProvider} from '../caseAssist/caseAssistClient';
|
|
17
17
|
export {CoveoInsightClient, InsightClientProvider} from '../insight/insightClient';
|
package/src/coveoua/plugins.ts
CHANGED
|
@@ -4,44 +4,46 @@ import {Link} from '../plugins/link';
|
|
|
4
4
|
import {SVC} from '../plugins/svc';
|
|
5
5
|
|
|
6
6
|
export class Plugins {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
public static readonly DefaultPlugins: string[] = [EC.Id, SVC.Id, Link.Id];
|
|
8
|
+
private registeredPluginsMap: Record<string, PluginClass> = {
|
|
9
|
+
[EC.Id]: EC,
|
|
10
|
+
[SVC.Id]: SVC,
|
|
11
|
+
[Link.Id]: Link,
|
|
12
|
+
};
|
|
13
|
+
private requiredPlugins: Record<string, BasePlugin> = {};
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
this.requiredPlugins[name] = new (pluginClass as any)(options);
|
|
15
|
+
require(name: string, options: PluginOptions): void {
|
|
16
|
+
const pluginClass = this.registeredPluginsMap[name];
|
|
17
|
+
if (!pluginClass) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`No plugin named "${name}" is currently registered. If you use a custom plugin, use 'provide' first.`
|
|
20
|
+
);
|
|
23
21
|
}
|
|
22
|
+
this.requiredPlugins[name] = new (pluginClass as any)(options);
|
|
23
|
+
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
provide(name: string, plugin: PluginClass) {
|
|
26
|
+
this.registeredPluginsMap[name] = plugin;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
clearRequired(): void {
|
|
30
|
+
this.requiredPlugins = {};
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
execute(name: string, fn: string, ...args: any[]): any {
|
|
34
|
+
const plugin = this.requiredPlugins[name] as Plugin;
|
|
35
|
+
if (!plugin) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`The plugin "${name}" is not required. Check that you required it on initialization.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
const actionFunction = plugin.getApi(fn);
|
|
41
|
+
if (!actionFunction) {
|
|
42
|
+
throw new Error(`The function "${fn}" does not exist on the plugin "${name}".`);
|
|
43
|
+
}
|
|
44
|
+
if (typeof actionFunction !== 'function') {
|
|
45
|
+
throw new Error(`"${fn}" of the plugin "${name}" is not a function.`);
|
|
46
46
|
}
|
|
47
|
+
return actionFunction.apply(plugin, args);
|
|
48
|
+
}
|
|
47
49
|
}
|