coveo.analytics 2.21.27 → 2.22.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coveo.analytics",
3
- "version": "2.21.27",
3
+ "version": "2.22.2",
4
4
  "description": "📈 Coveo analytics client (node and browser compatible) ",
5
5
  "main": "dist/library.js",
6
6
  "module": "dist/library.es.js",
@@ -23,7 +23,6 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
- "@react-native-async-storage/async-storage": "^1.17.10",
27
26
  "cross-fetch": "^3.1.5"
28
27
  },
29
28
  "devDependencies": {
@@ -51,8 +50,8 @@
51
50
  "rimraf": "^3.0.2",
52
51
  "rollup": "^2.50.6",
53
52
  "rollup-plugin-serve": "^1.0.1",
54
- "rollup-plugin-typescript2": "^0.27.0",
55
53
  "rollup-plugin-terser": "^7.0.2",
54
+ "rollup-plugin-typescript2": "^0.27.0",
56
55
  "stylelint": "^13.6.1",
57
56
  "ts-jest": "^25.2.0",
58
57
  "tsjs": "4.2.1",
@@ -66,6 +65,7 @@
66
65
  "dist/**/*.js",
67
66
  "dist/**/*.js.map",
68
67
  "src/**/*.ts",
68
+ "react-native/",
69
69
  "LICENSE"
70
70
  ],
71
71
  "husky": {
@@ -0,0 +1,9 @@
1
+ {
2
+ "private": true,
3
+ "name": "react-native",
4
+ "description": "Coveo analytics client for React Native",
5
+ "main": "../dist/react-native.es.js",
6
+ "module": "../dist/react-native.es.js",
7
+ "types": "../dist/definitions/react-native/index.d.ts",
8
+ "license": "MIT"
9
+ }
@@ -87,6 +87,11 @@ export interface BufferedRequest {
87
87
  type ProcessPayloadStep = (currentPayload: any) => any;
88
88
  type AsyncProcessPayloadStep = (currentPayload: any) => Promise<any>;
89
89
 
90
+ export function buildBaseUrl(endpoint = Endpoints.default, apiVersion = Version) {
91
+ const endpointIsCoveoProxy = endpoint.indexOf('.cloud.coveo.com') !== -1;
92
+ return `${endpoint}${endpointIsCoveoProxy ? '' : '/rest'}/${apiVersion}`;
93
+ }
94
+
90
95
  export class CoveoAnalyticsClient implements AnalyticsClient, VisitorIdProvider {
91
96
  private get defaultOptions(): ClientOptions {
92
97
  return {
@@ -469,9 +474,7 @@ export class CoveoAnalyticsClient implements AnalyticsClient, VisitorIdProvider
469
474
  }
470
475
 
471
476
  private get baseUrl(): string {
472
- const {version, endpoint} = this.options;
473
- const endpointIsCoveoProxy = endpoint.indexOf('.cloud.coveo.com') !== -1;
474
- return `${endpoint}${endpointIsCoveoProxy ? '' : '/rest'}/${version}`;
477
+ return buildBaseUrl(this.options.endpoint, this.options.version);
475
478
  }
476
479
  }
477
480
 
@@ -1,7 +1,12 @@
1
1
  import {mockFetch} from '../../tests/fetchMock';
2
2
  import CoveoAnalyticsClient from '../client/analytics';
3
3
  import {NoopAnalytics} from '../client/noopAnalytics';
4
- import {CustomEventsTypes, SearchPageEvents, StaticFilterToggleValueMetadata} from '../searchPage/searchPageEvents';
4
+ import {
5
+ CustomEventsTypes,
6
+ PartialDocumentInformation,
7
+ SearchPageEvents,
8
+ StaticFilterToggleValueMetadata,
9
+ } from '../searchPage/searchPageEvents';
5
10
  import {CoveoInsightClient, InsightClientProvider} from './insightClient';
6
11
  import doNotTrack from '../donottrack';
7
12
  import {InsightEvents, InsightStaticFilterToggleValueMetadata} from './insightEvents';
@@ -101,6 +106,37 @@ describe('InsightClient', () => {
101
106
  });
102
107
  };
103
108
 
109
+ const expectMatchDocumentPayload = (actionCause: SearchPageEvents, doc: PartialDocumentInformation, meta = {}) => {
110
+ const [, {body}] = fetchMock.lastCall();
111
+ const customData = {foo: 'bar', ...meta};
112
+ expect(JSON.parse(body.toString())).toMatchObject({
113
+ actionCause,
114
+ customData,
115
+ language: 'en',
116
+ clientId: 'visitor-id',
117
+ ...doc,
118
+ ...expectOrigins(),
119
+ });
120
+ };
121
+
122
+ const fakeDocInfo = {
123
+ collectionName: 'collection',
124
+ documentAuthor: 'author',
125
+ documentPosition: 1,
126
+ documentTitle: 'title',
127
+ documentUri: 'uri',
128
+ documentUriHash: 'hash',
129
+ documentUrl: 'url',
130
+ queryPipeline: 'my-pipeline',
131
+ rankingModifier: 'modifier',
132
+ sourceName: 'source',
133
+ };
134
+
135
+ const fakeDocID = {
136
+ contentIDKey: 'permanentID',
137
+ contentIDValue: 'the-permanent-id',
138
+ };
139
+
104
140
  beforeEach(() => {
105
141
  fetchMockBeforeEach();
106
142
 
@@ -277,6 +313,11 @@ describe('InsightClient', () => {
277
313
  await client.logSearchboxSubmit();
278
314
  expectMatchPayload(SearchPageEvents.searchboxSubmit);
279
315
  });
316
+
317
+ it('should send proper payload for #documentOpen', async () => {
318
+ await client.logDocumentOpen(fakeDocInfo, fakeDocID);
319
+ expectMatchDocumentPayload(SearchPageEvents.documentOpen, fakeDocInfo, fakeDocID);
320
+ });
280
321
  });
281
322
 
282
323
  describe('when the case metadata is included', () => {
@@ -623,6 +664,17 @@ describe('InsightClient', () => {
623
664
  await client.logSearchboxSubmit(metadata);
624
665
  expectMatchPayload(SearchPageEvents.searchboxSubmit, expectedMetadata);
625
666
  });
667
+
668
+ it('should send proper payload for #documentOpen', async () => {
669
+ const metadata = baseCaseMetadata;
670
+
671
+ const expectedMetadata = {
672
+ ...fakeDocID,
673
+ ...expectedBaseCaseMetadata,
674
+ };
675
+ await client.logDocumentOpen(fakeDocInfo, fakeDocID, metadata);
676
+ expectMatchDocumentPayload(SearchPageEvents.documentOpen, fakeDocInfo, expectedMetadata);
677
+ });
626
678
  });
627
679
 
628
680
  it('should enable analytics tracking by default', () => {
@@ -1,8 +1,14 @@
1
1
  import CoveoAnalyticsClient, {AnalyticsClient, ClientOptions} from '../client/analytics';
2
2
  import {NoopAnalytics} from '../client/noopAnalytics';
3
3
  import doNotTrack from '../donottrack';
4
- import {CustomEventRequest, SearchEventRequest} from '../events';
5
- import {CustomEventsTypes, FacetStateMetadata, SearchPageEvents} from '../searchPage/searchPageEvents';
4
+ import {ClickEventRequest, CustomEventRequest, SearchEventRequest} from '../events';
5
+ import {
6
+ CustomEventsTypes,
7
+ DocumentIdentifier,
8
+ FacetStateMetadata,
9
+ PartialDocumentInformation,
10
+ SearchPageEvents,
11
+ } from '../searchPage/searchPageEvents';
6
12
  import {
7
13
  ExpandToFullUIMetadata,
8
14
  InsightEvents,
@@ -213,6 +219,14 @@ export class CoveoInsightClient {
213
219
  return this.logCustomEvent(InsightEvents.expandToFullUI, metadataToSend);
214
220
  }
215
221
 
222
+ public logDocumentOpen(info: PartialDocumentInformation, identifier: DocumentIdentifier, metadata?: CaseMetadata) {
223
+ return this.logClickEvent(
224
+ SearchPageEvents.documentOpen,
225
+ info,
226
+ identifier,
227
+ metadata ? generateMetadataToSend(metadata, false) : undefined);
228
+ }
229
+
216
230
  public async logCustomEvent(event: SearchPageEvents | InsightEvents, metadata?: Record<string, any>) {
217
231
  const customData = {...this.provider.getBaseMetadata(), ...metadata};
218
232
 
@@ -229,6 +243,23 @@ export class CoveoInsightClient {
229
243
  return this.coveoAnalyticsClient.sendSearchEvent(await this.getBaseSearchEventRequest(event, metadata));
230
244
  }
231
245
 
246
+ public async logClickEvent(
247
+ event: SearchPageEvents,
248
+ info: PartialDocumentInformation,
249
+ identifier: DocumentIdentifier,
250
+ metadata?: Record<string, any>
251
+ ) {
252
+ const payload: ClickEventRequest = {
253
+ ...info,
254
+ ...(await this.getBaseEventRequest({...identifier, ...metadata})),
255
+ searchQueryUid: this.provider.getSearchUID(),
256
+ queryPipeline: this.provider.getPipeline(),
257
+ actionCause: event,
258
+ };
259
+
260
+ return this.coveoAnalyticsClient.sendClickEvent(payload);
261
+ }
262
+
232
263
  private async getBaseCustomEventRequest(metadata?: Record<string, any>) {
233
264
  return {
234
265
  ...(await this.getBaseEventRequest(metadata)),
@@ -1,3 +1,2 @@
1
- // TODO: v3 add in "coveo.analytics/react-native" subpackage
2
- export {ReactNativeRuntime} from './react-native-runtime';
3
- export {ReactNativeStorage} from './react-native-storage';
1
+ export {ReactNativeRuntime, ReactNativeRuntimeOptions, ReactNativeStorage} from './react-native-runtime';
2
+ export * from '../coveoua/headless';
@@ -1,17 +1,45 @@
1
1
  import {WebStorage} from '../storage';
2
2
  import {AnalyticsFetchClient} from '../client/analyticsFetchClient';
3
- import {ReactNativeStorage} from './react-native-storage';
4
3
  import {IRuntimeEnvironment} from '../client/runtimeEnvironment';
5
- import {IAnalyticsClientOptions} from '../client/analyticsRequestClient';
4
+ import {PreprocessAnalyticsRequest} from '../client/analyticsRequestClient';
5
+ import {uuidv4} from '../client/crypto';
6
+ import {buildBaseUrl} from '../client/analytics';
7
+
8
+ export type ReactNativeStorage = WebStorage;
9
+
10
+ export interface ReactNativeRuntimeOptions {
11
+ /**
12
+ * Mandatory Storage implementation.
13
+ *
14
+ * We recommend using a storage library. There are a few options presented in the readme: https://github.com/coveo/coveo.analytics.js#using-react-native
15
+ */
16
+ storage: ReactNativeStorage;
17
+ /**
18
+ * Key for storing the visitor ID value.
19
+ * @defaut visitorId
20
+ */
21
+ visitorIdKey?: string;
22
+ token?: string;
23
+ version?: string;
24
+ endpoint?: string;
25
+ preprocessRequest?: PreprocessAnalyticsRequest;
26
+ }
6
27
 
7
28
  export class ReactNativeRuntime implements IRuntimeEnvironment {
8
- public storage: WebStorage;
9
29
  public client: AnalyticsFetchClient;
30
+ public storage: ReactNativeStorage;
10
31
 
11
- // TODO: v3 switch to ClientOptions type, add default options
12
- // TODO: v3 reuse own ReactNativeStorage to implement VisitorIdProvider's getCurrentVisitorId, setCurrentVisitorId
13
- constructor(clientOptions: IAnalyticsClientOptions) {
14
- this.storage = new ReactNativeStorage();
15
- this.client = new AnalyticsFetchClient(clientOptions);
32
+ constructor(options: ReactNativeRuntimeOptions) {
33
+ const visitorIdKey = options.visitorIdKey ?? 'visitorId';
34
+ this.storage = options.storage;
35
+ this.client = new AnalyticsFetchClient({
36
+ preprocessRequest: options.preprocessRequest,
37
+ token: options.token,
38
+ baseUrl: buildBaseUrl(options.endpoint, options.version),
39
+ visitorIdProvider: {
40
+ getCurrentVisitorId: async () => (await this.storage.getItem(visitorIdKey)) || uuidv4(),
41
+ setCurrentVisitorId: (visitorId: string) => this.storage.setItem(visitorIdKey, visitorId),
42
+ },
43
+ });
16
44
  }
17
45
  }
@@ -1,16 +1,7 @@
1
1
  export const ReactNativeRuntimeWarning = `
2
2
  We've detected you're using React Native but have not provided the corresponding runtime,
3
- for an optimal experience please install @react-native-async-storage/async-storage and instantiate
4
- your analytics client as follows:
5
-
6
- import {ReactNativeRuntime} from 'coveo.analytics/src/react-native';
7
-
8
- const analytics = new CoveoAnalyticsClient({
9
- ...your options,
10
- runtimeEnvironment: new ReactNativeRuntime({
11
- baseUrl: '...',
12
- });
13
- })
3
+ for an optimal experience please use the "coveo.analytics/react-native" subpackage.
4
+ Follow the Readme on how to set it up: https://github.com/coveo/coveo.analytics.js#using-react-native
14
5
  `;
15
6
 
16
7
  export function isReactNative() {
@@ -7,8 +7,11 @@ describe('ReactNativeRuntime', () => {
7
7
 
8
8
  beforeEach(() => {
9
9
  runtimeEnvironment = new ReactNativeRuntime({
10
- baseUrl: 'https://www.coveo.com',
11
- visitorIdProvider: {getCurrentVisitorId: jest.fn(), setCurrentVisitorId: jest.fn()},
10
+ storage: {
11
+ getItem: jest.fn(),
12
+ setItem: jest.fn(),
13
+ removeItem: jest.fn(),
14
+ },
12
15
  });
13
16
  client = new CoveoAnalyticsClient({runtimeEnvironment});
14
17
  });
@@ -1,6 +0,0 @@
1
- import { WebStorage } from '../storage';
2
- export declare class ReactNativeStorage implements WebStorage {
3
- getItem(key: string): Promise<string | null>;
4
- setItem(key: string, data: string): Promise<void>;
5
- removeItem(key: string): Promise<void>;
6
- }
@@ -1,6 +0,0 @@
1
- import { WebStorage } from '../storage';
2
- export declare class ReactNativeStorage implements WebStorage {
3
- getItem(key: string): Promise<string | null>;
4
- setItem(key: string, data: string): Promise<void>;
5
- removeItem(key: string): Promise<void>;
6
- }
@@ -1,14 +0,0 @@
1
- import {WebStorage} from '../storage';
2
- import AsyncStorage from '@react-native-async-storage/async-storage';
3
-
4
- export class ReactNativeStorage implements WebStorage {
5
- async getItem(key: string) {
6
- return AsyncStorage.getItem(key);
7
- }
8
- async setItem(key: string, data: string) {
9
- return AsyncStorage.setItem(key, data);
10
- }
11
- async removeItem(key: string) {
12
- AsyncStorage.removeItem(key);
13
- }
14
- }