noibu-react-native 0.2.3 → 0.2.5

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 (71) hide show
  1. package/dist/api/clientConfig.js +20 -27
  2. package/dist/api/helpCode.js +61 -87
  3. package/dist/api/metroplexSocket.js +72 -65
  4. package/dist/api/storedPageVisit.js +150 -208
  5. package/dist/constants.js +3 -7
  6. package/dist/entry/init.js +13 -15
  7. package/dist/monitors/{appNavigationMonitor.js → AppNavigationMonitor.js} +10 -19
  8. package/dist/monitors/BaseMonitor.js +23 -0
  9. package/dist/monitors/ClickMonitor.js +198 -0
  10. package/dist/monitors/ErrorMonitor.js +206 -0
  11. package/dist/monitors/KeyboardInputMonitor.js +60 -0
  12. package/dist/monitors/PageMonitor.js +98 -0
  13. package/dist/monitors/RequestMonitor.js +390 -0
  14. package/dist/monitors/http-tools/GqlErrorValidator.js +259 -0
  15. package/dist/monitors/{httpDataBundler.js → http-tools/HTTPDataBundler.js} +23 -102
  16. package/dist/pageVisit/{eventDebouncer.js → EventDebouncer.js} +36 -47
  17. package/dist/pageVisit/pageVisitEventError.js +3 -3
  18. package/dist/pageVisit/pageVisitEventHTTP.js +5 -4
  19. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +22 -5
  20. package/dist/sessionRecorder/sessionRecorder.js +5 -2
  21. package/dist/src/api/clientConfig.d.ts +8 -13
  22. package/dist/src/api/clientConfig.test.d.ts +1 -0
  23. package/dist/src/api/helpCode.d.ts +10 -16
  24. package/dist/src/api/metroplexSocket.d.ts +52 -71
  25. package/dist/src/api/storedPageVisit.d.ts +12 -21
  26. package/dist/src/constants.d.ts +1 -0
  27. package/dist/src/monitors/AppNavigationMonitor.d.ts +18 -0
  28. package/dist/src/monitors/BaseMonitor.d.ts +13 -0
  29. package/dist/src/monitors/BaseMonitor.test.d.ts +1 -0
  30. package/dist/src/monitors/ClickMonitor.d.ts +31 -0
  31. package/dist/src/monitors/ErrorMonitor.d.ts +63 -0
  32. package/dist/src/monitors/{keyboardInputMonitor.d.ts → KeyboardInputMonitor.d.ts} +7 -4
  33. package/dist/src/monitors/{pageMonitor.d.ts → PageMonitor.d.ts} +6 -8
  34. package/dist/src/monitors/RequestMonitor.d.ts +94 -0
  35. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +59 -0
  36. package/dist/src/monitors/{httpDataBundler.d.ts → http-tools/HTTPDataBundler.d.ts} +13 -28
  37. package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +3 -2
  38. package/dist/src/pageVisit/{eventDebouncer.d.ts → EventDebouncer.d.ts} +3 -10
  39. package/dist/src/pageVisit/pageVisit.d.ts +1 -1
  40. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +3 -3
  41. package/dist/src/sessionRecorder/nativeSessionRecorderSubscription.d.ts +15 -0
  42. package/dist/src/storage/rnStorageProvider.d.ts +1 -1
  43. package/dist/src/storage/storage.d.ts +1 -1
  44. package/dist/src/storage/storageProvider.d.ts +2 -2
  45. package/dist/src/utils/function.d.ts +4 -5
  46. package/dist/src/utils/object.d.ts +3 -5
  47. package/dist/src/utils/polyfills.d.ts +1 -4
  48. package/dist/types/Metroplex.types.d.ts +73 -0
  49. package/dist/types/PageVisit.types.d.ts +2 -145
  50. package/dist/types/PageVisitErrors.types.d.ts +114 -0
  51. package/dist/types/PageVisitEvents.types.d.ts +91 -0
  52. package/dist/types/Storage.d.ts +1 -1
  53. package/dist/types/StoredPageVisit.types.d.ts +4 -45
  54. package/dist/utils/function.js +0 -1
  55. package/dist/utils/object.js +1 -0
  56. package/package.json +11 -7
  57. package/dist/monitors/clickMonitor.js +0 -258
  58. package/dist/monitors/errorMonitor.js +0 -202
  59. package/dist/monitors/gqlErrorValidator.js +0 -306
  60. package/dist/monitors/inputMonitor.js +0 -138
  61. package/dist/monitors/keyboardInputMonitor.js +0 -66
  62. package/dist/monitors/pageMonitor.js +0 -122
  63. package/dist/monitors/requestMonitor.js +0 -386
  64. package/dist/src/monitors/appNavigationMonitor.d.ts +0 -22
  65. package/dist/src/monitors/clickMonitor.d.ts +0 -44
  66. package/dist/src/monitors/errorMonitor.d.ts +0 -28
  67. package/dist/src/monitors/gqlErrorValidator.d.ts +0 -82
  68. package/dist/src/monitors/inputMonitor.d.ts +0 -34
  69. package/dist/src/monitors/requestMonitor.d.ts +0 -10
  70. package/dist/types/RRWeb.d.ts +0 -48
  71. 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 '../BaseMonitor.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 '../monitors/BaseMonitor.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 {
@@ -46,13 +46,30 @@ function initialize(projectId, config) {
46
46
  const refinedMaximumDailyNetworkUsageInMB = maximumDailyNetworkUsageInMB !== null && maximumDailyNetworkUsageInMB !== void 0 ? maximumDailyNetworkUsageInMB : 0;
47
47
  NativeSessionRecorder.initialize(projectId, userId, logLevel, allowMeteredNetworkUsage, enableWebViewCapture, allowedDomains, disableOnLowEndDevices, enableDailyNetworkUsageLimit, refinedMaximumDailyNetworkUsageInMB);
48
48
  }
49
+ /**
50
+ * Subscribes to a native event emitted by the Noibu Session Recorder.
51
+ *
52
+ * This function listens for the `noibuRecordingEvent` emitted from the native layer (only on Android)
53
+ * and invokes the provided callback whenever the event occurs. If the platform is not Android,
54
+ * the function will do nothing and return a no-op unsubscribe function.
55
+ *
56
+ * @param {function(RecorderEvent): void} callback - A callback function that will be invoked with
57
+ * the event data whenever the `noibuRecordingEvent` is emitted.
58
+ *
59
+ * @returns {UnsubscribeFn} A function to unsubscribe from the event. On Android, this will remove
60
+ * the event listener. On other platforms, it will be a no-op.
61
+ *
62
+ * @throws {Error} If the Noibu Session Recorder is not initialized before calling this function.
63
+ */
49
64
  function subscribeToNativeEvent(callback) {
50
- if (!nativeModuleEmitter) {
51
- throw new Error('You have to initialize Noibu Session Recorder first');
65
+ if (Platform.OS === 'android') {
66
+ if (!nativeModuleEmitter) {
67
+ throw new Error('You have to initialize Noibu Session Recorder first');
68
+ }
69
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
+ nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
71
+ // return () => subscription.remove();
52
72
  }
53
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
54
- nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
55
- // return () => subscription.remove();
56
73
  return () => { };
57
74
  }
58
75
 
@@ -4,10 +4,11 @@ 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';
11
+ import { Platform } from 'react-native';
11
12
 
12
13
  /** Singleton class to record user sessions */
13
14
  class SessionRecorder {
@@ -36,7 +37,9 @@ class SessionRecorder {
36
37
  const nativeSessionRecorderConfig = {
37
38
  logLevel: LogLevel.Verbose,
38
39
  };
39
- initialize('abc1234', nativeSessionRecorderConfig);
40
+ if (Platform.OS === 'android') {
41
+ initialize('abc1234', nativeSessionRecorderConfig);
42
+ }
40
43
  this.instance = new SessionRecorder();
41
44
  // todo handle RN clicks
42
45
  addSafeEventListener(window, 'click', () => {
@@ -1,12 +1,13 @@
1
1
  import { SEVERITY } from '../constants';
2
2
  import { CustomerConfig, StoredConfig } from '../../types/Config';
3
+ import { Singleton } from '../monitors/BaseMonitor';
3
4
  /**
4
5
  * Singleton class to manage the client configuration
5
6
  * this class will be responsible for controlling the disabled
6
7
  * status of the client script as well as managing all storage
7
8
  * storing and retrieval.
8
9
  */
9
- export default class ClientConfig {
10
+ export default class ClientConfig extends Singleton {
10
11
  readonly pageVisitId: string;
11
12
  browserId: StoredConfig['BrowserId'];
12
13
  private pageVisitSeq;
@@ -15,26 +16,20 @@ export default class ClientConfig {
15
16
  private cltErrorPostCounter;
16
17
  private readonly maxSocketInactiveTime;
17
18
  private locationBreadcrumbs;
18
- private static instance;
19
- static noibuErrorURL: string;
20
19
  customerDomain: string;
21
20
  isClientDisabled: boolean;
21
+ configurationPromise: Promise<void>;
22
22
  readonly listOfUrlsToCollectHttpDataFrom: CustomerConfig['listOfUrlsToCollectHttpDataFrom'];
23
23
  readonly enableHttpDataCollection: CustomerConfig['enableHttpDataCollection'];
24
24
  readonly blockedElements: CustomerConfig['blockedElements'];
25
25
  /**
26
26
  * Creates a ClientConfig singleton instance
27
27
  */
28
- constructor(noibuErrorURL: string, customerConfig: CustomerConfig);
29
- /** Configures the singleton instance */
30
- static configureInstance({ noibuErrorURL, customerConfig, }: {
31
- noibuErrorURL: string;
32
- customerConfig: CustomerConfig;
33
- }): Promise<void>;
28
+ constructor(noibuErrorURL?: string, customerConfig?: CustomerConfig);
34
29
  /**
35
- * gets the singleton instance
30
+ * Convenience method to check correct setup
36
31
  */
37
- static getInstance(): ClientConfig;
32
+ private hasAllNecessaryArgs;
38
33
  /** lockClient will disable the client script for a single pagevisit for
39
34
  * duration given in minuntes */
40
35
  lockClient(duration: number, msg: string): Promise<void>;
@@ -43,7 +38,7 @@ export default class ClientConfig {
43
38
  /** Updates the config object to store the given last active time */
44
39
  updateLastActiveTime(lastActiveTime: Date): Promise<void>;
45
40
  /** Gets the current page visit sequence number that should be used */
46
- getPageVisitSeq(): Promise<number | null>;
41
+ getPageVisitSeq(): Promise<number>;
47
42
  /**
48
43
  * Returns the client config object from storage or generates a new one
49
44
  * What is stored in storage will look like this
@@ -97,7 +92,7 @@ export default class ClientConfig {
97
92
  * and disable the client if required
98
93
  * severity expects one of the SEVERITY_x level constants, or else error will be used
99
94
  */
100
- postNoibuErrorAndOptionallyDisableClient(errorMsg: any, disableClient: boolean, severity: (typeof SEVERITY)[keyof typeof SEVERITY], keepAlive?: boolean): Promise<void>;
95
+ postNoibuErrorAndOptionallyDisableClient(errorMsg: any, disableClient?: boolean, severity?: (typeof SEVERITY)[keyof typeof SEVERITY], keepAlive?: boolean): Promise<void>;
101
96
  /**
102
97
  * Returns true if the page visit is considered to be inactive
103
98
  */
@@ -0,0 +1 @@
1
+ export {};
@@ -1,23 +1,13 @@
1
+ import { Singleton } from '../monitors/BaseMonitor';
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
  }