noibu-react-native 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/api/clientConfig.d.ts +4 -5
  2. package/dist/api/clientConfig.js +21 -15
  3. package/dist/api/inputManager.js +1 -1
  4. package/dist/api/metroplexSocket.d.ts +155 -0
  5. package/dist/api/metroplexSocket.js +667 -804
  6. package/dist/api/storedMetrics.js +2 -1
  7. package/dist/constants.d.ts +11 -0
  8. package/dist/constants.js +15 -2
  9. package/dist/entry/index.js +2 -0
  10. package/dist/entry/init.d.ts +1 -1
  11. package/dist/entry/init.js +9 -2
  12. package/dist/monitors/appNavigationMonitor.js +3 -2
  13. package/dist/monitors/clickMonitor.js +1 -1
  14. package/dist/monitors/errorMonitor.js +2 -2
  15. package/dist/monitors/httpDataBundler.js +62 -15
  16. package/dist/monitors/inputMonitor.js +5 -0
  17. package/dist/monitors/integrations/react-native-navigation-integration.d.ts +1 -2
  18. package/dist/monitors/keyboardInputMonitor.js +1 -1
  19. package/dist/monitors/requestMonitor.js +47 -310
  20. package/dist/pageVisit/pageVisit.js +5 -0
  21. package/dist/pageVisit/{pageVisitEventError/pageVisitEventError.js → pageVisitEventError.js} +18 -19
  22. package/dist/pageVisit/{pageVisitEventHTTP/pageVisitEventHTTP.js → pageVisitEventHTTP.js} +15 -7
  23. package/dist/pageVisit/{userStep/userStep.js → userStep.js} +2 -2
  24. package/dist/types/NavigationIntegration.d.ts +1 -2
  25. package/dist/types/globals.d.ts +6 -3
  26. package/dist/utils/function.d.ts +2 -3
  27. package/dist/utils/function.js +15 -10
  28. package/dist/utils/log.d.ts +5 -0
  29. package/dist/utils/log.js +17 -0
  30. package/dist/utils/object.d.ts +41 -0
  31. package/dist/utils/object.js +85 -108
  32. package/dist/utils/performance.d.ts +6 -0
  33. package/dist/utils/performance.js +1 -2
  34. package/package.json +5 -4
  35. package/dist/pageVisit/pageVisitEventError/blacklistedDomains.js +0 -9
@@ -1,78 +1,16 @@
1
1
  import 'react-native/Libraries/Network/fetch';
2
- import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError/pageVisitEventError.js';
3
- import { PageVisitEventHTTP, isHttpCodeFailure } from '../pageVisit/pageVisitEventHTTP/pageVisitEventHTTP.js';
2
+ import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
3
+ import { PageVisitEventHTTP, isHttpCodeFailure } from '../pageVisit/pageVisitEventHTTP.js';
4
4
  import { propWriteableOrMadeWriteable, replace } from '../utils/object.js';
5
- import 'react-native-device-info';
6
- import { PV_SEQ_ATT_NAME, XML_HTTP_REQUEST_ERROR_TYPE, GQL_ERROR_TYPE, SEVERITY, RESPONSE_ERROR_TYPE, HTTP_METHOD_ATT_NAME, HTTP_RESP_CODE_ATT_NAME, URL_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_RESP_LENGTH_ATT_NAME, FETCH_EXCEPTION_ERROR_TYPE } from '../constants.js';
7
- import { addSafeEventListener } from '../utils/eventlistener.js';
8
- import { HTTPDataBundler } from './httpDataBundler.js';
5
+ import { SEVERITY, PV_SEQ_ATT_NAME, RESPONSE_ERROR_TYPE, GQL_ERROR_TYPE, HTTP_METHOD_ATT_NAME, HTTP_RESP_CODE_ATT_NAME, URL_ATT_NAME, HTTP_RESP_TIME_ATT_NAME, HTTP_RESP_LENGTH_ATT_NAME, FETCH_EXCEPTION_ERROR_TYPE } from '../constants.js';
9
6
  import ClientConfig from '../api/clientConfig.js';
7
+ import { HTTPDataBundler } from './httpDataBundler.js';
10
8
  import GqlErrorValidator from './gqlErrorValidator.js';
9
+ import { noibuLog } from '../utils/log.js';
11
10
 
12
11
  /** @module RequestMonitor */
13
12
  // todo no idea why this works but it fixes fetch replacement
14
13
 
15
- /**
16
- * Takes an XHR object, method, url, response time, and payload, and returns the parameters to pass
17
- * the PageVisitEventHTTP constructor.
18
- * @param {object} xhrObj
19
- * @param {string} method
20
- * @param {string} url
21
- * @param {number} respTime
22
- * @param {*} rawPayload
23
- * @returns HTTP event and data
24
- */
25
- function _buildHttpEventDataObjectsForXHR(
26
- xhrObj,
27
- method,
28
- url,
29
- respTime,
30
- rawPayload = null,
31
- ) {
32
- const httpEvent = {
33
- [HTTP_METHOD_ATT_NAME]: method,
34
- [HTTP_RESP_CODE_ATT_NAME]: xhrObj.status,
35
- [URL_ATT_NAME]: url,
36
- [HTTP_RESP_TIME_ATT_NAME]: respTime,
37
- };
38
- let httpData = null;
39
-
40
- if (HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
41
- const responseHeaders = HTTPDataBundler.headersMapFromString(
42
- xhrObj.getAllResponseHeaders(),
43
- );
44
- // add response payload length, if any
45
- const contentLength =
46
- HTTPDataBundler.getInstance().contentLength(responseHeaders);
47
- if (contentLength > 0) {
48
- httpEvent[HTTP_RESP_LENGTH_ATT_NAME] = contentLength;
49
- }
50
-
51
- let responseBody = '';
52
- if (HTTPDataBundler.getInstance().shouldCollectPayloadForURL(url)) {
53
- // Set descriptive body if content is wrong type or too long.
54
- const droppedResponseText =
55
- HTTPDataBundler.getInstance().dropPayloadIfNecessaryFromHeaders(
56
- responseHeaders,
57
- );
58
-
59
- responseBody =
60
- droppedResponseText ||
61
- HTTPDataBundler.responseStringFromXHRResponseType(xhrObj);
62
- }
63
-
64
- httpData = HTTPDataBundler.getInstance().bundleHTTPData(
65
- url,
66
- xhrObj.noibuRequestHeaders,
67
- rawPayload,
68
- responseHeaders,
69
- responseBody,
70
- method,
71
- );
72
- }
73
- return [httpEvent, httpData];
74
- }
75
-
76
14
  /**
77
15
  * Called in the fetch() wrapper function, this specifically gets called after the promises which
78
16
  * return the request and response body complete.
@@ -83,6 +21,7 @@ function _buildHttpEventDataObjectsForXHR(
83
21
  * [0] is the response body, [1] is an optional response body.
84
22
  * @param {string} url the URL of the request
85
23
  * @param {string} method the method used in the fetch call
24
+ * @param {boolean} shouldCollectPayload
86
25
  * @returns the return from the bundleHTTPData() call
87
26
  */
88
27
  function _handleFetchOnPromiseCompletion(
@@ -92,7 +31,9 @@ function _handleFetchOnPromiseCompletion(
92
31
  bodyStrings,
93
32
  url,
94
33
  method,
34
+ shouldCollectPayload,
95
35
  ) {
36
+ noibuLog('_handleFetchOnPromiseCompletion', method, url);
96
37
  let reqBody; //
97
38
  let reqHeaders = new Map();
98
39
  let respHeaders = new Map();
@@ -147,6 +88,7 @@ function _handleFetchOnPromiseCompletion(
147
88
  respHeaders,
148
89
  bodyStrings[0],
149
90
  method,
91
+ shouldCollectPayload,
150
92
  );
151
93
  }
152
94
 
@@ -171,6 +113,7 @@ async function _buildHttpEventDataObjectsForFetch(
171
113
  respTime,
172
114
  requestTextPromise,
173
115
  ) {
116
+ noibuLog('_buildHttpEventDataObjectsForFetch started', method, url);
174
117
  const httpEvent = {
175
118
  [HTTP_METHOD_ATT_NAME]: method,
176
119
  [HTTP_RESP_CODE_ATT_NAME]: response.status,
@@ -192,15 +135,24 @@ async function _buildHttpEventDataObjectsForFetch(
192
135
  }
193
136
 
194
137
  let responseText = '';
195
- if (
196
- HTTPDataBundler.getInstance().shouldCollectPayloadForURL(url) &&
197
- response instanceof Response
198
- ) {
138
+ const shouldCollectPayload =
139
+ HTTPDataBundler.getInstance().shouldCollectPayloadForURL(url);
140
+ if (shouldCollectPayload && response instanceof Response) {
141
+ noibuLog('_buildHttpEventDataObjectsForFetch collecting response');
199
142
  const droppedResponseText =
200
143
  HTTPDataBundler.getInstance().dropPayloadIfNecessaryFromHeaders(
201
144
  response.headers,
202
145
  );
203
146
  responseText = droppedResponseText || response.clone().text();
147
+ } else {
148
+ noibuLog(
149
+ '_buildHttpEventDataObjectsForFetch not collecting payload, because of',
150
+ {
151
+ shouldCollectPayloadForURL:
152
+ HTTPDataBundler.getInstance().shouldCollectPayloadForURL(url),
153
+ instanceOfCheck: response instanceof Response,
154
+ },
155
+ );
204
156
  }
205
157
  const responseTextPromise = Promise.resolve(responseText);
206
158
 
@@ -222,224 +174,19 @@ async function _buildHttpEventDataObjectsForFetch(
222
174
  data,
223
175
  url,
224
176
  method,
177
+ shouldCollectPayload,
225
178
  ),
226
179
  )
227
180
  .then(httpDataReturn => {
228
181
  httpData = httpDataReturn;
229
182
  });
230
183
  }
184
+ noibuLog('_buildHttpEventDataObjectsForFetch ended');
231
185
  // This return will await the _handleFetchOnPromiseCompletion() call if necessary,
232
186
  // but won't if not. (See if above).
233
187
  return [httpEvent, httpData];
234
188
  }
235
189
 
236
- /**
237
- * Wraps the send prototype of the xmlhttp object
238
- * @param {object} proto window.XMLHTTPRequest's prototype
239
- */
240
- function wrapXMLHTTPSend(proto) {
241
- replace(
242
- proto,
243
- 'send',
244
- originalFunction =>
245
- // We set nbuWrapper to the handler function so if this returns an error
246
- // the trace message will start with nbuWrapper which would allow us to
247
- // detect that this is a wrapped function and not a NoibuJS error
248
- function nbuXMLHTTPSendWrapper(data) {
249
- // We wrap all of our logic in a try block to guarantee that we will complete the original
250
- // implementation if we throw an error in our logic.
251
- try {
252
- let method;
253
- if (this.noibuHttpMethod) {
254
- method = this.noibuHttpMethod;
255
- } else {
256
- // This is very hacky but we do not really have an option as
257
- // we do not have access to either the url nor the method when
258
- // overiding the send method
259
- method = data ? 'POST' : 'GET';
260
- }
261
- // not using safePerformanceNow as there is a 70% hit with using it.
262
- // We don't want every request to get impacted by this.
263
- const rCreatedAt = new Date();
264
- // on loadend we catch the event and
265
- // make sure it was correct
266
- addSafeEventListener(this, 'loadend', async () => {
267
- const rEndedAt = new Date();
268
- const respTime = Math.abs(rEndedAt - rCreatedAt);
269
- // Prefer the URL from the open() call if it is defined.
270
- const url = this.noibuHttpUrl || this.responseURL;
271
- const gqlError = await GqlErrorValidator.fromXhr(url, this);
272
-
273
- const [httpEvent, httpData] = _buildHttpEventDataObjectsForXHR(
274
- this,
275
- method,
276
- url,
277
- respTime,
278
- gqlError,
279
- data,
280
- );
281
-
282
- // Save HTTP Info
283
- let pageVisitEventHTTP = new PageVisitEventHTTP(
284
- httpEvent,
285
- httpData,
286
- );
287
- pageVisitEventHTTP.saveHTTPEvent();
288
-
289
- const seq =
290
- pageVisitEventHTTP.httpData &&
291
- pageVisitEventHTTP.httpData[PV_SEQ_ATT_NAME];
292
- if (isHttpCodeFailure(this.status)) {
293
- saveErrorToPagevisit(XML_HTTP_REQUEST_ERROR_TYPE, this, seq);
294
- }
295
-
296
- if (gqlError) {
297
- gqlError.forEach(error =>
298
- saveErrorToPagevisit(GQL_ERROR_TYPE, error, seq),
299
- );
300
- }
301
-
302
- // helping gc
303
- pageVisitEventHTTP = null;
304
- }); // End of loadend callback, return to synchronous code below
305
- } catch (e) {
306
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
307
- `Error in XHR.send() wrapper: ${e}`,
308
- false,
309
- SEVERITY.error,
310
- );
311
- }
312
- return originalFunction.call(this, data);
313
- },
314
- );
315
- }
316
-
317
- /**
318
- * Wraps the open prototype of the xmlhttp object
319
- * @param {object} proto window.XMLHTTPRequest's prototype
320
- * @param {boolean} shouldHandleLoadend Whether the wrapped XHR.open() function should be
321
- * responsible for listening to 'loadend' events. (Used in the case where the XHR.send()
322
- * function on the XHR prototype cannot be modified.)
323
- */
324
- function wrapXMLHTTPOpen(proto, shouldHandleLoadend) {
325
- replace(
326
- proto,
327
- 'open',
328
- originalFunction =>
329
- // We set nbuWrapper to the handler function so if this returns an error
330
- // the trace message will start with nbuWrapper which would allow us to
331
- // detect that this is a wrapped function and not a NoibuJS error
332
- function nbuXMLHTTPOpenWrapper(
333
- method,
334
- url,
335
- async = true,
336
- user = null,
337
- password = null,
338
- ) {
339
- // We wrap all of our logic in a try block to guarantee that we will complete the original
340
- // implementation if we throw an error in our logic.
341
- try {
342
- // We wrap assignment of the .noibu[...] variables in a try/catch, as we're assigning
343
- // properties to a built-in object type, and have no guarantee of success.
344
- try {
345
- this.noibuHttpMethod = method;
346
- this.noibuHttpUrl = url;
347
- } catch (error) {
348
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
349
- `Unable to set custom properties on XHR object: ${error}`,
350
- false,
351
- SEVERITY.warn,
352
- );
353
- }
354
-
355
- if (shouldHandleLoadend) {
356
- // on loadend we catch the event and
357
- // make sure it was correct
358
- const rCreatedAt = new Date();
359
- addSafeEventListener(this, 'loadend', async () => {
360
- const rEndedAt = new Date();
361
- const respTime = Math.abs(rEndedAt - rCreatedAt);
362
- const gqlError = await GqlErrorValidator.fromXhr(url, this);
363
-
364
- const [httpEvent, httpData] = _buildHttpEventDataObjectsForXHR(
365
- this,
366
- method,
367
- url,
368
- respTime,
369
- gqlError,
370
- );
371
-
372
- let pageVisitEventHTTP = new PageVisitEventHTTP(
373
- httpEvent,
374
- httpData,
375
- );
376
-
377
- // Save HTTP Info
378
- pageVisitEventHTTP.saveHTTPEvent();
379
- const seq =
380
- pageVisitEventHTTP.httpData &&
381
- pageVisitEventHTTP.httpData[PV_SEQ_ATT_NAME];
382
- if (isHttpCodeFailure(this.status)) {
383
- saveErrorToPagevisit(XML_HTTP_REQUEST_ERROR_TYPE, this, seq);
384
- }
385
-
386
- if (gqlError) {
387
- gqlError.forEach(error =>
388
- saveErrorToPagevisit(GQL_ERROR_TYPE, error, seq),
389
- );
390
- }
391
-
392
- // helping gc
393
- pageVisitEventHTTP = null;
394
- }); // End of loadend callback, return to synchronous code below
395
- }
396
- } catch (e) {
397
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
398
- `Error in XHR.open() wrapper: ${e}`,
399
- false,
400
- SEVERITY.error,
401
- );
402
- }
403
- return originalFunction.call(this, method, url, async, user, password);
404
- },
405
- );
406
- }
407
-
408
- /**
409
- * Replaces the native XMLHTTPRequest.setHeader() function. We use this to build an array of
410
- * request headers as these are not stored by the XMLHTTPRequest object.
411
- * @param {object} proto window.XMLHTTPRequest's prototype
412
- */
413
- function wrapXMLHTTPSetRequestHeader(proto) {
414
- replace(
415
- proto,
416
- 'setRequestHeader',
417
- originalFunction =>
418
- function nbuXMLHTTPSetRequestHeaderWrapper(header, value) {
419
- // We wrap all of our logic in a try block to guarantee that we will complete the original
420
- // implementation if we throw an error in our logic.
421
- try {
422
- if (
423
- !this.noibuRequestHeaders ||
424
- !(this.noibuRequestHeaders instanceof Map)
425
- ) {
426
- this.noibuRequestHeaders = new Map();
427
- }
428
- // Ensure it's a string. This also converts null to "null"
429
- const stringValue = typeof value === 'string' ? value : String(value);
430
- this.noibuRequestHeaders.set(header.toLowerCase(), stringValue);
431
- } catch (error) {
432
- ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
433
- `Error in XHR.setRequestHeader() wrapper: ${error}`,
434
- false,
435
- SEVERITY.error,
436
- );
437
- }
438
- return originalFunction.call(this, header, value);
439
- },
440
- );
441
- }
442
-
443
190
  /**
444
191
  * Handles fetch failure
445
192
  * @param {} err
@@ -473,12 +220,12 @@ function handleFetchFailure(err, url) {
473
220
  */
474
221
  function setupGlobalFetchWrapper() {
475
222
  const proto = global;
476
-
477
223
  // Ensure we're able to replace the fetch() function
478
224
  if (!propWriteableOrMadeWriteable(proto, 'fetch')) {
225
+ noibuLog('setupGlobalFetchWrapper fetch is not writable');
479
226
  return;
480
227
  }
481
-
228
+ noibuLog('setupGlobalFetchWrapper replacing fetch');
482
229
  replace(
483
230
  proto,
484
231
  'fetch',
@@ -500,6 +247,7 @@ function setupGlobalFetchWrapper() {
500
247
  // We wrap everything in try/catch to ensure the original function is called even if we throw
501
248
  // an unexpected error.
502
249
  try {
250
+ noibuLog('nbuGlobalFetchWrapper start call', { resource });
503
251
  // There is no valid reason for fetch() to be called without a resource but we
504
252
  // see it on a bunch of websites. It seems to work the same as empty string
505
253
  if (!resource) {
@@ -524,11 +272,24 @@ function setupGlobalFetchWrapper() {
524
272
  resource.clone &&
525
273
  resource.text
526
274
  ) {
275
+ noibuLog('nbuGlobalFetchWrapper collecting request object');
527
276
  // We clone the request object, as its body can only be read once per instance.
528
277
  // It's important that we do this before the original function is called, as it
529
278
  // cannot be cloned afterwards.
530
279
  request = resource.clone();
531
280
  requestTextPromise = request.text();
281
+ } else {
282
+ noibuLog(
283
+ 'nbuGlobalFetchWrapper not collecting request object, because one of these is false',
284
+ {
285
+ shouldCollectPayloadForURL:
286
+ HTTPDataBundler.getInstance().shouldCollectPayloadForURL(
287
+ url,
288
+ ),
289
+ clone: !!resource.clone,
290
+ text: !!resource.text,
291
+ },
292
+ );
532
293
  }
533
294
  }
534
295
  } catch (e) {
@@ -541,6 +302,7 @@ function setupGlobalFetchWrapper() {
541
302
 
542
303
  // Break out of the try wrapper momentarily to make the original call
543
304
 
305
+ noibuLog('nbuGlobalFetchWrapper call original');
544
306
  // Can't put this inside finally as const needs to be defined outside it.
545
307
  const promiseFromOriginalFetch = originalFunction.call(
546
308
  this,
@@ -552,6 +314,7 @@ function setupGlobalFetchWrapper() {
552
314
  const rCreatedAt = new Date();
553
315
  promiseFromOriginalFetch
554
316
  .then(async response => {
317
+ noibuLog('nbuGlobalFetchWrapper got response');
555
318
  // We wrap the callback in try in order to only catch real fetch failures in the promise's
556
319
  // .catch() call
557
320
  try {
@@ -624,41 +387,15 @@ function setupGlobalFetchWrapper() {
624
387
  },
625
388
  );
626
389
  }
627
-
628
- /**
629
- * Setting up the wrapper around send functions to try and
630
- * catch http errors
631
- */
632
- function setupGlobalXMLHttpWrapper() {
633
- const XMLHttp = window.XMLHttpRequest;
634
- // The event target needs to have a prototype and have the open function
635
- const proto = XMLHttp && XMLHttp.prototype;
636
-
637
- const canWriteOpen = propWriteableOrMadeWriteable(proto, 'open');
638
- const canWriteSend = propWriteableOrMadeWriteable(proto, 'send');
639
- const canWriteSetHeader = propWriteableOrMadeWriteable(
640
- proto,
641
- 'setRequestHeader',
642
- );
643
-
644
- if (canWriteOpen) {
645
- // If we can't wrap the XHR.send() function, we need the wrapped .open() function to
646
- // set the listener on 'loadend' events.
647
- wrapXMLHTTPOpen(proto, !canWriteSend);
648
- }
649
- if (canWriteSend) {
650
- wrapXMLHTTPSend(proto);
651
- }
652
- if (canWriteSetHeader) {
653
- wrapXMLHTTPSetRequestHeader(proto);
654
- }
655
- }
656
390
  /**
657
391
  * Monitors all requests
658
392
  */
659
393
  function monitorRequests() {
660
- setupGlobalXMLHttpWrapper();
394
+ noibuLog('monitorRequests started');
395
+ /** todo: disabling xmlhttp since it seems to duplicate fetch wrapper, but lacks response body capture */
396
+ // setupGlobalXMLHttpWrapper();
661
397
  setupGlobalFetchWrapper();
398
+ noibuLog('monitorRequests ended');
662
399
  }
663
400
 
664
401
  export { handleFetchFailure, monitorRequests };
@@ -3,6 +3,7 @@ import { TYPE_ATT_NAME, OCCURRED_AT_ATT_NAME, MAX_PAGEVISIT_EVENTS, MAX_PAGEVISI
3
3
  import ClientConfig from '../api/clientConfig.js';
4
4
  import MetroplexSocket from '../api/metroplexSocket.js';
5
5
  import StoredMetrics from '../api/storedMetrics.js';
6
+ import { noibuLog } from '../utils/log.js';
6
7
 
7
8
  /** @module Pagevisit */
8
9
 
@@ -64,6 +65,10 @@ class PageVisit {
64
65
  * @param {} type
65
66
  */
66
67
  addPageVisitEvent(eventObj, type) {
68
+ noibuLog('addPageVisitEvent', {
69
+ eventObj,
70
+ type,
71
+ });
67
72
  const id = this._addPageVisitEvent(eventObj, type);
68
73
  this._sendPageVisitMessage();
69
74
  return id;
@@ -1,12 +1,22 @@
1
- import { isValidURL, asString, getMaxSubstringAllowed, getJSStack, stringifyJSON } from '../../utils/function.js';
2
- import { EVENT_ERROR_TYPE, URL_ATT_NAME, 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
- import blacklisedDomains from './blacklistedDomains.js';
4
- import ClientConfig from '../../api/clientConfig.js';
5
- import { InputMonitor } from '../../monitors/inputMonitor.js';
6
- import StoredMetrics from '../../api/storedMetrics.js';
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, PV_SEQ_ATT_NAME, GQL_EVENT_TYPE, GQL_ERROR_ATT_NAME } from '../constants.js';
3
+ import ClientConfig from '../api/clientConfig.js';
4
+ import { InputMonitor } from '../monitors/inputMonitor.js';
5
+ import StoredMetrics from '../api/storedMetrics.js';
7
6
 
8
7
  /** @module PageVisitEventError */
9
8
 
9
+ /**
10
+ * gets the onURL of a string, defaulting to the location of the webpage
11
+ */
12
+ function getOnURL(realOnURL) {
13
+ if (realOnURL && realOnURL.trim() !== '' && realOnURL !== 'undefined') {
14
+ return asString(getMaxSubstringAllowed(realOnURL));
15
+ }
16
+
17
+ return ClientConfig.getInstance().globalUrl;
18
+ }
19
+
10
20
  /**
11
21
  * getPVErrorFromResponse will create the error information from an
12
22
  * http response error type.
@@ -25,21 +35,10 @@ function getPVErrorFromResponse(errPayload, httpDataSeqNum) {
25
35
  return errorObject;
26
36
  }
27
37
 
28
- /**
29
- * gets the onURL of a string, defaulting to the location of the webpage
30
- */
31
- function getOnURL(realOnURL) {
32
- if (realOnURL && realOnURL.trim() !== '' && realOnURL !== 'undefined') {
33
- return asString(getMaxSubstringAllowed(realOnURL));
34
- }
35
-
36
- return ClientConfig.getInstance().globalUrl;
37
- }
38
-
39
38
  /**
40
39
  * getPVErrorFromGqlError will create the error information from an
41
40
  * GraphQL error payload.
42
- * @param {} errPayload
41
+ * @param payload
43
42
  * @param {} httpDataSeqNum
44
43
  */
45
44
  function getPVErrorFromGqlError(payload, httpDataSeqNum) {
@@ -303,7 +302,7 @@ function saveErrorToPagevisit(type, payload, httpDataSeqNum) {
303
302
  const urlOb = new URL(currErrURL);
304
303
 
305
304
  // if the domain is blacklisted we drop the error
306
- if (urlOb.hostname in blacklisedDomains) {
305
+ if (urlOb.hostname in BLOCKLISTED_DOMAINS) {
307
306
  return;
308
307
  }
309
308
  }
@@ -1,10 +1,11 @@
1
- import { getMaxSubstringAllowed, asString } from '../../utils/function.js';
2
- import { timestampWrapper } from '../../utils/date.js';
3
- import { InputMonitor } from '../../monitors/inputMonitor.js';
4
- import { HTTP_METHOD_ATT_NAME, MAX_HTTP_DATA_EVENT_COUNT, PV_SEQ_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME } from '../../constants.js';
5
- import { PageVisit } from '../pageVisit.js';
6
- import StoredMetrics from '../../api/storedMetrics.js';
7
- import MetroplexSocket from '../../api/metroplexSocket.js';
1
+ import { getMaxSubstringAllowed, asString } from '../utils/function.js';
2
+ import { timestampWrapper } from '../utils/date.js';
3
+ import { InputMonitor } from '../monitors/inputMonitor.js';
4
+ import { HTTP_METHOD_ATT_NAME, MAX_HTTP_DATA_EVENT_COUNT, PV_SEQ_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, HTTP_EVENT_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME } from '../constants.js';
5
+ import { PageVisit } from './pageVisit.js';
6
+ import StoredMetrics from '../api/storedMetrics.js';
7
+ import MetroplexSocket from '../api/metroplexSocket.js';
8
+ import { noibuLog } from '../utils/log.js';
8
9
 
9
10
  /** @module PageVisitEventHTTP */
10
11
 
@@ -49,12 +50,14 @@ class PageVisitEventHTTP {
49
50
 
50
51
  /** Saves the HTTP event to the pageVisit Queue */
51
52
  saveHTTPEvent() {
53
+ noibuLog('saveHTTPEvent');
52
54
  // we do not store http events that have empty urls
53
55
  if (
54
56
  !this.httpEvent ||
55
57
  !this.httpEvent.url ||
56
58
  this.httpEvent.url.trim() === ''
57
59
  ) {
60
+ noibuLog('saveHTTPEvent dropped due to empty url');
58
61
  return;
59
62
  }
60
63
  // we register an http event
@@ -62,6 +65,7 @@ class PageVisitEventHTTP {
62
65
 
63
66
  // send http data down to metroplex
64
67
  if (this.httpData) {
68
+ noibuLog('saveHTTPEvent got httpData, working');
65
69
  // add the sequence number to both events
66
70
  const sequenceNumber = StoredMetrics.getInstance().httpSequenceNumber;
67
71
  // restrict total number of events collected per page visit to ensure we don't
@@ -79,6 +83,9 @@ class PageVisitEventHTTP {
79
83
  metroplexMsg,
80
84
  );
81
85
  } else {
86
+ noibuLog(
87
+ 'saveHTTPEvent have collected more than the max number of http requests for this page visit, so increment the over request limit count',
88
+ );
82
89
  // have collected more than the max number of http requests for this
83
90
  // page visit, so increment the over request limit count
84
91
  StoredMetrics.getInstance().addHttpDataOverLimit();
@@ -86,6 +93,7 @@ class PageVisitEventHTTP {
86
93
  }
87
94
  // if this was an error, send immediately so we don't lose it
88
95
  if (isHttpCodeFailure(this.httpEvent.code)) {
96
+ noibuLog('saveHTTPEvent is an error, sending immediately');
89
97
  PageVisit.getInstance().addPageVisitEvent(
90
98
  {
91
99
  event: this.httpEvent,
@@ -1,5 +1,5 @@
1
- import { asString } from '../../utils/function.js';
2
- import { CSS_CLASS_ATT_NAME } from '../../constants.js';
1
+ import { asString } from '../utils/function.js';
2
+ import { CSS_CLASS_ATT_NAME } from '../constants.js';
3
3
 
4
4
  /** @module UserStep */
5
5
  /**
@@ -1,7 +1,6 @@
1
- import type { NavigationDelegate } from 'react-native-navigation/lib/dist/src/NavigationDelegate';
2
1
  /**
3
2
  * interface enforces constructor signature
4
3
  */
5
4
  export interface NavigationIntegration {
6
- register(navigation: NavigationDelegate, onNavigation: (breadcrumbs: string[]) => void): void;
5
+ register(navigation: any, onNavigation: (breadcrumbs: string[]) => void): void;
7
6
  }
@@ -14,6 +14,9 @@ declare global {
14
14
  const MAX_METROPLEX_RECONNECTION_NUMBER: number;
15
15
  const METROPLEX_CONSECUTIVE_CONNECTION_DELAY: number;
16
16
  const SCRIPT_ID: string;
17
+ const ENABLE_LOGGING: string;
18
+ const ENV: string;
19
+ const DEVICE_ENV: string | undefined;
17
20
  type Window = {
18
21
  noibuJSLoaded?: boolean;
19
22
  };
@@ -32,10 +35,10 @@ declare global {
32
35
  enablePromiseRejectionTracker?: (options: PromiseRejectionTrackerOptions) => void;
33
36
  setPromiseRejectionTrackingHook?: (enable: (options: PromiseRejectionTrackerOptions) => void) => void;
34
37
  };
35
- Promise: {
36
- _m: () => void;
37
- };
38
38
  };
39
+ interface PromiseConstructor {
40
+ _m: <T>(promise: Promise<T>, error: any) => void;
41
+ }
39
42
  const global: global;
40
43
  const globalThis: global;
41
44
  const window: Window & global;
@@ -48,9 +48,8 @@ export declare function makeRequest(method: string, url: string, data: unknown,
48
48
  */
49
49
  export declare function isValidURL(str: string): boolean;
50
50
  /**
51
- * Because of the nature of user agent in react native, we have to make this async.
52
- * But I promise, this is really fast, since we memoize the result for the whole session :)
53
- * @returns {Promise<string>}
51
+ * Fakes the user agent retrieval, since there are no good libraries that support both expo and plain RN
52
+ * caches the result for the session
54
53
  */
55
54
  export declare function getUserAgent(): Promise<string>;
56
55
  /**