noibu-react-native 0.2.2 → 0.2.4

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 (100) hide show
  1. package/README.md +1 -1
  2. package/dist/api/clientConfig.js +225 -217
  3. package/dist/api/helpCode.js +61 -87
  4. package/dist/api/metroplexSocket.js +460 -463
  5. package/dist/api/storedPageVisit.js +150 -208
  6. package/dist/constants.js +10 -2
  7. package/dist/entry/init.js +65 -63
  8. package/dist/monitors/{appNavigationMonitor.js → AppNavigationMonitor.js} +12 -22
  9. package/dist/monitors/ClickMonitor.js +198 -0
  10. package/dist/monitors/ErrorMonitor.js +206 -0
  11. package/dist/monitors/KeyboardInputMonitor.js +60 -0
  12. package/dist/monitors/PageMonitor.js +98 -0
  13. package/dist/monitors/RequestMonitor.js +390 -0
  14. package/dist/monitors/http-tools/GqlErrorValidator.js +259 -0
  15. package/dist/monitors/http-tools/HTTPDataBundler.js +458 -0
  16. package/dist/monitors/integrations/react-native-navigation-integration.js +4 -2
  17. package/dist/pageVisit/EventDebouncer.js +99 -0
  18. package/dist/pageVisit/pageVisitEventError.js +2 -2
  19. package/dist/pageVisit/pageVisitEventHTTP.js +79 -93
  20. package/dist/react/ErrorBoundary.js +18 -15
  21. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +3 -2
  22. package/dist/sessionRecorder/sessionRecorder.js +152 -151
  23. package/dist/{api → src/api}/clientConfig.d.ts +2 -2
  24. package/dist/{api → src/api}/helpCode.d.ts +10 -16
  25. package/dist/{api → src/api}/metroplexSocket.d.ts +48 -67
  26. package/dist/{api → src/api}/storedPageVisit.d.ts +12 -21
  27. package/dist/{constants.d.ts → src/constants.d.ts} +45 -0
  28. package/dist/{entry → src/entry}/init.d.ts +1 -1
  29. package/dist/src/monitors/AppNavigationMonitor.d.ts +18 -0
  30. package/dist/src/monitors/ClickMonitor.d.ts +31 -0
  31. package/dist/src/monitors/ErrorMonitor.d.ts +63 -0
  32. package/dist/{monitors/keyboardInputMonitor.d.ts → src/monitors/KeyboardInputMonitor.d.ts} +7 -4
  33. package/dist/{monitors/pageMonitor.d.ts → src/monitors/PageMonitor.d.ts} +6 -8
  34. package/dist/src/monitors/RequestMonitor.d.ts +94 -0
  35. package/dist/src/monitors/http-tools/GqlErrorValidator.d.ts +59 -0
  36. package/dist/src/monitors/http-tools/HTTPDataBundler.d.ts +112 -0
  37. package/dist/{monitors → src/monitors}/integrations/react-native-navigation-integration.d.ts +3 -2
  38. package/dist/src/pageVisit/EventDebouncer.d.ts +24 -0
  39. package/dist/{pageVisit → src/pageVisit}/pageVisit.d.ts +1 -1
  40. package/dist/src/pageVisit/pageVisitEventHTTP.d.ts +25 -0
  41. package/dist/{sessionRecorder → src/sessionRecorder}/types.d.ts +1 -1
  42. package/dist/{storage → src/storage}/rnStorageProvider.d.ts +1 -1
  43. package/dist/{storage → src/storage}/storage.d.ts +2 -2
  44. package/dist/{storage → src/storage}/storageProvider.d.ts +3 -3
  45. package/dist/{utils → src/utils}/function.d.ts +27 -7
  46. package/dist/{utils → src/utils}/object.d.ts +11 -8
  47. package/dist/src/utils/piiRedactor.d.ts +11 -0
  48. package/dist/src/utils/polyfills.d.ts +4 -0
  49. package/dist/storage/rnStorageProvider.js +7 -4
  50. package/dist/storage/storage.js +43 -35
  51. package/dist/storage/storageProvider.js +23 -19
  52. package/dist/types/Config.d.ts +24 -20
  53. package/dist/types/Metroplex.types.d.ts +73 -0
  54. package/dist/types/Monitor.d.ts +11 -0
  55. package/dist/types/Monitor.js +19 -0
  56. package/dist/types/PageVisit.types.d.ts +8 -0
  57. package/dist/types/PageVisitErrors.types.d.ts +114 -0
  58. package/dist/types/PageVisitEvents.types.d.ts +91 -0
  59. package/dist/types/PageVisitMetrics.types.d.ts +27 -0
  60. package/dist/types/Storage.d.ts +1 -1
  61. package/dist/types/StoredPageVisit.types.d.ts +4 -47
  62. package/dist/types/WrappedObjects.d.ts +6 -0
  63. package/dist/utils/function.js +110 -77
  64. package/dist/utils/object.js +59 -6
  65. package/dist/utils/piiRedactor.js +98 -0
  66. package/dist/utils/polyfills.js +24 -0
  67. package/package.json +8 -8
  68. package/dist/monitors/appNavigationMonitor.d.ts +0 -22
  69. package/dist/monitors/clickMonitor.d.ts +0 -44
  70. package/dist/monitors/clickMonitor.js +0 -251
  71. package/dist/monitors/errorMonitor.d.ts +0 -28
  72. package/dist/monitors/errorMonitor.js +0 -180
  73. package/dist/monitors/gqlErrorValidator.d.ts +0 -82
  74. package/dist/monitors/gqlErrorValidator.js +0 -306
  75. package/dist/monitors/httpDataBundler.d.ts +0 -161
  76. package/dist/monitors/httpDataBundler.js +0 -725
  77. package/dist/monitors/inputMonitor.d.ts +0 -34
  78. package/dist/monitors/inputMonitor.js +0 -138
  79. package/dist/monitors/keyboardInputMonitor.js +0 -66
  80. package/dist/monitors/pageMonitor.js +0 -122
  81. package/dist/monitors/requestMonitor.d.ts +0 -10
  82. package/dist/monitors/requestMonitor.js +0 -401
  83. package/dist/pageVisit/pageVisitEventHTTP.d.ts +0 -18
  84. package/dist/types/PageVisit.d.ts +0 -22
  85. package/dist/types/ReactNative.d.ts +0 -4
  86. package/dist/types/globals.d.ts +0 -45
  87. /package/dist/{api → src/api}/inputManager.d.ts +0 -0
  88. /package/dist/{api → src/api}/storedMetrics.d.ts +0 -0
  89. /package/dist/{const_matchers.d.ts → src/const_matchers.d.ts} +0 -0
  90. /package/dist/{entry → src/entry}/index.d.ts +0 -0
  91. /package/dist/{pageVisit → src/pageVisit}/pageVisitEventError.d.ts +0 -0
  92. /package/dist/{pageVisit → src/pageVisit}/userStep.d.ts +0 -0
  93. /package/dist/{react → src/react}/ErrorBoundary.d.ts +0 -0
  94. /package/dist/{sessionRecorder → src/sessionRecorder}/nativeSessionRecorderSubscription.d.ts +0 -0
  95. /package/dist/{sessionRecorder → src/sessionRecorder}/sessionRecorder.d.ts +0 -0
  96. /package/dist/{utils → src/utils}/date.d.ts +0 -0
  97. /package/dist/{utils → src/utils}/eventlistener.d.ts +0 -0
  98. /package/dist/{utils → src/utils}/log.d.ts +0 -0
  99. /package/dist/{utils → src/utils}/performance.d.ts +0 -0
  100. /package/dist/{utils → src/utils}/stacktrace-parser.d.ts +0 -0
@@ -1,6 +1,7 @@
1
+ import { __awaiter } from 'tslib';
1
2
  import { Platform } from 'react-native';
2
3
  import { parseStack } from './stacktrace-parser.js';
3
- import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, REQUIRED_DATA_PROCESSING_URLS, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PII_DIGIT_PATTERN, DEFAULT_STACK_FRAME_FIELD_VALUE } from '../constants.js';
4
+ import { MAX_STRING_LENGTH, MAX_BEACON_PAYLOAD_SIZE, REQUIRED_DATA_PROCESSING_URLS, PII_EMAIL_PATTERN, PII_REDACTION_REPLACEMENT_STRING, PII_DIGIT_PATTERN, JS_STACK_LINE_ATT_NAME, DEFAULT_STACK_FRAME_FIELD_VALUE, JS_STACK_METHOD_ATT_NAME, JS_STACK_FILE_ATT_NAME } from '../constants.js';
4
5
  import { noibuLog } from './log.js';
5
6
  import { unwrapNoibuWrapped } from './object.js';
6
7
 
@@ -8,9 +9,9 @@ import { unwrapNoibuWrapped } from './object.js';
8
9
  * Returns a stack trace frame with default filed values
9
10
  */
10
11
  const getDefaultFrame = () => ({
11
- line: DEFAULT_STACK_FRAME_FIELD_VALUE,
12
- mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
13
- file: DEFAULT_STACK_FRAME_FIELD_VALUE,
12
+ [JS_STACK_LINE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
13
+ [JS_STACK_METHOD_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
14
+ [JS_STACK_FILE_ATT_NAME]: DEFAULT_STACK_FRAME_FIELD_VALUE,
14
15
  });
15
16
  /**
16
17
  * returns a string that satisfies a max length
@@ -27,7 +28,6 @@ function getMaxSubstringAllowed(stringToVerify, length = MAX_STRING_LENGTH) {
27
28
  }
28
29
  /**
29
30
  * Processes the raw stack frames and creates a readable stack in a safe manner
30
- * @param {StackFrame[]} rawFrames
31
31
  */
32
32
  function processFrames(rawFrames) {
33
33
  return rawFrames.map(frame => {
@@ -60,13 +60,7 @@ function processFrames(rawFrames) {
60
60
  * @param errObj error to extract stack from
61
61
  */
62
62
  function getJSStack(errObj) {
63
- let frames = [
64
- {
65
- line: DEFAULT_STACK_FRAME_FIELD_VALUE,
66
- mname: DEFAULT_STACK_FRAME_FIELD_VALUE,
67
- file: DEFAULT_STACK_FRAME_FIELD_VALUE,
68
- },
69
- ];
63
+ let frames = [getDefaultFrame()];
70
64
  // if the errObj type is not an object or null
71
65
  // return a default frame
72
66
  if (typeof errObj !== 'object' || !errObj || !errObj.stack) {
@@ -85,10 +79,9 @@ function getJSStack(errObj) {
85
79
  /**
86
80
  * Checks if possiblyStacktrace has any stack frames present
87
81
  */
88
- function isStackTrace(possiblyStacktrace) {
82
+ function isStackTrace(_possiblyStacktrace) {
89
83
  try {
90
- // todo disable temporary
91
- // return parseStack(possiblyStacktrace).length > 0;
84
+ // todo implement for react native
92
85
  return false;
93
86
  }
94
87
  catch (e) {
@@ -126,52 +119,54 @@ function stringifyJSON(jsonObject) {
126
119
  * @param timeout
127
120
  * @param sendAndForget
128
121
  */
129
- async function makeRequest(method, url, data, headers, timeout, sendAndForget) {
130
- const ua = Object.keys(headers).findLast(k => k.toLowerCase() === 'user-agent');
131
- const headersWithUa = { ...headers };
132
- if (!headers[ua]) {
133
- headersWithUa['User-Agent'] = await getUserAgent();
134
- }
135
- // a send-and-forget request is made by using the beacon API (fetch + keepalive)
136
- if (sendAndForget) {
137
- const stringData = stringifyJSON(data);
138
- const currentPayloadSize = new Blob([stringData]).size;
139
- // if we have a large object or fetch is not available, we skip sending the message
140
- if (currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
141
- return Promise.resolve();
122
+ function makeRequest(method, url, data, headers, timeout, sendAndForget) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ const ua = Object.keys(headers).findLast(k => k.toLowerCase() === 'user-agent');
125
+ const headersWithUa = Object.assign({}, headers);
126
+ if (!headers[ua]) {
127
+ headersWithUa['User-Agent'] = yield getUserAgent();
142
128
  }
143
- return unwrapNoibuWrapped(fetch)(url, {
144
- method: 'POST',
145
- headers: headersWithUa,
146
- body: stringifyJSON(data),
147
- // keep alive outlives the current page, its the same as beacon
148
- keepalive: true,
149
- });
150
- }
151
- return new Promise((resolve, reject) => {
152
- const xhr = new XMLHttpRequest();
153
- xhr.open(method, url);
154
- xhr.timeout = timeout;
155
- Object.keys(headersWithUa).forEach(header => {
156
- xhr.setRequestHeader(header, headers[header]);
157
- });
158
- xhr.onload = () => {
159
- if (xhr.status >= 200 && xhr.status < 300) {
160
- resolve(xhr.response);
129
+ // a send-and-forget request is made by using the beacon API (fetch + keepalive)
130
+ if (sendAndForget) {
131
+ const stringData = stringifyJSON(data);
132
+ const currentPayloadSize = new Blob([stringData]).size;
133
+ // if we have a large object or fetch is not available, we skip sending the message
134
+ if (currentPayloadSize > MAX_BEACON_PAYLOAD_SIZE) {
135
+ return Promise.resolve();
161
136
  }
162
- else {
137
+ return unwrapNoibuWrapped(fetch)(url, {
138
+ method: 'POST',
139
+ headers: headersWithUa,
140
+ body: stringifyJSON(data),
141
+ // keep alive outlives the current page, its the same as beacon
142
+ keepalive: true,
143
+ });
144
+ }
145
+ return new Promise((resolve, reject) => {
146
+ const xhr = new XMLHttpRequest();
147
+ xhr.open(method, url);
148
+ xhr.timeout = timeout;
149
+ Object.keys(headersWithUa).forEach(header => {
150
+ xhr.setRequestHeader(header, headers[header]);
151
+ });
152
+ xhr.onload = () => {
153
+ if (xhr.status >= 200 && xhr.status < 300) {
154
+ resolve(xhr.response);
155
+ }
156
+ else {
157
+ reject(new Error(`Custom Request failed: ${xhr.statusText}`));
158
+ }
159
+ };
160
+ xhr.onerror = () => {
163
161
  reject(new Error(`Custom Request failed: ${xhr.statusText}`));
162
+ };
163
+ if (data) {
164
+ xhr.send(stringifyJSON(data));
164
165
  }
165
- };
166
- xhr.onerror = () => {
167
- reject(new Error(`Custom Request failed: ${xhr.statusText}`));
168
- };
169
- if (data) {
170
- xhr.send(stringifyJSON(data));
171
- }
172
- else {
173
- xhr.send();
174
- }
166
+ else {
167
+ xhr.send();
168
+ }
169
+ });
175
170
  });
176
171
  }
177
172
  /**
@@ -190,20 +185,22 @@ let userAgentCache = '';
190
185
  * Fakes the user agent retrieval, since there are no good libraries that support both expo and plain RN
191
186
  * caches the result for the session
192
187
  */
193
- async function getUserAgent() {
194
- if (userAgentCache) {
188
+ function getUserAgent() {
189
+ return __awaiter(this, void 0, void 0, function* () {
190
+ if (userAgentCache) {
191
+ return userAgentCache;
192
+ }
193
+ noibuLog('getUserAgent start');
194
+ if (Platform.OS === 'android') {
195
+ const { Brand, Model, Release } = Platform.constants;
196
+ userAgentCache = `Mozilla/5.0 (Linux; Android ${Release}; ${Brand} ${Model}; React Native ${Platform.Version}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36`;
197
+ }
198
+ else if (Platform.OS === 'ios') {
199
+ userAgentCache = `Mozilla/5.0 (iPhone; CPU iPhone OS ${Platform.constants.osVersion} like Mac OS X; React Native ${Platform.Version}) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1`;
200
+ }
201
+ noibuLog('getUserAgent end', { userAgentCache });
195
202
  return userAgentCache;
196
- }
197
- noibuLog('getUserAgent start');
198
- if (Platform.OS === 'android') {
199
- const { Brand, Model, Release } = Platform.constants;
200
- userAgentCache = `Mozilla/5.0 (Linux; Android ${Release}; ${Brand} ${Model}; React Native ${Platform.Version}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36`;
201
- }
202
- else if (Platform.OS === 'ios') {
203
- userAgentCache = `Mozilla/5.0 (iPhone; CPU iPhone OS ${Platform.constants.osVersion} like Mac OS X; React Native ${Platform.Version}) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1`;
204
- }
205
- noibuLog('getUserAgent end', { userAgentCache });
206
- return userAgentCache;
203
+ });
207
204
  }
208
205
  /**
209
206
  * isInvalidURLConfig will verify that Collect is being initializes with
@@ -272,14 +269,50 @@ function isInstanceOf(instance, type) {
272
269
  /**
273
270
  * To grab the video recorder type based on the device we run the app on.
274
271
  */
275
- async function getVideoRecorderType() {
276
- if (Platform.OS === 'android') {
277
- return 'AndroidNative';
272
+ function getVideoRecorderType() {
273
+ return __awaiter(this, void 0, void 0, function* () {
274
+ if (Platform.OS === 'android') {
275
+ return 'AndroidNative';
276
+ }
277
+ if (Platform.OS === 'ios') {
278
+ return 'IOSNative';
279
+ }
280
+ return '';
281
+ });
282
+ }
283
+ /** String.trim, but safe */
284
+ function safeTrim(text) {
285
+ if (typeof text !== 'string') {
286
+ return '';
278
287
  }
279
- if (Platform.OS === 'ios') {
280
- return 'IOSNative';
288
+ return text.trim();
289
+ }
290
+ /**
291
+ * Tries to get the stack trace from the given error object and returns it.
292
+ * If the error object does not have a stack trace, an empty string is returned.
293
+ *
294
+ * @param {Error} error - The error object from which to retrieve the stack trace.
295
+ * @returns {string} The stack trace of the error, if available. Otherwise, an empty string is returned.
296
+ */
297
+ function tryGetStackTrace(error) {
298
+ let result = '';
299
+ try {
300
+ if (error && error.stack) {
301
+ result = `(stack: ${error.stack})`;
302
+ }
281
303
  }
282
- return '';
304
+ catch (_a) {
305
+ // non-standard property - that's fine
306
+ }
307
+ return result;
308
+ }
309
+ /**
310
+ * Checks whether the given value is a string or an instance of String.
311
+ * @param {*} value - The value to be checked.
312
+ * @returns {boolean} Returns true if the value is a string or an instance of String, otherwise returns false.
313
+ */
314
+ function isString(value) {
315
+ return typeof value === 'string' || value instanceof String;
283
316
  }
284
317
 
285
- export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, getVideoRecorderType, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isStackTrace, isValidURL, makeRequest, maskTextInput, processFrames, stringifyJSON };
318
+ export { asString, getJSStack, getMaxSubstringAllowed, getUserAgent, getVideoRecorderType, isInstanceOf, isInvalidURLConfig, isNoibuJSAlreadyLoaded, isStackTrace, isString, isValidURL, makeRequest, maskTextInput, processFrames, safeTrim, stringifyJSON, tryGetStackTrace };
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
1
2
  /** @module Object */
2
3
  /**
3
4
  * Replaces an attribute value found in an object with another value
@@ -51,9 +52,7 @@ function unwrapNoibuWrapped(anything) {
51
52
  * Checks whether the prototype's property is writeable. If it is not,
52
53
  * checks whether the property can be made writeable. If it can, it is
53
54
  * set to writeable.
54
- * @param {object} proto
55
- * @param {string} property
56
- * @returns {boolean} Whether the property on the prototype is (or is now) writeable
55
+ * returns Whether the property on the prototype is (or is now) writeable
57
56
  */
58
57
  const propWriteableOrMadeWriteable = (proto, property) => {
59
58
  if (!proto ||
@@ -65,9 +64,9 @@ const propWriteableOrMadeWriteable = (proto, property) => {
65
64
  // has under the open property
66
65
  const propDescriptor = Object.getOwnPropertyDescriptor(proto, property);
67
66
  // Checking if the open property is read-only
68
- if (!propDescriptor?.writable) {
67
+ if (!(propDescriptor === null || propDescriptor === void 0 ? void 0 : propDescriptor.writable)) {
69
68
  // Checking if we can write to it
70
- if (propDescriptor?.configurable) {
69
+ if (propDescriptor === null || propDescriptor === void 0 ? void 0 : propDescriptor.configurable) {
71
70
  // Making it writable to wrap it
72
71
  Object.defineProperty(proto, property, {
73
72
  writable: true,
@@ -117,5 +116,59 @@ const iterateObjectRecursively = (instance, visit, limit = { depth: 5 }) => {
117
116
  };
118
117
  iterate(instance, 1);
119
118
  };
119
+ const safeEntries = (obj) => {
120
+ const collection = [];
121
+ if (!obj) {
122
+ return collection;
123
+ }
124
+ if (obj instanceof Headers) {
125
+ obj.forEach((value, key) => {
126
+ collection.push([key, value]);
127
+ });
128
+ }
129
+ else if (typeof obj === 'object') {
130
+ collection.push(...Object.entries(obj));
131
+ }
132
+ return collection;
133
+ };
134
+ /**
135
+ * Determines if the given instance is iterable.
136
+ * An object is considered iterable if it has a method whose key is `Symbol.iterator`.
137
+ * This method checks if `instance[Symbol.iterator]` is a function, and if so, returns `true`.
138
+ * If `instance` is `null` or `undefined`, or if accessing `instance[Symbol.iterator]` throws an error,
139
+ * this method returns `false`.
140
+ */
141
+ function isIterable(instance) {
142
+ if (!instance) {
143
+ return false;
144
+ }
145
+ try {
146
+ return typeof instance[Symbol.iterator] === 'function';
147
+ }
148
+ catch (e) {
149
+ return false;
150
+ }
151
+ }
152
+ /**
153
+ * Replaces the behaviour of Object.fromEntries() as it is not supported on all browsers
154
+ * @param {Iterable} entries The iterable to parse into an object
155
+ * @returns An object containing the same key/values as the iterable passed
156
+ */
157
+ const safeFromEntries = (entries) => {
158
+ if (!isIterable(entries)) {
159
+ return {};
160
+ }
161
+ const obj = {};
162
+ try {
163
+ // eslint-disable-next-line no-restricted-syntax
164
+ for (const [key, value] of entries) {
165
+ obj[key] = value;
166
+ }
167
+ }
168
+ catch (e) {
169
+ // noting we can do - give up
170
+ }
171
+ return obj;
172
+ };
120
173
 
121
- export { iterateObjectRecursively, propWriteableOrMadeWriteable, replace, unwrapNoibuWrapped };
174
+ export { iterateObjectRecursively, propWriteableOrMadeWriteable, replace, safeEntries, safeFromEntries, unwrapNoibuWrapped };
@@ -0,0 +1,98 @@
1
+ import { iterateObjectRecursively } from './object.js';
2
+ import { HTTP_PII_BLOCKING_PATTERNS, PII_REDACTION_REPLACEMENT_STRING } from '../constants.js';
3
+ import { stringifyJSON } from './function.js';
4
+
5
+ const fuzzyFieldsToRedact = [
6
+ 'password',
7
+ 'address',
8
+ 'credit',
9
+ 'postal',
10
+ 'token',
11
+ 'phone',
12
+ 'mobile',
13
+ 'expiry',
14
+ 'account',
15
+ 'email',
16
+ ];
17
+ const exactFieldsToRedact = [
18
+ 'firstname',
19
+ 'lastname',
20
+ 'street',
21
+ 'fullname',
22
+ 'creditcard',
23
+ 'postcode',
24
+ 'zipcode',
25
+ 'city',
26
+ 'town',
27
+ 'county',
28
+ 'cc',
29
+ 'cardtype',
30
+ 'cardnumber',
31
+ 'email',
32
+ ];
33
+ /**
34
+ * Redacts one string, returns redacted value or false if nothing to redact
35
+ */
36
+ function shouldRedact(field) {
37
+ // check for exact and fuzzy matches
38
+ return (exactFieldsToRedact.some(v => field === v) ||
39
+ fuzzyFieldsToRedact.some(v => field.indexOf(v) >= 0));
40
+ }
41
+ /**
42
+ * Try to parse content as a JSON object and
43
+ * iterate it recursively removing PII.
44
+ * Returns original content if nothing was changes or error is thrown.
45
+ * @param {String} content
46
+ */
47
+ function tryParseObjectAndRemovePII(content) {
48
+ const first = content[0];
49
+ const isParsable = first === '{' || first === '[';
50
+ if (!isParsable) {
51
+ return content;
52
+ }
53
+ let redacted = false;
54
+ try {
55
+ const instance = JSON.parse(content);
56
+ iterateObjectRecursively(instance, (current, property) => {
57
+ if (typeof property !== 'string') {
58
+ return undefined;
59
+ }
60
+ const propertyLowerCase = property.toLowerCase();
61
+ const shouldRedactField = shouldRedact(propertyLowerCase);
62
+ if (shouldRedactField) {
63
+ redacted = true;
64
+ return PII_REDACTION_REPLACEMENT_STRING;
65
+ }
66
+ return undefined;
67
+ });
68
+ return redacted ? stringifyJSON(instance) : content;
69
+ }
70
+ catch (e) {
71
+ return content;
72
+ }
73
+ }
74
+ /**
75
+ * Takes a string and redacts any PII we're able to detect
76
+ *
77
+ * content - the string from which we want to redact PII
78
+ * returns the string with any PII we're able to detect redacted.
79
+ */
80
+ function removePII(content) {
81
+ /* eslint-disable no-param-reassign */
82
+ // In order to be fail-safe, let's return null if we won't be able to remove PII.
83
+ if (typeof content !== 'string') {
84
+ return '';
85
+ }
86
+ if (!content.length) {
87
+ return content;
88
+ }
89
+ content = tryParseObjectAndRemovePII(content);
90
+ // Go through each of the PII matching patterns
91
+ HTTP_PII_BLOCKING_PATTERNS.forEach(pattern => {
92
+ // Replace all matches with the appropriate number of asterisks
93
+ content = content.replace(pattern, PII_REDACTION_REPLACEMENT_STRING);
94
+ });
95
+ return content;
96
+ }
97
+
98
+ export { removePII, shouldRedact };
@@ -0,0 +1,24 @@
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noibu-react-native",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "targetNjsVersion": "1.0.104",
5
5
  "description": "React-Native SDK for NoibuJS to collect errors in React-Native applications",
6
6
  "main": "dist/entry/index.js",
@@ -18,6 +18,7 @@
18
18
  "build:dev": "node ./build.watch.js",
19
19
  "prepare": "npm run clean; npm run build;",
20
20
  "test": "jest --coverage --passWithNoTests",
21
+ "tsc": "tsc",
21
22
  "lint": "eslint src -c .eslintrc.json --ext js,ts,jsx,tsx",
22
23
  "lint_output": "eslint src -c .eslintrc.json --ext js,ts,jsx,tsx -f json > eslint_report.json",
23
24
  "codecov": "codecov"
@@ -38,13 +39,12 @@
38
39
  "@react-native-async-storage/async-storage": "^1.19.0",
39
40
  "fflate": "^0.8.2",
40
41
  "react": ">=16.13.1 <=18",
41
- "react-native": "^0.63.0",
42
+ "react-native": ">=0.63.0",
42
43
  "react-native-navigation": ">=2.29.0",
43
44
  "react-native-url-polyfill": "^1.3.0",
44
45
  "react-native-uuid": "^2.0.1"
45
46
  },
46
47
  "devDependencies": {
47
- "@babel/preset-env": "^7.24.8",
48
48
  "@jest/globals": "^29.7.0",
49
49
  "@react-native-async-storage/async-storage": "1.19.0",
50
50
  "@rollup/plugin-commonjs": "^25.0.0",
@@ -56,9 +56,9 @@
56
56
  "@types/jest": "^29.5.1",
57
57
  "@types/node": "^20.2.3",
58
58
  "@types/react": "16.14.62",
59
- "@types/react-native": "0.63.50",
60
59
  "@types/react-test-renderer": "^18.0.0",
61
- "@typescript-eslint/eslint-plugin": "^5.59.6",
60
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
61
+ "@typescript-eslint/parser": "^6.21.0",
62
62
  "babel-jest": "^29.7.0",
63
63
  "babel-plugin-transform-flow-strip-types": "^6.22.0",
64
64
  "codecov": "^3.8.3",
@@ -72,12 +72,12 @@
72
72
  "jest": "^29.7.0",
73
73
  "prettier": "^2.8.8",
74
74
  "react": "16.13.1",
75
- "react-native": "^0.63.0",
76
- "react-native-navigation": "2.29.0",
75
+ "react-native": "0.63.0",
76
+ "react-native-navigation": "^7.40.3",
77
77
  "react-native-url-polyfill": "1.3.0",
78
78
  "react-native-uuid": "2.0.1",
79
79
  "rimraf": "^5.0.1",
80
- "rollup": "^3.24.0",
80
+ "rollup": "^4.27.4",
81
81
  "rollup-plugin-dotenv": "^0.5.0",
82
82
  "ts-jest": "^29.2.3",
83
83
  "typescript": "^5.5.3"
@@ -1,22 +0,0 @@
1
- /**
2
- * Attaches corresponding listener to the passed navigation integration
3
- */
4
- export declare class AppNavigationMonitor {
5
- private static instance;
6
- /**
7
- * guesses which navigation is used in app, and registers a listener if found
8
- */
9
- constructor();
10
- /**
11
- * handler for updating navigation breadcrumbs and notifying metro of location change
12
- */
13
- onNavigation(breadcrumbs: string[]): void;
14
- /**
15
- * Gets the singleton instance
16
- */
17
- static getInstance(): AppNavigationMonitor;
18
- /**
19
- * Called when the event needs to be emitted
20
- */
21
- private reportLocationChange;
22
- }
@@ -1,44 +0,0 @@
1
- /** Monitors the clicks which we capture and later process */
2
- export class ClickMonitor {
3
- /** gets the singleton instance
4
- * @returns {ClickMonitor}
5
- */
6
- static getInstance(): ClickMonitor;
7
- /**
8
- * Gets selectors to prevent those elements from being recorded
9
- */
10
- static getBlockedElements(): string[];
11
- textCapturedWhiteListRegex: RegExp;
12
- htmlIDAllowListRegex: RegExp;
13
- /** Starts monitoring clicks on every Press-able component */
14
- monitorClicks(): void;
15
- /**
16
- * Handles a single click event
17
- * @param {{ _targetInst: RNNode }} event
18
- */
19
- _onClickHandle(event: {
20
- _targetInst: RNNode;
21
- }): void;
22
- /** Gets the textual content from an element, if any
23
- * @param {} element
24
- */
25
- _getTextualContentFromEl(element: any): string;
26
- /** Parse and trim text
27
- * @param {} text
28
- */
29
- _trimText(text: any): any;
30
- /**
31
- * Recursively parses element's inner content and masks blocked css classes
32
- * @param {NReactNative.Node} element
33
- * @param {String} text
34
- * @param {Number} textLimit
35
- * @param {Object} counter
36
- */
37
- _parseInnerContent(element: NReactNative.Node, text: string, textLimit: number, counter: Object): string;
38
- /**
39
- * normalize value and append to the resulting text if not empty
40
- * @param {String} text
41
- * @param {Array.<any>} values
42
- */
43
- _parseAndAppendText(text: string, values: Array<any>): string;
44
- }