noibu-react-native 0.2.3 → 0.2.4

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 (66) hide show
  1. package/dist/api/helpCode.js +61 -87
  2. package/dist/api/metroplexSocket.js +72 -65
  3. package/dist/api/storedPageVisit.js +150 -208
  4. package/dist/constants.js +3 -7
  5. package/dist/entry/init.js +11 -11
  6. package/dist/monitors/{appNavigationMonitor.js → AppNavigationMonitor.js} +10 -19
  7. package/dist/monitors/ClickMonitor.js +198 -0
  8. package/dist/monitors/ErrorMonitor.js +206 -0
  9. package/dist/monitors/KeyboardInputMonitor.js +60 -0
  10. package/dist/monitors/PageMonitor.js +98 -0
  11. package/dist/monitors/RequestMonitor.js +390 -0
  12. package/dist/monitors/http-tools/GqlErrorValidator.js +259 -0
  13. package/dist/monitors/{httpDataBundler.js → http-tools/HTTPDataBundler.js} +23 -102
  14. package/dist/pageVisit/{eventDebouncer.js → EventDebouncer.js} +36 -47
  15. package/dist/pageVisit/pageVisitEventError.js +3 -3
  16. package/dist/pageVisit/pageVisitEventHTTP.js +5 -4
  17. package/dist/sessionRecorder/sessionRecorder.js +1 -1
  18. package/dist/src/api/clientConfig.d.ts +1 -1
  19. package/dist/src/api/helpCode.d.ts +10 -16
  20. package/dist/src/api/metroplexSocket.d.ts +52 -71
  21. package/dist/src/api/storedPageVisit.d.ts +12 -21
  22. package/dist/src/constants.d.ts +1 -0
  23. package/dist/src/monitors/AppNavigationMonitor.d.ts +18 -0
  24. package/dist/src/monitors/ClickMonitor.d.ts +31 -0
  25. package/dist/src/monitors/ErrorMonitor.d.ts +63 -0
  26. package/dist/src/monitors/{keyboardInputMonitor.d.ts → KeyboardInputMonitor.d.ts} +7 -4
  27. package/dist/src/monitors/{pageMonitor.d.ts → PageMonitor.d.ts} +6 -8
  28. package/dist/src/monitors/RequestMonitor.d.ts +94 -0
  29. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +59 -0
  30. package/dist/src/monitors/{httpDataBundler.d.ts → http-tools/HTTPDataBundler.d.ts} +13 -28
  31. package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +3 -2
  32. package/dist/src/pageVisit/{eventDebouncer.d.ts → EventDebouncer.d.ts} +3 -10
  33. package/dist/src/pageVisit/pageVisit.d.ts +1 -1
  34. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +3 -3
  35. package/dist/src/storage/rnStorageProvider.d.ts +1 -1
  36. package/dist/src/storage/storage.d.ts +1 -1
  37. package/dist/src/storage/storageProvider.d.ts +2 -2
  38. package/dist/src/utils/function.d.ts +4 -5
  39. package/dist/src/utils/object.d.ts +3 -5
  40. package/dist/src/utils/polyfills.d.ts +1 -4
  41. package/dist/types/Metroplex.types.d.ts +73 -0
  42. package/dist/types/Monitor.d.ts +11 -0
  43. package/dist/types/Monitor.js +19 -0
  44. package/dist/types/PageVisit.types.d.ts +2 -145
  45. package/dist/types/PageVisitErrors.types.d.ts +114 -0
  46. package/dist/types/PageVisitEvents.types.d.ts +91 -0
  47. package/dist/types/Storage.d.ts +1 -1
  48. package/dist/types/StoredPageVisit.types.d.ts +4 -45
  49. package/dist/utils/function.js +0 -1
  50. package/dist/utils/object.js +1 -0
  51. package/package.json +4 -3
  52. package/dist/monitors/clickMonitor.js +0 -258
  53. package/dist/monitors/errorMonitor.js +0 -202
  54. package/dist/monitors/gqlErrorValidator.js +0 -306
  55. package/dist/monitors/inputMonitor.js +0 -138
  56. package/dist/monitors/keyboardInputMonitor.js +0 -66
  57. package/dist/monitors/pageMonitor.js +0 -122
  58. package/dist/monitors/requestMonitor.js +0 -386
  59. package/dist/src/monitors/appNavigationMonitor.d.ts +0 -22
  60. package/dist/src/monitors/clickMonitor.d.ts +0 -44
  61. package/dist/src/monitors/errorMonitor.d.ts +0 -28
  62. package/dist/src/monitors/gqlErrorValidator.d.ts +0 -82
  63. package/dist/src/monitors/inputMonitor.d.ts +0 -34
  64. package/dist/src/monitors/requestMonitor.d.ts +0 -10
  65. package/dist/types/RRWeb.d.ts +0 -48
  66. package/dist/types/ReactNative.d.ts +0 -4
@@ -1,17 +1,19 @@
1
1
  import { __awaiter } from 'tslib';
2
- import { HUMAN_READABLE_CONTENT_TYPE_REGEX, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, SEVERITY, HTTP_BODY_NULL_STRING, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_BODY_DROPPED_LENGTH_MSG, HTTP_BODY_DROPPED_TYPE_MSG, CONTENT_TYPE, CONTENT_LENGTH, BLOCKED_HTTP_HEADER_KEYS, PII_REDACTION_REPLACEMENT_STRING, MAX_HTTP_DATA_PAYLOAD_LENGTH, MAX_SUCCESS_HTTP_DATA_PAYLOAD_LENGTH } from '../constants.js';
3
- import ClientConfig from '../api/clientConfig.js';
4
- import StoredMetrics from '../api/storedMetrics.js';
5
- import { safeFromEntries, safeEntries } from '../utils/object.js';
6
- import { safeTrim, stringifyJSON, isString } from '../utils/function.js';
7
- import { removePII } from '../utils/piiRedactor.js';
2
+ import { HUMAN_READABLE_CONTENT_TYPE_REGEX, DEFAULT_WEBSITE_SUBDOMAIN_PATTERN, SEVERITY, HTTP_BODY_NULL_STRING, HTTP_DATA_REQ_HEADERS_ATT_NAME, HTTP_DATA_PAYLOAD_ATT_NAME, HTTP_DATA_RESP_HEADERS_ATT_NAME, HTTP_DATA_RESP_PAYLOAD_ATT_NAME, HTTP_BODY_DROPPED_LENGTH_MSG, HTTP_BODY_DROPPED_TYPE_MSG, CONTENT_TYPE, CONTENT_LENGTH, BLOCKED_HTTP_HEADER_KEYS, PII_REDACTION_REPLACEMENT_STRING, MAX_HTTP_DATA_PAYLOAD_LENGTH, MAX_SUCCESS_HTTP_DATA_PAYLOAD_LENGTH } from '../../constants.js';
3
+ import ClientConfig from '../../api/clientConfig.js';
4
+ import StoredMetrics from '../../api/storedMetrics.js';
5
+ import { safeFromEntries, safeEntries } from '../../utils/object.js';
6
+ import { safeTrim, stringifyJSON, isString } from '../../utils/function.js';
7
+ import { removePII } from '../../utils/piiRedactor.js';
8
+ import { Singleton } from '../../types/Monitor.js';
8
9
 
9
10
  /** Bundles HTTP payloads and headers */
10
- class HTTPDataBundler {
11
+ class HTTPDataBundler extends Singleton {
11
12
  /**
12
13
  * Creates an instance of the ClickMonitor instance
13
14
  */
14
15
  constructor() {
16
+ super();
15
17
  // compile regex only once
16
18
  this.contentTypeReadableRegex = new RegExp(HUMAN_READABLE_CONTENT_TYPE_REGEX, 'i');
17
19
  // pull out the domain hostname
@@ -43,15 +45,6 @@ class HTTPDataBundler {
43
45
  // TODO: disabled for beta. NOI-4253
44
46
  // this.uniqueRequests = new Set();
45
47
  }
46
- /** gets the singleton instance
47
- * @returns {HTTPDataBundler}
48
- * */
49
- static getInstance() {
50
- if (!this.instance) {
51
- this.instance = new HTTPDataBundler();
52
- }
53
- return this.instance;
54
- }
55
48
  /**
56
49
  * Builds the HTTP payload allowed regexes for full and relative URLs
57
50
  * @param allowedURLs A list of allowed URLs
@@ -77,13 +70,12 @@ class HTTPDataBundler {
77
70
  }
78
71
  /**
79
72
  * Takes an iterator and returns a map of strings representing headers.
80
- * @param {object} headersIterable any iterable object
81
- * @returns a map of strings (as expected by metroplex) representing HTTP
73
+ * param {object} headersIterable any iterable object
74
+ * returns a map of strings (as expected by metroplex) representing HTTP
82
75
  * request or response headers
83
76
  */
84
77
  static headersMapFromIterable(headersIterable) {
85
78
  const headerMap = new Map();
86
- // eslint-disable-next-line no-restricted-syntax
87
79
  for (const header of headersIterable) {
88
80
  // Ensure we're working with strings
89
81
  // This will also automatically convert null to "null"
@@ -153,65 +145,11 @@ class HTTPDataBundler {
153
145
  return null;
154
146
  });
155
147
  }
156
- /**
157
- * Takes a URL and returns true if it is determined to be on the same domain as the URL
158
- * the script is running on. Ignores protocol and path, and allows the URL to be a subdomain.
159
- * @param {string} requestURL the URL of a request to compare to the script website's URL
160
- * @param {bool} isHostnameCheck the URL is a domain hostname, could be a super or sub domain
161
- */
162
- isURLSameDomain(requestURL, isHostnameCheck = false) {
163
- if (typeof requestURL !== 'string' ||
164
- !this.initialURLPartsReversed ||
165
- this.initialURLPartsReversed.length < 1) {
166
- return false;
167
- }
168
- let requestHostname = isHostnameCheck ? requestURL : ''; // has to be declared outside of `try`
169
- // Use URL constructor to extract hostname
170
- if (!isHostnameCheck) {
171
- try {
172
- let requestURLWithProtocol = requestURL;
173
- if (requestURL.startsWith('//')) {
174
- // eslint-disable-next-line prefer-template
175
- requestURLWithProtocol = 'https:' + requestURL;
176
- }
177
- requestHostname = new URL(requestURLWithProtocol).hostname;
178
- }
179
- catch (e) {
180
- // Return false if URL() is unable to parse the request URL
181
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Unable to determine hostname for request URL: ${e}`, false, SEVERITY.warn);
182
- return false;
183
- }
184
- }
185
- const requestParts = requestHostname.split('.');
186
- // Remove first subdomain from either URL if it is www., www1., etc.
187
- if (requestParts.length < 1)
188
- return false;
189
- /* eslint-disable no-unused-expressions */
190
- DEFAULT_WEBSITE_SUBDOMAIN_PATTERN.test(requestParts[0]) &&
191
- requestParts.shift();
192
- /* eslint-enable no-unused-expressions */
193
- // Reverse order array
194
- requestParts.reverse();
195
- if (!isHostnameCheck &&
196
- requestParts.length < this.initialURLPartsReversed.length)
197
- return false;
198
- // Return true if for every part in the website part, the same part exists
199
- // in the request part, or if alsoCheckSuperDomain is true.
200
- if (isHostnameCheck) {
201
- const isSubDomain = requestParts.length >= this.initialURLPartsReversed.length &&
202
- this.initialURLPartsReversed.every((part, i) => part === requestParts[i]);
203
- const isSuperDomain = requestParts.length <= this.initialURLPartsReversed.length &&
204
- requestParts.every((part, i) => part === this.initialURLPartsReversed[i]);
205
- return isSubDomain || isSuperDomain;
206
- }
207
- // Default return false if alsoCheckSuperDomain is not true
208
- return this.initialURLPartsReversed.every((part, i) => part === requestParts[i]);
209
- }
210
148
  /**
211
149
  * Builds an HTTP Data bundle
212
150
  */
213
151
  bundleHTTPData(url, requestHeaders, rawRequestPayload, responseHeaders, rawResponsePayload, method, isError) {
214
- if (!this.isValidRequest(url, method)) {
152
+ if (!this.isValidRequest(method)) {
215
153
  return null;
216
154
  }
217
155
  // stringify payload if correct type and not too large
@@ -253,24 +191,9 @@ class HTTPDataBundler {
253
191
  /**
254
192
  * Validates a request based on the URL and method. When enabled, will handle
255
193
  * de-duping the requests
256
- * @param {string} url
257
- * @param {string} method
258
- * @returns boolean indicating whether the validation passed
259
194
  */
260
- isValidRequest(url, method) {
261
- if (!this.httpDataCollectionEnabled)
262
- return false;
263
- if (!method || typeof method !== 'string') {
264
- return false;
265
- }
266
- // TODO: Check below disabled for beta. NOI-4253
267
- // only bundle and send once per request/method/response code combination
268
- // const urlWithoutParams = url.split('?')[0];
269
- // const requestSignature = `${urlWithoutParams}-${method}-${responseCode}`;
270
- // if (this.uniqueRequests.has(requestSignature)) {
271
- // return false;
272
- // }
273
- return true;
195
+ isValidRequest(method) {
196
+ return (this.httpDataCollectionEnabled && method && typeof method === 'string');
274
197
  }
275
198
  /**
276
199
  * Checks two things: that the URL is either on the same domain (or an address relative to the
@@ -288,15 +211,15 @@ class HTTPDataBundler {
288
211
  // URL is absolute; either "http://example.com" or "//example.com"
289
212
  if (HTTPDataBundler.isAbsoluteURL(url)) {
290
213
  // Only capture requests on the same domain or in the allowed list
291
- if (!this.isURLSameDomain(url) && !this.shouldCollectPayloadForURL(url))
214
+ if (!this.shouldCollectPayloadForURL(url)) {
292
215
  return false;
216
+ }
293
217
  } // end `if` (if URL is relative, it is on the same domain.)
294
218
  return true;
295
219
  }
296
220
  /**
297
- * Determins if the URL is absolute or relative
298
- * @param {string} url
299
- * @returns boolean indicating whether the URL passed is either absolute or relative
221
+ * Determines if the URL is absolute or relative
222
+ * returns boolean indicating whether the URL passed is either absolute or relative
300
223
  */
301
224
  static isAbsoluteURL(url) {
302
225
  if (!url || typeof url !== 'string') {
@@ -306,22 +229,20 @@ class HTTPDataBundler {
306
229
  }
307
230
  /**
308
231
  * Checks whether HTTP payloads can be collected on this URL
309
- * @returns boolean indicating whether HTTP payloads can be collected on this URL
232
+ * returns boolean indicating whether HTTP payloads can be collected on this URL
310
233
  */
311
234
  shouldCollectPayloadForURL(url) {
235
+ var _a, _b;
312
236
  if (!url || typeof url !== 'string') {
313
237
  return false;
314
238
  }
315
239
  // check if in the full URL allowed list
316
- const isAllowedAsAbsolute = !!this.httpDataAllowedAbsoluteRegex &&
317
- this.httpDataAllowedAbsoluteRegex.test(url.toLowerCase());
318
- const isRelative = !HTTPDataBundler.isAbsoluteURL(url) || this.isURLSameDomain(url);
240
+ const isAllowedAsAbsolute = (_a = this.httpDataAllowedAbsoluteRegex) === null || _a === void 0 ? void 0 : _a.test(url.toLowerCase());
241
+ const isRelative = !HTTPDataBundler.isAbsoluteURL(url);
319
242
  // check if in the relative URL allowed list or if it is on the same domain
320
243
  const isAllowedAsRelative =
321
244
  // if this is a relative URL (isURLSameDomain will fail) OR a full URL on domain
322
- isRelative &&
323
- !!this.httpDataAllowedRelativeRegex &&
324
- this.httpDataAllowedRelativeRegex.test(url.toLowerCase());
245
+ isRelative && ((_b = this.httpDataAllowedRelativeRegex) === null || _b === void 0 ? void 0 : _b.test(url.toLowerCase()));
325
246
  return isAllowedAsAbsolute || isAllowedAsRelative;
326
247
  }
327
248
  /**
@@ -1,65 +1,54 @@
1
1
  import { PageVisit } from './pageVisit.js';
2
- import { LOCATION_EVENT_TYPE, TITLE_EVENT_TYPE, PAGE_TYPE_EVENT_TYPE, PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, ERROR_EVENT_TYPE, HTTP_EVENT_TYPE, NETWORK_STATS_EVENT_TYPE, KEYBOARD_EVENT_TYPE, USERSTEP_EVENT_TYPE, ECOMMERCE_EVENT_TYPE, SEVERITY } from '../constants.js';
2
+ import { APP_NAVIGATION_EVENT_TYPE, PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, ERROR_EVENT_TYPE, HTTP_EVENT_TYPE, KEYBOARD_EVENT_TYPE, SEVERITY } from '../constants.js';
3
3
  import { timestampWrapper } from '../utils/date.js';
4
4
  import { addSafeEventListener } from '../utils/eventlistener.js';
5
5
  import ClientConfig from '../api/clientConfig.js';
6
+ import { Singleton } from '../types/Monitor.js';
6
7
 
7
8
  /** @module EventDebouncer */
8
9
  /**
9
10
  * Singleton class responsible for debouncing all events
10
11
  * that are registered
11
12
  */
12
- class EventDebouncer {
13
+ class EventDebouncer extends Singleton {
13
14
  /**
14
15
  * Creates an instance of EventDebouncer
15
16
  */
16
17
  constructor() {
17
- // events are stored in queues that are debounced seperatly
18
- // each object in this map is
19
- // type: {
20
- // timeout: timeout,
21
- // events: [...],
22
- // debouncePeriod: period at which we debounce events,
23
- // eventName: name of the event, could be different than type
24
- // (clicks and keyboards are usersteps)
25
- // }
26
- this.eventsToDebounce = {};
27
- // setting up debouncers for all events
28
- // we send clicks directly to the socket so they aren't registered here
29
- // we dont wait to send location changes, they happen at most once per second.
30
- this.registerInputType(LOCATION_EVENT_TYPE, 0);
31
- this.registerInputType(TITLE_EVENT_TYPE, 0);
32
- this.registerInputType(PAGE_TYPE_EVENT_TYPE, 0);
33
- this.registerInputType(PAGE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
34
- this.registerInputType(ERROR_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
35
- this.registerInputType(HTTP_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
36
- this.registerInputType(NETWORK_STATS_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
37
- this.registerInputType(KEYBOARD_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS, USERSTEP_EVENT_TYPE);
38
- this.registerInputType(ECOMMERCE_EVENT_TYPE, MAX_TIME_FOR_UNSENT_DATA_MILLIS);
39
- this._setupUnloadHandler();
40
- }
41
- /**
42
- * gets the instance of EventDebouncer
43
- */
44
- static getInstance() {
45
- if (!this.instance) {
46
- this.instance = new EventDebouncer();
47
- }
48
- return this.instance;
49
- }
50
- /** will debounce all events that are of this type by the debounce period
51
- */
52
- registerInputType(type, debouncePeriod, eventName = type) {
53
- if (type in this.eventsToDebounce) {
54
- return;
55
- }
56
- // registering this event type as a debouncable
57
- this.eventsToDebounce[type] = {
58
- timeout: null,
59
- events: [],
60
- debouncePeriod,
61
- eventName,
18
+ super();
19
+ this.eventsToDebounce = {
20
+ [APP_NAVIGATION_EVENT_TYPE]: {
21
+ timeout: null,
22
+ events: [],
23
+ debouncePeriod: 0,
24
+ eventName: APP_NAVIGATION_EVENT_TYPE,
25
+ },
26
+ [PAGE_EVENT_TYPE]: {
27
+ timeout: null,
28
+ events: [],
29
+ debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
30
+ eventName: PAGE_EVENT_TYPE,
31
+ },
32
+ [ERROR_EVENT_TYPE]: {
33
+ timeout: null,
34
+ events: [],
35
+ debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
36
+ eventName: ERROR_EVENT_TYPE,
37
+ },
38
+ [HTTP_EVENT_TYPE]: {
39
+ timeout: null,
40
+ events: [],
41
+ debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
42
+ eventName: HTTP_EVENT_TYPE,
43
+ },
44
+ [KEYBOARD_EVENT_TYPE]: {
45
+ timeout: null,
46
+ events: [],
47
+ debouncePeriod: MAX_TIME_FOR_UNSENT_DATA_MILLIS,
48
+ eventName: KEYBOARD_EVENT_TYPE,
49
+ },
62
50
  };
51
+ this._setupUnloadHandler();
63
52
  }
64
53
  /**
65
54
  * Creates an event object with the event and the time it was added then pushes
@@ -1,8 +1,8 @@
1
1
  import { isValidURL, getJSStack, stringifyJSON, getMaxSubstringAllowed, asString } from '../utils/function.js';
2
- import { EVENT_ERROR_TYPE, URL_ATT_NAME, BLOCKLISTED_DOMAINS, ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, FETCH_EXCEPTION_ERROR_TYPE, WRAPPED_EXCEPTION_ERROR_TYPE, GQL_ERROR_TYPE, RESPONSE_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, TYPE_ATT_NAME, JS_EVENT_TYPE, JS_ERROR_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, SEVERITY, JS_STACK_MESSAGE_ATT_NAME, HTTP_EVENT_TYPE, NOIBU_INPUT_URLS, HTTP_CODE_ATT_NAME, GQL_EVENT_TYPE, GQL_ERROR_ATT_NAME, PV_SEQ_ATT_NAME } from '../constants.js';
2
+ import { EVENT_ERROR_TYPE, URL_ATT_NAME, BLOCKLISTED_DOMAINS, ERROR_EVENT_TYPE, ERROR_EVENT_ERROR_TYPE, CUSTOM_ERROR_EVENT_TYPE, ERROR_EVENT_UNHANDLED_REJECTION_TYPE, ERROR_LOG_EVENT_ERROR_TYPE, FETCH_EXCEPTION_ERROR_TYPE, WRAPPED_EXCEPTION_ERROR_TYPE, GQL_ERROR_TYPE, RESPONSE_ERROR_TYPE, XML_HTTP_REQUEST_ERROR_TYPE, ERROR_SOURCE_ATT_NAME, TYPE_ATT_NAME, JS_EVENT_TYPE, JS_ERROR_ATT_NAME, JS_STACK_FRAMES_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_METHOD_ATT_NAME, SEVERITY, JS_STACK_MESSAGE_ATT_NAME, HTTP_EVENT_TYPE, NOIBU_INPUT_URLS, HTTP_CODE_ATT_NAME, PV_SEQ_ATT_NAME, GQL_EVENT_TYPE, GQL_ERROR_ATT_NAME } from '../constants.js';
3
3
  import ClientConfig from '../api/clientConfig.js';
4
- import { InputMonitor } from '../monitors/inputMonitor.js';
5
4
  import StoredMetrics from '../api/storedMetrics.js';
5
+ import { EventDebouncer } from './EventDebouncer.js';
6
6
 
7
7
  /** @module PageVisitEventError */
8
8
 
@@ -314,7 +314,7 @@ function saveErrorToPagevisit(type, payload, httpDataSeqNum) {
314
314
  // we register an error event
315
315
  StoredMetrics.getInstance().addError();
316
316
  // debounce event
317
- InputMonitor.getInstance().addEvent(pvError, ERROR_EVENT_TYPE);
317
+ EventDebouncer.getInstance().addEvent(pvError, ERROR_EVENT_TYPE);
318
318
  }
319
319
 
320
320
  export { getOnURL, isErrorCollectedByNoibu, saveErrorToPagevisit };
@@ -1,10 +1,10 @@
1
1
  import { timestampWrapper } from '../utils/date.js';
2
- import { HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_METHOD_ATT_NAME, URL_ATT_NAME, PV_SEQ_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT, PAGE_VISIT_HTTP_DATA_ATT_NAME } from '../constants.js';
2
+ import { HTTP_RESP_CODE_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_METHOD_ATT_NAME, URL_ATT_NAME, PV_SEQ_ATT_NAME, PAGE_VISIT_HTTP_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, MAX_HTTP_DATA_EVENT_COUNT, MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT } from '../constants.js';
3
3
  import { PageVisit } from './pageVisit.js';
4
4
  import StoredMetrics from '../api/storedMetrics.js';
5
5
  import MetroplexSocket from '../api/metroplexSocket.js';
6
6
  import { getMaxSubstringAllowed, asString, safeTrim } from '../utils/function.js';
7
- import { EventDebouncer } from './eventDebouncer.js';
7
+ import { EventDebouncer } from './EventDebouncer.js';
8
8
 
9
9
  /** @module PageVisitEventHTTP */
10
10
  /**
@@ -54,8 +54,9 @@ class PageVisitEventHTTP {
54
54
  this.httpEvent[PV_SEQ_ATT_NAME] = sequenceNumber;
55
55
  // increment the count
56
56
  StoredMetrics.getInstance().addHttpData();
57
- const metroplexMsg = {};
58
- metroplexMsg[PAGE_VISIT_HTTP_DATA_ATT_NAME] = this.httpData;
57
+ const metroplexMsg = {
58
+ [PAGE_VISIT_HTTP_DATA_ATT_NAME]: this.httpData,
59
+ };
59
60
  MetroplexSocket.getInstance().sendMessage(HTTP_DATA_METROPLEX_TYPE, metroplexMsg);
60
61
  }
61
62
  else {
@@ -4,7 +4,7 @@ import { LogLevel, initialize, subscribeToNativeEvent } from './nativeSessionRec
4
4
  import StoredMetrics from '../api/storedMetrics.js';
5
5
  import ClientConfig from '../api/clientConfig.js';
6
6
  import { stringifyJSON } from '../utils/function.js';
7
- import { SEVERITY, POST_METRICS_EVENT_NAME, MAX_TIME_FOR_RECORDER_USER_EVENTS, MAX_RECORDER_EVENT_BUFFER, MAX_TIME_FOR_UNSENT_DATA_MILLIS, VIDEO_FRAG_ATT_NAME, PV_SEQ_ATT_NAME, LENGTH_ATT_NAME, CSS_URLS_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME } from '../constants.js';
7
+ import { MAX_TIME_FOR_RECORDER_USER_EVENTS, SEVERITY, MAX_RECORDER_EVENT_BUFFER, MAX_TIME_FOR_UNSENT_DATA_MILLIS, VIDEO_FRAG_ATT_NAME, PV_SEQ_ATT_NAME, LENGTH_ATT_NAME, CSS_URLS_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, POST_METRICS_EVENT_NAME } from '../constants.js';
8
8
  import MetroplexSocket from '../api/metroplexSocket.js';
9
9
  import { addSafeEventListener } from '../utils/eventlistener.js';
10
10
  import { noibuLog } from '../utils/log.js';
@@ -43,7 +43,7 @@ export default class ClientConfig {
43
43
  /** Updates the config object to store the given last active time */
44
44
  updateLastActiveTime(lastActiveTime: Date): Promise<void>;
45
45
  /** Gets the current page visit sequence number that should be used */
46
- getPageVisitSeq(): Promise<number | null>;
46
+ getPageVisitSeq(): Promise<number>;
47
47
  /**
48
48
  * Returns the client config object from storage or generates a new one
49
49
  * What is stored in storage will look like this
@@ -1,23 +1,13 @@
1
+ import { Singleton } from '../../types/Monitor';
1
2
  /**
2
3
  * HelpCode class is responsible for help code feature related functionality
3
4
  */
4
- export default class HelpCode {
5
+ export default class HelpCode extends Singleton {
6
+ private requestContext;
5
7
  /**
6
- * Singleton instance
7
- * @returns {HelpCode}
8
+ * Constructs instance and sets up event listeners
8
9
  */
9
- static getInstance(): HelpCode;
10
- requestContext: {
11
- resolve: null;
12
- reject: null;
13
- promise: null;
14
- } | null;
15
- /**
16
- * Handles the received help code event.
17
- * @param {CustomEvent<string>} event - The event object with string detail property.
18
- * @returns {void}
19
- */
20
- receiveHelpCode(event: CustomEvent<string>): void;
10
+ constructor();
21
11
  /**
22
12
  * Requests a help code and returns a Promise that resolves when the help code is obtained
23
13
  * or rejects if the noibu connection is unavailable.
@@ -25,5 +15,9 @@ export default class HelpCode {
25
15
  * @returns {Promise<string>} Promise object representing the help code request.
26
16
  * @throws {string} Throws an error if the noibu connection is unavailable.
27
17
  */
28
- requestHelpCode(): Promise<string>;
18
+ requestHelpCode(): Promise<unknown>;
19
+ /**
20
+ * Handles the received help code event.
21
+ */
22
+ receiveHelpCode(event: CustomEvent<string>): void;
29
23
  }
@@ -1,67 +1,67 @@
1
- import { END_AT_ATT_NAME } from '../constants';
1
+ import { PAGE_VISIT_PART_ATT_NAME, PAGE_VISIT_VID_FRAG_ATT_NAME } from '../constants';
2
+ import { Singleton } from '../../types/Monitor';
3
+ import { CompletePageVisit, InboundMessageType, OutboundMessageType, OutboundMessageTypeMap, PageVisitFrag, PageVisitInfo, SlidingMessage, VideoFrag } from '../../types/Metroplex.types';
4
+ import { PVEventMessage } from '../../types/PageVisitEvents.types';
5
+ /**
6
+ * Implements rolling window of specified size,
7
+ * but only makes a cut once array length exceeds 150%.
8
+ * During downsize deletes oldest (lowest indexes) elements.
9
+ */
10
+ export declare function createSlidingArrayOfSize<T>(size: number, arraySource?: T[], downsizeThreshold?: number, downsizeFactor?: number): T[];
2
11
  /** Manages the socket to Metroplex */
3
- export default class MetroplexSocket {
4
- _initialURL: any;
5
- ackedOnce: any;
6
- connectionCount: any;
7
- connectionPromise: Promise<any>;
8
- connectionURL: any;
9
- currentConnectionAttempts: any;
10
- forceClosed: any;
11
- helpCodeCb: null | ((...args: any[]) => any);
12
- initialReferingURL: any;
13
- static instance: MetroplexSocket;
14
- instanceId: any;
15
- isRetryLoopDisabled: any;
16
- latestReceivedSeqNumStoredTime: any;
17
- latestReceivedSeqNumber: any;
18
- messageSequenceNum: any;
19
- metroRetryFrequencyMS: any;
20
- metroplexTypeLock: Record<any, any>;
21
- pageVisitInfoSent: any;
22
- postURL: any;
23
- previousMessageType: any;
24
- retryMessageQueue: any[];
25
- retryMetroplexInterval: null | number;
26
- scriptInstanceId: any;
27
- sessionLength: any;
28
- sessionStartTime: any;
29
- sessionTimestamp: any;
12
+ export default class MetroplexSocket extends Singleton {
13
+ forceClosed: boolean;
30
14
  socket: WebSocket | null;
31
- socketInstanceId: string | number[] | null;
15
+ socketInstanceId: string | null;
16
+ previousMessageType: string;
17
+ currentConnectionAttempts: number;
18
+ connectionCount: number;
19
+ sessionStartTime: any;
20
+ connectionPromise: Promise<void> | null;
21
+ pageVisitInfoSent: boolean;
22
+ connectionURL: string;
23
+ postURL: string;
24
+ messageSequenceNum: number;
25
+ latestReceivedSeqNumber: number;
26
+ isRetryLoopDisabled: boolean;
27
+ /** messages that need to be resent to metroplex since they are lacking confirmation */
28
+ retryMessageQueue: SlidingMessage<keyof OutboundMessageTypeMap>[];
29
+ metroplexTypeLock: Record<OutboundMessageType, boolean>;
30
+ initialURL: string;
31
+ initialReferringURL: string;
32
+ sessionTimestamp: Date;
33
+ latestReceivedSeqNumStoredTime: Date;
34
+ instanceId: string;
35
+ scriptInstanceId?: string;
36
+ sessionLength: number;
32
37
  socketCloseCodes: string[];
33
38
  socketOpens: string[];
39
+ ackedOnce: boolean;
40
+ metroRetryFrequencyMS: 30000;
41
+ retryMetroplexInterval: ReturnType<typeof setTimeout> | null;
42
+ private helpCodeCb;
34
43
  /**
35
44
  * Creates an instance of metroplex
36
45
  * id of script, to make sure only a single socket is open
37
46
  */
38
- constructor(scriptInstanceId?: string | number[]);
39
- /**
40
- * gets the singleton instance
41
- * @returns {MetroplexSocket}
42
- */
43
- static getInstance(scriptInstanceId?: string | number[]): MetroplexSocket;
47
+ constructor(scriptInstanceId?: string);
48
+ private static readonly typeToPayloadPropMap;
44
49
  /**
45
50
  * Adds the seq num field to the given payload depending on whether its
46
51
  * a page visit part or video frag
47
52
  */
48
- _addSeqNumToPayload(type: string, payload: any): void;
49
- /**
50
- * sets the seq num in the payload for the given key and increments the
51
- * global seq number
52
- */
53
- _setSeqNumInPayloadAndIncrementSeqNum(payloadKey: string, payload: any): void;
53
+ _addSeqNumToPayload<T>(type: OutboundMessageType, payload: T): T;
54
54
  /** requests help code and saves a callback to be called on response */
55
- requestHelpCode(cb: (typeof this)['helpCodeCb']): Promise<boolean>;
55
+ requestHelpCode(cb: typeof this.helpCodeCb): Promise<boolean>;
56
56
  /**
57
57
  * Immediately sends a message to Metroplex over the web socket
58
58
  * Queues the message if the connection isn't open yet.
59
59
  * returns true if message was sent succefully, false otherwise
60
60
  */
61
- sendMessage(type: string, payload: any): Promise<boolean>;
61
+ sendMessage<T extends OutboundMessageType>(type: T, payload: OutboundMessageTypeMap[T]): Promise<boolean>;
62
62
  /** Updates the latest pv message sent timestamp if events contain any user steps
63
63
  */
64
- _updateLatestPvTimestamp(events: any[]): Promise<void>;
64
+ _updateLatestPvTimestamp(events: PVEventMessage[]): Promise<void>;
65
65
  /** returns true if the socket is either connecting or connected to metroplex */
66
66
  isConnected(): boolean;
67
67
  /** returns true if we are connecting to the socket */
@@ -75,25 +75,23 @@ export default class MetroplexSocket {
75
75
  * connectSocket will establish a websocket connection to the metroplex
76
76
  * service
77
77
  */
78
- connectSocket(): Promise<any>;
78
+ connectSocket(): Promise<void>;
79
79
  /** Calculates and sets the end_at field of the payload
80
80
  * @param {} payload
81
81
  * @param {} isPageVisit
82
82
  */
83
- addEndTimeToPayload(payload: any, isPageVisit: boolean): typeof payload & {
84
- [END_AT_ATT_NAME]: string;
85
- };
83
+ addEndTimeToPayload<T extends VideoFrag | PageVisitFrag>(payload: T, isPageVisit: boolean): T;
86
84
  /** open handler for socket */
87
85
  _onSocketOpen(): Promise<void>;
88
86
  /** message handler for socket
89
87
  * @param {} event
90
88
  */
91
- _onSocketMessage(event: any): Promise<void>;
89
+ _onSocketMessage(event: InboundMessageType): Promise<void>;
92
90
  /**
93
91
  * Returns true if the message's payload has the payload type given and has a sequence
94
92
  * number higher than seqNum
95
93
  */
96
- _messagePayloadHasLargerSeqNum(message: any, payloadType: string, seqNum: number): any;
94
+ _messagePayloadHasLargerSeqNum(message: SlidingMessage, payloadType: typeof PAGE_VISIT_PART_ATT_NAME | typeof PAGE_VISIT_VID_FRAG_ATT_NAME, seqNum: number): boolean;
97
95
  /**
98
96
  * removes messages from the retry queue that are smaller than the
99
97
  * latest stored message in metroplex
@@ -118,39 +116,22 @@ export default class MetroplexSocket {
118
116
  /**
119
117
  * will send a message to metroplex via a post request that will outlive the current page
120
118
  */
121
- postMessage(msg: any): Promise<void>;
119
+ postMessage(msg: CompletePageVisit): Promise<void>;
122
120
  /**
123
121
  * Stringifies the payload into JSON, sends it to the back end if the session
124
122
  * is active and returns true. If inactive the session and socket are closed
125
123
  * and this method returns false.
126
124
  */
127
- _sendSocketMessage(payload: any): Promise<void>;
125
+ _sendSocketMessage<T extends ValueOf<OutboundMessageTypeMap>>(payload: T): Promise<void>;
128
126
  /**
129
127
  * Closes the socket connection if the session is inactive. Returns true if the
130
128
  * session is inactive
131
129
  */
132
130
  closeIfInactive(): Promise<boolean>;
133
131
  /** will get page information, calling this will increase the connection count */
134
- getPageInformation(): Promise<{
135
- br_id: string;
136
- pv_id: string;
137
- v: 5;
138
- seq: number | null;
139
- on_url: any;
140
- ref_url: any;
141
- start_at: any;
142
- conc: any;
143
- cv: 2;
144
- last: boolean;
145
- script_id: string;
146
- script_inst_id: any;
147
- mp_sock_inst_id: any;
148
- sock_inst_id: string | number[] | null;
149
- video_recorder: string;
150
- }>;
132
+ getPageInformation(): Promise<PageVisitInfo>;
151
133
  /**
152
134
  * Try to parse help code response and fire custom event
153
- * @param {String} response
154
135
  */
155
- _tryProcessHelpCodeResponse(response: any): boolean;
136
+ _tryProcessHelpCodeResponse(response: unknown): boolean;
156
137
  }
@@ -1,39 +1,30 @@
1
+ import { Singleton } from '../../types/Monitor';
2
+ import { CompletePageVisit, PageVisitFrag, PageVisitInfo, SlidingMessage } from '../../types/Metroplex.types';
1
3
  /**
2
4
  * This class holds the final page visit. It flushes it to storage and then
3
5
  * finally sends it to Metroplex via the post route when the next page is loaded
4
6
  */
5
- export default class StoredPageVisit {
6
- /** gets the singleton instance */
7
- static getInstance(): StoredPageVisit;
8
- latestPageVisitFrag: any;
9
- writeTimeout: any;
10
- flushedStorage: boolean;
7
+ export default class StoredPageVisit extends Singleton {
8
+ /**
9
+ * Creates a new instance of StoredPageVisit
10
+ */
11
+ constructor();
11
12
  /**
12
13
  * Check if the events contain a click or location change. If they do then write the retry
13
14
  * queue (which contains the metroplex msg sent above) to storage
14
- * @param {} retryMessageQueue
15
- * @param {} pvInfo
16
15
  */
17
- checkAndStoreRetryQueue(retryMessageQueue: any, pvInfo: any): void;
16
+ checkAndStoreRetryQueue(retryMessageQueue: SlidingMessage[], pvInfo: PageVisitInfo): void;
18
17
  /** Writes the page visit frags in the retry queue to storage
19
- * @param {} retryMessageQueue
20
- * @param {} pvInfo
21
18
  */
22
- writePageVisitsFromRetryQueue(retryMessageQueue: any, pvInfo: any): void;
19
+ writePageVisitsFromRetryQueue(retryMessageQueue: SlidingMessage[], pvInfo: PageVisitInfo): void;
23
20
  /** Write the given page visit frags to storage
24
- * @param {} pageVisitFrags
25
- * @param {} pvInfo
26
21
  */
27
- _writePageVisitFrags(pageVisitFrags: any, pvInfo: any): Promise<void>;
22
+ _writePageVisitFrags(pageVisitFrags: PageVisitFrag[], pvInfo: PageVisitInfo): Promise<void>;
28
23
  /**
29
24
  * Read the stored page visit from storage, create a complete page visit object
30
25
  * and then post that to Metroplex
31
26
  */
32
- _getPostData(): Promise<{
33
- pvi: any;
34
- pvp: never[];
35
- pvvf: never[];
36
- } | null>;
27
+ _getPostData(): Promise<CompletePageVisit>;
37
28
  /**
38
29
  * Creates and tries to resolve a promise that posts the previous page visit
39
30
  * to Metroplex from storage
@@ -45,5 +36,5 @@ export default class StoredPageVisit {
45
36
  */
46
37
  _updateStorageFlushed(): void;
47
38
  /** Returns a promise that resolves to post the page visit in storage to Metroplex */
48
- _getPostPageVisitPromise(): Promise<any>;
39
+ _getPostPageVisitPromise(): Promise<void>;
49
40
  }