noibu-react-native 0.2.6 → 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.
- package/README.md +15 -15
- package/dist/api/{clientConfig.js → ClientConfig.js} +69 -52
- package/dist/api/{helpCode.js → HelpCode.js} +6 -13
- package/dist/api/InputManager.js +156 -0
- package/dist/api/{metroplexSocket.js → MetroplexSocket.js} +189 -178
- package/dist/api/StoredMetrics.js +158 -0
- package/dist/api/{storedPageVisit.js → StoredPageVisit.js} +61 -48
- package/dist/const_matchers.js +1 -5
- package/dist/constants.js +15 -390
- package/dist/entry/index.js +3 -4
- package/dist/entry/init.js +33 -19
- package/dist/monitors/AppNavigationMonitor.js +19 -19
- package/dist/monitors/BaseMonitor.js +9 -4
- package/dist/monitors/ClickMonitor.js +72 -76
- package/dist/monitors/ErrorMonitor.js +45 -55
- package/dist/monitors/KeyboardInputMonitor.js +13 -11
- package/dist/monitors/PageMonitor.js +25 -2
- package/dist/monitors/RequestMonitor.js +46 -57
- package/dist/monitors/http-tools/GqlErrorValidator.js +39 -69
- package/dist/monitors/http-tools/HTTPDataBundler.js +71 -66
- package/dist/monitors/integrations/{react-native-navigation-integration.js → ReactNativeNavigationIntegration.js} +15 -12
- package/dist/pageVisit/EventDebouncer.js +43 -74
- package/dist/pageVisit/HttpEventManager.js +88 -0
- package/dist/pageVisit/PageVisitManager.js +99 -0
- package/dist/pageVisit/pageVisitEventError.js +170 -280
- package/dist/react/ErrorBoundary.js +3 -6
- package/dist/sessionRecorder/{sessionRecorder.js → SessionRecorder.js} +58 -70
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -5
- package/dist/storage/{rnStorageProvider.js → RNStorageProvider.js} +3 -7
- package/dist/storage/{storage.js → Storage.js} +17 -30
- package/dist/storage/{storageProvider.js → StorageProvider.js} +7 -8
- package/dist/utils/date.js +39 -50
- package/dist/utils/eventlistener.js +5 -12
- package/dist/utils/function.js +42 -113
- package/dist/utils/log.js +5 -5
- package/dist/utils/object.js +12 -12
- package/dist/utils/piiRedactor.js +31 -3
- package/dist/utils/stacktrace-parser.js +29 -21
- 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/clientConfig.d.ts +0 -100
- package/dist/src/api/clientConfig.test.d.ts +0 -1
- package/dist/src/api/helpCode.d.ts +0 -23
- package/dist/src/api/inputManager.d.ts +0 -87
- package/dist/src/api/metroplexSocket.d.ts +0 -137
- package/dist/src/api/storedMetrics.d.ts +0 -73
- package/dist/src/api/storedPageVisit.d.ts +0 -40
- package/dist/src/const_matchers.d.ts +0 -1
- package/dist/src/constants.d.ts +0 -290
- package/dist/src/entry/index.d.ts +0 -14
- package/dist/src/entry/init.d.ts +0 -5
- package/dist/src/monitors/AppNavigationMonitor.d.ts +0 -18
- package/dist/src/monitors/BaseMonitor.d.ts +0 -13
- package/dist/src/monitors/BaseMonitor.test.d.ts +0 -1
- package/dist/src/monitors/ClickMonitor.d.ts +0 -31
- package/dist/src/monitors/ErrorMonitor.d.ts +0 -63
- package/dist/src/monitors/KeyboardInputMonitor.d.ts +0 -20
- package/dist/src/monitors/PageMonitor.d.ts +0 -20
- package/dist/src/monitors/RequestMonitor.d.ts +0 -94
- package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +0 -59
- package/dist/src/monitors/http-tools/HTTPDataBundler.d.ts +0 -112
- package/dist/src/monitors/integrations/react-native-navigation-integration.d.ts +0 -20
- package/dist/src/pageVisit/EventDebouncer.d.ts +0 -24
- 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/react/ErrorBoundary.d.ts +0 -72
- package/dist/src/sessionRecorder/nativeSessionRecorderSubscription.d.ts +0 -79
- package/dist/src/sessionRecorder/sessionRecorder.d.ts +0 -60
- package/dist/src/sessionRecorder/types.d.ts +0 -91
- package/dist/src/storage/rnStorageProvider.d.ts +0 -23
- package/dist/src/storage/storage.d.ts +0 -39
- package/dist/src/storage/storageProvider.d.ts +0 -26
- package/dist/src/utils/date.d.ts +0 -6
- package/dist/src/utils/eventlistener.d.ts +0 -8
- package/dist/src/utils/function.d.ts +0 -102
- package/dist/src/utils/log.d.ts +0 -4
- package/dist/src/utils/object.d.ts +0 -44
- package/dist/src/utils/performance.d.ts +0 -6
- package/dist/src/utils/piiRedactor.d.ts +0 -11
- package/dist/src/utils/polyfills.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/NavigationIntegration.d.ts +0 -6
- 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
|
@@ -1,10 +1,9 @@
|
|
|
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/
|
|
5
|
+
import { SEVERITY } from '../constants.js';
|
|
6
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
8
7
|
import { noibuLog } from '../utils/log.js';
|
|
9
8
|
import { tryGetStackTrace, safeTrim } from '../utils/function.js';
|
|
10
9
|
import { promiseAll } from '../utils/polyfills.js';
|
|
@@ -12,10 +11,12 @@ import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
|
12
11
|
import { HTTPDataBundler } from './http-tools/HTTPDataBundler.js';
|
|
13
12
|
import GqlErrorValidator from './http-tools/GqlErrorValidator.js';
|
|
14
13
|
import { Singleton } from './BaseMonitor.js';
|
|
14
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.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
|
};
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import { isInstanceOf, getMaxSubstringAllowed } from '../../utils/function.js';
|
|
3
3
|
import { CONTENT_TYPE, SEVERITY } from '../../constants.js';
|
|
4
|
-
import ClientConfig from '../../api/
|
|
4
|
+
import ClientConfig from '../../api/ClientConfig.js';
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
6
|
+
const GQL_EXTENSIONS_ATT_NAME = 'extensions';
|
|
7
|
+
const GQL_LOCATIONS_ATT_NAME = 'locations';
|
|
8
|
+
const GQL_PATH_ATT_NAME = 'path';
|
|
9
|
+
const GQL_LINE_ATT_NAME = 'line';
|
|
10
|
+
const GQL_COLUMN_ATT_NAME = 'column';
|
|
11
|
+
const GQL_MESSAGE_ATT_NAME = 'message';
|
|
12
12
|
const MESSAGE_MAX_LENGTH = 1000;
|
|
13
13
|
/* eslint-disable no-restricted-syntax */
|
|
14
14
|
/* eslint-disable no-param-reassign */
|
|
15
|
-
/**
|
|
16
|
-
* Try detecting GraphQL errors from http response
|
|
17
|
-
*/
|
|
15
|
+
/** Try detecting GraphQL errors from http response */
|
|
18
16
|
class GqlErrorValidator {
|
|
19
|
-
/**
|
|
20
|
-
* Retrieves GQL error object based on fetch request/response
|
|
21
|
-
*/
|
|
17
|
+
/** Retrieves GQL error object based on fetch request/response */
|
|
22
18
|
static fromFetch(url, options, request, response) {
|
|
23
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
24
20
|
try {
|
|
@@ -42,15 +38,11 @@ class GqlErrorValidator {
|
|
|
42
38
|
return null;
|
|
43
39
|
});
|
|
44
40
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Retrieves GQL error object based on XHR object
|
|
47
|
-
*/
|
|
41
|
+
/** Retrieves GQL error object based on XHR object */
|
|
48
42
|
static fromXhr(url, xhr) {
|
|
49
43
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
44
|
try {
|
|
51
|
-
const isResponseValid = isInstanceOf(xhr, XMLHttpRequest) &&
|
|
52
|
-
xhr.status >= 200 &&
|
|
53
|
-
xhr.status <= 299;
|
|
45
|
+
const isResponseValid = isInstanceOf(xhr, XMLHttpRequest) && xhr.status >= 200 && xhr.status <= 299;
|
|
54
46
|
if (!isResponseValid) {
|
|
55
47
|
return null;
|
|
56
48
|
}
|
|
@@ -84,9 +76,7 @@ class GqlErrorValidator {
|
|
|
84
76
|
return null;
|
|
85
77
|
});
|
|
86
78
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Try safely parse a string and return null if fails
|
|
89
|
-
*/
|
|
79
|
+
/** Try safely parse a string and return null if fails */
|
|
90
80
|
static _parseJsonSafely(content) {
|
|
91
81
|
try {
|
|
92
82
|
return JSON.parse(content);
|
|
@@ -95,9 +85,7 @@ class GqlErrorValidator {
|
|
|
95
85
|
return null;
|
|
96
86
|
}
|
|
97
87
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Try to get content type for fetch arguments
|
|
100
|
-
*/
|
|
88
|
+
/** Try to get content type for fetch arguments */
|
|
101
89
|
static _getContentTypeFromFetchArguments(options, request) {
|
|
102
90
|
let headers = null;
|
|
103
91
|
if (isInstanceOf(request, Request)) {
|
|
@@ -125,9 +113,7 @@ class GqlErrorValidator {
|
|
|
125
113
|
}
|
|
126
114
|
return false;
|
|
127
115
|
}
|
|
128
|
-
/**
|
|
129
|
-
* Determines if request should be processed
|
|
130
|
-
*/
|
|
116
|
+
/** Determines if request should be processed */
|
|
131
117
|
static _shouldHandleRequest(url, contentType) {
|
|
132
118
|
if (contentType) {
|
|
133
119
|
contentType = contentType.toLowerCase();
|
|
@@ -139,36 +125,31 @@ class GqlErrorValidator {
|
|
|
139
125
|
}
|
|
140
126
|
isGqlUrl = url.toLowerCase().includes('graphql');
|
|
141
127
|
}
|
|
142
|
-
return (
|
|
143
|
-
contentType === 'application/graphql');
|
|
128
|
+
return (contentType === 'application/json' && isGqlUrl) || contentType === 'application/graphql';
|
|
144
129
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Sanitizes payload object
|
|
147
|
-
*/
|
|
130
|
+
/** Sanitizes payload object */
|
|
148
131
|
static _validate(data, validationIssues) {
|
|
149
|
-
if (!(typeof data === 'object' &&
|
|
150
|
-
data &&
|
|
151
|
-
Array.isArray(data.errors))) {
|
|
132
|
+
if (!(typeof data === 'object' && data && Array.isArray(data.errors))) {
|
|
152
133
|
return null;
|
|
153
134
|
}
|
|
154
135
|
const errors = data.errors;
|
|
155
|
-
errors.forEach(error => {
|
|
136
|
+
errors.forEach((error) => {
|
|
156
137
|
if (typeof error !== 'object' || !error) {
|
|
157
138
|
return;
|
|
158
139
|
}
|
|
159
140
|
const properties = Object.keys(error);
|
|
160
141
|
for (const property of properties) {
|
|
161
142
|
switch (property) {
|
|
162
|
-
case
|
|
143
|
+
case GQL_MESSAGE_ATT_NAME:
|
|
163
144
|
this._validateMessage(error);
|
|
164
145
|
break;
|
|
165
|
-
case
|
|
146
|
+
case GQL_LOCATIONS_ATT_NAME:
|
|
166
147
|
this._validateLocations(error, validationIssues);
|
|
167
148
|
break;
|
|
168
|
-
case
|
|
149
|
+
case GQL_PATH_ATT_NAME:
|
|
169
150
|
this._validatePath(error, validationIssues);
|
|
170
151
|
break;
|
|
171
|
-
case
|
|
152
|
+
case GQL_EXTENSIONS_ATT_NAME:
|
|
172
153
|
this._validateExtensions(error);
|
|
173
154
|
break;
|
|
174
155
|
default:
|
|
@@ -183,32 +164,27 @@ class GqlErrorValidator {
|
|
|
183
164
|
}
|
|
184
165
|
return errors;
|
|
185
166
|
}
|
|
186
|
-
/**
|
|
187
|
-
* Sanitizes message object
|
|
188
|
-
*/
|
|
167
|
+
/** Sanitizes message object */
|
|
189
168
|
static _validateMessage(error) {
|
|
190
|
-
error[
|
|
169
|
+
error[GQL_MESSAGE_ATT_NAME] = getMaxSubstringAllowed(error[GQL_MESSAGE_ATT_NAME], MESSAGE_MAX_LENGTH);
|
|
191
170
|
}
|
|
192
171
|
/**
|
|
193
172
|
* Sanitizes extensions object
|
|
194
|
-
* @param {any} error
|
|
195
173
|
*/
|
|
196
174
|
static _validateExtensions(error) {
|
|
197
|
-
const json = JSON.stringify(error[
|
|
198
|
-
error[
|
|
175
|
+
const json = JSON.stringify(error[GQL_EXTENSIONS_ATT_NAME]);
|
|
176
|
+
error[GQL_EXTENSIONS_ATT_NAME] = getMaxSubstringAllowed(json, MESSAGE_MAX_LENGTH);
|
|
199
177
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Sanitizes locations object
|
|
202
|
-
*/
|
|
178
|
+
/** Sanitizes locations object */
|
|
203
179
|
static _validateLocations(error, validationIssues) {
|
|
204
|
-
const locations = error[
|
|
180
|
+
const locations = error[GQL_LOCATIONS_ATT_NAME];
|
|
205
181
|
if (Array.isArray(locations)) {
|
|
206
182
|
for (const location of locations) {
|
|
207
183
|
const properties = Object.keys(location);
|
|
208
184
|
for (const property of properties) {
|
|
209
185
|
switch (property) {
|
|
210
|
-
case
|
|
211
|
-
case
|
|
186
|
+
case GQL_LINE_ATT_NAME:
|
|
187
|
+
case GQL_COLUMN_ATT_NAME:
|
|
212
188
|
if (!Number.isSafeInteger(location[property])) {
|
|
213
189
|
const value = location[property];
|
|
214
190
|
location[property] = 0;
|
|
@@ -224,35 +200,29 @@ class GqlErrorValidator {
|
|
|
224
200
|
}
|
|
225
201
|
}
|
|
226
202
|
else {
|
|
227
|
-
delete error[
|
|
203
|
+
delete error[GQL_LOCATIONS_ATT_NAME];
|
|
228
204
|
validationIssues.push(`unexpected error.locations`);
|
|
229
205
|
}
|
|
230
206
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Sanitizes path object
|
|
233
|
-
*/
|
|
207
|
+
/** Sanitizes path object */
|
|
234
208
|
static _validatePath(error, validationIssues) {
|
|
235
|
-
const path = error[
|
|
209
|
+
const path = error[GQL_PATH_ATT_NAME];
|
|
236
210
|
if (Array.isArray(path)) {
|
|
237
|
-
error[
|
|
211
|
+
error[GQL_PATH_ATT_NAME] = error[GQL_PATH_ATT_NAME].map(x => x.toString());
|
|
238
212
|
}
|
|
239
213
|
else {
|
|
240
|
-
delete error[
|
|
214
|
+
delete error[GQL_PATH_ATT_NAME];
|
|
241
215
|
validationIssues.push(`unexpected error.path`);
|
|
242
216
|
}
|
|
243
217
|
}
|
|
244
|
-
/**
|
|
245
|
-
* Posts error
|
|
246
|
-
*/
|
|
218
|
+
/** Posts error */
|
|
247
219
|
static _postError(message) {
|
|
248
|
-
ClientConfig.getInstance().
|
|
220
|
+
ClientConfig.getInstance().postInternalError({ msg: `GQL parse error: ${message}` }, false, SEVERITY.error);
|
|
249
221
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Posts issue found during object sanitization
|
|
252
|
-
*/
|
|
222
|
+
/** Posts issue found during object sanitization */
|
|
253
223
|
static _postValidationIssues(validationIssues) {
|
|
254
224
|
const message = validationIssues.join(',');
|
|
255
|
-
ClientConfig.getInstance().
|
|
225
|
+
ClientConfig.getInstance().postInternalError({ msg: `GQL error validation warning: ${message}` }, false, SEVERITY.error);
|
|
256
226
|
}
|
|
257
227
|
}
|
|
258
228
|
|