noibu-react-native 0.2.5 → 0.2.7

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 (98) hide show
  1. package/README.md +15 -15
  2. package/android/build.gradle +1 -1
  3. package/dist/api/{clientConfig.js → ClientConfig.js} +69 -52
  4. package/dist/api/{helpCode.js → HelpCode.js} +6 -13
  5. package/dist/api/InputManager.js +156 -0
  6. package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +189 -178
  7. package/dist/api/StoredMetrics.js +158 -0
  8. package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +61 -48
  9. package/dist/const_matchers.js +1 -5
  10. package/dist/constants.js +15 -390
  11. package/dist/entry/index.js +3 -4
  12. package/dist/entry/init.js +33 -19
  13. package/dist/monitors/AppNavigationMonitor.js +19 -19
  14. package/dist/monitors/BaseMonitor.js +9 -4
  15. package/dist/monitors/ClickMonitor.js +72 -76
  16. package/dist/monitors/ErrorMonitor.js +45 -55
  17. package/dist/monitors/KeyboardInputMonitor.js +13 -11
  18. package/dist/monitors/PageMonitor.js +25 -2
  19. package/dist/monitors/RequestMonitor.js +46 -57
  20. package/dist/monitors/http-tools/GqlErrorValidator.js +39 -69
  21. package/dist/monitors/http-tools/HTTPDataBundler.js +71 -66
  22. package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
  23. package/dist/pageVisit/EventDebouncer.js +43 -74
  24. package/dist/pageVisit/HttpEventManager.js +88 -0
  25. package/dist/pageVisit/PageVisitManager.js +99 -0
  26. package/dist/pageVisit/pageVisitEventError.js +170 -280
  27. package/dist/react/ErrorBoundary.js +3 -6
  28. package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +58 -70
  29. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
  30. package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
  31. package/dist/storage/{storage.js → Storage.js} +17 -30
  32. package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
  33. package/dist/utils/date.js +39 -50
  34. package/dist/utils/eventlistener.js +5 -12
  35. package/dist/utils/function.js +42 -113
  36. package/dist/utils/log.js +5 -5
  37. package/dist/utils/object.js +12 -12
  38. package/dist/utils/piiRedactor.js +31 -3
  39. package/dist/utils/stacktrace-parser.js +29 -21
  40. package/package.json +14 -14
  41. package/dist/api/inputManager.js +0 -227
  42. package/dist/api/storedMetrics.js +0 -198
  43. package/dist/pageVisit/pageVisit.js +0 -181
  44. package/dist/pageVisit/pageVisitEventHTTP.js +0 -98
  45. package/dist/pageVisit/userStep.js +0 -20
  46. package/dist/src/api/clientConfig.d.ts +0 -100
  47. package/dist/src/api/clientConfig.test.d.ts +0 -1
  48. package/dist/src/api/helpCode.d.ts +0 -23
  49. package/dist/src/api/inputManager.d.ts +0 -87
  50. package/dist/src/api/metroplexSocket.d.ts +0 -137
  51. package/dist/src/api/storedMetrics.d.ts +0 -73
  52. package/dist/src/api/storedPageVisit.d.ts +0 -40
  53. package/dist/src/const_matchers.d.ts +0 -1
  54. package/dist/src/constants.d.ts +0 -290
  55. package/dist/src/entry/index.d.ts +0 -14
  56. package/dist/src/entry/init.d.ts +0 -5
  57. package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
  58. package/dist/src/monitors/BaseMonitor.d.ts +0 -13
  59. package/dist/src/monitors/BaseMonitor.test.d.ts +0 -1
  60. package/dist/src/monitors/ClickMonitor.d.ts +0 -31
  61. package/dist/src/monitors/ErrorMonitor.d.ts +0 -63
  62. package/dist/src/monitors/KeyboardInputMonitor.d.ts +0 -20
  63. package/dist/src/monitors/PageMonitor.d.ts +0 -20
  64. package/dist/src/monitors/RequestMonitor.d.ts +0 -94
  65. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
  66. package/dist/src/monitors/http-tools/HTTPDataBundler.d.ts +0 -112
  67. package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
  68. package/dist/src/pageVisit/EventDebouncer.d.ts +0 -24
  69. package/dist/src/pageVisit/pageVisit.d.ts +0 -52
  70. package/dist/src/pageVisit/pageVisitEventError.d.ts +0 -15
  71. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +0 -25
  72. package/dist/src/pageVisit/userStep.d.ts +0 -5
  73. package/dist/src/react/ErrorBoundary.d.ts +0 -72
  74. package/dist/src/sessionRecorder/nativeSessionRecorderSubscription.d.ts +0 -79
  75. package/dist/src/sessionRecorder/sessionRecorder.d.ts +0 -60
  76. package/dist/src/sessionRecorder/types.d.ts +0 -91
  77. package/dist/src/storage/rnStorageProvider.d.ts +0 -23
  78. package/dist/src/storage/storage.d.ts +0 -39
  79. package/dist/src/storage/storageProvider.d.ts +0 -26
  80. package/dist/src/utils/date.d.ts +0 -6
  81. package/dist/src/utils/eventlistener.d.ts +0 -8
  82. package/dist/src/utils/function.d.ts +0 -102
  83. package/dist/src/utils/log.d.ts +0 -4
  84. package/dist/src/utils/object.d.ts +0 -44
  85. package/dist/src/utils/performance.d.ts +0 -6
  86. package/dist/src/utils/piiRedactor.d.ts +0 -11
  87. package/dist/src/utils/polyfills.d.ts +0 -4
  88. package/dist/src/utils/stacktrace-parser.d.ts +0 -7
  89. package/dist/types/Config.d.ts +0 -31
  90. package/dist/types/Metroplex.types.d.ts +0 -73
  91. package/dist/types/NavigationIntegration.d.ts +0 -6
  92. package/dist/types/PageVisit.types.d.ts +0 -8
  93. package/dist/types/PageVisitErrors.types.d.ts +0 -114
  94. package/dist/types/PageVisitEvents.types.d.ts +0 -91
  95. package/dist/types/PageVisitMetrics.types.d.ts +0 -27
  96. package/dist/types/Storage.d.ts +0 -14
  97. package/dist/types/StoredPageVisit.types.d.ts +0 -11
  98. package/dist/types/WrappedObjects.d.ts +0 -6
package/README.md CHANGED
@@ -27,7 +27,8 @@ Install using favourite node package manager (npm, yarn, etc.):
27
27
  npm install noibu-react-native --save
28
28
  ```
29
29
 
30
- Additionally, for iOS target do:
30
+ Additionally, for iOS target do:
31
+
31
32
  ```bash
32
33
  npx pod-install
33
34
  ```
@@ -65,22 +66,21 @@ That's it! First time the module is set up, it runs an init and starts listening
65
66
  ## Configuration
66
67
 
67
68
  `setupNoibu(config): void` method accepts following parameters:
68
- - `config` which consists of
69
- - `@property domain {string}` - indicates which Noibu dashboard session recordings should go to ([learn more about domains](https://help.noibu.com/hc/en-us/articles/4846518088845-Domains-Overview))
70
- - `@property [blockedElements] {string[]}` - lets you specify component ids to be ignored by SDK when collecting error information
71
- - `@property [enableHttpDataCollection] {boolean}` - indicates whether SDK should collect HTTP information like headers or body from requests
72
- - `@property [listOfUrlsToCollectHttpDataFrom] {string[]}` - is an allow list of URLs to allow HTTP data collection from, works best with `enableHttpDataCollection` enabled
73
69
 
74
- Example:
70
+ - `config` which consists of
71
+ - `@property domain {string}` - indicates which Noibu dashboard session recordings should go to ([learn more about domains](https://help.noibu.com/hc/en-us/articles/4846518088845-Domains-Overview))
72
+ - `@property [blockedElements] {string[]}` - lets you specify component ids to be ignored by SDK when collecting error information
73
+ - `@property [enableHttpDataCollection] {boolean}` - indicates whether SDK should collect HTTP information like headers or body from requests
74
+ - `@property [listOfUrlsToCollectHttpDataFrom] {string[]}` - is an allow list of URLs to allow HTTP data collection from, works best with `enableHttpDataCollection` enabled
75
+
76
+ Example:
77
+
75
78
  ```js
76
79
  setupNoibu({
77
- domain: 'react-native-app.myshop.com',
78
- enableHttpDataCollection: true,
79
- listOfUrlsToCollectHttpDataFrom: [
80
- 'https://react-native-app.myshop.com/backend',
81
- 'https://example.com/some-path/',
82
- ],
83
- blockedElements: ['sensitive-info']
80
+ domain: 'react-native-app.myshop.com',
81
+ enableHttpDataCollection: true,
82
+ listOfUrlsToCollectHttpDataFrom: ['https://react-native-app.myshop.com/backend', 'https://example.com/some-path/'],
83
+ blockedElements: ['sensitive-info'],
84
84
  });
85
85
  ```
86
86
 
@@ -101,7 +101,7 @@ Requests a help code from the HelpCode instance. To read more about help codes,
101
101
  ```jsx
102
102
  import { NoibuJS } from 'noibu-react-native';
103
103
  import { useCallback, useState } from 'react';
104
- import { Alert, Text, Pressable, View} from 'react-native';
104
+ import { Alert, Text, Pressable, View } from 'react-native';
105
105
 
106
106
  const AlertHelpCode = () => {
107
107
  const triggerHelpCodeAlert = useCallback(async () => {
@@ -67,7 +67,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
67
67
  dependencies {
68
68
  implementation "com.facebook.react:react-native:+"
69
69
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
70
- implementation "com.noibu:sessionreplay-recorder:0.1.0"
70
+ implementation "com.noibu:sessionreplay-recorder:0.2.0"
71
71
  }
72
72
 
73
73
  if (isNewArchitectureEnabled()) {
@@ -1,12 +1,22 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import uuid from 'react-native-uuid';
3
- import { MAX_METROPLEX_SOCKET_INNACTIVE_TIME, SEVERITY, NOIBU_BROWSER_ID_KYWRD, PV_SEQ_NUM_RESET_TIME_MINUTES, JS_ENV, MAX_PAGEVISIT_VISITED, CLIENT_LOCK_TIME_MINUTES, GET_SCRIPT_ID, GET_DEVICE_ENV, MAX_COLLECT_ERROR_LOG } from '../constants.js';
4
- import { stringifyJSON, getMaxSubstringAllowed, getUserAgent, makeRequest } from '../utils/function.js';
5
- import Storage from '../storage/storage.js';
6
- import { noibuLog } from '../utils/log.js';
3
+ import { SEVERITY, MAX_METROPLEX_SOCKET_INNACTIVE_TIME, GET_SCRIPT_ID, GET_DEVICE_ENV } from '../constants.js';
4
+ import { stringifyJSON, getMaxSubstringAllowed, getUserAgent, postRequest } from '../utils/function.js';
5
+ import Storage from '../storage/Storage.js';
6
+ import { noibuLog, noibuErr } from '../utils/log.js';
7
7
  import { unwrapNoibuWrapped } from '../utils/object.js';
8
8
  import { Singleton } from '../monitors/BaseMonitor.js';
9
9
 
10
+ // maximum number of page visits assigned to a single browser id
11
+ const MAX_PAGEVISIT_VISITED = 300;
12
+ // The amount of time to lock the client for if they have exceeded things
13
+ // like the maximum number of pagevisits
14
+ const CLIENT_LOCK_TIME_MINUTES = 45;
15
+ // The amount of inactive time required for us to reset the page visit sequence numbers
16
+ const PV_SEQ_NUM_RESET_TIME_MINUTES = 45;
17
+ // number of errors that collect can send to metroplex before shutting himself off.
18
+ const MAX_COLLECT_ERROR_LOG = 50;
19
+ const NOIBU_BROWSER_ID_KYWRD = 'n_browser_data';
10
20
  /**
11
21
  * Singleton class to manage the client configuration
12
22
  * this class will be responsible for controlling the disabled
@@ -14,9 +24,18 @@ import { Singleton } from '../monitors/BaseMonitor.js';
14
24
  * storing and retrieval.
15
25
  */
16
26
  class ClientConfig extends Singleton {
17
- /**
18
- * Creates a ClientConfig singleton instance
19
- */
27
+ /** Error handling for constructor */
28
+ handleConstructorError(noibuErrorURL, customerConfig) {
29
+ const reason = {
30
+ msg: 'ClientConfig was not properly configured',
31
+ noibuErrorURL,
32
+ customerConfig,
33
+ globalUrl: this.globalUrl,
34
+ };
35
+ void this.postInternalError(reason, true, SEVERITY.error);
36
+ this.configurationPromise = Promise.reject(reason);
37
+ }
38
+ /** Creates a ClientConfig singleton instance */
20
39
  constructor(noibuErrorURL, customerConfig) {
21
40
  super();
22
41
  this.pageVisitId = uuid.v4();
@@ -33,26 +52,25 @@ class ClientConfig extends Singleton {
33
52
  this.maxSocketInactiveTime = MAX_METROPLEX_SOCKET_INNACTIVE_TIME;
34
53
  this.locationBreadcrumbs = [];
35
54
  this.isClientDisabled = false;
55
+ if (!noibuErrorURL || !customerConfig) {
56
+ this.handleConstructorError(noibuErrorURL, customerConfig);
57
+ return;
58
+ }
36
59
  this.noibuErrorURL = noibuErrorURL;
37
60
  this.customerDomain = customerConfig.domain;
38
- this.listOfUrlsToCollectHttpDataFrom =
39
- customerConfig.listOfUrlsToCollectHttpDataFrom;
40
- this.enableHttpDataCollection = customerConfig.enableHttpDataCollection;
41
- this.blockedElements = customerConfig.blockedElements;
42
- if (!noibuErrorURL || !this.hasAllNecessaryArgs()) {
43
- const reason = Object.assign({ msg: 'ClientConfig was not properly configured' }, customerConfig);
44
- void this.postNoibuErrorAndOptionallyDisableClient(reason, true, SEVERITY.error);
45
- this.configurationPromise = Promise.reject(reason);
61
+ if (!this.hasAllNecessaryArgs(customerConfig)) {
62
+ this.handleConstructorError(noibuErrorURL, customerConfig);
46
63
  return;
47
64
  }
65
+ this.listOfUrlsToCollectHttpDataFrom = customerConfig.listOfUrlsToCollectHttpDataFrom;
66
+ this.enableHttpDataCollection = customerConfig.enableHttpDataCollection;
67
+ this.blockedElements = customerConfig.blockedElements;
48
68
  // sets up this.browserId, this.isClientDisabled, this.pageVisitSeq
49
69
  this.configurationPromise = this._setupStorageVars();
50
70
  }
51
- /**
52
- * Convenience method to check correct setup
53
- */
54
- hasAllNecessaryArgs() {
55
- return (!!this.customerDomain && this.globalUrl.includes(this.customerDomain));
71
+ /** Convenience method to check correct setup */
72
+ hasAllNecessaryArgs(customerConfig) {
73
+ return !!customerConfig.domain && this.globalUrl.includes(customerConfig.domain);
56
74
  }
57
75
  /** lockClient will disable the client script for a single pagevisit for
58
76
  * duration given in minuntes */
@@ -64,12 +82,12 @@ class ClientConfig extends Singleton {
64
82
  noibuLSObject.DisabledStatus = true;
65
83
  noibuLSObject.ClientUnlockTime = expiryTime;
66
84
  yield this._storeBrowserData(noibuLSObject);
67
- yield this.postNoibuErrorAndOptionallyDisableClient(msg, true, SEVERITY.warn);
85
+ yield this.postInternalError(msg, true, SEVERITY.warn);
68
86
  });
69
87
  }
70
88
  /** Locks the client until the next page loads */
71
89
  lockClientUntilNextPage(msg) {
72
- return this.postNoibuErrorAndOptionallyDisableClient(msg, true, SEVERITY.warn);
90
+ return this.postInternalError(msg, true, SEVERITY.warn);
73
91
  }
74
92
  /** Updates the config object to store the given last active time */
75
93
  updateLastActiveTime(lastActiveTime) {
@@ -133,9 +151,7 @@ class ClientConfig extends Singleton {
133
151
  return parsedConfig;
134
152
  });
135
153
  }
136
- /**
137
- * Check if we have surpassed the last active time and the page visit seq number needs resetting
138
- */
154
+ /** Check if we have surpassed the last active time and the page visit seq number needs resetting */
139
155
  _pageVisitSeqNeedsReset() {
140
156
  return __awaiter(this, void 0, void 0, function* () {
141
157
  const noibuLSObject = yield this._getClientState();
@@ -155,7 +171,7 @@ class ClientConfig extends Singleton {
155
171
  return __awaiter(this, void 0, void 0, function* () {
156
172
  const storage = Storage.getInstance();
157
173
  if (!(yield storage.isAvailable())) {
158
- void this.postNoibuErrorAndOptionallyDisableClient(`Storage is unavailable, disabling client. ${yield storage.getDiagnoseInfo()}`, true, SEVERITY.error);
174
+ void this.postInternalError({ msg: `Storage is unavailable, disabling client.`, diagnosis: yield storage.getDiagnoseInfo() }, true, SEVERITY.error);
159
175
  return;
160
176
  }
161
177
  // getting the current content of the storage
@@ -175,11 +191,6 @@ class ClientConfig extends Singleton {
175
191
  // Update the LS object values before storing it for the next page visit
176
192
  noibuLSObject.CurrentPageVisitCount += 1;
177
193
  noibuLSObject.LastActive = new Date();
178
- // Expose page visit ID in storage for use by Trailbreaker video tests
179
- // This will be done for the testvideo and lambdavideo bundles used by Trailbreaker
180
- if (JS_ENV().includes('video')) {
181
- noibuLSObject.pvId = this.pageVisitId;
182
- }
183
194
  // if we have reached the max page visits for a browser id then
184
195
  // we disabled collect for 45 minutes
185
196
  if (noibuLSObject.CurrentPageVisitCount >= MAX_PAGEVISIT_VISITED) {
@@ -190,7 +201,7 @@ class ClientConfig extends Singleton {
190
201
  // setting the lock time
191
202
  noibuLSObject.ClientUnlockTime = expiryTime;
192
203
  noibuLSObject.DisabledStatus = true;
193
- yield this.postNoibuErrorAndOptionallyDisableClient(`Hit max page visits, disabling client for ${CLIENT_LOCK_TIME_MINUTES}mins`, true, SEVERITY.error);
204
+ yield this.postInternalError({ msg: `Hit max page visits, disabling client for ${CLIENT_LOCK_TIME_MINUTES}mins` }, true, SEVERITY.error);
194
205
  }
195
206
  // we now check if we successfully saved the data
196
207
  const savedData = yield this._storeBrowserData(noibuLSObject);
@@ -198,7 +209,7 @@ class ClientConfig extends Singleton {
198
209
  // error happened, thus we disable collect.
199
210
  if (!savedData.BrowserId) {
200
211
  // we do not set a lock expiry date here since we cannot store to storage
201
- void this.postNoibuErrorAndOptionallyDisableClient(`Null browser in storage, disabling client`, true, SEVERITY.error);
212
+ void this.postInternalError({ msg: `Null browser in storage, disabling client` }, true, SEVERITY.error);
202
213
  this.browserId = '';
203
214
  }
204
215
  });
@@ -213,8 +224,7 @@ class ClientConfig extends Singleton {
213
224
  return __awaiter(this, void 0, void 0, function* () {
214
225
  const newConfigData = yield this._getLsObject();
215
226
  // if the lock expired, we remove the lock period and enable the client
216
- if (newConfigData.ClientUnlockTime &&
217
- new Date(newConfigData.ClientUnlockTime) <= new Date()) {
227
+ if (newConfigData.ClientUnlockTime && new Date(newConfigData.ClientUnlockTime) <= new Date()) {
218
228
  newConfigData.ClientUnlockTime = undefined;
219
229
  newConfigData.DisabledStatus = false;
220
230
  yield this._storeBrowserData(newConfigData);
@@ -237,18 +247,12 @@ class ClientConfig extends Singleton {
237
247
  * and persisted throughout a session
238
248
  */
239
249
  _generateNewBrowserData() {
240
- const noibuBrowserData = {
250
+ return {
241
251
  DisabledStatus: false,
242
252
  BrowserId: uuid.v4(),
243
253
  CurrentPageVisitCount: 0,
244
254
  LastActive: new Date(),
245
255
  };
246
- // Expose page visit ID in storage for use by Trailbreaker video tests
247
- // This will be done for the testvideo and lambdavideo bundles used by Trailbreaker
248
- if (JS_ENV().includes('video')) {
249
- noibuBrowserData.pvId = this.pageVisitId;
250
- }
251
- return noibuBrowserData;
252
256
  }
253
257
  /**
254
258
  * _storeBrowserData will store the passed object in storage.
@@ -262,7 +266,10 @@ class ClientConfig extends Singleton {
262
266
  return data;
263
267
  }
264
268
  catch (e) {
265
- yield this.postNoibuErrorAndOptionallyDisableClient(`Error writing browser data to storage, disabling client: ${e.message}, ${yield storage.getDiagnoseInfo()}`, true, SEVERITY.error);
269
+ yield this.postInternalError({
270
+ msg: 'Error writing browser data to storage, disabling client: ' + e.message,
271
+ diagnosis: yield storage.getDiagnoseInfo(),
272
+ }, true, SEVERITY.error);
266
273
  // sending empty fields if we encountered errors while storing in the LS
267
274
  return this._generateNewBrowserData();
268
275
  }
@@ -285,13 +292,13 @@ class ClientConfig extends Singleton {
285
292
  return getMaxSubstringAllowed(globalUrl.toString());
286
293
  }
287
294
  /**
288
- * postNoibuErrorAndOptionallyDisableClient will post errors that were thrown by collect
295
+ * postInternalError will post errors that were thrown by collect
289
296
  * and disable the client if required
290
297
  * severity expects one of the SEVERITY_x level constants, or else error will be used
291
298
  */
292
- postNoibuErrorAndOptionallyDisableClient(errorMsg_1) {
299
+ postInternalError(errorMsg_1) {
293
300
  return __awaiter(this, arguments, void 0, function* (errorMsg, disableClient = false, severity = SEVERITY.error, keepAlive = false) {
294
- noibuLog('postNoibuErrorAndOptionallyDisableClient', {
301
+ noibuErr('postInternalError', {
295
302
  errorMsg,
296
303
  disableClient,
297
304
  severity,
@@ -313,7 +320,7 @@ class ClientConfig extends Singleton {
313
320
  scriptId: GET_SCRIPT_ID(),
314
321
  ua: yield getUserAgent(),
315
322
  deviceEnv: GET_DEVICE_ENV(),
316
- error: stringifyJSON(errorMsg),
323
+ msg: stringifyJSON(errorMsg),
317
324
  };
318
325
  // if the page visits sends more errors than the
319
326
  // allowed threshold we disable the client
@@ -329,7 +336,7 @@ class ClientConfig extends Singleton {
329
336
  this.isClientDisabled = true;
330
337
  // end of lock
331
338
  // overriding the message to be an alert that we are shutting collect off.
332
- collectError.error = `Shutting collect off, we reached the maximum limit of collect errors sent.`;
339
+ collectError.msg = `Shutting collect off, we reached the maximum limit of collect errors sent.`;
333
340
  }
334
341
  const errorContent = {
335
342
  url: this.globalUrl,
@@ -340,7 +347,7 @@ class ClientConfig extends Singleton {
340
347
  'content-type': 'application/json',
341
348
  };
342
349
  if (!keepAlive) {
343
- makeRequest('POST', this.noibuErrorURL, errorContent, headers, 2000, false).catch(() => {
350
+ postRequest(this.noibuErrorURL, errorContent, headers, false, 2000).catch(() => {
344
351
  // we do nothing and let this error silently fail
345
352
  });
346
353
  }
@@ -359,14 +366,24 @@ class ClientConfig extends Singleton {
359
366
  }
360
367
  });
361
368
  }
362
- /**
363
- * Returns true if the page visit is considered to be inactive
364
- */
369
+ /** Returns true if the page visit is considered to be inactive */
365
370
  isInactive() {
366
371
  const someTimeAgo = new Date();
367
372
  someTimeAgo.setSeconds(someTimeAgo.getSeconds() - this.maxSocketInactiveTime);
368
373
  return this.lastActiveTime < someTimeAgo;
369
374
  }
375
+ /**
376
+ * Wraps a function in a try catch block and posts the error if one is thrown
377
+ * explanation will be inserted into the error message as 'Error in {explanation}'
378
+ */
379
+ wrapInternal(explanation, fun) {
380
+ try {
381
+ fun();
382
+ }
383
+ catch (error) {
384
+ this.postInternalError({ msg: `Error in ${explanation}`, error }, false, SEVERITY.error);
385
+ }
386
+ }
370
387
  }
371
388
 
372
389
  export { ClientConfig as default };
@@ -1,16 +1,14 @@
1
1
  import { __awaiter } from 'tslib';
2
- import MetroplexSocket from './metroplexSocket.js';
2
+ import MetroplexSocket from './MetroplexSocket.js';
3
3
  import { SEVERITY } from '../constants.js';
4
- import ClientConfig from './clientConfig.js';
4
+ import ClientConfig from './ClientConfig.js';
5
5
  import { Singleton } from '../monitors/BaseMonitor.js';
6
6
 
7
7
  /**
8
8
  * HelpCode class is responsible for help code feature related functionality
9
9
  */
10
10
  class HelpCode extends Singleton {
11
- /**
12
- * Constructs instance and sets up event listeners
13
- */
11
+ /** Constructs instance and sets up event listeners */
14
12
  constructor() {
15
13
  super();
16
14
  this.requestContext = null;
@@ -19,9 +17,6 @@ class HelpCode extends Singleton {
19
17
  /**
20
18
  * Requests a help code and returns a Promise that resolves when the help code is obtained
21
19
  * or rejects if the noibu connection is unavailable.
22
-
23
- * @returns {Promise<string>} Promise object representing the help code request.
24
- * @throws {string} Throws an error if the noibu connection is unavailable.
25
20
  */
26
21
  requestHelpCode() {
27
22
  return __awaiter(this, void 0, void 0, function* () {
@@ -46,16 +41,14 @@ class HelpCode extends Singleton {
46
41
  return this.requestContext.promise;
47
42
  });
48
43
  }
49
- /**
50
- * Handles the received help code event.
51
- */
44
+ /** Handles the received help code event. */
52
45
  receiveHelpCode(event) {
53
46
  var _a, _b;
54
47
  if (this.requestContext === null) {
55
48
  const { success, data } = event.detail;
56
49
  if (!success) {
57
- const message = `Noibu help code is not available due to ${data}`;
58
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(message, false, SEVERITY.error);
50
+ const msg = `Noibu help code is not available due to ${data}`;
51
+ ClientConfig.getInstance().postInternalError({ msg }, false, SEVERITY.error);
59
52
  }
60
53
  return;
61
54
  }
@@ -0,0 +1,156 @@
1
+ import { __awaiter } from 'tslib';
2
+ import MetroplexSocket from './MetroplexSocket.js';
3
+ import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
4
+ import HelpCode from './HelpCode.js';
5
+ import { Singleton } from '../monitors/BaseMonitor.js';
6
+ import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
7
+ import { PageVisitErrorSource } from '../node_modules/@noibu/metroplex-ts-bindings/dist/PageVisitErrorSource.js';
8
+ import { WebsocketMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WebsocketMessageType.js';
9
+
10
+ // maximum ids that a user can add to a pagevisit
11
+ const MAX_CUSTOM_IDS_PER_PAGEVISIT = 10;
12
+ const MAX_CUSTOM_ERRORS_PER_PAGEVISIT = 500;
13
+ const TOO_MANY_IDS_ADDED_MSG = 'TOO_MANY_IDS_ADDED';
14
+ const ID_NAME_ALREADY_ADDED_MSG = 'ID_NAME_ALREADY_ADDED';
15
+ const NAME_TOO_LONG_MSG = 'NAME_TOO_LONG';
16
+ const VALUE_TOO_LONG_MSG = 'VALUE_TOO_LONG';
17
+ const INVALID_NAME_TYPE_MSG = 'INVALID_NAME_TYPE';
18
+ const INVALID_VALUE_TYPE_MSG = 'INVALID_VALUE_TYPE';
19
+ const NAME_HAS_NO_LENGTH_MSG = 'NAME_HAS_NO_LENGTH';
20
+ const VALUE_HAS_NO_LENGTH_MSG = 'VALUE_HAS_NO_LENGTH';
21
+ const SUCCESS_MSG = 'SUCCESS';
22
+ const ERROR_HAS_NO_MSG_MSG = 'ERROR_HAS_NO_MSG';
23
+ const ERROR_HAS_NO_STACK_MSG = 'ERROR_HAS_NO_STACK';
24
+ const NULL_CUSTOM_ERR_MSG = 'NULL_CUSTOM_ERROR';
25
+ const TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT_MSG = 'TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT';
26
+ /** this class controls the input that customers can inject into
27
+ * our script via the NoibuJS SDK
28
+ */
29
+ class InputManager extends Singleton {
30
+ constructor() {
31
+ super(...arguments);
32
+ this.customIDs = {};
33
+ this.customErrorsCount = 0;
34
+ }
35
+ /** exposes functions to the window of the browser for the clients
36
+ * to interact with on their end
37
+ */
38
+ exposeFunctions() {
39
+ return {
40
+ // adding all the functions and binding the current context
41
+ // so that we can use the exposed function as if they are running`
42
+ // in the noibujs script
43
+ requestHelpCode: this._requestHelpCode.bind(this),
44
+ addCustomAttribute: this._addCustomAttribute.bind(this),
45
+ addError: this._addCustomError.bind(this),
46
+ addJsSdkError: this._addErrorFromJSSdk.bind(this),
47
+ };
48
+ }
49
+ /** validates the custom error that was passed */
50
+ getErrorValidationError(customError) {
51
+ if (!customError) {
52
+ return NULL_CUSTOM_ERR_MSG;
53
+ }
54
+ if (!customError.message) {
55
+ return ERROR_HAS_NO_MSG_MSG;
56
+ }
57
+ if (!customError.stack) {
58
+ return ERROR_HAS_NO_STACK_MSG;
59
+ }
60
+ return SUCCESS_MSG;
61
+ }
62
+ /** Validates and sets the custom error to our internal trackers */
63
+ _validateAndSetCustomError(customError) {
64
+ // we cap the number of errors allowed to be sent
65
+ if (this.customErrorsCount >= MAX_CUSTOM_ERRORS_PER_PAGEVISIT) {
66
+ return TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT_MSG;
67
+ }
68
+ // need to validate first before we start operating with the received
69
+ // data
70
+ const validationResult = this.getErrorValidationError(customError);
71
+ if (validationResult !== SUCCESS_MSG) {
72
+ return validationResult;
73
+ }
74
+ this.customErrorsCount += 1;
75
+ return SUCCESS_MSG;
76
+ }
77
+ /** adds an error from a JS Sdk to the session */
78
+ _addErrorFromJSSdk(customError, errorSource) {
79
+ const validationAndSettingResult = this._validateAndSetCustomError(customError);
80
+ if (validationAndSettingResult !== SUCCESS_MSG) {
81
+ return validationAndSettingResult;
82
+ }
83
+ saveErrorToPagevisit({ error: customError, type: `${errorSource}` });
84
+ return validationAndSettingResult;
85
+ }
86
+ /** adds a custom Error to the session */
87
+ _addCustomError(customError) {
88
+ const validationAndSettingResult = this._validateAndSetCustomError(customError);
89
+ if (validationAndSettingResult !== SUCCESS_MSG) {
90
+ return validationAndSettingResult;
91
+ }
92
+ // customError is validated at this point
93
+ saveErrorToPagevisit({ type: PageVisitErrorSource.CustomError, error: customError });
94
+ return validationAndSettingResult;
95
+ }
96
+ /**
97
+ * adds a custom id to the session
98
+ * todo wrong param types, should be unknown
99
+ */
100
+ _addCustomAttribute(name, value) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ // we return if we are over the limit of ids
103
+ if (Object.keys(this.customIDs).length >= MAX_CUSTOM_IDS_PER_PAGEVISIT) {
104
+ return TOO_MANY_IDS_ADDED_MSG;
105
+ }
106
+ // need to validate first before we start operating with the received
107
+ // data
108
+ const validationResult = this.getValidationError(name, value);
109
+ if (validationResult !== SUCCESS_MSG) {
110
+ return validationResult;
111
+ }
112
+ // we do not want to keep sending something that was already sent
113
+ if (name in this.customIDs) {
114
+ return ID_NAME_ALREADY_ADDED_MSG;
115
+ }
116
+ this.customIDs[name] = value;
117
+ yield MetroplexSocket.getInstance().sendMessage({
118
+ type: WebsocketMessageType.PageVisitMeta,
119
+ payload: {
120
+ id_name: name,
121
+ id_val: value,
122
+ },
123
+ });
124
+ return SUCCESS_MSG;
125
+ });
126
+ }
127
+ /** validation function for customer input */
128
+ getValidationError(name, value) {
129
+ // all ids need to be strings and less than 50 chars and more than 0 chars
130
+ if (typeof name !== 'string') {
131
+ return INVALID_NAME_TYPE_MSG;
132
+ }
133
+ if (typeof value !== 'string') {
134
+ return INVALID_VALUE_TYPE_MSG;
135
+ }
136
+ if (value.length > 50) {
137
+ return VALUE_TOO_LONG_MSG;
138
+ }
139
+ if (name.length > 50) {
140
+ return NAME_TOO_LONG_MSG;
141
+ }
142
+ if (value.length === 0) {
143
+ return VALUE_HAS_NO_LENGTH_MSG;
144
+ }
145
+ if (name.length === 0) {
146
+ return NAME_HAS_NO_LENGTH_MSG;
147
+ }
148
+ return SUCCESS_MSG;
149
+ }
150
+ /** Requests a help code from the HelpCode instance. */
151
+ _requestHelpCode() {
152
+ return HelpCode.getInstance().requestHelpCode();
153
+ }
154
+ }
155
+
156
+ export { InputManager as default };