noibu-react-native 0.0.1 → 0.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.
Files changed (38) hide show
  1. package/README.md +9 -7
  2. package/dist/api/clientConfig.js +50 -48
  3. package/dist/api/helpCode.js +3 -3
  4. package/dist/api/inputManager.js +5 -5
  5. package/dist/api/metroplexSocket.js +31 -43
  6. package/dist/api/storedMetrics.js +18 -22
  7. package/dist/api/storedPageVisit.js +27 -29
  8. package/dist/constants.d.ts +2 -2
  9. package/dist/constants.js +7 -48
  10. package/dist/entry/index.d.ts +8 -1
  11. package/dist/entry/index.js +8 -2
  12. package/dist/entry/init.js +6 -5
  13. package/dist/monitors/clickMonitor.js +1 -2
  14. package/dist/monitors/elementMonitor.js +4 -1
  15. package/dist/monitors/errorMonitor.d.ts +25 -0
  16. package/dist/monitors/errorMonitor.js +109 -262
  17. package/dist/monitors/httpDataBundler.js +11 -12
  18. package/dist/monitors/inputMonitor.js +4 -1
  19. package/dist/monitors/locationChangeMonitor.js +4 -16
  20. package/dist/monitors/pageMonitor.js +4 -1
  21. package/dist/monitors/requestMonitor.js +5 -19
  22. package/dist/pageVisit/pageVisit.js +3 -1
  23. package/dist/pageVisit/pageVisitEventError/blacklistedDomains.js +9 -0
  24. package/dist/pageVisit/pageVisitEventError/pageVisitEventError.js +9 -14
  25. package/dist/pageVisit/pageVisitEventHTTP/pageVisitEventHTTP.js +3 -14
  26. package/dist/storage/rnStorageProvider.d.ts +23 -0
  27. package/dist/storage/rnStorageProvider.js +23 -52
  28. package/dist/storage/storage.d.ts +38 -0
  29. package/dist/storage/storage.js +69 -104
  30. package/dist/storage/storageProvider.d.ts +25 -0
  31. package/dist/storage/storageProvider.js +38 -71
  32. package/dist/utils/function.js +80 -53
  33. package/dist/utils/performance.js +0 -7
  34. package/dist/utils/stacktrace-parser.d.ts +9 -0
  35. package/dist/utils/stacktrace-parser.js +156 -0
  36. package/package.json +4 -4
  37. package/dist/storage/localStorageProvider.js +0 -23
  38. package/dist/storage/sessionStorageProvider.js +0 -23
package/README.md CHANGED
@@ -29,12 +29,14 @@ npm install noibu-react-native --save
29
29
 
30
30
  ## Usage
31
31
 
32
- Wrap your root App component into SDK ErrorBoundary:
32
+ Call a setup method and wrap your root App component into SDK ErrorBoundary:
33
33
 
34
34
  ```jsx
35
35
  import React from 'react';
36
36
  import { View, Text } from 'react-native';
37
- import { ErrorBoundary } from 'noibu-react-native';
37
+ import { ErrorBoundary, setupNoibu } from 'noibu-react-native';
38
+
39
+ setupNoibu({ domain: 'react-native-app.myshop.com' })
38
40
 
39
41
  export default function App() {
40
42
  return (
@@ -53,7 +55,7 @@ export default function App() {
53
55
  }
54
56
  ```
55
57
 
56
- That's it! First time the module is imported, it runs an init and starts listening to errors.
58
+ That's it! First time the module is set up, it runs an init and starts listening to errors.
57
59
 
58
60
  ## Configuration
59
61
 
@@ -95,19 +97,19 @@ const AlertHelpCode = () => {
95
97
  };
96
98
  ```
97
99
 
98
- #### `addCustomAttribute(name: string, value: string) => string`
100
+ #### `addCustomAttribute(name: string, value: string) => Promise<string>`
99
101
 
100
102
  Adds a custom attribute to the session.
101
103
 
102
104
  - `@param {string} name` - Name of a custom attribute.
103
105
  - `@param {any} value` - It's value, should be a JSON.stringify-able type.
104
- - `@returns {string}` - A success message, or validation failure cause.
106
+ - `@returns {Promise<string>}` - A success message, or validation failure cause.
105
107
 
106
108
  ```js
107
109
  import { NoibuJS } from 'noibu-react-native';
108
110
 
109
- NoibuJS.addCustomAttribute('myNameIs', 'Jeff'); // SUCCESS
110
- NoibuJS.addCustomAttribute('veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong', 'Jeff'); // NAME_TOO_LONG
111
+ NoibuJS.addCustomAttribute('myNameIs', 'Jeff'); // Promise<SUCCESS>
112
+ NoibuJS.addCustomAttribute('veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong', 'Jeff'); // Promise<NAME_TOO_LONG>
111
113
  ```
112
114
 
113
115
  #### `addError(customError: Error) => string`
@@ -1,6 +1,6 @@
1
1
  import uuid from 'react-native-uuid';
2
2
  import { MAX_METROPLEX_SOCKET_INNACTIVE_TIME, DISABLED_STATUS_KEY, CLIENT_UNLOCK_TIME_KEY, SEVERITY_WARN, LAST_ACTIVE_TIME_KEY, CURRENT_PAGE_VISIT_COUNT_KEY, NOIBU_BROWSER_ID_KYWRD, BROWSER_ID_KEY, PV_SEQ_NUM_RESET_TIME_MINUTES, SEVERITY_ERROR, JS_ENV, PAGE_VISIT_ID_KEY, MAX_PAGEVISIT_VISITED, CLIENT_LOCK_TIME_MINUTES, GET_SCRIPT_ID, MAX_COLLECT_ERROR_LOG } from '../constants.js';
3
- import { stringifyJSON, getUserAgent, asString, makeRequest } from '../utils/function.js';
3
+ import { stringifyJSON, getUserAgent, asString, getProperGlobalUrl, makeRequest } from '../utils/function.js';
4
4
  import Storage from '../storage/storage.js';
5
5
 
6
6
  /** @module ClientConfig */
@@ -14,9 +14,10 @@ import Storage from '../storage/storage.js';
14
14
  class ClientConfig {
15
15
  /**
16
16
  * Creates a ClientConfig singleton instance
17
- * @param {} noibuErrorURL
17
+ * @param {string} noibuErrorURL
18
+ * @param {string} customerDomain
18
19
  */
19
- constructor(noibuErrorURL) {
20
+ constructor(noibuErrorURL, customerDomain) {
20
21
  // sets up this.browserId, this.disabledStatus
21
22
  this.pageVisitId = uuid.v4();
22
23
  // variables stored in storage
@@ -36,16 +37,18 @@ class ClientConfig {
36
37
  // variables for checking if the socket is inactive
37
38
  // used a class variables in order to be changed in testing
38
39
  this.maxSocketInactiveTime = MAX_METROPLEX_SOCKET_INNACTIVE_TIME;
40
+
41
+ this.customerDomain = customerDomain;
39
42
  }
40
43
 
41
44
  /** Configures the singleton instance */
42
- static configureInstance(noibuErrorURL) {
45
+ static configureInstance({ noibuErrorURL, customerDomain }) {
43
46
  if (!this.instance) {
44
47
  // Set this.noibuErrorURL preemptively in case ClientConfig isn't able to be
45
48
  // configured properly and throws an error.
46
49
  // This will ensure we get the expected error POST request at the correct URL.
47
50
  this.noibuErrorURL = noibuErrorURL;
48
- this.instance = new ClientConfig(noibuErrorURL);
51
+ this.instance = new ClientConfig(noibuErrorURL, customerDomain);
49
52
  this.instance.noibuErrorURL = noibuErrorURL;
50
53
  }
51
54
  }
@@ -64,14 +67,14 @@ class ClientConfig {
64
67
 
65
68
  /** lockClient will disable the client script for a single pagevisit for
66
69
  * duration given in minuntes */
67
- lockClient(duration, msg) {
70
+ async lockClient(duration, msg) {
68
71
  const expiryTime = new Date();
69
72
  expiryTime.setMinutes(expiryTime.getMinutes() + duration);
70
73
 
71
- const noibuLSObject = this._getClientState();
74
+ const noibuLSObject = await this._getClientState();
72
75
  noibuLSObject[DISABLED_STATUS_KEY] = true;
73
76
  noibuLSObject[CLIENT_UNLOCK_TIME_KEY] = expiryTime;
74
- this._storeBrowserData(noibuLSObject);
77
+ await this._storeBrowserData(noibuLSObject);
75
78
  this.postNoibuErrorAndOptionallyDisableClient(msg, true, SEVERITY_WARN);
76
79
  }
77
80
 
@@ -81,23 +84,23 @@ class ClientConfig {
81
84
  }
82
85
 
83
86
  /** Updates the config object to store the given last active time */
84
- updateLastActiveTime(lastActiveTime) {
87
+ async updateLastActiveTime(lastActiveTime) {
85
88
  this.lastActiveTime = lastActiveTime;
86
- const newConfigData = this._getLsObject();
89
+ const newConfigData = await this._getLsObject();
87
90
  newConfigData[LAST_ACTIVE_TIME_KEY] = lastActiveTime;
88
- this._storeBrowserData(newConfigData);
91
+ await this._storeBrowserData(newConfigData);
89
92
  }
90
93
 
91
94
  /** Gets the current page visit sequence number that should be used */
92
- getPageVisitSeq() {
93
- if (this._pageVisitSeqNeedsReset()) {
95
+ async getPageVisitSeq() {
96
+ if (await this._pageVisitSeqNeedsReset()) {
94
97
  // Reset the page visit sequence number to zero and store the next seq number in storage
95
98
  this.pageVisitSeq = 0;
96
- const newConfigData = this._getLsObject();
99
+ const newConfigData = await this._getLsObject();
97
100
  newConfigData[CURRENT_PAGE_VISIT_COUNT_KEY] = this.pageVisitSeq + 1;
98
101
  // Update the last active time since we are actively requesting the seq
99
102
  newConfigData[LAST_ACTIVE_TIME_KEY] = new Date();
100
- this._storeBrowserData(newConfigData);
103
+ await this._storeBrowserData(newConfigData);
101
104
  }
102
105
 
103
106
  return this.pageVisitSeq;
@@ -115,9 +118,9 @@ class ClientConfig {
115
118
  * LastActiveTime: DATE OBJ
116
119
  * }
117
120
  */
118
- _getLsObject() {
121
+ async _getLsObject() {
119
122
  const storage = Storage.getInstance();
120
- const storedConfig = storage.load(NOIBU_BROWSER_ID_KYWRD);
123
+ const storedConfig = await storage.load(NOIBU_BROWSER_ID_KYWRD);
121
124
 
122
125
  // first time browsing since noibu was installed
123
126
  if (!storedConfig) {
@@ -148,8 +151,8 @@ class ClientConfig {
148
151
  /**
149
152
  * Check if we have surpased the last active time and the page visit seq number needs resetting
150
153
  */
151
- _pageVisitSeqNeedsReset() {
152
- const noibuLSObject = this._getClientState();
154
+ async _pageVisitSeqNeedsReset() {
155
+ const noibuLSObject = await this._getClientState();
153
156
  const someTimeAgo = new Date();
154
157
  someTimeAgo.setMinutes(
155
158
  someTimeAgo.getMinutes() - PV_SEQ_NUM_RESET_TIME_MINUTES,
@@ -161,11 +164,11 @@ class ClientConfig {
161
164
  * _setupStorageVars will set all class variables that depend
162
165
  * on the storage's value.
163
166
  */
164
- _setupStorageVars() {
167
+ async _setupStorageVars() {
165
168
  const storage = Storage.getInstance();
166
- if (!storage.isAvailable()) {
169
+ if (!(await storage.isAvailable())) {
167
170
  this.postNoibuErrorAndOptionallyDisableClient(
168
- `Storage is unavailable, disabling client. ${storage.getDiagnoseInfo()}`,
171
+ `Storage is unavailable, disabling client. ${await storage.getDiagnoseInfo()}`,
169
172
  true,
170
173
  SEVERITY_ERROR,
171
174
  );
@@ -173,10 +176,10 @@ class ClientConfig {
173
176
  }
174
177
 
175
178
  // getting the current content of the storage
176
- const noibuLSObject = this._getClientState();
179
+ const noibuLSObject = await this._getClientState();
177
180
 
178
181
  // Check if we have surpased the last active time and reset the sequence number if so
179
- if (this._pageVisitSeqNeedsReset()) {
182
+ if (await this._pageVisitSeqNeedsReset()) {
180
183
  noibuLSObject[CURRENT_PAGE_VISIT_COUNT_KEY] = 0;
181
184
  }
182
185
 
@@ -216,7 +219,7 @@ class ClientConfig {
216
219
  }
217
220
 
218
221
  // we now check if we successfully saved the data
219
- const savedData = this._storeBrowserData(noibuLSObject);
222
+ const savedData = await this._storeBrowserData(noibuLSObject);
220
223
 
221
224
  // if the browser is null, we cannot access the storage or an
222
225
  // error happened, thus we disable collect.
@@ -237,8 +240,8 @@ class ClientConfig {
237
240
  * Get it from storage if the expiry date is not in the past
238
241
  * Generate a brand new one if the expiry date is in the past
239
242
  */
240
- _getClientState() {
241
- const newConfigData = this._getLsObject();
243
+ async _getClientState() {
244
+ const newConfigData = await this._getLsObject();
242
245
 
243
246
  // if the lock expired, we remove the lock period and enable the client
244
247
  if (
@@ -247,7 +250,7 @@ class ClientConfig {
247
250
  ) {
248
251
  newConfigData[CLIENT_UNLOCK_TIME_KEY] = null;
249
252
  newConfigData[DISABLED_STATUS_KEY] = false;
250
- this._storeBrowserData(newConfigData);
253
+ await this._storeBrowserData(newConfigData);
251
254
  }
252
255
  // return the stored browserId
253
256
  return newConfigData;
@@ -257,9 +260,8 @@ class ClientConfig {
257
260
  * _generateAndStoreData generates brand new data and then proceeds to store
258
261
  * it.
259
262
  */
260
- _generateAndStoreData() {
261
- const data = this._storeBrowserData(this._generateNewBrowserData());
262
- return data;
263
+ async _generateAndStoreData() {
264
+ return this._storeBrowserData(this._generateNewBrowserData());
263
265
  }
264
266
 
265
267
  /**
@@ -288,25 +290,24 @@ class ClientConfig {
288
290
  * _storeBrowserData will store the passed object in storage.
289
291
  * @param {} data the data to be stored
290
292
  */
291
- _storeBrowserData(data) {
293
+ async _storeBrowserData(data) {
292
294
  const storage = Storage.getInstance();
293
295
  try {
294
- storage.save(NOIBU_BROWSER_ID_KYWRD, stringifyJSON(data));
296
+ await storage.save(NOIBU_BROWSER_ID_KYWRD, stringifyJSON(data));
295
297
  return data;
296
298
  } catch (e) {
297
299
  this.postNoibuErrorAndOptionallyDisableClient(
298
300
  `Error writing browser data to storage, disabling client: ${e.message}, ` +
299
- `${storage.getDiagnoseInfo()}`,
301
+ `${await storage.getDiagnoseInfo()}`,
300
302
  true,
301
303
  SEVERITY_ERROR,
302
304
  );
303
305
  // sending empty fields if we encountered errors while storing in the LS
304
- const invalidData = {
306
+ return {
305
307
  [DISABLED_STATUS_KEY]: true,
306
308
  [BROWSER_ID_KEY]: null,
307
309
  [CURRENT_PAGE_VISIT_COUNT_KEY]: 0,
308
310
  };
309
- return invalidData;
310
311
  }
311
312
  }
312
313
 
@@ -352,10 +353,10 @@ class ClientConfig {
352
353
  const expiryTime = new Date();
353
354
  expiryTime.setMinutes(expiryTime.getMinutes() + 10); // 10 minutes lock
354
355
 
355
- const noibuLSObject = this._getClientState();
356
+ const noibuLSObject = await this._getClientState();
356
357
  noibuLSObject[DISABLED_STATUS_KEY] = true;
357
358
  noibuLSObject[CLIENT_UNLOCK_TIME_KEY] = expiryTime;
358
- this._storeBrowserData(noibuLSObject);
359
+ await this._storeBrowserData(noibuLSObject);
359
360
  this.isClientDisabled = true;
360
361
  // end of lock
361
362
  // overriding the message to be an alert that we are shutting collect off.
@@ -365,15 +366,24 @@ class ClientConfig {
365
366
  }
366
367
 
367
368
  const errorContent = {
368
- url: (global.location && global.location.href) || '',
369
+ url: getProperGlobalUrl(),
369
370
  err_msg: errMsg,
370
371
  sev: severity,
371
372
  };
372
373
  const headers = {
373
374
  'content-type': 'application/json',
375
+ 'User-Agent': await getUserAgent(),
374
376
  };
375
377
 
376
- if (!keepAlive) {
378
+ if (keepAlive) {
379
+ global.fetch(this.noibuErrorURL, {
380
+ method: 'POST',
381
+ headers,
382
+ body: stringifyJSON(errorContent),
383
+ // keep alive outlives the current page, its the same as beacon
384
+ keepalive: true,
385
+ });
386
+ } else {
377
387
  makeRequest(
378
388
  'POST',
379
389
  this.noibuErrorURL,
@@ -384,14 +394,6 @@ class ClientConfig {
384
394
  ).catch(() => {
385
395
  // we do nothing and let this error silently fail
386
396
  });
387
- } else {
388
- fetch(this.noibuErrorURL, {
389
- method: 'POST',
390
- headers,
391
- body: stringifyJSON(errorContent),
392
- // keep alive outlives the current page, its the same as beacon
393
- keepalive: true,
394
- });
395
397
  }
396
398
 
397
399
  // only increment if this was an actual error, not a warning or otherwise
@@ -32,8 +32,8 @@ class HelpCode {
32
32
  * @returns {Promise<string>} Promise object representing the help code request.
33
33
  * @throws {string} Throws an error if the noibu connection is unavailable.
34
34
  */
35
- requestHelpCode() {
36
- if (this.requestContext != null) {
35
+ async requestHelpCode() {
36
+ if (this.requestContext !== null) {
37
37
  return this.requestContext.promise;
38
38
  }
39
39
 
@@ -50,7 +50,7 @@ class HelpCode {
50
50
 
51
51
  this.requestContext = context;
52
52
 
53
- const result = this._sendRequest();
53
+ const result = await this._sendRequest();
54
54
 
55
55
  if (result === false) {
56
56
  this.requestContext = null;
@@ -54,7 +54,7 @@ class InputManager {
54
54
  * gets the sdk object that will be assigned to a window variable
55
55
  * @returns {{
56
56
  * requestHelpCode: (alert?: boolean) => Promise<string>,
57
- * addCustomAttribute: (name: string, value: string) => string,
57
+ * addCustomAttribute: (name: string, value: string) => Promise<string>,
58
58
  * addError: (customError: Error) => string,
59
59
  * addJsSdkError: (customError: string, errorSource: string) => string
60
60
  * }}
@@ -157,7 +157,7 @@ class InputManager {
157
157
  * @param {} name
158
158
  * @param {} value
159
159
  */
160
- _addCustomAttribute(name, value) {
160
+ async _addCustomAttribute(name, value) {
161
161
  // we return if we are over the limit of ids
162
162
  if (Object.keys(this.customIDs).length >= MAX_CUSTOM_IDS_PER_PAGEVISIT) {
163
163
  return this.TOO_MANY_IDS_ADDED_MSG;
@@ -176,7 +176,7 @@ class InputManager {
176
176
  }
177
177
 
178
178
  this.customIDs[name] = value;
179
- MetroplexSocket.getInstance().sendMessage(META_DATA_METROPLEX_TYPE, {
179
+ await MetroplexSocket.getInstance().sendMessage(META_DATA_METROPLEX_TYPE, {
180
180
  [PAGE_VISIT_META_DATA_ATT_NAME]: {
181
181
  [CUSTOM_ID_NAME_TYPE]: name,
182
182
  [CUSTOM_ID_VALUE_TYPE]: value,
@@ -225,8 +225,8 @@ class InputManager {
225
225
  * @param {boolean} [alertUser=true] - Whether to alert the user about the help code request.
226
226
  * @returns {Promise<string>} A promise that resolves with the requested help code.
227
227
  */
228
- _requestHelpCode(alertUser = true) {
229
- return HelpCode.getInstance().requestHelpCode(alertUser);
228
+ _requestHelpCode() {
229
+ return HelpCode.getInstance().requestHelpCode();
230
230
  }
231
231
  }
232
232
 
@@ -1,7 +1,7 @@
1
1
  import uuid from 'react-native-uuid';
2
- import { getProperGlobalUrl, getMaxSubstringAllowed, getUserAgent, stringifyJSON, getUserLanguage } from '../utils/function.js';
2
+ import { getProperGlobalUrl, getUserAgent, stringifyJSON, getUserLanguage } from '../utils/function.js';
3
3
  import { addSafeEventListener } from '../utils/eventlistener.js';
4
- import { GET_METROPLEX_BASE_SOCKET_URL, METROPLEX_FRAG_ROUTE, GET_METROPLEX_POST_URL, METROPLEX_RETRY_FREQUENCY, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_METROPLEX_TYPE, PAGE_VISIT_PART_ATT_NAME, SEQ_NUM_ATT_NAME, WORK_REQUEST_ATT_NAME, PV_EVENTS_ATT_NAME, TYPE_ATT_NAME, USERSTEP_EVENT_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, MAX_METROPLEX_CONNECTION_COUNT, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, END_AT_ATT_NAME, SEVERITY_ERROR, OK_SOCKET_MESSAGE, CLOSE_CONNECTION_FORCEFULLY, BLOCK_SOCKET_MESSAGE, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, MAX_BEACON_PAYLOAD_SIZE, PAGE_VISIT_INFORMATION_ATT_NAME, VIDEO_PART_COUNT_ATT_NAME, IS_LAST_ATT_NAME, SEVERITY_WARN, JS_ENV, BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, VER_ATT_NAME, CURRENT_PV_VERSION, PV_SEQ_ATT_NAME, ON_URL_ATT_NAME, REF_URL_ATT_NAME, STARTED_AT_ATT_NAME, CONN_COUNT_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, SCRIPT_ID_ATT_NAME, GET_SCRIPT_ID, SCRIPT_INSTANCE_ID_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, LANG_ATT_NAME, HELP_CODE_ATT_NAME } from '../constants.js';
4
+ import { GET_METROPLEX_BASE_SOCKET_URL, METROPLEX_FRAG_ROUTE, GET_METROPLEX_POST_URL, METROPLEX_RETRY_FREQUENCY, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_METROPLEX_TYPE, PAGE_VISIT_PART_ATT_NAME, SEQ_NUM_ATT_NAME, WORK_REQUEST_ATT_NAME, PV_EVENTS_ATT_NAME, TYPE_ATT_NAME, USERSTEP_EVENT_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, MAX_METROPLEX_CONNECTION_COUNT, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, END_AT_ATT_NAME, SEVERITY_ERROR, OK_SOCKET_MESSAGE, CLOSE_CONNECTION_FORCEFULLY, BLOCK_SOCKET_MESSAGE, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, MAX_BEACON_PAYLOAD_SIZE, PAGE_VISIT_INFORMATION_ATT_NAME, VIDEO_PART_COUNT_ATT_NAME, IS_LAST_ATT_NAME, SEVERITY_WARN, BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, VER_ATT_NAME, CURRENT_PV_VERSION, PV_SEQ_ATT_NAME, ON_URL_ATT_NAME, REF_URL_ATT_NAME, STARTED_AT_ATT_NAME, CONN_COUNT_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, SCRIPT_ID_ATT_NAME, GET_SCRIPT_ID, SCRIPT_INSTANCE_ID_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, LANG_ATT_NAME, HELP_CODE_ATT_NAME } from '../constants.js';
5
5
  import ClientConfig from './clientConfig.js';
6
6
  import StoredMetrics from './storedMetrics.js';
7
7
  import StoredPageVisit from './storedPageVisit.js';
@@ -59,10 +59,7 @@ class MetroplexSocket {
59
59
  // current page visit has the real initial onURL. Fragments and SPA's
60
60
  // can change the URL without reloading the page.
61
61
  this.initialURL = getProperGlobalUrl();
62
- this.initialReferingURL =
63
- global.document && global.document.referrer
64
- ? getMaxSubstringAllowed(global.document.referrer)
65
- : '';
62
+ this.initialReferingURL = '';
66
63
  this.sessionTimestamp = new Date();
67
64
 
68
65
  // latest time that we received a confirmation message from metroplex
@@ -164,9 +161,9 @@ class MetroplexSocket {
164
161
  * Queues the message if the connection isn't open yet.
165
162
  * @param {} type
166
163
  * @param {} payload
167
- * @returns {boolean} true if message was sent succefully, false otherwise
164
+ * @returns {Promise<boolean>} true if message was sent succefully, false otherwise
168
165
  */
169
- sendMessage(type, payload) {
166
+ async sendMessage(type, payload) {
170
167
  // if we have a lock on this specific type, we dont send it
171
168
  if (
172
169
  type in this.metroplexTypeLock ||
@@ -186,7 +183,7 @@ class MetroplexSocket {
186
183
  this.retryMessageQueue.push({ payload: payloadData, type });
187
184
  StoredPageVisit.getInstance().checkAndStoreRetryQueue(
188
185
  this.retryMessageQueue,
189
- this.getPageInformation(),
186
+ await this.getPageInformation(),
190
187
  );
191
188
  }
192
189
 
@@ -264,7 +261,7 @@ class MetroplexSocket {
264
261
  });
265
262
  this.socketInstanceId = uuid.v4();
266
263
 
267
- this.socket.onerror = () => {
264
+ this.socket.onerror = e => {
268
265
  // use for metrics
269
266
  // there is no useful error message/description from this event
270
267
  };
@@ -395,23 +392,21 @@ class MetroplexSocket {
395
392
  this.sessionLength = delta;
396
393
  }
397
394
 
398
- const endTime = new Date(
399
- this.sessionTimestamp.getTime() + delta,
400
- ).toISOString();
401
-
402
395
  // Assigning this value here is much better than copying the whole object.
403
396
  // eslint-disable-next-line no-param-reassign
404
- payload[END_AT_ATT_NAME] = endTime;
397
+ payload[END_AT_ATT_NAME] = new Date(
398
+ this.sessionTimestamp.getTime() + delta,
399
+ ).toISOString();
405
400
  }
406
401
 
407
402
  /** open handler for socket */
408
- _onSocketOpen() {
403
+ async _onSocketOpen() {
409
404
  // if we are not connected, we do not send any messages
410
405
  if (!this.isConnected() || ClientConfig.getInstance().isClientDisabled) {
411
406
  return;
412
407
  }
413
408
 
414
- this._sendSocketMessage(this.getPageInformation());
409
+ this._sendSocketMessage(await this.getPageInformation());
415
410
  // Set this to allow normal page visit and video frag messages to be sent
416
411
  this.pageVisitInfoSent = true;
417
412
  this.currentConnectionAttempts = 0;
@@ -631,7 +626,7 @@ class MetroplexSocket {
631
626
  * will try to empty both the queues with beacons.
632
627
  * @param {} maxMessageSize
633
628
  */
634
- postFullPageVisit(maxMessageSize) {
629
+ async postFullPageVisit(maxMessageSize) {
635
630
  if (this.retryMessageQueue.length === 0) {
636
631
  return;
637
632
  }
@@ -645,14 +640,14 @@ class MetroplexSocket {
645
640
 
646
641
  let currentMsgPayloadSize = 0;
647
642
  let currentCompletePv = {
648
- [PAGE_VISIT_INFORMATION_ATT_NAME]: this.getPageInformation(),
643
+ [PAGE_VISIT_INFORMATION_ATT_NAME]: await this.getPageInformation(),
649
644
  [PAGE_VISIT_PART_ATT_NAME]: [],
650
645
  [PAGE_VISIT_VID_FRAG_ATT_NAME]: [],
651
646
  [PAGE_VISIT_HTTP_DATA_ATT_NAME]: [],
652
647
  [VIDEO_PART_COUNT_ATT_NAME]: this.connectionCount,
653
648
  };
654
649
  currentCompletePv[PAGE_VISIT_INFORMATION_ATT_NAME][IS_LAST_ATT_NAME] = true;
655
-
650
+ const pageInfo = await this.getPageInformation();
656
651
  this.retryMessageQueue.forEach(msg => {
657
652
  // can't use two variables types in obj deconstruction
658
653
  // eslint-disable-next-line prefer-const
@@ -677,9 +672,9 @@ class MetroplexSocket {
677
672
 
678
673
  // resetting currentCompletePv, since we need to keep adding
679
674
  // events to a blank object to send to metroplex.
680
- // retain the video part count so we don't overwrite anything
675
+ // retain the video part count, so we don't overwrite anything
681
676
  currentCompletePv = {
682
- [PAGE_VISIT_INFORMATION_ATT_NAME]: this.getPageInformation(),
677
+ [PAGE_VISIT_INFORMATION_ATT_NAME]: pageInfo,
683
678
  [PAGE_VISIT_PART_ATT_NAME]: [],
684
679
  [PAGE_VISIT_VID_FRAG_ATT_NAME]: [],
685
680
  [PAGE_VISIT_HTTP_DATA_ATT_NAME]: [],
@@ -765,30 +760,23 @@ class MetroplexSocket {
765
760
  * will send a message to metroplex via a post request that will outlive the current page
766
761
  * @param {} msg
767
762
  */
768
- postMessage(msg) {
763
+ async postMessage(msg) {
769
764
  const updatedMsg = msg;
770
765
 
771
766
  // ensure a unique video part number each call
772
767
  updatedMsg[VIDEO_PART_COUNT_ATT_NAME] += 1;
773
768
 
774
- // we use the beacon api in testing since the version of chromium we are using
775
- // does not support the keepalive flag
776
- if (JS_ENV() === 'test') {
777
- navigator.sendBeacon(this.postURL, stringifyJSON(updatedMsg));
778
- // we only write to the pv route if the fetch api is enabled in the current browser
779
- // and we need to fetch api to set the application/json header for metroplex
780
- } else if (global.fetch) {
781
- // we send the remainder elements
782
- fetch(this.postURL, {
783
- method: 'POST',
784
- headers: {
785
- 'content-type': 'application/json',
786
- },
787
- body: stringifyJSON(updatedMsg),
788
- // keep alive outlives the current page, its the same as beacon
789
- keepalive: true,
790
- });
791
- }
769
+ // we send the remainder elements
770
+ global.fetch(this.postURL, {
771
+ method: 'POST',
772
+ headers: {
773
+ 'content-type': 'application/json',
774
+ 'User-Agent': await getUserAgent(),
775
+ },
776
+ body: stringifyJSON(updatedMsg),
777
+ // keep alive outlives the current page, its the same as beacon
778
+ keepalive: true,
779
+ });
792
780
  }
793
781
 
794
782
  /**
@@ -832,12 +820,12 @@ class MetroplexSocket {
832
820
  }
833
821
 
834
822
  /** will get page information, calling this will increase the connection count */
835
- getPageInformation() {
823
+ async getPageInformation() {
836
824
  const pvi = {
837
825
  [BROWSER_ID_ATT_NAME]: ClientConfig.getInstance().browserId,
838
826
  [PV_ID_ATT_NAME]: ClientConfig.getInstance().pageVisitId,
839
827
  [VER_ATT_NAME]: CURRENT_PV_VERSION,
840
- [PV_SEQ_ATT_NAME]: ClientConfig.getInstance().getPageVisitSeq(),
828
+ [PV_SEQ_ATT_NAME]: await ClientConfig.getInstance().getPageVisitSeq(),
841
829
  [ON_URL_ATT_NAME]: this.initialURL,
842
830
  [REF_URL_ATT_NAME]: this.initialReferingURL,
843
831
  [STARTED_AT_ATT_NAME]: this.sessionTimestamp.toISOString(),
@@ -1,13 +1,13 @@
1
1
  import { BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, VER_ATT_NAME, CURRENT_METRICS_VERSION, EXP_VIDEO_LENGTH_ATT_NAME, PV_EXP_VF_SEQ_ATT_NAME, PV_EXP_PART_COUNTER_ATT_NAME, PV_EXP_HTTP_DATA_SEQ_ATT_NAME, PV_HTTP_PAYLOADS_COLLECTED_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_OVERSIZE_ATT_NAME, PV_HTTP_PAYLOADS_DROPPED_TYPE_ATT_NAME, PV_HTTP_REQUESTS_DROPPED_OVER_LIMIT, VIDEO_CLICKS_ATT_NAME, PV_CLICKS_ATT_NAME, DID_CUT_PV_ATT_NAME, DID_CUT_VID_ATT_NAME, DID_START_VID_ATT_NAME, HTTP_COUNT_EXPECTED_ATT_NAME, ERR_COUNT_EXPECTED_ATT_NAME, ON_URL_ATT_NAME, GET_METROPLEX_METRICS_URL } from '../constants.js';
2
2
  import ClientConfig from './clientConfig.js';
3
- import { stringifyJSON } from '../utils/function.js';
3
+ import { getProperGlobalUrl, getUserAgent, stringifyJSON } from '../utils/function.js';
4
4
  import { addSafeEventListener } from '../utils/eventlistener.js';
5
5
 
6
6
  /** @module StoredMetrics */
7
7
 
8
8
  /**
9
9
  * This class holds the final page visit and video frag metrics. It flushes
10
- * them to local storage and then finally sends them to Metroplex via the post
10
+ * them to storage and then finally sends them to Metroplex via the post
11
11
  * route when the next page is loaded
12
12
  */
13
13
  class StoredMetrics {
@@ -35,7 +35,10 @@ class StoredMetrics {
35
35
  this._setupListeners();
36
36
  }
37
37
 
38
- /** gets the singleton instance */
38
+ /**
39
+ * gets the singleton instance
40
+ * @returns {StoredMetrics}
41
+ */
39
42
  static getInstance() {
40
43
  if (!this.instance) {
41
44
  this.instance = new StoredMetrics();
@@ -148,9 +151,8 @@ class StoredMetrics {
148
151
  }
149
152
 
150
153
  /** posts the metrics to metroplex using the beacon API
151
- * @param {} eventName
152
154
  */
153
- postMetrics(eventName) {
155
+ async postMetrics() {
154
156
  // Create a new object to write to local storage that doesnt have the timeout and flush members.
155
157
  const lsMetrics = {
156
158
  // metadata
@@ -177,24 +179,18 @@ class StoredMetrics {
177
179
  [DID_START_VID_ATT_NAME]: this.didStartVideo,
178
180
  [HTTP_COUNT_EXPECTED_ATT_NAME]: this.httpCount,
179
181
  [ERR_COUNT_EXPECTED_ATT_NAME]: this.errCount,
180
- [ON_URL_ATT_NAME]:
181
- (global.document &&
182
- global.document.location &&
183
- global.document.location.href) ||
184
- 'http://localhost',
182
+ [ON_URL_ATT_NAME]: getProperGlobalUrl(), // todo implement navigation
185
183
  };
186
-
187
- if (global.fetch) {
188
- global.fetch(GET_METROPLEX_METRICS_URL(), {
189
- method: 'POST',
190
- headers: {
191
- 'content-type': 'application/json',
192
- },
193
- body: stringifyJSON(lsMetrics),
194
- // keep alive outlives the current page, its the same as beacon
195
- keepalive: true,
196
- });
197
- }
184
+ global.fetch(GET_METROPLEX_METRICS_URL(), {
185
+ method: 'POST',
186
+ headers: {
187
+ 'content-type': 'application/json',
188
+ 'User-Agent': await getUserAgent(),
189
+ },
190
+ body: stringifyJSON(lsMetrics),
191
+ // keep alive outlives the current page, its the same as beacon
192
+ keepalive: true,
193
+ });
198
194
  }
199
195
  }
200
196