coveo.analytics 2.25.3 → 2.26.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.
- package/README.md +31 -0
- package/dist/coveoua.browser.js +1 -1
- package/dist/coveoua.browser.js.map +1 -1
- package/dist/coveoua.debug.js +291 -105
- 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 +4 -0
- package/dist/definitions/coveoua/plugins.d.ts +2 -6
- package/dist/definitions/coveoua/simpleanalytics.d.ts +1 -1
- package/dist/definitions/plugins/BasePlugin.d.ts +8 -3
- package/dist/definitions/plugins/ec.d.ts +1 -0
- package/dist/definitions/plugins/link.d.ts +21 -0
- package/dist/definitions/plugins/svc.d.ts +1 -0
- package/dist/definitions/src/coveoua/plugins.d.ts +2 -6
- package/dist/definitions/src/coveoua/simpleanalytics.d.ts +1 -1
- package/dist/definitions/src/plugins/ec.d.ts +1 -0
- package/dist/definitions/version.d.ts +1 -1
- package/dist/library.es.js +233 -88
- package/dist/library.js +294 -108
- package/dist/react-native.es.js +238 -93
- package/package.json +1 -1
- package/src/client/analytics.spec.ts +122 -0
- package/src/client/analytics.ts +33 -1
- package/src/coveoua/plugins.ts +7 -8
- package/src/coveoua/simpleanalytics.spec.ts +15 -10
- package/src/coveoua/simpleanalytics.ts +2 -2
- package/src/plugins/BasePlugin.ts +21 -7
- package/src/plugins/ec.ts +13 -0
- package/src/plugins/link.spec.ts +171 -0
- package/src/plugins/link.ts +109 -0
- package/src/plugins/svc.ts +11 -0
- package/dist/definitions/src/client/location.d.ts +0 -1
|
@@ -19,10 +19,19 @@ class TestPluginWithSpy extends TestPlugin {
|
|
|
19
19
|
super({client, uuidGenerator});
|
|
20
20
|
TestPluginWithSpy.spy = jest.fn();
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
public getApi(name: string): Function | null {
|
|
24
|
+
switch (name) {
|
|
25
|
+
case 'testMethod':
|
|
26
|
+
return this.testMethod;
|
|
27
|
+
default:
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
testMethod(...args: any[]) {
|
|
23
33
|
TestPluginWithSpy.spy(args);
|
|
24
34
|
}
|
|
25
|
-
someProperty: string = 'foo';
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
describe('simpleanalytics', () => {
|
|
@@ -122,21 +131,24 @@ describe('simpleanalytics', () => {
|
|
|
122
131
|
expect(fetchMock.lastUrl()).toMatch(/^https:\/\/someendpoint\.com/);
|
|
123
132
|
});
|
|
124
133
|
|
|
125
|
-
it('uses EC and
|
|
134
|
+
it('uses EC, SVC and Link plugins by default', () => {
|
|
126
135
|
coveoua('init', 'SOME TOKEN');
|
|
127
136
|
expect(() => coveoua('callPlugin', 'ec', 'nosuchfunction')).toThrow(/does not exist/);
|
|
128
137
|
expect(() => coveoua('callPlugin', 'svc', 'nosuchfunction')).toThrow(/does not exist/);
|
|
138
|
+
expect(() => coveoua('callPlugin', 'link', 'nosuchfunction')).toThrow(/does not exist/);
|
|
129
139
|
});
|
|
130
140
|
|
|
131
141
|
it('can accept no plugins', () => {
|
|
132
142
|
coveoua('init', 'SOME TOKEN', {plugins: []});
|
|
133
143
|
expect(() => coveoua('callPlugin', 'ec', 'nosuchfunction')).toThrow(/is not required/);
|
|
134
144
|
expect(() => coveoua('callPlugin', 'svc', 'nosuchfunction')).toThrow(/is not required/);
|
|
145
|
+
expect(() => coveoua('callPlugin', 'link', 'nosuchfunction')).toThrow(/is not required/);
|
|
135
146
|
});
|
|
136
147
|
|
|
137
148
|
it('can accept one plugin', () => {
|
|
138
149
|
coveoua('init', 'SOME TOKEN', {plugins: ['svc']});
|
|
139
150
|
expect(() => coveoua('callPlugin', 'ec', 'nosuchfunction')).toThrow(/is not required/);
|
|
151
|
+
expect(() => coveoua('callPlugin', 'link', 'nosuchfunction')).toThrow(/is not required/);
|
|
140
152
|
expect(() => coveoua('callPlugin', 'svc', 'nosuchfunction')).toThrow(/does not exist/);
|
|
141
153
|
});
|
|
142
154
|
|
|
@@ -151,7 +163,7 @@ describe('simpleanalytics', () => {
|
|
|
151
163
|
expect(() => coveoua('initForProxy')).toThrow(`You must pass your endpoint when you call 'initForProxy'`);
|
|
152
164
|
});
|
|
153
165
|
|
|
154
|
-
it(`throw if the initForProxy receive an endpoint that
|
|
166
|
+
it(`throw if the initForProxy receive an endpoint that is not a string`, () => {
|
|
155
167
|
expect(() => coveoua('initForProxy', {})).toThrow(
|
|
156
168
|
`You must pass a string as the endpoint parameter when you call 'initForProxy'`
|
|
157
169
|
);
|
|
@@ -404,13 +416,6 @@ describe('simpleanalytics', () => {
|
|
|
404
416
|
|
|
405
417
|
expect(() => coveoua('callPlugin', 'svc', 'fooBarBaz')).toThrow(/does not exist/);
|
|
406
418
|
});
|
|
407
|
-
|
|
408
|
-
it('throws when a namespaced action is called and that this action is not a function on the plugin', () => {
|
|
409
|
-
coveoua('provide', 'test', TestPluginWithSpy);
|
|
410
|
-
|
|
411
|
-
coveoua('init', 'SOME TOKEN', {plugins: ['test']});
|
|
412
|
-
expect(() => coveoua('callPlugin', 'test', 'someProperty')).toThrow(/is not a function/);
|
|
413
|
-
});
|
|
414
419
|
});
|
|
415
420
|
|
|
416
421
|
describe('require', () => {
|
|
@@ -129,8 +129,8 @@ export class CoveoUA {
|
|
|
129
129
|
this.plugins.require(name, {...options, client: this.client});
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
callPlugin(pluginName: string, fn: string, ...args: any):
|
|
133
|
-
this.plugins.execute(pluginName, fn, ...args);
|
|
132
|
+
callPlugin(pluginName: string, fn: string, ...args: any): any {
|
|
133
|
+
return this.plugins.execute(pluginName, fn, ...args);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
reset() {
|
|
@@ -7,8 +7,7 @@ type PluginWithId = {
|
|
|
7
7
|
readonly Id: string;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export type PluginClass = typeof
|
|
11
|
-
|
|
10
|
+
export type PluginClass = typeof Plugin & PluginWithId;
|
|
12
11
|
export const BasePluginEventTypes = {
|
|
13
12
|
pageview: 'pageview',
|
|
14
13
|
event: 'event',
|
|
@@ -16,9 +15,17 @@ export const BasePluginEventTypes = {
|
|
|
16
15
|
|
|
17
16
|
export type PluginOptions = {client: AnalyticsClient; uuidGenerator?: typeof uuidv4};
|
|
18
17
|
|
|
19
|
-
export abstract class
|
|
18
|
+
export abstract class Plugin {
|
|
20
19
|
protected client: AnalyticsClient;
|
|
21
20
|
protected uuidGenerator: typeof uuidv4;
|
|
21
|
+
constructor({client, uuidGenerator = uuidv4}: PluginOptions) {
|
|
22
|
+
this.client = client;
|
|
23
|
+
this.uuidGenerator = uuidGenerator;
|
|
24
|
+
}
|
|
25
|
+
public abstract getApi(name: string): any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export abstract class BasePlugin extends Plugin {
|
|
22
29
|
protected action?: string;
|
|
23
30
|
protected actionData: {[name: string]: string} = {};
|
|
24
31
|
private pageViewId: string;
|
|
@@ -28,8 +35,7 @@ export abstract class BasePlugin {
|
|
|
28
35
|
private lastReferrer: string;
|
|
29
36
|
|
|
30
37
|
constructor({client, uuidGenerator = uuidv4}: PluginOptions) {
|
|
31
|
-
|
|
32
|
-
this.uuidGenerator = uuidGenerator;
|
|
38
|
+
super({client, uuidGenerator});
|
|
33
39
|
this.pageViewId = uuidGenerator();
|
|
34
40
|
this.nextPageViewId = this.pageViewId;
|
|
35
41
|
this.currentLocation = getFormattedLocation(window.location);
|
|
@@ -37,10 +43,18 @@ export abstract class BasePlugin {
|
|
|
37
43
|
|
|
38
44
|
this.addHooks();
|
|
39
45
|
}
|
|
40
|
-
|
|
41
46
|
protected abstract addHooks(): void;
|
|
42
47
|
protected abstract clearPluginData(): void;
|
|
43
48
|
|
|
49
|
+
public getApi(name: string): Function | null {
|
|
50
|
+
switch (name) {
|
|
51
|
+
case 'setAction':
|
|
52
|
+
return this.setAction;
|
|
53
|
+
default:
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
44
58
|
public setAction(action: string, options?: any) {
|
|
45
59
|
this.action = action;
|
|
46
60
|
this.actionData = options;
|
|
@@ -59,7 +73,7 @@ export abstract class BasePlugin {
|
|
|
59
73
|
};
|
|
60
74
|
}
|
|
61
75
|
|
|
62
|
-
|
|
76
|
+
protected updateLocationInformation(eventType: string, payload: any) {
|
|
63
77
|
this.updateLocationForNextPageView(eventType, payload);
|
|
64
78
|
}
|
|
65
79
|
|
package/src/plugins/ec.ts
CHANGED
|
@@ -71,6 +71,19 @@ export class ECPlugin extends BasePlugin {
|
|
|
71
71
|
super({client, uuidGenerator});
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
public getApi(name: string): Function | null {
|
|
75
|
+
const superCall: Function | null = super.getApi(name);
|
|
76
|
+
if (superCall !== null) return superCall;
|
|
77
|
+
switch (name) {
|
|
78
|
+
case 'addProduct':
|
|
79
|
+
return this.addProduct;
|
|
80
|
+
case 'addImpression':
|
|
81
|
+
return this.addImpression;
|
|
82
|
+
default:
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
74
87
|
protected addHooks(): void {
|
|
75
88
|
this.addHooksForPageView();
|
|
76
89
|
this.addHooksForEvent();
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {CoveoLinkParam, LinkPlugin} from './link';
|
|
2
|
+
import {createAnalyticsClientMock} from '../../tests/analyticsClientMock';
|
|
3
|
+
import {v4 as uuidv4} from 'uuid';
|
|
4
|
+
|
|
5
|
+
function currentSecsSinceEpoch() {
|
|
6
|
+
return Math.floor(Date.now() / 1000);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe('CoveoLinkParam class', () => {
|
|
10
|
+
it('can create a new link using a uuid', () => {
|
|
11
|
+
const uuid = uuidv4();
|
|
12
|
+
const link: CoveoLinkParam = new CoveoLinkParam(uuid, Date.now());
|
|
13
|
+
expect(link.clientId).toBe(uuid);
|
|
14
|
+
expect(link.creationDate).toBe(currentSecsSinceEpoch());
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('can create a new link using a uuid and timestamp', () => {
|
|
18
|
+
const uuid = uuidv4();
|
|
19
|
+
const link: CoveoLinkParam = new CoveoLinkParam(uuid, 1676298678329);
|
|
20
|
+
expect(link.clientId).toBe(uuid);
|
|
21
|
+
expect(link.creationDate).toBe(1676298678);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('can not create a new link using a non uuid', () => {
|
|
25
|
+
const uuid = 'Not_a_uuid';
|
|
26
|
+
expect(() => new CoveoLinkParam(uuid, Date.now())).toThrow('Not a valid uuid');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('can parse a link from a string', () => {
|
|
30
|
+
const link = 'c0b48880743e484f8044d7c37910c55b.1676298678';
|
|
31
|
+
const coveoLinkParam: CoveoLinkParam | null = CoveoLinkParam.fromString(link);
|
|
32
|
+
expect(coveoLinkParam).not.toBeNull;
|
|
33
|
+
expect(coveoLinkParam?.clientId).toBe('c0b48880-743e-484f-8044-d7c37910c55b');
|
|
34
|
+
expect(coveoLinkParam?.creationDate).toBe(1676298678);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('will not parse links without a valid uuid', () => {
|
|
38
|
+
const link = 'a0c56830743d46537f703.1676298678';
|
|
39
|
+
const coveoLinkParam: CoveoLinkParam | null = CoveoLinkParam.fromString(link);
|
|
40
|
+
expect(coveoLinkParam).toBe(null);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('will not parse links with an invalid structure', () => {
|
|
44
|
+
const link = 'a0c56830743d46537f703.1676298678.353673463';
|
|
45
|
+
const coveoLinkParam: CoveoLinkParam | null = CoveoLinkParam.fromString(link);
|
|
46
|
+
expect(coveoLinkParam).toBe(null);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('will not parse links with invalid timestamps', () => {
|
|
50
|
+
const link = 'a0c56830743d46537f703.invalidtimestamp';
|
|
51
|
+
const coveoLinkParam: CoveoLinkParam | null = CoveoLinkParam.fromString(link);
|
|
52
|
+
expect(coveoLinkParam).toBe(null);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('can serialize a link to a string', () => {
|
|
56
|
+
const coveoLink: CoveoLinkParam = new CoveoLinkParam('074af291-224b-4705-9dc5-a47bd80a8db9', Date.now());
|
|
57
|
+
const link = coveoLink.toString();
|
|
58
|
+
const parts = link.split('.');
|
|
59
|
+
expect(parts[0]).toBe('074af291224b47059dc5a47bd80a8db9');
|
|
60
|
+
expect(Number.parseInt(parts[1])).toBe(currentSecsSinceEpoch());
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('checks for expiration on a link', () => {
|
|
64
|
+
const coveoLink1: CoveoLinkParam = new CoveoLinkParam('074af291-224b-4705-9dc5-a47bd80a8db9', Date.now());
|
|
65
|
+
expect(coveoLink1.expired).toBe(false);
|
|
66
|
+
const coveoLink2: CoveoLinkParam = new CoveoLinkParam(
|
|
67
|
+
'074af291-224b-4705-9dc5-a47bd80a8db9',
|
|
68
|
+
Date.now() - 180000
|
|
69
|
+
);
|
|
70
|
+
expect(coveoLink2.expired).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('checks for expiration on a link if the timestamp is in the future', () => {
|
|
74
|
+
const coveoLink1: CoveoLinkParam = new CoveoLinkParam('074af291-224b-4705-9dc5-a47bd80a8db9', Date.now());
|
|
75
|
+
expect(coveoLink1.expired).toBe(false);
|
|
76
|
+
const coveoLink2: CoveoLinkParam = new CoveoLinkParam(
|
|
77
|
+
'074af291-224b-4705-9dc5-a47bd80a8db9',
|
|
78
|
+
Date.now() + 5000
|
|
79
|
+
);
|
|
80
|
+
expect(coveoLink2.expired).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('checks validation on referrers', () => {
|
|
84
|
+
const coveoLink1: CoveoLinkParam = new CoveoLinkParam('074af291-224b-4705-9dc5-a47bd80a8db9', Date.now());
|
|
85
|
+
expect(coveoLink1.validate('http://sub.mysite.com', ['*'])).toBe(true);
|
|
86
|
+
expect(coveoLink1.validate('http://sub.mysite.com', ['*.mysite.com', '*'])).toBe(true);
|
|
87
|
+
expect(coveoLink1.validate('http://sub.mysite.com', ['*.mysite.com'])).toBe(true);
|
|
88
|
+
expect(coveoLink1.validate('http://sub.notmysite.com', ['*.mysite.com'])).toBe(false);
|
|
89
|
+
expect(coveoLink1.validate('http://sub.mysite.com', [])).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('escapes backslash correctly', () => {
|
|
93
|
+
const coveoLink1: CoveoLinkParam = new CoveoLinkParam('074af291-224b-4705-9dc5-a47bd80a8db9', Date.now());
|
|
94
|
+
expect(coveoLink1.validate('http://sub.mysite.com', ['\\w'])).toBe(false); // This should not be treated as a \w regexp!
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('CoveoLinkPlugin', () => {
|
|
99
|
+
let link: LinkPlugin;
|
|
100
|
+
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
jest.clearAllMocks();
|
|
103
|
+
const analyticsClient = createAnalyticsClientMock();
|
|
104
|
+
analyticsClient.getCurrentVisitorId = jest.fn(() => Promise.resolve('85698661-efdf-4c6d-9cad-c4632bf81ce3'));
|
|
105
|
+
link = new LinkPlugin({client: analyticsClient});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('decorates links with valid urls and no params', async () => {
|
|
109
|
+
const url: string = 'https://coveo.com';
|
|
110
|
+
const result: string = await link.decorate(url);
|
|
111
|
+
expect(result).toBe('https://coveo.com/?cvo_cid=85698661efdf4c6d9cadc4632bf81ce3.' + currentSecsSinceEpoch());
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('decorates links with valid urls and no params', async () => {
|
|
115
|
+
const url: string = 'https://coveo.com/some/path/';
|
|
116
|
+
const result: string = await link.decorate(url);
|
|
117
|
+
expect(result).toBe(
|
|
118
|
+
'https://coveo.com/some/path/?cvo_cid=85698661efdf4c6d9cadc4632bf81ce3.' + currentSecsSinceEpoch()
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('decorates links with valid urls and existing params', async () => {
|
|
123
|
+
const url: string = 'https://coveo.com/query?q=something&p=param';
|
|
124
|
+
const result: string = await link.decorate(url);
|
|
125
|
+
expect(result).toBe(
|
|
126
|
+
'https://coveo.com/query?q=something&p=param&cvo_cid=85698661efdf4c6d9cadc4632bf81ce3.' +
|
|
127
|
+
currentSecsSinceEpoch()
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('decorates links with valid urls, existing params and fragments', async () => {
|
|
132
|
+
const url: string = 'https://coveo.com/?q=something#frag';
|
|
133
|
+
const result: string = await link.decorate(url);
|
|
134
|
+
expect(result).toBe(
|
|
135
|
+
'https://coveo.com/?q=something&cvo_cid=85698661efdf4c6d9cadc4632bf81ce3.' +
|
|
136
|
+
currentSecsSinceEpoch() +
|
|
137
|
+
'#frag'
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('updates an existing decoration links with valid urls and no params', async () => {
|
|
142
|
+
const url: string = 'https://coveo.com/?cvo_cid=c0b48880743e484f8044d7c37910c55b.1676298678';
|
|
143
|
+
const result: string = await link.decorate(url);
|
|
144
|
+
expect(result).toBe('https://coveo.com/?cvo_cid=85698661efdf4c6d9cadc4632bf81ce3.' + currentSecsSinceEpoch());
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('errors on invalid urls', async () => {
|
|
148
|
+
const url: string = 'somethingthatisobviouslynotaurl';
|
|
149
|
+
await expect(link.decorate(url)).rejects.toThrow('Invalid URL provided');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('errors when there is no current clientId', async () => {
|
|
153
|
+
// initialize with missing clientId method
|
|
154
|
+
const analyticsClient = createAnalyticsClientMock();
|
|
155
|
+
analyticsClient.getCurrentVisitorId = undefined;
|
|
156
|
+
link = new LinkPlugin({client: analyticsClient});
|
|
157
|
+
|
|
158
|
+
const url: string = 'https://coveo.com/';
|
|
159
|
+
await expect(link.decorate(url)).rejects.toThrow('Could not retrieve current clientId');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('can set a list of referrers on the client', () => {
|
|
163
|
+
const analyticsClient = createAnalyticsClientMock();
|
|
164
|
+
const mock: jest.Mock = jest.fn();
|
|
165
|
+
analyticsClient.setAcceptedLinkReferrers = mock;
|
|
166
|
+
link = new LinkPlugin({client: analyticsClient});
|
|
167
|
+
link.acceptFrom(['*.somedomain.com', 'www.coveo.com']);
|
|
168
|
+
|
|
169
|
+
expect(mock).toHaveBeenCalledTimes(1);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {validate as uuidvalidate, v4 as uuidv4} from 'uuid';
|
|
2
|
+
import {Plugin, PluginOptions, PluginClass} from './BasePlugin';
|
|
3
|
+
|
|
4
|
+
export class CoveoLinkParam {
|
|
5
|
+
public static readonly cvo_cid: string = 'cvo_cid'; // name of the url parameter
|
|
6
|
+
private static readonly expirationTime: number = 120; // expirationTime in secs
|
|
7
|
+
public readonly clientId: string; //uuid
|
|
8
|
+
public readonly creationDate: number; //seconds since epoch to save space in serialized param
|
|
9
|
+
|
|
10
|
+
constructor(clientId: string, timestamp: number) {
|
|
11
|
+
if (!uuidvalidate(clientId)) throw Error('Not a valid uuid');
|
|
12
|
+
this.clientId = clientId;
|
|
13
|
+
this.creationDate = Math.floor(timestamp / 1000);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public toString(): string {
|
|
17
|
+
// strips the dashes and uses second granularity to save on url length.
|
|
18
|
+
return this.clientId.replace(/-/g, '') + '.' + this.creationDate.toString();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public get expired(): boolean {
|
|
22
|
+
const age = Math.floor(Date.now() / 1000) - this.creationDate;
|
|
23
|
+
return age < 0 || age > CoveoLinkParam.expirationTime;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public validate(referrerString: string, referrerList: string[]): boolean {
|
|
27
|
+
return !this.expired && this.matchReferrer(referrerString, referrerList);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private matchReferrer(referrerString: string, referrerList: string[]): boolean {
|
|
31
|
+
try {
|
|
32
|
+
const url: URL = new URL(referrerString);
|
|
33
|
+
return referrerList.some((value: string) => {
|
|
34
|
+
const hostRegExp: RegExp = new RegExp(
|
|
35
|
+
value.replace(/\\/g, '\\\\').replace(/\./g, '\\.').replace(/\*/g, '.*') + '$'
|
|
36
|
+
);
|
|
37
|
+
return hostRegExp.test(url.host);
|
|
38
|
+
});
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public static fromString(input: string): CoveoLinkParam | null {
|
|
45
|
+
const parts = input.split('.');
|
|
46
|
+
if (parts.length !== 2) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const [clientIdPart, creationDate] = parts;
|
|
50
|
+
if (clientIdPart.length !== 32 || isNaN(parseInt(creationDate))) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const clientId =
|
|
54
|
+
clientIdPart.substring(0, 8) +
|
|
55
|
+
'-' +
|
|
56
|
+
clientIdPart.substring(8, 12) +
|
|
57
|
+
'-' +
|
|
58
|
+
clientIdPart.substring(12, 16) +
|
|
59
|
+
'-' +
|
|
60
|
+
clientIdPart.substring(16, 20) +
|
|
61
|
+
'-' +
|
|
62
|
+
clientIdPart.substring(20, 32);
|
|
63
|
+
if (uuidvalidate(clientId)) {
|
|
64
|
+
return new CoveoLinkParam(clientId, Number.parseInt(creationDate) * 1000);
|
|
65
|
+
} else {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class LinkPlugin extends Plugin {
|
|
72
|
+
public static readonly Id = 'link';
|
|
73
|
+
|
|
74
|
+
constructor({client, uuidGenerator = uuidv4}: PluginOptions) {
|
|
75
|
+
super({client, uuidGenerator});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public getApi(name: string): Function | null {
|
|
79
|
+
switch (name) {
|
|
80
|
+
case 'decorate':
|
|
81
|
+
return this.decorate;
|
|
82
|
+
case 'acceptFrom':
|
|
83
|
+
return this.acceptFrom;
|
|
84
|
+
default:
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public async decorate(urlString: string): Promise<string> {
|
|
90
|
+
// Note: clientId retrieval function is marked as optional
|
|
91
|
+
if (!this.client.getCurrentVisitorId) {
|
|
92
|
+
throw new Error('Could not retrieve current clientId');
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const url = new URL(urlString);
|
|
96
|
+
const clientId: string = await this.client.getCurrentVisitorId!();
|
|
97
|
+
url.searchParams.set(CoveoLinkParam.cvo_cid, new CoveoLinkParam(clientId, Date.now()).toString());
|
|
98
|
+
return url.toString();
|
|
99
|
+
} catch (error) {
|
|
100
|
+
throw new Error('Invalid URL provided');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public acceptFrom(acceptedReferrers: string[]) {
|
|
105
|
+
this.client.setAcceptedLinkReferrers!(acceptedReferrers);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const Link: PluginClass = LinkPlugin;
|
package/src/plugins/svc.ts
CHANGED
|
@@ -34,6 +34,17 @@ export class SVCPlugin extends BasePlugin {
|
|
|
34
34
|
super({client, uuidGenerator});
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
public getApi(name: string): Function | null {
|
|
38
|
+
const superCall: Function | null = super.getApi(name);
|
|
39
|
+
if (superCall !== null) return superCall;
|
|
40
|
+
switch (name) {
|
|
41
|
+
case 'setTicket':
|
|
42
|
+
return this.setTicket;
|
|
43
|
+
default:
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
protected addHooks(): void {
|
|
38
49
|
this.addHooksForEvent();
|
|
39
50
|
this.addHooksForPageView();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const getFormattedLocation: (location: Location) => string;
|