noibu-react-native 0.2.6 → 0.2.8
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.
- package/README.md +15 -15
- package/android/build.gradle +1 -1
- package/dist/{src/api/clientConfig.d.ts → api/ClientConfig.d.ts} +19 -20
- package/dist/api/{clientConfig.js → ClientConfig.js} +82 -63
- package/dist/{src/api/helpCode.d.ts → api/HelpCode.d.ts} +3 -10
- package/dist/api/{helpCode.js → HelpCode.js} +8 -14
- package/dist/api/InputManager.d.ts +39 -0
- package/dist/api/InputManager.js +156 -0
- package/dist/{src/api/metroplexSocket.d.ts → api/MetroplexSocket.d.ts} +33 -38
- package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +190 -178
- package/dist/{src/api/storedMetrics.d.ts → api/StoredMetrics.d.ts} +10 -20
- package/dist/api/StoredMetrics.js +158 -0
- package/dist/{src/api/storedPageVisit.d.ts → api/StoredPageVisit.d.ts} +11 -8
- package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +62 -48
- package/dist/const_matchers.js +1 -5
- package/dist/constants.d.ts +48 -0
- package/dist/constants.js +15 -397
- package/dist/{src/entry → entry}/index.d.ts +5 -6
- package/dist/entry/index.js +3 -4
- package/dist/entry/init.d.ts +8 -0
- package/dist/entry/init.js +34 -19
- package/dist/monitors/AppNavigationMonitor.d.ts +10 -0
- package/dist/monitors/AppNavigationMonitor.js +19 -19
- package/dist/monitors/AppNavigationMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/BaseMonitor.d.ts +5 -5
- package/dist/monitors/BaseMonitor.js +9 -4
- package/dist/monitors/BaseMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/ClickMonitor.d.ts +10 -13
- package/dist/monitors/ClickMonitor.js +72 -76
- package/dist/monitors/ClickMonitor.test.d.ts +1 -0
- package/dist/{src/monitors → monitors}/ErrorMonitor.d.ts +4 -28
- package/dist/monitors/ErrorMonitor.js +45 -55
- package/dist/{src/monitors → monitors}/KeyboardInputMonitor.d.ts +1 -3
- package/dist/monitors/KeyboardInputMonitor.js +13 -11
- package/dist/{src/monitors → monitors}/PageMonitor.d.ts +1 -1
- package/dist/monitors/PageMonitor.js +25 -2
- package/dist/{src/monitors → monitors}/RequestMonitor.d.ts +9 -29
- package/dist/monitors/RequestMonitor.js +46 -57
- package/dist/monitors/http-tools/GqlErrorValidator.d.ts +35 -0
- package/dist/monitors/http-tools/GqlErrorValidator.js +42 -70
- package/dist/{src/monitors → monitors}/http-tools/HTTPDataBundler.d.ts +9 -15
- package/dist/monitors/http-tools/HTTPDataBundler.js +74 -67
- package/dist/monitors/integrations/ReactNativeNavigationIntegration.d.ts +17 -0
- package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
- package/dist/{src/pageVisit → pageVisit}/EventDebouncer.d.ts +9 -10
- package/dist/pageVisit/EventDebouncer.js +43 -74
- package/dist/pageVisit/HttpEventManager.d.ts +14 -0
- package/dist/pageVisit/HttpEventManager.js +88 -0
- package/dist/pageVisit/PageVisitManager.d.ts +31 -0
- package/dist/pageVisit/PageVisitManager.js +99 -0
- package/dist/pageVisit/pageVisitEventError.d.ts +12 -0
- package/dist/pageVisit/pageVisitEventError.js +170 -280
- package/dist/{src/react → react}/ErrorBoundary.d.ts +4 -9
- package/dist/react/ErrorBoundary.js +3 -6
- package/dist/{src/sessionRecorder/sessionRecorder.d.ts → sessionRecorder/SessionRecorder.d.ts} +7 -17
- package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +60 -71
- package/dist/{src/sessionRecorder → sessionRecorder}/nativeSessionRecorderSubscription.d.ts +4 -6
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
- package/dist/{src/storage/rnStorageProvider.d.ts → storage/RNStorageProvider.d.ts} +4 -8
- package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
- package/dist/{src/storage/storage.d.ts → storage/Storage.d.ts} +8 -18
- package/dist/storage/{storage.js → Storage.js} +17 -30
- package/dist/{src/storage/storageProvider.d.ts → storage/StorageProvider.d.ts} +5 -8
- package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
- package/dist/types/NavigationIntegration.d.ts +1 -1
- package/dist/utils/date.d.ts +7 -0
- package/dist/utils/date.js +41 -51
- package/dist/utils/eventlistener.js +6 -14
- package/dist/{src/utils → utils}/function.d.ts +13 -43
- package/dist/utils/function.js +42 -113
- package/dist/utils/log.d.ts +4 -0
- package/dist/utils/log.js +2 -4
- package/dist/{src/utils → utils}/object.d.ts +10 -8
- package/dist/utils/object.js +12 -12
- package/dist/{src/utils → utils}/performance.d.ts +1 -1
- package/dist/utils/piiRedactor.js +31 -3
- package/dist/utils/stacktrace-parser.d.ts +8 -0
- package/dist/utils/stacktrace-parser.js +29 -21
- package/dist/utils/stacktrace-parser.test.d.ts +1 -0
- package/package.json +14 -14
- package/dist/api/inputManager.js +0 -227
- package/dist/api/storedMetrics.js +0 -198
- package/dist/pageVisit/pageVisit.js +0 -181
- package/dist/pageVisit/pageVisitEventHTTP.js +0 -98
- package/dist/pageVisit/userStep.js +0 -20
- package/dist/src/api/inputManager.d.ts +0 -87
- package/dist/src/constants.d.ts +0 -290
- package/dist/src/entry/init.d.ts +0 -5
- package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
- package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
- package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
- package/dist/src/pageVisit/pageVisit.d.ts +0 -52
- package/dist/src/pageVisit/pageVisitEventError.d.ts +0 -15
- package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +0 -25
- package/dist/src/pageVisit/userStep.d.ts +0 -5
- package/dist/src/utils/date.d.ts +0 -6
- package/dist/src/utils/log.d.ts +0 -4
- package/dist/src/utils/stacktrace-parser.d.ts +0 -7
- package/dist/types/Config.d.ts +0 -31
- package/dist/types/Metroplex.types.d.ts +0 -73
- package/dist/types/PageVisit.types.d.ts +0 -8
- package/dist/types/PageVisitErrors.types.d.ts +0 -114
- package/dist/types/PageVisitEvents.types.d.ts +0 -91
- package/dist/types/PageVisitMetrics.types.d.ts +0 -27
- package/dist/types/Storage.d.ts +0 -14
- package/dist/types/StoredPageVisit.types.d.ts +0 -11
- package/dist/types/WrappedObjects.d.ts +0 -6
- /package/dist/{src/api/clientConfig.test.d.ts → api/ClientConfig.test.d.ts} +0 -0
- /package/dist/{src/monitors/BaseMonitor.test.d.ts → api/MetroplexSocket.test.d.ts} +0 -0
- /package/dist/{src/const_matchers.d.ts → const_matchers.d.ts} +0 -0
- /package/dist/{src/sessionRecorder → sessionRecorder}/types.d.ts +0 -0
- /package/dist/{src/utils → utils}/eventlistener.d.ts +0 -0
- /package/dist/{src/utils → utils}/piiRedactor.d.ts +0 -0
- /package/dist/{src/utils → utils}/polyfills.d.ts +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { updatePayload } from '../pageVisit/userStep.js';
|
|
2
|
-
import { SOURCE_ATT_NAME, TEXT_ATT_NAME, TAGNAME_ATT_NAME, TYPE_ATT_NAME, KEYBOARD_EVENT_TYPE } from '../constants.js';
|
|
3
1
|
import { EventDebouncer } from '../pageVisit/EventDebouncer.js';
|
|
4
2
|
import { TextInput } from 'react-native';
|
|
5
3
|
import { Singleton } from './BaseMonitor.js';
|
|
4
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
5
|
+
import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
|
|
6
|
+
import { UserStepType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/UserStepType.js';
|
|
6
7
|
|
|
7
8
|
/** @module KeyboardInputMonitor */
|
|
8
9
|
/**
|
|
@@ -37,9 +38,7 @@ class KeyboardInputMonitor extends Singleton {
|
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Validates an event
|
|
42
|
-
*/
|
|
41
|
+
/** Validates an event */
|
|
43
42
|
static handle(uiViewClassName, props) {
|
|
44
43
|
if (!/(text|input)/i.test(uiViewClassName)) {
|
|
45
44
|
return;
|
|
@@ -48,12 +47,15 @@ class KeyboardInputMonitor extends Singleton {
|
|
|
48
47
|
if (!name) {
|
|
49
48
|
return;
|
|
50
49
|
}
|
|
51
|
-
EventDebouncer.getInstance().
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
EventDebouncer.getInstance().debounce({
|
|
51
|
+
type: EventType.UserStep,
|
|
52
|
+
userstep: {
|
|
53
|
+
src: '',
|
|
54
|
+
txt: name,
|
|
55
|
+
tag: uiViewClassName.toLowerCase(),
|
|
56
|
+
type: UserStepType.Keyboard,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -10,7 +10,7 @@ export declare class PageMonitor extends Singleton implements Monitor {
|
|
|
10
10
|
*/
|
|
11
11
|
_onPageEventHandle(event: Event): void;
|
|
12
12
|
/** Returns document state */
|
|
13
|
-
getDocumentState(): "
|
|
13
|
+
getDocumentState(): "passive" | "hidden" | "active";
|
|
14
14
|
/**
|
|
15
15
|
* Returns object size in bytes
|
|
16
16
|
* @param {} obj
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
import { PAGE_EVENTS_WINDOW, PAGE_EVENTS_DOCUMENT, PAGE_EVENT_TYPE } from '../constants.js';
|
|
2
1
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
3
2
|
import { EventDebouncer } from '../pageVisit/EventDebouncer.js';
|
|
4
3
|
import { Singleton } from './BaseMonitor.js';
|
|
4
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
5
|
+
import { EventType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/EventType.js';
|
|
5
6
|
|
|
6
7
|
/** @module PageMonitor */
|
|
8
|
+
const PAGE_EVENTS_DOCUMENT = ['visibilitychange', 'resume', 'freeze', 'readystatechange', 'cut', 'copy', 'paste'];
|
|
9
|
+
// page events we track in the session
|
|
10
|
+
// don't include beforeunload, it will affect bfcache
|
|
11
|
+
const PAGE_EVENTS_WINDOW = [
|
|
12
|
+
'pagehide',
|
|
13
|
+
'pageshow',
|
|
14
|
+
'focus',
|
|
15
|
+
'blur',
|
|
16
|
+
'popstate',
|
|
17
|
+
'online',
|
|
18
|
+
'offline',
|
|
19
|
+
'messageerror',
|
|
20
|
+
'languagechange',
|
|
21
|
+
'hashchange',
|
|
22
|
+
'beforeprint',
|
|
23
|
+
'afterprint',
|
|
24
|
+
'load',
|
|
25
|
+
'resize',
|
|
26
|
+
];
|
|
7
27
|
/** Monitors the page events which we capture and later process */
|
|
8
28
|
class PageMonitor extends Singleton {
|
|
9
29
|
/** Starts monitoring page events on the document */
|
|
@@ -65,7 +85,10 @@ class PageMonitor extends Singleton {
|
|
|
65
85
|
// do nothing
|
|
66
86
|
}
|
|
67
87
|
// storing the page event in the page visit queue
|
|
68
|
-
EventDebouncer.getInstance().
|
|
88
|
+
EventDebouncer.getInstance().debounce({
|
|
89
|
+
type: EventType.Page,
|
|
90
|
+
page: payload,
|
|
91
|
+
});
|
|
69
92
|
}
|
|
70
93
|
/** Returns document state */
|
|
71
94
|
getDocumentState() {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/** @module RequestMonitor */
|
|
2
|
-
import 'react-native/Libraries/Network/fetch';
|
|
3
1
|
import { Monitor, Singleton } from './BaseMonitor';
|
|
4
|
-
/**
|
|
5
|
-
* Monitors all requests
|
|
6
|
-
*/
|
|
2
|
+
/** Monitors all requests */
|
|
7
3
|
export default class RequestMonitor extends Singleton implements Monitor {
|
|
8
4
|
/** main method */
|
|
9
5
|
monitor(): void;
|
|
@@ -15,54 +11,38 @@ export default class RequestMonitor extends Singleton implements Monitor {
|
|
|
15
11
|
* thus client code may throw an error.
|
|
16
12
|
*/
|
|
17
13
|
private static consumeResponseAndGetBodyText;
|
|
18
|
-
/**
|
|
19
|
-
* Generates new PVEventHTTP
|
|
20
|
-
*/
|
|
14
|
+
/** Generates new PVEventHTTP */
|
|
21
15
|
private static getPvEventHttp;
|
|
22
|
-
/**
|
|
23
|
-
* Gets headers from request or request options. Handles different scenarios where simple conversion is not possible
|
|
24
|
-
*/
|
|
16
|
+
/** Gets headers from request or request options. Handles different scenarios where simple conversion is not possible */
|
|
25
17
|
private static getRequestHeaders;
|
|
26
18
|
/**
|
|
27
19
|
* Gets response headers.
|
|
28
20
|
* It is always a Headers object.
|
|
29
21
|
*/
|
|
30
22
|
private static getResponseHeaders;
|
|
31
|
-
/**
|
|
32
|
-
* Gets request body from body strings or Request options
|
|
33
|
-
*/
|
|
23
|
+
/** Gets request body from body strings or Request options */
|
|
34
24
|
private static getRequestBody;
|
|
35
|
-
/**
|
|
36
|
-
* Returns the parameters to pass the PageVisitEventHTTP constructor. Specific to the fetch wrapper.
|
|
37
|
-
*/
|
|
25
|
+
/** Returns the parameters to pass the HttpEventManager constructor. Specific to the fetch wrapper. */
|
|
38
26
|
private static getHttpDataFromFetch;
|
|
39
27
|
/** Clones Response / Request or returns original object if cloning is not possible */
|
|
40
28
|
private static cloneResponse;
|
|
41
|
-
/**
|
|
42
|
-
* Handles fetch response safely. Reports PageVisitEventHTTP and error to Pagevisit if needed.
|
|
43
|
-
*/
|
|
29
|
+
/** Handles fetch response safely. Reports HttpEventManager and error to Pagevisit if needed. */
|
|
44
30
|
private static safeHandleFetchResponse;
|
|
45
|
-
/**
|
|
46
|
-
* Safe function to get method and url from fetch args
|
|
47
|
-
*/
|
|
31
|
+
/** Safe function to get method and url from fetch args */
|
|
48
32
|
private static getMethodUrlFromFetchArgs;
|
|
49
33
|
/**
|
|
50
34
|
* Setting up the wrapper around fetch functions to try and
|
|
51
35
|
* catch http errors
|
|
52
36
|
*/
|
|
53
37
|
private static setupGlobalFetchWrapper;
|
|
54
|
-
/**
|
|
55
|
-
* Does a check if data collection is enabled and combines it into HttpDataBundle
|
|
56
|
-
*/
|
|
38
|
+
/** Does a check if data collection is enabled and combines it into HttpDataBundle */
|
|
57
39
|
private static getHttpDataFromXhr;
|
|
58
40
|
/**
|
|
59
41
|
* on loadend we catch the event and
|
|
60
42
|
* make sure it was correct
|
|
61
43
|
*/
|
|
62
44
|
private static loadendHandler;
|
|
63
|
-
/**
|
|
64
|
-
* Handles fetch failure
|
|
65
|
-
*/
|
|
45
|
+
/** Handles fetch failure */
|
|
66
46
|
private static handleFetchFailure;
|
|
67
47
|
/** gets method from xhr */
|
|
68
48
|
private static getMethodFromXHR;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import 'react-native/Libraries/Network/fetch';
|
|
3
2
|
import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
|
|
4
|
-
import { isHttpCodeFailure,
|
|
3
|
+
import { isHttpCodeFailure, saveHTTPEvent } from '../pageVisit/HttpEventManager.js';
|
|
5
4
|
import { safeEntries, propWriteableOrMadeWriteable, replace } from '../utils/object.js';
|
|
6
|
-
import
|
|
7
|
-
import ClientConfig from '../api/clientConfig.js';
|
|
5
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
8
6
|
import { noibuLog } from '../utils/log.js';
|
|
9
7
|
import { tryGetStackTrace, safeTrim } from '../utils/function.js';
|
|
10
8
|
import { promiseAll } from '../utils/polyfills.js';
|
|
@@ -12,10 +10,13 @@ import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
|
12
10
|
import { HTTPDataBundler } from './http-tools/HTTPDataBundler.js';
|
|
13
11
|
import GqlErrorValidator from './http-tools/GqlErrorValidator.js';
|
|
14
12
|
import { Singleton } from './BaseMonitor.js';
|
|
13
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
14
|
+
import { Severity } from '../node_modules/@noibu/metroplex-ts-bindings/dist/Severity.js';
|
|
15
|
+
import { PageVisitErrorSource } from '../node_modules/@noibu/metroplex-ts-bindings/dist/PageVisitErrorSource.js';
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
*/
|
|
17
|
+
/** request monitor */
|
|
18
|
+
const BODY_USED_ERROR = 'Response data unavailable due to an improperly wrapped fetch call';
|
|
19
|
+
/** Monitors all requests */
|
|
19
20
|
class RequestMonitor extends Singleton {
|
|
20
21
|
/** main method */
|
|
21
22
|
monitor() {
|
|
@@ -42,27 +43,23 @@ class RequestMonitor extends Singleton {
|
|
|
42
43
|
return response.text();
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Generates new PVEventHTTP
|
|
47
|
-
*/
|
|
46
|
+
/** Generates new PVEventHTTP */
|
|
48
47
|
static getPvEventHttp(status, responseHeaders, method, url, responseTime) {
|
|
49
48
|
const httpEvent = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
mtd: method,
|
|
50
|
+
code: status,
|
|
51
|
+
url,
|
|
52
|
+
r_time: responseTime,
|
|
54
53
|
};
|
|
55
54
|
const bundler = HTTPDataBundler.getInstance();
|
|
56
55
|
// add response payload length, if any
|
|
57
56
|
const contentLength = bundler.contentLength(responseHeaders);
|
|
58
57
|
if (contentLength > 0 && bundler.shouldContinueForURL(url)) {
|
|
59
|
-
httpEvent
|
|
58
|
+
httpEvent.resp_len = contentLength;
|
|
60
59
|
}
|
|
61
60
|
return httpEvent;
|
|
62
61
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Gets headers from request or request options. Handles different scenarios where simple conversion is not possible
|
|
65
|
-
*/
|
|
62
|
+
/** Gets headers from request or request options. Handles different scenarios where simple conversion is not possible */
|
|
66
63
|
static getRequestHeaders(request, options) {
|
|
67
64
|
const headers = safeEntries((request === null || request === void 0 ? void 0 : request.headers) || (options === null || options === void 0 ? void 0 : options.headers));
|
|
68
65
|
return HTTPDataBundler.headersMapFromIterable(headers);
|
|
@@ -75,9 +72,7 @@ class RequestMonitor extends Singleton {
|
|
|
75
72
|
const headers = safeEntries(response === null || response === void 0 ? void 0 : response.headers);
|
|
76
73
|
return HTTPDataBundler.headersMapFromIterable(headers);
|
|
77
74
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Gets request body from body strings or Request options
|
|
80
|
-
*/
|
|
75
|
+
/** Gets request body from body strings or Request options */
|
|
81
76
|
static getRequestBody(requestText, options) {
|
|
82
77
|
if (typeof requestText === 'string') {
|
|
83
78
|
return requestText;
|
|
@@ -85,9 +80,7 @@ class RequestMonitor extends Singleton {
|
|
|
85
80
|
// it's fine if it's falsy or an empty string, we catch that in HTTPDataBundler.getInstance().bundleHTTPData
|
|
86
81
|
return options === null || options === void 0 ? void 0 : options.body;
|
|
87
82
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Returns the parameters to pass the PageVisitEventHTTP constructor. Specific to the fetch wrapper.
|
|
90
|
-
*/
|
|
83
|
+
/** Returns the parameters to pass the HttpEventManager constructor. Specific to the fetch wrapper. */
|
|
91
84
|
static getHttpDataFromFetch(request, response, method, url, options, isError, requestText, responseText) {
|
|
92
85
|
return __awaiter(this, void 0, void 0, function* () {
|
|
93
86
|
if (!HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
|
|
@@ -103,17 +96,15 @@ class RequestMonitor extends Singleton {
|
|
|
103
96
|
}
|
|
104
97
|
return ogResponse; // body consumed already, no http response body for us
|
|
105
98
|
}
|
|
106
|
-
/**
|
|
107
|
-
* Handles fetch response safely. Reports PageVisitEventHTTP and error to Pagevisit if needed.
|
|
108
|
-
*/
|
|
99
|
+
/** Handles fetch response safely. Reports HttpEventManager and error to Pagevisit if needed. */
|
|
109
100
|
static safeHandleFetchResponse(startTime, url, method, options, request) {
|
|
110
101
|
return (ogResponse) => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
-
var _a
|
|
102
|
+
var _a;
|
|
112
103
|
try {
|
|
113
104
|
if (!ogResponse) {
|
|
114
105
|
// no idea how, but this happens sometimes, esp if other libs override fetch
|
|
115
106
|
// logging to track the issue if it becomes widespread
|
|
116
|
-
return ClientConfig.getInstance().
|
|
107
|
+
return ClientConfig.getInstance().postInternalError({ msg: 'No response object in fetch callback', url, method, options, request }, false, Severity.ERROR);
|
|
117
108
|
}
|
|
118
109
|
const clonedResponse = RequestMonitor.cloneResponse(ogResponse); // have to do it as early as possible
|
|
119
110
|
const graphqlResponse = RequestMonitor.cloneResponse(clonedResponse); // and two times more for each consumption
|
|
@@ -129,15 +120,17 @@ class RequestMonitor extends Singleton {
|
|
|
129
120
|
]);
|
|
130
121
|
const httpEvent = RequestMonitor.getPvEventHttp(status, headers, method, url, respTime);
|
|
131
122
|
const httpData = yield RequestMonitor.getHttpDataFromFetch(request, httpEventDataResponse, method, url, options, isHttpError || !!gqlError, maybeRequestText, responseText);
|
|
132
|
-
const
|
|
133
|
-
pageVisitEventHTTP.saveHTTPEvent();
|
|
134
|
-
const seq = (_b = pageVisitEventHTTP.httpData) === null || _b === void 0 ? void 0 : _b[PV_SEQ_ATT_NAME];
|
|
123
|
+
const seq = saveHTTPEvent(httpEvent, httpData, !!gqlError);
|
|
135
124
|
if (isHttpError) {
|
|
136
125
|
// this does not consume response body so no need to clone it
|
|
137
|
-
saveErrorToPagevisit(
|
|
126
|
+
saveErrorToPagevisit(Object.assign(Object.assign({}, clonedResponse), { type: PageVisitErrorSource.Response }), seq);
|
|
138
127
|
}
|
|
139
128
|
if (gqlError) {
|
|
140
|
-
gqlError.forEach(error => saveErrorToPagevisit(
|
|
129
|
+
gqlError.forEach(error => saveErrorToPagevisit({
|
|
130
|
+
url: ClientConfig.getInstance().globalUrl,
|
|
131
|
+
gql_err: error,
|
|
132
|
+
type: PageVisitErrorSource.Response,
|
|
133
|
+
}, seq));
|
|
141
134
|
}
|
|
142
135
|
}
|
|
143
136
|
catch (e) {
|
|
@@ -146,13 +139,11 @@ class RequestMonitor extends Singleton {
|
|
|
146
139
|
return;
|
|
147
140
|
}
|
|
148
141
|
const stack = tryGetStackTrace(e);
|
|
149
|
-
ClientConfig.getInstance().
|
|
142
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error in custom fetch() callback`, error: e, stack }, false, Severity.ERROR);
|
|
150
143
|
}
|
|
151
144
|
});
|
|
152
145
|
}
|
|
153
|
-
/**
|
|
154
|
-
* Safe function to get method and url from fetch args
|
|
155
|
-
*/
|
|
146
|
+
/** Safe function to get method and url from fetch args */
|
|
156
147
|
static getMethodUrlFromFetchArgs(resource, options) {
|
|
157
148
|
const defaultResource = { method: 'GET', url: '' };
|
|
158
149
|
try {
|
|
@@ -170,7 +161,7 @@ class RequestMonitor extends Singleton {
|
|
|
170
161
|
};
|
|
171
162
|
}
|
|
172
163
|
catch (e) {
|
|
173
|
-
ClientConfig.getInstance().
|
|
164
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error in fetch() wrapper`, error: e }, false, Severity.ERROR);
|
|
174
165
|
}
|
|
175
166
|
return defaultResource;
|
|
176
167
|
}
|
|
@@ -206,9 +197,7 @@ class RequestMonitor extends Singleton {
|
|
|
206
197
|
};
|
|
207
198
|
});
|
|
208
199
|
}
|
|
209
|
-
/**
|
|
210
|
-
* Does a check if data collection is enabled and combines it into HttpDataBundle
|
|
211
|
-
*/
|
|
200
|
+
/** Does a check if data collection is enabled and combines it into HttpDataBundle */
|
|
212
201
|
static getHttpDataFromXhr(xhrObj_1, method_1, url_1, isError_1) {
|
|
213
202
|
return __awaiter(this, arguments, void 0, function* (xhrObj, method, url, isError, requestPayload = null, responseText) {
|
|
214
203
|
if (!HTTPDataBundler.getInstance().shouldContinueForURL(url)) {
|
|
@@ -224,28 +213,27 @@ class RequestMonitor extends Singleton {
|
|
|
224
213
|
*/
|
|
225
214
|
static loadendHandler(xhr, startTime, url, method, requestPayload) {
|
|
226
215
|
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
-
var _a;
|
|
228
216
|
const respTime = Date.now() - startTime;
|
|
229
217
|
const gqlError = yield GqlErrorValidator.fromXhr(url, xhr);
|
|
230
218
|
const httpError = isHttpCodeFailure(xhr.status);
|
|
231
219
|
const responseText = yield HTTPDataBundler.getResponseStringFromXHR(xhr);
|
|
232
220
|
const httpEvent = RequestMonitor.getPvEventHttp(xhr.status, HTTPDataBundler.headersMapFromString(xhr.getAllResponseHeaders()), method, url, respTime);
|
|
233
221
|
const httpData = yield RequestMonitor.getHttpDataFromXhr(xhr, method, url, httpError || !!gqlError, requestPayload, responseText);
|
|
234
|
-
const pageVisitEventHTTP = new PageVisitEventHTTP(httpEvent, httpData, !!gqlError);
|
|
235
222
|
// Save HTTP Info
|
|
236
|
-
|
|
237
|
-
const seq = (_a = pageVisitEventHTTP.httpData) === null || _a === void 0 ? void 0 : _a[PV_SEQ_ATT_NAME];
|
|
223
|
+
const seq = saveHTTPEvent(httpEvent, httpData, !!gqlError);
|
|
238
224
|
if (httpError) {
|
|
239
|
-
saveErrorToPagevisit(
|
|
225
|
+
saveErrorToPagevisit({ url: xhr.responseURL, status: xhr.status, type: PageVisitErrorSource.XMLHttpRequest }, seq);
|
|
240
226
|
}
|
|
241
227
|
if (gqlError) {
|
|
242
|
-
gqlError.forEach(error => saveErrorToPagevisit(
|
|
228
|
+
gqlError.forEach(error => saveErrorToPagevisit({
|
|
229
|
+
url: ClientConfig.getInstance().globalUrl,
|
|
230
|
+
gql_err: error,
|
|
231
|
+
type: PageVisitErrorSource.Response,
|
|
232
|
+
}, seq));
|
|
243
233
|
}
|
|
244
234
|
});
|
|
245
235
|
}
|
|
246
|
-
/**
|
|
247
|
-
* Handles fetch failure
|
|
248
|
-
*/
|
|
236
|
+
/** Handles fetch failure */
|
|
249
237
|
static handleFetchFailure(maybeErr, url) {
|
|
250
238
|
if (!maybeErr || typeof maybeErr !== 'object') {
|
|
251
239
|
return;
|
|
@@ -263,8 +251,9 @@ class RequestMonitor extends Singleton {
|
|
|
263
251
|
errorFromFetch.message = `${err.message}${urlMessage}`;
|
|
264
252
|
const errorPayload = {
|
|
265
253
|
error: errorFromFetch,
|
|
254
|
+
type: PageVisitErrorSource.FetchException,
|
|
266
255
|
};
|
|
267
|
-
saveErrorToPagevisit(
|
|
256
|
+
saveErrorToPagevisit(errorPayload);
|
|
268
257
|
}
|
|
269
258
|
/** gets method from xhr */
|
|
270
259
|
static getMethodFromXHR(xhr, payload) {
|
|
@@ -292,7 +281,7 @@ class RequestMonitor extends Singleton {
|
|
|
292
281
|
}
|
|
293
282
|
catch (e) {
|
|
294
283
|
const stack = tryGetStackTrace(e);
|
|
295
|
-
ClientConfig.getInstance().
|
|
284
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error in XHR.send() wrapper`, error: e, stack }, false, Severity.ERROR);
|
|
296
285
|
}
|
|
297
286
|
return originalFunction.call(this, payload);
|
|
298
287
|
};
|
|
@@ -310,14 +299,14 @@ class RequestMonitor extends Singleton {
|
|
|
310
299
|
try {
|
|
311
300
|
/**
|
|
312
301
|
* We wrap assignment of the .noibu[...] variables in a try/catch, as we're assigning
|
|
313
|
-
* properties to a built-in object
|
|
302
|
+
* properties to a built-in object source, and have no guarantee of success.
|
|
314
303
|
*/
|
|
315
304
|
try {
|
|
316
305
|
this.noibuHttpMethod = method;
|
|
317
306
|
this.noibuHttpUrl = url;
|
|
318
307
|
}
|
|
319
308
|
catch (error) {
|
|
320
|
-
ClientConfig.getInstance().
|
|
309
|
+
ClientConfig.getInstance().postInternalError({ msg: `Unable to set custom properties on XHR object`, error }, false, Severity.WARN);
|
|
321
310
|
}
|
|
322
311
|
if (shouldHandleLoadend) {
|
|
323
312
|
const startTime = Date.now();
|
|
@@ -326,7 +315,7 @@ class RequestMonitor extends Singleton {
|
|
|
326
315
|
}
|
|
327
316
|
catch (e) {
|
|
328
317
|
const stack = tryGetStackTrace(e);
|
|
329
|
-
ClientConfig.getInstance().
|
|
318
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error in XHR.open() wrapper`, error: e, stack }, false, Severity.ERROR);
|
|
330
319
|
}
|
|
331
320
|
return originalFunction.call(this, method, url, async, user, password);
|
|
332
321
|
};
|
|
@@ -353,7 +342,7 @@ class RequestMonitor extends Singleton {
|
|
|
353
342
|
}
|
|
354
343
|
}
|
|
355
344
|
catch (error) {
|
|
356
|
-
ClientConfig.getInstance().
|
|
345
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error in XHR.setRequestHeader() wrapper`, error }, false, Severity.ERROR);
|
|
357
346
|
}
|
|
358
347
|
return originalFunction.call(this, header, value);
|
|
359
348
|
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GQLError } from '@noibu/metroplex-ts-bindings';
|
|
2
|
+
/** Try detecting GraphQL errors from http response */
|
|
3
|
+
export default class GqlErrorValidator {
|
|
4
|
+
/** Retrieves GQL error object based on fetch request/response */
|
|
5
|
+
static fromFetch(url: string, options: RequestInit | undefined, request: Request | undefined, response: Response): Promise<GQLError[] | null>;
|
|
6
|
+
/** Retrieves GQL error object based on XHR object */
|
|
7
|
+
static fromXhr(url: string, xhr: unknown): Promise<GQLError[] | null>;
|
|
8
|
+
/** Try safely parse a string and return null if fails */
|
|
9
|
+
static _parseJsonSafely(content: string): any;
|
|
10
|
+
/** Try to get content type for fetch arguments */
|
|
11
|
+
static _getContentTypeFromFetchArguments(options?: RequestInit, request?: Request): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Checks if request is aborted
|
|
14
|
+
* If it has been aborted we are not able to consume the response
|
|
15
|
+
*/
|
|
16
|
+
static _isRequestAborted(options?: RequestInit, request?: RequestInit): boolean | null | undefined;
|
|
17
|
+
/** Determines if request should be processed */
|
|
18
|
+
static _shouldHandleRequest(url: string, contentType?: string | null): boolean;
|
|
19
|
+
/** Sanitizes payload object */
|
|
20
|
+
static _validate(data: unknown, validationIssues: string[]): GQLError[] | null;
|
|
21
|
+
/** Sanitizes message object */
|
|
22
|
+
static _validateMessage(error: GQLError): void;
|
|
23
|
+
/**
|
|
24
|
+
* Sanitizes extensions object
|
|
25
|
+
*/
|
|
26
|
+
static _validateExtensions(error: GQLError): void;
|
|
27
|
+
/** Sanitizes locations object */
|
|
28
|
+
static _validateLocations(error: GQLError, validationIssues: string[]): void;
|
|
29
|
+
/** Sanitizes path object */
|
|
30
|
+
static _validatePath(error: object, validationIssues: string[]): void;
|
|
31
|
+
/** Posts error */
|
|
32
|
+
static _postError(message: unknown): void;
|
|
33
|
+
/** Posts issue found during object sanitization */
|
|
34
|
+
static _postValidationIssues(validationIssues: string[]): void;
|
|
35
|
+
}
|