noibu-react-native 0.0.1

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 (40) hide show
  1. package/README.md +155 -0
  2. package/dist/api/clientConfig.js +416 -0
  3. package/dist/api/helpCode.js +106 -0
  4. package/dist/api/inputManager.js +233 -0
  5. package/dist/api/metroplexSocket.js +882 -0
  6. package/dist/api/storedMetrics.js +201 -0
  7. package/dist/api/storedPageVisit.js +235 -0
  8. package/dist/const_matchers.js +260 -0
  9. package/dist/constants.d.ts +264 -0
  10. package/dist/constants.js +528 -0
  11. package/dist/entry/index.d.ts +8 -0
  12. package/dist/entry/index.js +15 -0
  13. package/dist/entry/init.js +91 -0
  14. package/dist/monitors/clickMonitor.js +284 -0
  15. package/dist/monitors/elementMonitor.js +174 -0
  16. package/dist/monitors/errorMonitor.js +295 -0
  17. package/dist/monitors/gqlErrorValidator.js +306 -0
  18. package/dist/monitors/httpDataBundler.js +665 -0
  19. package/dist/monitors/inputMonitor.js +130 -0
  20. package/dist/monitors/keyboardInputMonitor.js +67 -0
  21. package/dist/monitors/locationChangeMonitor.js +30 -0
  22. package/dist/monitors/pageMonitor.js +119 -0
  23. package/dist/monitors/requestMonitor.js +679 -0
  24. package/dist/pageVisit/pageVisit.js +172 -0
  25. package/dist/pageVisit/pageVisitEventError/pageVisitEventError.js +313 -0
  26. package/dist/pageVisit/pageVisitEventHTTP/pageVisitEventHTTP.js +115 -0
  27. package/dist/pageVisit/userStep/userStep.js +20 -0
  28. package/dist/react/ErrorBoundary.d.ts +72 -0
  29. package/dist/react/ErrorBoundary.js +102 -0
  30. package/dist/storage/localStorageProvider.js +23 -0
  31. package/dist/storage/rnStorageProvider.js +62 -0
  32. package/dist/storage/sessionStorageProvider.js +23 -0
  33. package/dist/storage/storage.js +119 -0
  34. package/dist/storage/storageProvider.js +83 -0
  35. package/dist/utils/date.js +62 -0
  36. package/dist/utils/eventlistener.js +67 -0
  37. package/dist/utils/function.js +398 -0
  38. package/dist/utils/object.js +144 -0
  39. package/dist/utils/performance.js +21 -0
  40. package/package.json +57 -0
@@ -0,0 +1,398 @@
1
+ import * as stackTraceParser from 'stacktrace-parser';
2
+ import DeviceInfo from 'react-native-device-info';
3
+ import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, REQUIRED_DATA_PROCESSING_URLS, HTTP_DATA_COLLECTION_FLAG_NAME, HTTP_DATA_PAYLOAD_URL_REGEXES_FLAG_NAME, WIN_BLOCKED_SELECTOR_ATT_NAME, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PII_DIGIT_PATTERN, NOIBUJS_CONFIG, JS_STACK_FRAMES_ATT_NAME, JS_STACK_MESSAGE_ATT_NAME, JS_STACK_FILE_ATT_NAME, JS_STACK_LINE_ATT_NAME, JS_STACK_COL_ATT_NAME, MAX_FRAMES_IN_ARRAY, JS_STACK_METHOD_ATT_NAME, DEFAULT_STACK_FRAME_FIELD_VALUE } from '../constants.js';
4
+
5
+ /** @module Functions */
6
+
7
+ /**
8
+ *
9
+ * returns a string that satisfies a max length
10
+ * stringToVerify: string that needs to be verified
11
+ * length :optional, max length that stringToVerify can be
12
+ * @param stringToVerify
13
+ * @param length
14
+ */
15
+ function getMaxSubstringAllowed(
16
+ stringToVerify,
17
+ length = MAX_STRING_LENGTH,
18
+ ) {
19
+ if (!stringToVerify) {
20
+ return stringToVerify;
21
+ }
22
+ if (stringToVerify.length < length) return stringToVerify;
23
+ return stringToVerify.substring(0, length);
24
+ }
25
+
26
+ /**
27
+ *
28
+ * getProperGlobalUrl gets the proper global url from the window
29
+ */
30
+ function getProperGlobalUrl() {
31
+ let globalUrl =
32
+ (window.location && window.location.href) || 'http://localhost';
33
+ // first we try to get the location
34
+ // if it does not follow the http protocol,
35
+ // then we check the parent frame and if that
36
+ // fails then we return what we have without
37
+ // trying anything else
38
+ if (
39
+ (
40
+ (window.location && window.location.href) ||
41
+ 'http://localhost'
42
+ ).startsWith('http')
43
+ ) {
44
+ globalUrl = (window.location && window.location.href) || 'http://localhost';
45
+ } else if (
46
+ window.parent &&
47
+ window.parent.location &&
48
+ window.parent.location.href.startsWith('http')
49
+ ) {
50
+ globalUrl = window.parent.location.href;
51
+ }
52
+
53
+ return getMaxSubstringAllowed(globalUrl);
54
+ }
55
+
56
+ /**
57
+ * Processes the raw stack frames and creates a readable stack in a safe manner
58
+ * @param rawFrames
59
+ */
60
+ function processFrames(rawFrames) {
61
+ return rawFrames.map(frame => {
62
+ const processedFrame = {
63
+ [JS_STACK_LINE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
64
+ [JS_STACK_METHOD_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
65
+ [JS_STACK_FILE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
66
+ };
67
+
68
+ // stringification
69
+ if (frame.lineNumber && frame.lineNumber !== '<unknown>') {
70
+ processedFrame[JS_STACK_LINE_ATT_NAME] = String(frame.lineNumber);
71
+ }
72
+
73
+ if (frame.methodName && frame.methodName !== '<unknown>') {
74
+ processedFrame[JS_STACK_METHOD_ATT_NAME] = String(frame.methodName);
75
+ }
76
+
77
+ if (frame.file && frame.file !== '<unknown>') {
78
+ processedFrame[JS_STACK_FILE_ATT_NAME] = String(frame.file);
79
+ }
80
+
81
+ if (frame.column && typeof frame.column === 'number') {
82
+ processedFrame[JS_STACK_COL_ATT_NAME] = frame.column;
83
+ }
84
+
85
+ return processedFrame;
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Retrieves the javascript stack and message from an error event object
91
+ * @param errObj error to extract stack from
92
+ */
93
+ function getJSStack(errObj) {
94
+ let frames = [
95
+ {
96
+ [JS_STACK_LINE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
97
+ [JS_STACK_METHOD_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
98
+ [JS_STACK_FILE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
99
+ },
100
+ ];
101
+
102
+ // if the errObj type is not an object or null
103
+ // return a default frame
104
+ if (typeof errObj !== 'object' || !errObj) {
105
+ return {
106
+ [JS_STACK_FRAMES_ATT_NAME]: frames,
107
+ [JS_STACK_MESSAGE_ATT_NAME]: '',
108
+ };
109
+ }
110
+
111
+ // If there is no stack field present then try to read the single file/line/column values
112
+ if (!errObj.stack) {
113
+ if (errObj.fileName && typeof errObj.fileName === 'string') {
114
+ frames[0][JS_STACK_FILE_ATT_NAME] = errObj.fileName;
115
+ }
116
+ if (errObj.lineNumber) {
117
+ frames[0][JS_STACK_LINE_ATT_NAME] = String(errObj.lineNumber);
118
+ }
119
+ if (errObj.columnNumber && Number.isInteger(errObj.columnNumber)) {
120
+ frames[0][JS_STACK_COL_ATT_NAME] = errObj.columnNumber;
121
+ }
122
+ } else {
123
+ frames = processFrames(stackTraceParser.parse(errObj.stack));
124
+ }
125
+
126
+ if (frames.length >= MAX_FRAMES_IN_ARRAY) {
127
+ frames = frames.slice(0, MAX_FRAMES_IN_ARRAY);
128
+ }
129
+
130
+ const msg = errObj.message ? getMaxSubstringAllowed(errObj.message) : '';
131
+ return {
132
+ [JS_STACK_FRAMES_ATT_NAME]: frames,
133
+ [JS_STACK_MESSAGE_ATT_NAME]: msg,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * safely stringifies an object
139
+ * @param jsonObject
140
+ */
141
+ function stringifyJSON(jsonObject) {
142
+ // prototype.js version < 1.7 defines a toJSON on the prototype of
143
+ // arrays. This is wrong and they have fixed it since, but some old websites
144
+ // still use that lib and it messes up our the expected serilization on metroplex's
145
+ // side.
146
+ if (Array.prototype.toJSON) {
147
+ // this piece of code is safe since js guarentees that only one thing is running
148
+ // at once, therefore the prototype will be changed only while this function is executing
149
+ const oldToJSON = Array.prototype.toJSON;
150
+ delete Array.prototype.toJSON;
151
+ const jsonString = JSON.stringify(jsonObject);
152
+ // we want to re-enable the existing prototype behaviour
153
+ // eslint-disable-next-line no-extend-native
154
+ Array.prototype.toJSON = oldToJSON;
155
+ return jsonString;
156
+ }
157
+ return JSON.stringify(jsonObject);
158
+ }
159
+
160
+ /**
161
+ * Wrapper for a request, since we have to do some special handling
162
+ * @param method
163
+ * @param url
164
+ * @param data
165
+ * @param headers
166
+ * @param timeout
167
+ * @param sendAndForget
168
+ */
169
+ function makeRequest(
170
+ method,
171
+ url,
172
+ data,
173
+ headers,
174
+ timeout,
175
+ sendAndForget,
176
+ ) {
177
+ // a send and forget request is made by using the beacon API (fetch + keepalive)
178
+ if (sendAndForget) {
179
+ const stringData = stringifyJSON(data);
180
+ const currentPayloadSize = new Blob([stringData]).size;
181
+ // if we have a large object or fetch is not available, we skip sending the message
182
+ if (!window.fetch || currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
183
+ return new Promise(resolve => {
184
+ resolve();
185
+ });
186
+ }
187
+
188
+ return fetch(url, {
189
+ method: 'POST',
190
+ headers,
191
+ body: stringifyJSON(data),
192
+ // keep alive outlives the current page, its the same as beacon
193
+ keepalive: true,
194
+ });
195
+ }
196
+
197
+ return new Promise((resolve, reject) => {
198
+ const xhr = new XMLHttpRequest();
199
+ xhr.open(method, url);
200
+ xhr.timeout = timeout;
201
+ Object.keys(headers).forEach(header => {
202
+ xhr.setRequestHeader(header, headers[header]);
203
+ });
204
+
205
+ xhr.onload = () => {
206
+ if (xhr.status >= 200 && xhr.status < 300) {
207
+ resolve(xhr.response);
208
+ } else {
209
+ reject(new Error(`Custom Request failed: ${xhr.statusText}`));
210
+ }
211
+ };
212
+ xhr.onerror = () => {
213
+ reject(new Error(`Custom Request failed: ${xhr.statusText}`));
214
+ };
215
+ if (data) {
216
+ xhr.send(stringifyJSON(data));
217
+ } else {
218
+ xhr.send();
219
+ }
220
+ });
221
+ }
222
+
223
+ /** determines if we have received the block selector */
224
+ function checkBlockedSelectorExistence() {
225
+ const noibuConfig = NOIBUJS_CONFIG();
226
+ return (
227
+ noibuConfig[WIN_BLOCKED_SELECTOR_ATT_NAME] &&
228
+ Array.isArray(noibuConfig[WIN_BLOCKED_SELECTOR_ATT_NAME])
229
+ );
230
+ }
231
+
232
+ /** checks if http data collection is enabled */
233
+ function checkHttpDataCollectionEnabled() {
234
+ const noibuConfig = NOIBUJS_CONFIG();
235
+ // Just a boolean, so safe to return truthiness. If undefined, will return false.
236
+ return !!noibuConfig[HTTP_DATA_COLLECTION_FLAG_NAME];
237
+ }
238
+
239
+ /** determines if we have received the http allowed urls */
240
+ function checkHttpPayloadAllowedURLsExistence() {
241
+ const noibuConfig = NOIBUJS_CONFIG();
242
+ return (
243
+ noibuConfig[HTTP_DATA_PAYLOAD_URL_REGEXES_FLAG_NAME] &&
244
+ Array.isArray(noibuConfig[HTTP_DATA_PAYLOAD_URL_REGEXES_FLAG_NAME])
245
+ );
246
+ }
247
+
248
+ /** gets http data payload allowed URLs */
249
+ function getHttpPayloadAllowedURLs() {
250
+ const noibuConfig = NOIBUJS_CONFIG();
251
+ // return the allowed list or an empty list
252
+ if (checkHttpPayloadAllowedURLsExistence()) {
253
+ return noibuConfig[HTTP_DATA_PAYLOAD_URL_REGEXES_FLAG_NAME];
254
+ }
255
+ return [];
256
+ }
257
+ /**
258
+ * Gets all the blocked css classes to prevent those elements from being recorded
259
+ */
260
+ function getBlockedCSSForCurrentDomain() {
261
+ const noibuConfig = NOIBUJS_CONFIG();
262
+ const blockedCSS = ['noibu-blocked'];
263
+ if (checkBlockedSelectorExistence()) {
264
+ noibuConfig[WIN_BLOCKED_SELECTOR_ATT_NAME].forEach(sel => {
265
+ // this means that we are looking at a class
266
+ if (sel.startsWith('.') && sel.length > 0) {
267
+ // selecting everything after and including the element at index 1
268
+ blockedCSS.push(sel.substring(1));
269
+ }
270
+ });
271
+ }
272
+ return blockedCSS;
273
+ }
274
+ /**
275
+ * makes sure the url sent is a valid URL
276
+ * @param {} string url to be validated
277
+ */
278
+ function isValidURL(string) {
279
+ try {
280
+ const _ = new URL(string);
281
+ return true;
282
+ } catch (_) {
283
+ return false;
284
+ }
285
+ }
286
+
287
+ let userAgentCache = '';
288
+
289
+ /**
290
+ * Because of the nature of user agent in react native, we have to make this async.
291
+ * But I promise, this is really fast, since we memoize the result for the whole session :)
292
+ * @returns {Promise<string>}
293
+ */
294
+ async function getUserAgent() {
295
+ if (userAgentCache) {
296
+ return userAgentCache;
297
+ }
298
+ userAgentCache = await DeviceInfo.getUserAgent();
299
+ return userAgentCache;
300
+ }
301
+
302
+ /**
303
+ * isInvalidURLConfig will verify that Collect is being initializes with
304
+ * the correct env vars.
305
+ * @param {} urlConfig
306
+ */
307
+ function isInvalidURLConfig(urlConfig) {
308
+ for (let i = 0; i < REQUIRED_DATA_PROCESSING_URLS.length; i += 1) {
309
+ const u = REQUIRED_DATA_PROCESSING_URLS[i];
310
+ if (!urlConfig[u]) {
311
+ return true;
312
+ }
313
+ }
314
+
315
+ return false;
316
+ }
317
+
318
+ /**
319
+ * isNoibuJSAlreadyLoaded will verify if there are already other
320
+ * copies of NoibuJS runnung
321
+ */
322
+ function isNoibuJSAlreadyLoaded() {
323
+ // check if the global variable exists and its value
324
+ const loaded = window.noibuJSLoaded !== undefined;
325
+ // set the variable so future copies of the script
326
+ // will know this instance is running
327
+ window.noibuJSLoaded = true;
328
+ return loaded;
329
+ }
330
+
331
+ /** asString will create a string out of anything passed to it.
332
+ * @param {} obj
333
+ */
334
+ function asString(obj) {
335
+ if (!obj) {
336
+ return '';
337
+ }
338
+ // we've seen the url be an object in some cases
339
+ // we would still like to send those to our backend in the case
340
+ // that this is an issue and needs to be queried
341
+ if (typeof obj === 'object') {
342
+ return stringifyJSON(obj);
343
+ }
344
+
345
+ return String(obj);
346
+ }
347
+
348
+ /** masks textual content if it ressembles something sensitive
349
+ * @param {} text
350
+ */
351
+ function maskTextInput(text) {
352
+ // if it has an email or digit(s), we mask the text
353
+ return text
354
+ .replace(PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING)
355
+ .replace(PII_DIGIT_PATTERN, '*');
356
+ }
357
+
358
+ /** gets the onURL of a string, defaulting to the location of the webpage
359
+ * @param {} realOnURL
360
+ */
361
+ function getOnURL(realOnURL) {
362
+ let onURL = getMaxSubstringAllowed(
363
+ (window.location && window.location.href) || 'http://localhost',
364
+ );
365
+ if (realOnURL && realOnURL.trim() !== '' && realOnURL !== 'undefined') {
366
+ onURL = asString(getMaxSubstringAllowed(realOnURL));
367
+ }
368
+
369
+ return onURL;
370
+ }
371
+
372
+ /** gets the user language from the browser */
373
+ function getUserLanguage() {
374
+ const lang = window.navigator.userLanguage || window.navigator.language;
375
+
376
+ if (lang === '' || !lang) {
377
+ return null;
378
+ }
379
+
380
+ return lang.toLowerCase();
381
+ }
382
+
383
+ /**
384
+ * Checks if the provided object is an instance of the specified type.
385
+ * It's safer than `instanceof` operator as it handles cases
386
+ * where type is not actually a type but an object.
387
+ * @param {any} instance
388
+ * @param {any} type
389
+ */
390
+ function isInstanceOf(instance, type) {
391
+ try {
392
+ return typeof type === 'function' && instance instanceof type;
393
+ } catch (e) {
394
+ return false;
395
+ }
396
+ }
397
+
398
+ export { asString, checkHttpDataCollectionEnabled, getBlockedCSSForCurrentDomain, getHttpPayloadAllowedURLs, getJSStack, getMaxSubstringAllowed, getOnURL, getProperGlobalUrl, getUserAgent, getUserLanguage, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isValidURL, makeRequest, maskTextInput, processFrames, stringifyJSON };
@@ -0,0 +1,144 @@
1
+ /** @module Object */
2
+ /**
3
+ * Replaces an attribute value found in an object with another value
4
+ * sourceObject: source object whose attribute will get replaced
5
+ * attributeName: the attribute key whose value will be replace
6
+ * processingFunction: function that accepts the original value
7
+ * and returns the newValue
8
+ * @param {} sourceObject
9
+ * @param {} attributeName
10
+ * @param {} processingFunction
11
+ */
12
+ const replace = (sourceObject, attributeName, processingFunction) => {
13
+ if (!(attributeName in sourceObject)) {
14
+ return;
15
+ }
16
+
17
+ const originalAttribute = sourceObject[attributeName];
18
+ const newValue = processingFunction(originalAttribute);
19
+
20
+ if (typeof newValue === 'function') {
21
+ try {
22
+ newValue.prototype = newValue.prototype || {};
23
+ Object.defineProperties(newValue, {
24
+ __noibu__: {
25
+ enumerable: false,
26
+ value: true,
27
+ },
28
+ __noibu_original__: {
29
+ enumerable: false,
30
+ value: originalAttribute,
31
+ },
32
+ __noibu_wrapped__: {
33
+ enumerable: false,
34
+ value: newValue,
35
+ },
36
+ });
37
+ } catch (err) {
38
+ // silent fail
39
+ }
40
+ }
41
+
42
+ // eslint-disable-next-line no-param-reassign
43
+ sourceObject[attributeName] = newValue;
44
+ };
45
+
46
+ /**
47
+ * Checks whether the prototype's property is writeable. If it is not,
48
+ * checks whether the property can be made writeable. If it can, it is
49
+ * set to writeable.
50
+ * @param {object} proto
51
+ * @param {string} property
52
+ * @returns {boolean} Whether the property on the prototype is (or is now) writeable
53
+ */
54
+ const propWriteableOrMadeWriteable = (proto, property) => {
55
+ if (
56
+ !proto ||
57
+ !proto.hasOwnProperty ||
58
+ !Object.prototype.hasOwnProperty.call(proto, property)
59
+ ) {
60
+ return false;
61
+ }
62
+
63
+ // Getting the properties that this the prototype
64
+ // has under the open property
65
+ const propDescriptor = Object.getOwnPropertyDescriptor(proto, property);
66
+
67
+ // Checking if the open property is read-only
68
+ if (!propDescriptor.writable) {
69
+ // Checking if we can write to it
70
+ if (propDescriptor.configurable) {
71
+ // Making it writable to wrap it
72
+ Object.defineProperty(proto, property, {
73
+ writable: true,
74
+ });
75
+ } else {
76
+ return false;
77
+ }
78
+ }
79
+ return true;
80
+ };
81
+
82
+ /**
83
+ * Replaces the behaviour of Object.fromEntries() as it is not supported on all browsers
84
+ * @param {Iterable} entries The iterable to parse into an object
85
+ * @returns An object containing the same key/values as the iterable passed
86
+ */
87
+ const safeFromEntries = entries => {
88
+ if (!entries || !entries[Symbol.iterator]) {
89
+ throw new Error('Object.fromEntries() requires a single iterable argument');
90
+ }
91
+ const obj = {};
92
+ // eslint-disable-next-line no-restricted-syntax
93
+ for (const [key, value] of entries) {
94
+ obj[key] = value;
95
+ }
96
+ return obj;
97
+ };
98
+
99
+ /**
100
+ * Iterates object recursively and calls visit function
101
+ * for each property allowing to override its value
102
+ * @param {Object} instance An object to iterate through
103
+ * @param {Function} visit A callback function that is called for each property
104
+ * There are 3 arguments: current object, current property and its value
105
+ * @param {{depth: number}} limit Use limit config object to set depth of the recursion
106
+ */
107
+ const iterateObjectRecursively = (
108
+ instance,
109
+ visit,
110
+ limit = { depth: 5 },
111
+ ) => {
112
+ /* eslint-disable no-shadow, no-restricted-syntax, no-param-reassign, guard-for-in */
113
+ /**
114
+ * internal recursive function
115
+ * @param {Object} instance Current object
116
+ * @param {Number} depth Current depth
117
+ */
118
+ const iterate = (instance, depth) => {
119
+ // stop to go deeper if it is deep enough already
120
+ if (depth > limit.depth) return;
121
+ for (const property in instance) {
122
+ try {
123
+ // call visit function and assign its result if not undefined
124
+ const newValue = visit(instance, property, instance[property]);
125
+ if (newValue !== undefined) {
126
+ instance[property] = newValue;
127
+ }
128
+ // go one level deeper if it is an object
129
+ if (
130
+ instance[property] !== null &&
131
+ typeof instance[property] === 'object'
132
+ ) {
133
+ iterate(instance[property], depth + 1);
134
+ }
135
+ } catch (e) {
136
+ // just continue to the next property
137
+ }
138
+ }
139
+ };
140
+
141
+ iterate(instance, 1);
142
+ };
143
+
144
+ export { iterateObjectRecursively, propWriteableOrMadeWriteable, replace, safeFromEntries };
@@ -0,0 +1,21 @@
1
+ import { timestampWrapper } from './date.js';
2
+
3
+ /** @module Performance */
4
+
5
+ /**
6
+ * Wrapper function for window.performance.now() to ensure
7
+ * it's available before calling it. If it's not available,
8
+ * we return Date.now() instead.
9
+ */
10
+ function safePerformanceNow() {
11
+ if (window.performance && window.performance.now) {
12
+ // There is a 70% hit with using this
13
+ // https://jsperf.com/perf-vs-date/1
14
+ // performance.now is for relative time measurement
15
+ // cannot be used instead of Date.getTime() on it's own
16
+ return window.performance.now();
17
+ }
18
+ return timestampWrapper(Date.now());
19
+ }
20
+
21
+ export { safePerformanceNow };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "noibu-react-native",
3
+ "version": "0.0.1",
4
+ "description": "React-Native SDK for NoibuJS to collect errors in React-Native applications",
5
+ "main": "dist/entry/index.js",
6
+ "types": "dist/entry/index.d.ts",
7
+ "files": [
8
+ "dist/*",
9
+ "README.md"
10
+ ],
11
+ "author": "Noibu Inc",
12
+ "license": "ISC",
13
+
14
+ "scripts": {
15
+ "clean": "rimraf ./dist/*",
16
+ "build": "node ./build.js",
17
+ "build:dev": "node ./build.watch.js",
18
+ "prepare": "npm run clean; npm run build;",
19
+ "test": "jest --coverage --passWithNoTests",
20
+ "lint": "eslint src -c .eslintrc.json --ext js,ts,jsx,tsx",
21
+ "lint_output": "eslint src -c .eslintrc.json --ext js,ts,jsx,tsx -f json > eslint_report.json",
22
+ "codecov": "codecov"
23
+ },
24
+ "peerDependencies": {
25
+ "react": ">=16.11.0",
26
+ "react-native": ">=0.63.0",
27
+ "react-native-device-info": "^10.6.0",
28
+ "react-native-url-polyfill": "^1.3.0",
29
+ "react-native-uuid": "^2.0.1",
30
+ "stacktrace-parser": "^0.1.10"
31
+ },
32
+ "devDependencies": {
33
+ "@rollup/plugin-commonjs": "^25.0.0",
34
+ "@rollup/plugin-json": "^6.0.0",
35
+ "@rollup/plugin-node-resolve": "^15.1.0",
36
+ "@rollup/plugin-replace": "^5.0.2",
37
+ "@rollup/plugin-typescript": "^11.1.1",
38
+ "@tsconfig/react-native": "^3.0.2",
39
+ "@types/jest": "^29.5.1",
40
+ "@types/node": "^20.2.3",
41
+ "@types/react": "^18.2.6",
42
+ "@types/react-test-renderer": "^18.0.0",
43
+ "@typescript-eslint/eslint-plugin": "^5.59.6",
44
+ "codecov": "^3.8.3",
45
+ "dotenv": "^16.1.3",
46
+ "eslint": "^8.41.0",
47
+ "eslint-config-airbnb": "^19.0.4",
48
+ "eslint-config-prettier": "^8.8.0",
49
+ "eslint-plugin-jsdoc": "^44.2.4",
50
+ "eslint-plugin-prettier": "^4.2.1",
51
+ "jest": "^29.5.0",
52
+ "prettier": "^2.8.8",
53
+ "rimraf": "^5.0.1",
54
+ "rollup": "^3.24.0",
55
+ "rollup-plugin-dotenv": "^0.5.0"
56
+ }
57
+ }