noibu-react-native 0.2.34-rc.1 → 0.2.34-rc.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.
- package/dist/constants.js +1 -1
- package/dist/entry/init.js +12 -6
- package/dist/monitors/ErrorMonitor.js +1 -1
- package/dist/monitors/RequestMonitor.d.ts +7 -11
- package/dist/monitors/RequestMonitor.js +126 -42
- package/dist/monitors/http-tools/GqlErrorValidator.d.ts +4 -0
- package/dist/monitors/http-tools/GqlErrorValidator.js +33 -1
- package/dist/sessionRecorder/SessionRecorder.js +3 -14
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +0 -1
- package/package.json +1 -1
- package/dist/utils/polyfills.js +0 -24
package/dist/constants.js
CHANGED
|
@@ -24,7 +24,7 @@ const CONTENT_TYPE = 'content-type';
|
|
|
24
24
|
* Gets the script id from the cookie object, returns default if cannot be found
|
|
25
25
|
*/
|
|
26
26
|
function GET_SCRIPT_ID() {
|
|
27
|
-
return "1.0.104-rn-sdk-0.2.34-rc.
|
|
27
|
+
return "1.0.104-rn-sdk-0.2.34-rc.3" ;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Gets the max metro recon number
|
package/dist/entry/init.js
CHANGED
|
@@ -76,17 +76,23 @@ function globalInit(customerConfig) {
|
|
|
76
76
|
const clickMonitor = ClickMonitor.getInstance();
|
|
77
77
|
const pageMonitor = PageMonitor.getInstance();
|
|
78
78
|
AppNavigationMonitor.getInstance().monitor();
|
|
79
|
-
//
|
|
80
|
-
if (ClientConfig.getInstance().enableHttpDataCollection) {
|
|
81
|
-
HTTPDataBundler.getInstance();
|
|
82
|
-
RequestMonitor.getInstance().monitor();
|
|
83
|
-
}
|
|
84
|
-
// monitoring calls
|
|
79
|
+
// monitoring calls - each wrapped independently so one failure doesn't affect others
|
|
85
80
|
ErrorMonitor.getInstance().monitor();
|
|
86
81
|
clickMonitor.monitor();
|
|
87
82
|
keyboardInputMonitor.monitor();
|
|
88
83
|
pageMonitor.monitor();
|
|
89
84
|
SessionRecorder.getInstance().recordUserSession();
|
|
85
|
+
// Initialize HTTP data collection and request monitoring if enabled
|
|
86
|
+
// This is done after other monitors so failures here don't affect session recording
|
|
87
|
+
if (ClientConfig.getInstance().enableHttpDataCollection) {
|
|
88
|
+
try {
|
|
89
|
+
HTTPDataBundler.getInstance();
|
|
90
|
+
RequestMonitor.getInstance().monitor();
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error initializing HTTP data collection`, error }, false, Severity.ERROR);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
90
96
|
if (metroplexSocket.connectionPromise) {
|
|
91
97
|
metroplexSocket.connectionPromise.catch((error) => ClientConfig.getInstance().postInternalError({ msg: `Error during metroplexSocket initial connection`, error }, false, Severity.ERROR));
|
|
92
98
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isStackTrace, asString } from '../utils/function.js';
|
|
2
2
|
import { saveErrorToPagevisit } from '../pageVisit/pageVisitEventError.js';
|
|
3
3
|
import { replace } from '../utils/object.js';
|
|
4
4
|
import { Singleton } from './BaseMonitor.js';
|
|
@@ -3,14 +3,12 @@ import { Monitor, Singleton } from './BaseMonitor';
|
|
|
3
3
|
export default class RequestMonitor extends Singleton implements Monitor {
|
|
4
4
|
/** main method */
|
|
5
5
|
monitor(): void;
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*/
|
|
13
|
-
private static consumeResponseAndGetBodyText;
|
|
6
|
+
/** Decodes an ArrayBuffer into UTF-8 text. */
|
|
7
|
+
private static decodeArrayBufferToText;
|
|
8
|
+
/** Reads the response body once and returns both raw body and decoded text. */
|
|
9
|
+
private static readResponseBody;
|
|
10
|
+
/** Creates a fresh Response for the customer, preserving metadata. */
|
|
11
|
+
private static buildCustomerResponse;
|
|
14
12
|
/** Generates new PVEventHTTP */
|
|
15
13
|
private static getPvEventHttp;
|
|
16
14
|
/** Gets headers from request or request options. Handles different scenarios where simple conversion is not possible */
|
|
@@ -24,10 +22,8 @@ export default class RequestMonitor extends Singleton implements Monitor {
|
|
|
24
22
|
private static getRequestBody;
|
|
25
23
|
/** Returns the parameters to pass the HttpEventManager constructor. Specific to the fetch wrapper. */
|
|
26
24
|
private static getHttpDataFromFetch;
|
|
27
|
-
/** Clones Response / Request or returns original object if cloning is not possible */
|
|
28
|
-
private static cloneResponse;
|
|
29
25
|
/** Handles fetch response safely. Reports HttpEventManager and error to Pagevisit if needed. */
|
|
30
|
-
private static
|
|
26
|
+
private static handleFetchResponse;
|
|
31
27
|
/** Safe function to get method and url from fetch args */
|
|
32
28
|
private static getMethodUrlFromFetchArgs;
|
|
33
29
|
/**
|
|
@@ -5,7 +5,6 @@ import { safeEntries, propWriteableOrMadeWriteable, replace } from '../utils/obj
|
|
|
5
5
|
import ClientConfig from '../api/ClientConfig.js';
|
|
6
6
|
import { noibuLog } from '../utils/log.js';
|
|
7
7
|
import { tryGetStackTrace, safeTrim } from '../utils/function.js';
|
|
8
|
-
import { promiseAll } from '../utils/polyfills.js';
|
|
9
8
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
10
9
|
import { HTTPDataBundler } from './http-tools/HTTPDataBundler.js';
|
|
11
10
|
import GqlErrorValidator from './http-tools/GqlErrorValidator.js';
|
|
@@ -23,24 +22,100 @@ class RequestMonitor extends Singleton {
|
|
|
23
22
|
RequestMonitor.setupGlobalXMLHttpWrapper();
|
|
24
23
|
noibuLog('monitorRequests ended');
|
|
25
24
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
/** Decodes an ArrayBuffer into UTF-8 text. */
|
|
26
|
+
static decodeArrayBufferToText(buffer) {
|
|
27
|
+
try {
|
|
28
|
+
if (typeof TextDecoder !== 'undefined') {
|
|
29
|
+
return new TextDecoder('utf-8').decode(buffer);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (_a) {
|
|
33
|
+
// ignore and fall back to manual decode
|
|
34
|
+
}
|
|
35
|
+
const bytes = new Uint8Array(buffer);
|
|
36
|
+
const chunkSize = 0x8000;
|
|
37
|
+
let result = '';
|
|
38
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
39
|
+
const chunk = bytes.subarray(i, i + chunkSize);
|
|
40
|
+
result += String.fromCharCode.apply(null, Array.from(chunk));
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
/** Reads the response body once and returns both raw body and decoded text. */
|
|
45
|
+
static readResponseBody(response) {
|
|
34
46
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
47
|
if (!(response instanceof Response)) {
|
|
36
|
-
return
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const tryRead = (target) => __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
try {
|
|
52
|
+
const buffer = yield target.arrayBuffer();
|
|
53
|
+
return { body: buffer, text: RequestMonitor.decodeArrayBufferToText(buffer) };
|
|
54
|
+
}
|
|
55
|
+
catch (_a) {
|
|
56
|
+
// Fall back to text() if arrayBuffer() is unsupported or fails
|
|
57
|
+
try {
|
|
58
|
+
const text = yield target.text();
|
|
59
|
+
return { body: text, text };
|
|
60
|
+
}
|
|
61
|
+
catch (_b) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// Prefer reading from a clone to avoid mutating the original Response.
|
|
67
|
+
try {
|
|
68
|
+
if (!response.bodyUsed && typeof response.clone === 'function') {
|
|
69
|
+
const clone = response.clone();
|
|
70
|
+
const clonedResult = yield tryRead(clone);
|
|
71
|
+
if (clonedResult) {
|
|
72
|
+
return clonedResult;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (_a) {
|
|
77
|
+
// ignore and fall back to reading the original response
|
|
37
78
|
}
|
|
38
79
|
if (response.bodyUsed) {
|
|
39
|
-
return
|
|
80
|
+
return null;
|
|
40
81
|
}
|
|
41
|
-
return response
|
|
82
|
+
return tryRead(response);
|
|
42
83
|
});
|
|
43
84
|
}
|
|
85
|
+
/** Creates a fresh Response for the customer, preserving metadata. */
|
|
86
|
+
static buildCustomerResponse(ogResponse, body) {
|
|
87
|
+
try {
|
|
88
|
+
const headers = new Headers(ogResponse.headers);
|
|
89
|
+
const customerResponse = new Response(body, {
|
|
90
|
+
status: ogResponse.status,
|
|
91
|
+
statusText: ogResponse.statusText,
|
|
92
|
+
headers,
|
|
93
|
+
});
|
|
94
|
+
// Best-effort copy of read-only metadata (works in some polyfills).
|
|
95
|
+
try {
|
|
96
|
+
Object.defineProperty(customerResponse, 'url', { value: ogResponse.url, configurable: true });
|
|
97
|
+
}
|
|
98
|
+
catch (_a) {
|
|
99
|
+
// ignore
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
Object.defineProperty(customerResponse, 'redirected', { value: ogResponse.redirected, configurable: true });
|
|
103
|
+
}
|
|
104
|
+
catch (_b) {
|
|
105
|
+
// ignore
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
Object.defineProperty(customerResponse, 'type', { value: ogResponse.type, configurable: true });
|
|
109
|
+
}
|
|
110
|
+
catch (_c) {
|
|
111
|
+
// ignore
|
|
112
|
+
}
|
|
113
|
+
return customerResponse;
|
|
114
|
+
}
|
|
115
|
+
catch (_d) {
|
|
116
|
+
return ogResponse;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
44
119
|
/** Generates new PVEventHTTP */
|
|
45
120
|
static getPvEventHttp(status, responseHeaders, method, url, responseTime) {
|
|
46
121
|
const httpEvent = {
|
|
@@ -87,16 +162,9 @@ class RequestMonitor extends Singleton {
|
|
|
87
162
|
return HTTPDataBundler.getInstance().bundleHTTPData(url, RequestMonitor.getRequestHeaders(request, options), RequestMonitor.getRequestBody(requestText, options), RequestMonitor.getResponseHeaders(response), responseText, method, isError);
|
|
88
163
|
});
|
|
89
164
|
}
|
|
90
|
-
/** Clones Response / Request or returns original object if cloning is not possible */
|
|
91
|
-
static cloneResponse(ogResponse) {
|
|
92
|
-
if (!ogResponse.bodyUsed) {
|
|
93
|
-
return ogResponse.clone();
|
|
94
|
-
}
|
|
95
|
-
return ogResponse; // body consumed already, no http response body for us
|
|
96
|
-
}
|
|
97
165
|
/** Handles fetch response safely. Reports HttpEventManager and error to Pagevisit if needed. */
|
|
98
|
-
static
|
|
99
|
-
return
|
|
166
|
+
static handleFetchResponse(startTime, url, method, options, request, ogResponse, responseText, shouldCaptureBody, shouldCheckGql) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
100
168
|
var _a;
|
|
101
169
|
try {
|
|
102
170
|
if (!ogResponse) {
|
|
@@ -104,31 +172,26 @@ class RequestMonitor extends Singleton {
|
|
|
104
172
|
// logging to track the issue if it becomes widespread
|
|
105
173
|
return ClientConfig.getInstance().postInternalError({ msg: 'No response object in fetch callback', url, method, options, request }, false, Severity.ERROR);
|
|
106
174
|
}
|
|
107
|
-
|
|
108
|
-
const graphqlResponse = RequestMonitor.cloneResponse(clonedResponse); // and two times more for each consumption
|
|
109
|
-
const httpEventDataResponse = RequestMonitor.cloneResponse(clonedResponse);
|
|
175
|
+
// Read metadata directly from ogResponse (sync, does not consume body)
|
|
110
176
|
const respTime = Date.now() - startTime;
|
|
111
|
-
const status =
|
|
112
|
-
const headers =
|
|
113
|
-
const gqlError =
|
|
177
|
+
const status = ogResponse.status;
|
|
178
|
+
const headers = ogResponse.headers;
|
|
179
|
+
const gqlError = shouldCheckGql && responseText
|
|
180
|
+
? yield GqlErrorValidator.fromFetchResponseText(url, options, request, status, responseText)
|
|
181
|
+
: null;
|
|
114
182
|
const isHttpError = isHttpCodeFailure(status);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
? yield promiseAll([
|
|
120
|
-
Promise.resolve((_a = request === null || request === void 0 ? void 0 : request.text) === null || _a === void 0 ? void 0 : _a.call(request)),
|
|
121
|
-
RequestMonitor.consumeResponseAndGetBodyText(httpEventDataResponse),
|
|
122
|
-
])
|
|
123
|
-
: [undefined, undefined];
|
|
183
|
+
const maybeRequestText = shouldCaptureBody ? yield Promise.resolve((_a = request === null || request === void 0 ? void 0 : request.text) === null || _a === void 0 ? void 0 : _a.call(request)) : undefined;
|
|
184
|
+
const responseTextForHttp = shouldCaptureBody
|
|
185
|
+
? responseText !== null && responseText !== void 0 ? responseText : BODY_USED_ERROR
|
|
186
|
+
: undefined;
|
|
124
187
|
const httpEvent = RequestMonitor.getPvEventHttp(status, headers, method, url, respTime);
|
|
125
188
|
const httpData = shouldCaptureBody
|
|
126
|
-
? yield RequestMonitor.getHttpDataFromFetch(request,
|
|
189
|
+
? yield RequestMonitor.getHttpDataFromFetch(request, ogResponse, method, url, options, isHttpError || !!gqlError, maybeRequestText, responseTextForHttp)
|
|
127
190
|
: null;
|
|
128
191
|
const seq = saveHTTPEvent(httpEvent, httpData, !!gqlError);
|
|
129
192
|
if (isHttpError) {
|
|
130
193
|
// this does not consume response body so no need to clone it
|
|
131
|
-
saveErrorToPagevisit(Object.assign(Object.assign({},
|
|
194
|
+
saveErrorToPagevisit(Object.assign(Object.assign({}, ogResponse), { type: PageVisitErrorSource.Response }), seq);
|
|
132
195
|
}
|
|
133
196
|
if (gqlError) {
|
|
134
197
|
gqlError.forEach(error => saveErrorToPagevisit({
|
|
@@ -193,12 +256,33 @@ class RequestMonitor extends Singleton {
|
|
|
193
256
|
}
|
|
194
257
|
const startTime = Date.now();
|
|
195
258
|
const promiseFromOriginalFetch = originalFunction.call(this, resource, options);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Return a promise that resolves with a response safe for the customer.
|
|
261
|
+
* When HTTP collection or GQL validation need the response body, we read it
|
|
262
|
+
* once and rebuild a fresh Response to avoid mutating the customer's bodyUsed.
|
|
263
|
+
*/
|
|
264
|
+
const customerPromise = promiseFromOriginalFetch.then((ogResponse) => __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
const shouldCheckGql = GqlErrorValidator.shouldCheckRequest(url, options, request);
|
|
266
|
+
const shouldCaptureBody = HTTPDataBundler.getInstance().shouldContinueForURL(url);
|
|
267
|
+
const shouldReadBody = shouldCaptureBody || shouldCheckGql;
|
|
268
|
+
let customerResponse = ogResponse;
|
|
269
|
+
let responseText;
|
|
270
|
+
if (shouldReadBody) {
|
|
271
|
+
const buffered = yield RequestMonitor.readResponseBody(ogResponse);
|
|
272
|
+
if (buffered) {
|
|
273
|
+
responseText = buffered.text;
|
|
274
|
+
customerResponse = RequestMonitor.buildCustomerResponse(ogResponse, buffered.body);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
RequestMonitor.handleFetchResponse(startTime, url, method, options, request, ogResponse, responseText, shouldCaptureBody, shouldCheckGql).catch(() => {
|
|
278
|
+
// errors are handled inside handleFetchResponse
|
|
279
|
+
});
|
|
280
|
+
return customerResponse;
|
|
281
|
+
}));
|
|
282
|
+
customerPromise.catch(err => {
|
|
199
283
|
RequestMonitor.handleFetchFailure(err, url);
|
|
200
284
|
});
|
|
201
|
-
return
|
|
285
|
+
return customerPromise;
|
|
202
286
|
};
|
|
203
287
|
});
|
|
204
288
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { GQLError } from 'noibu-metroplex-ts-bindings';
|
|
2
2
|
/** Try detecting GraphQL errors from http response */
|
|
3
3
|
export default class GqlErrorValidator {
|
|
4
|
+
/** Determines if a request should be checked for GQL errors. */
|
|
5
|
+
static shouldCheckRequest(url: string, options?: RequestInit, request?: Request): boolean;
|
|
6
|
+
/** Retrieves GQL error object based on response body text */
|
|
7
|
+
static fromFetchResponseText(url: string, options: RequestInit | undefined, request: Request | undefined, status: number, responseText: string | null | undefined): Promise<GQLError[] | null>;
|
|
4
8
|
/** Retrieves GQL error object based on fetch request/response */
|
|
5
9
|
static fromFetch(url: string, options: RequestInit | undefined, request: Request | undefined, response: Response): Promise<GQLError[] | null>;
|
|
6
10
|
/** Retrieves GQL error object based on XHR object */
|
|
@@ -15,11 +15,43 @@ const MESSAGE_MAX_LENGTH = 1000;
|
|
|
15
15
|
/* eslint-disable no-param-reassign */
|
|
16
16
|
/** Try detecting GraphQL errors from http response */
|
|
17
17
|
class GqlErrorValidator {
|
|
18
|
+
/** Determines if a request should be checked for GQL errors. */
|
|
19
|
+
static shouldCheckRequest(url, options, request) {
|
|
20
|
+
const contentType = this._getContentTypeFromFetchArguments(options, request);
|
|
21
|
+
return this._shouldHandleRequest(url, contentType);
|
|
22
|
+
}
|
|
23
|
+
/** Retrieves GQL error object based on response body text */
|
|
24
|
+
static fromFetchResponseText(url, options, request, status, responseText) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
try {
|
|
27
|
+
if (!responseText) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const isResponseValid = status >= 200 && status <= 299;
|
|
31
|
+
if (!isResponseValid) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const contentType = this._getContentTypeFromFetchArguments(options, request);
|
|
35
|
+
if (this._shouldHandleRequest(url, contentType)) {
|
|
36
|
+
const data = this._parseJsonSafely(responseText);
|
|
37
|
+
if (data) {
|
|
38
|
+
return this._validate(data, []);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
if (!this._isRequestAborted(options, request)) {
|
|
44
|
+
this._postError(e);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
18
50
|
/** Retrieves GQL error object based on fetch request/response */
|
|
19
51
|
static fromFetch(url, options, request, response) {
|
|
20
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
53
|
try {
|
|
22
|
-
const isResponseValid = isInstanceOf(response, Response) && response.ok;
|
|
54
|
+
const isResponseValid = isInstanceOf(response, Response) && response.ok && !response.bodyUsed;
|
|
23
55
|
if (!isResponseValid) {
|
|
24
56
|
return null;
|
|
25
57
|
}
|
|
@@ -11,8 +11,6 @@ import { Severity, MetroplexMessageType } from 'noibu-metroplex-ts-bindings';
|
|
|
11
11
|
|
|
12
12
|
// custom event name for posting metrics
|
|
13
13
|
const POST_METRICS_EVENT_NAME = 'noibuPostMetrics';
|
|
14
|
-
// the max amount of time to wait for user events until freezing rrweb mutation events
|
|
15
|
-
const MAX_TIME_FOR_RECORDER_USER_EVENTS = 2000;
|
|
16
14
|
// Maximum number of events in the RRWEB session recorder buffer
|
|
17
15
|
// before sending to Metroplex
|
|
18
16
|
const MAX_RECORDER_EVENT_BUFFER = 10;
|
|
@@ -105,22 +103,13 @@ class SessionRecorder extends Singleton {
|
|
|
105
103
|
this.freeze();
|
|
106
104
|
return;
|
|
107
105
|
}
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
106
|
+
// Note: Automatic freeze timeout is disabled for React Native.
|
|
107
|
+
// The native SDK handles its own event throttling/batching.
|
|
108
|
+
// Freezing is still triggered by closeIfInactive() and didCutVideo checks above.
|
|
111
109
|
if (this.pauseTimeout) {
|
|
112
|
-
// received a user event, extend the timeout
|
|
113
110
|
clearTimeout(this.pauseTimeout);
|
|
114
111
|
this.freezingEvents = false;
|
|
115
112
|
}
|
|
116
|
-
this.pauseTimeout = setTimeout(() => {
|
|
117
|
-
// stop recording page mutations after 2s of inactivity
|
|
118
|
-
// otherwise sites with many mutations will hit max video size
|
|
119
|
-
// in a short amount of time without any user events
|
|
120
|
-
this.freezingEvents = true;
|
|
121
|
-
// freezePage stops emitting events until the next user event is received
|
|
122
|
-
this.freeze();
|
|
123
|
-
}, MAX_TIME_FOR_RECORDER_USER_EVENTS);
|
|
124
113
|
// Set the first recorded timestamp if it hasn't been set yet.
|
|
125
114
|
// We usually only want this to be set once as the first recorded timestamp
|
|
126
115
|
// should not change.
|
|
@@ -86,7 +86,6 @@ function subscribeToNativeEvent(callback) {
|
|
|
86
86
|
try {
|
|
87
87
|
const batch = yield NativeSessionRecorder.consumeEvents();
|
|
88
88
|
if (Array.isArray(batch) && batch.length > 0) {
|
|
89
|
-
noibuLog("Actual batch: ", batch);
|
|
90
89
|
for (const message of batch) {
|
|
91
90
|
try {
|
|
92
91
|
const _a = JSON.parse(message), { data } = _a, rest = __rest(_a, ["data"]);
|
package/package.json
CHANGED
package/dist/utils/polyfills.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
var _a, _b;
|
|
2
|
-
/**
|
|
3
|
-
* In case Promise.all is not available, use this polyfill
|
|
4
|
-
*/
|
|
5
|
-
const promiseAll = ((_b = (_a = Promise === null || Promise === void 0 ? void 0 : Promise.all) === null || _a === void 0 ? void 0 : _a.bind) === null || _b === void 0 ? void 0 : _b.call(_a, Promise)) ||
|
|
6
|
-
((values) => {
|
|
7
|
-
return new Promise(function (resolve, reject) {
|
|
8
|
-
const result = [];
|
|
9
|
-
let total = 0;
|
|
10
|
-
values.forEach((item, index) => {
|
|
11
|
-
Promise.resolve(item)
|
|
12
|
-
.then(res => {
|
|
13
|
-
result[index] = res;
|
|
14
|
-
total += 1;
|
|
15
|
-
if (total === values.length) {
|
|
16
|
-
resolve(result);
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
.catch(reject);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
export { promiseAll };
|