noibu-react-native 0.2.5 → 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/android/build.gradle +1 -1
- 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,52 +1,49 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import { strToU8, zlibSync, strFromU8 } from 'fflate';
|
|
3
3
|
import { LogLevel, initialize, subscribeToNativeEvent } from './nativeSessionRecorderSubscription.js';
|
|
4
|
-
import StoredMetrics from '../api/
|
|
5
|
-
import ClientConfig from '../api/
|
|
4
|
+
import StoredMetrics from '../api/StoredMetrics.js';
|
|
5
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
6
6
|
import { stringifyJSON } from '../utils/function.js';
|
|
7
|
-
import {
|
|
8
|
-
import MetroplexSocket from '../api/
|
|
7
|
+
import { SEVERITY, MAX_TIME_FOR_UNSENT_DATA_MILLIS } from '../constants.js';
|
|
8
|
+
import MetroplexSocket from '../api/MetroplexSocket.js';
|
|
9
9
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
10
10
|
import { noibuLog } from '../utils/log.js';
|
|
11
11
|
import { Platform } from 'react-native';
|
|
12
|
+
import { Singleton } from '../monitors/BaseMonitor.js';
|
|
13
|
+
import '../node_modules/@noibu/metroplex-ts-bindings/dist/index.js';
|
|
14
|
+
import { WebsocketMessageType } from '../node_modules/@noibu/metroplex-ts-bindings/dist/WebsocketMessageType.js';
|
|
12
15
|
|
|
16
|
+
// custom event name for posting metrics
|
|
17
|
+
const POST_METRICS_EVENT_NAME = 'noibuPostMetrics';
|
|
18
|
+
// the max amount of time to wait for user events until freezing rrweb mutation events
|
|
19
|
+
const MAX_TIME_FOR_RECORDER_USER_EVENTS = 2000;
|
|
20
|
+
// Maximum number of events in the RRWEB session recorder buffer
|
|
21
|
+
// before sending to Metroplex
|
|
22
|
+
const MAX_RECORDER_EVENT_BUFFER = 10;
|
|
13
23
|
/** Singleton class to record user sessions */
|
|
14
|
-
class SessionRecorder {
|
|
15
|
-
/**
|
|
16
|
-
* Creates an instance of the session recorder
|
|
17
|
-
*/
|
|
24
|
+
class SessionRecorder extends Singleton {
|
|
25
|
+
/** Setups the SessionRecorder instance for usage */
|
|
18
26
|
constructor() {
|
|
19
|
-
|
|
27
|
+
super();
|
|
20
28
|
this.eventBuffer = [];
|
|
21
29
|
this.vfCounter = 0;
|
|
22
30
|
this.didSetupRecorder = false;
|
|
23
|
-
this.recordStopper = null;
|
|
24
|
-
this.firstRecordedTimestamp = null;
|
|
25
|
-
this.lastRecordedTimestamp = null;
|
|
26
31
|
this.isVideoLengthNegativeInvalid = false;
|
|
27
32
|
this.lastFragPostTimestamp = Date.now();
|
|
28
33
|
this.pauseTimeout = null;
|
|
34
|
+
this.lastRecordedTimestamp = null;
|
|
35
|
+
this.firstRecordedTimestamp = null;
|
|
36
|
+
this.recordStopper = null;
|
|
37
|
+
this.freezingEvents = false;
|
|
29
38
|
this.setupUnloadHandler();
|
|
30
39
|
this.setupPostMetricsHandler();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!this.instance) {
|
|
37
|
-
const nativeSessionRecorderConfig = {
|
|
38
|
-
logLevel: LogLevel.Verbose,
|
|
39
|
-
};
|
|
40
|
-
if (Platform.OS === 'android') {
|
|
41
|
-
initialize('abc1234', nativeSessionRecorderConfig);
|
|
42
|
-
}
|
|
43
|
-
this.instance = new SessionRecorder();
|
|
44
|
-
// todo handle RN clicks
|
|
45
|
-
addSafeEventListener(window, 'click', () => {
|
|
46
|
-
this.instance.handleFragPost();
|
|
47
|
-
});
|
|
40
|
+
const nativeSessionRecorderConfig = {
|
|
41
|
+
logLevel: LogLevel.Verbose,
|
|
42
|
+
};
|
|
43
|
+
if (Platform.OS === 'android') {
|
|
44
|
+
initialize('abc1234', nativeSessionRecorderConfig);
|
|
48
45
|
}
|
|
49
|
-
|
|
46
|
+
addSafeEventListener(window, 'click', () => this.handleFragPost());
|
|
50
47
|
}
|
|
51
48
|
/** Sets up the page hide handler to try to push remaining video events */
|
|
52
49
|
setupUnloadHandler() {
|
|
@@ -64,8 +61,7 @@ class SessionRecorder {
|
|
|
64
61
|
// Get the event name that triggered postMetrics from the custom event
|
|
65
62
|
const eventName = e.detail;
|
|
66
63
|
// Calculate the total expected video length
|
|
67
|
-
const totalVideoTime = this.lastRecordedTimestamp === null ||
|
|
68
|
-
this.firstRecordedTimestamp === null
|
|
64
|
+
const totalVideoTime = this.lastRecordedTimestamp === null || this.firstRecordedTimestamp === null
|
|
69
65
|
? 0
|
|
70
66
|
: this.lastRecordedTimestamp - this.firstRecordedTimestamp;
|
|
71
67
|
const sessionLength = MetroplexSocket.getInstance().sessionLength
|
|
@@ -77,7 +73,8 @@ class SessionRecorder {
|
|
|
77
73
|
// debug message gets through
|
|
78
74
|
const clientDisabled = ClientConfig.getInstance().isClientDisabled;
|
|
79
75
|
ClientConfig.getInstance().isClientDisabled = false;
|
|
80
|
-
ClientConfig.getInstance().
|
|
76
|
+
ClientConfig.getInstance().postInternalError({
|
|
77
|
+
msg: 'large retry message queue',
|
|
81
78
|
eventName,
|
|
82
79
|
totalVideoTime,
|
|
83
80
|
sessionLength,
|
|
@@ -85,15 +82,12 @@ class SessionRecorder {
|
|
|
85
82
|
}
|
|
86
83
|
});
|
|
87
84
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Starts recording the user session
|
|
90
|
-
*/
|
|
85
|
+
/** Starts recording the user session */
|
|
91
86
|
recordUserSession() {
|
|
92
87
|
return __awaiter(this, void 0, void 0, function* () {
|
|
93
88
|
// check if inactive before starting any recording
|
|
94
89
|
noibuLog('recordUserSession');
|
|
95
|
-
if ((yield MetroplexSocket.getInstance().closeIfInactive()) ||
|
|
96
|
-
StoredMetrics.getInstance().didCutVideo) {
|
|
90
|
+
if ((yield MetroplexSocket.getInstance().closeIfInactive()) || StoredMetrics.getInstance().didCutVideo) {
|
|
97
91
|
return;
|
|
98
92
|
}
|
|
99
93
|
// making sure we are not attempting to call this method
|
|
@@ -116,8 +110,7 @@ class SessionRecorder {
|
|
|
116
110
|
return __awaiter(this, void 0, void 0, function* () {
|
|
117
111
|
const timestamp = Date.now();
|
|
118
112
|
// check if inactive before any processing
|
|
119
|
-
if ((yield MetroplexSocket.getInstance().closeIfInactive()) ||
|
|
120
|
-
StoredMetrics.getInstance().didCutVideo) {
|
|
113
|
+
if ((yield MetroplexSocket.getInstance().closeIfInactive()) || StoredMetrics.getInstance().didCutVideo) {
|
|
121
114
|
this.freeze();
|
|
122
115
|
return;
|
|
123
116
|
}
|
|
@@ -153,9 +146,8 @@ class SessionRecorder {
|
|
|
153
146
|
// the metrics 'exp_vid_len' data.
|
|
154
147
|
// If we don't adjust for time, we assume that the expected video length is
|
|
155
148
|
// the difference between the first recorded timestamp and the last recorded timestamp.
|
|
156
|
-
if (this.firstRecordedTimestamp &&
|
|
157
|
-
|
|
158
|
-
ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(`Detected time rewind. Client has been disabled.`, true, SEVERITY.error, true);
|
|
149
|
+
if (this.firstRecordedTimestamp && timestamp < this.firstRecordedTimestamp) {
|
|
150
|
+
ClientConfig.getInstance().postInternalError({ msg: `Detected time rewind. Client has been disabled.` }, true, SEVERITY.error, true);
|
|
159
151
|
return;
|
|
160
152
|
}
|
|
161
153
|
const packedEvent = yield this.pack(recorderEvent.message);
|
|
@@ -167,30 +159,26 @@ class SessionRecorder {
|
|
|
167
159
|
// todo if there are clicks, call StoredMetrics.getInstance().addVideoClick(); for each click
|
|
168
160
|
const now = Date.now();
|
|
169
161
|
const delta = now - this.lastFragPostTimestamp;
|
|
170
|
-
if (this.eventBuffer.length >= MAX_RECORDER_EVENT_BUFFER ||
|
|
171
|
-
delta > MAX_TIME_FOR_UNSENT_DATA_MILLIS) {
|
|
162
|
+
if (this.eventBuffer.length >= MAX_RECORDER_EVENT_BUFFER || delta > MAX_TIME_FOR_UNSENT_DATA_MILLIS) {
|
|
172
163
|
this.handleFragPost();
|
|
173
164
|
}
|
|
174
165
|
});
|
|
175
166
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Compress event
|
|
178
|
-
*/
|
|
167
|
+
/** Compress event */
|
|
179
168
|
pack(recorderEvent) {
|
|
180
169
|
return __awaiter(this, void 0, void 0, function* () {
|
|
181
170
|
// return JSON.stringify(recorderEvent);
|
|
182
171
|
return SessionRecorder.compress(recorderEvent);
|
|
183
172
|
});
|
|
184
173
|
}
|
|
174
|
+
/** Compresses the snapshot */
|
|
185
175
|
static compress(snapshot) {
|
|
186
176
|
const uncompressedString = stringifyJSON(snapshot);
|
|
187
177
|
const uncompressedData = strToU8(uncompressedString);
|
|
188
178
|
const compressedData = zlibSync(uncompressedData, { level: 1 });
|
|
189
|
-
|
|
190
|
-
return compressedString;
|
|
179
|
+
return strFromU8(compressedData, true);
|
|
191
180
|
}
|
|
192
|
-
/** builds a log message with debug info
|
|
193
|
-
*/
|
|
181
|
+
/** builds a log message with debug info */
|
|
194
182
|
buildDebugMessage(eventName, totalVideoTime, sessionLength) {
|
|
195
183
|
return JSON.stringify({ eventName, totalVideoTime, sessionLength });
|
|
196
184
|
}
|
|
@@ -215,21 +203,20 @@ class SessionRecorder {
|
|
|
215
203
|
try {
|
|
216
204
|
let totalVideoTime = 0;
|
|
217
205
|
// checking if we have those values set in the first place
|
|
218
|
-
if (this.firstRecordedTimestamp &&
|
|
219
|
-
this.lastRecordedTimestamp
|
|
220
|
-
!this.isVideoLengthNegativeInvalid) {
|
|
221
|
-
totalVideoTime =
|
|
222
|
-
this.lastRecordedTimestamp - this.firstRecordedTimestamp;
|
|
206
|
+
if (this.firstRecordedTimestamp && this.lastRecordedTimestamp && !this.isVideoLengthNegativeInvalid) {
|
|
207
|
+
totalVideoTime = this.lastRecordedTimestamp - this.firstRecordedTimestamp;
|
|
223
208
|
}
|
|
224
209
|
// In the past we have seen the video LengthMS field to be negative
|
|
225
210
|
// and bigger than the long limit of scala. Which is less than the
|
|
226
211
|
// safe integer limit of js.
|
|
227
|
-
if (!this.isVideoLengthNegativeInvalid &&
|
|
228
|
-
(totalVideoTime < 0 || totalVideoTime >= Number.MAX_SAFE_INTEGER)) {
|
|
212
|
+
if (!this.isVideoLengthNegativeInvalid && (totalVideoTime < 0 || totalVideoTime >= Number.MAX_SAFE_INTEGER)) {
|
|
229
213
|
// we log an error to know if this is still happening
|
|
230
|
-
ClientConfig.getInstance().
|
|
231
|
-
|
|
232
|
-
|
|
214
|
+
ClientConfig.getInstance().postInternalError({
|
|
215
|
+
msg: 'video length MS is invalid',
|
|
216
|
+
totalVideoTime,
|
|
217
|
+
'start time': this.firstRecordedTimestamp,
|
|
218
|
+
'end time': this.lastRecordedTimestamp,
|
|
219
|
+
}, false, SEVERITY.error);
|
|
233
220
|
this.isVideoLengthNegativeInvalid = true;
|
|
234
221
|
totalVideoTime = 0;
|
|
235
222
|
}
|
|
@@ -239,23 +226,24 @@ class SessionRecorder {
|
|
|
239
226
|
// when being sent to metroplex which we will then unmarshall into
|
|
240
227
|
// a struct to parse it's inner urls
|
|
241
228
|
// If stringifying this event buffer takes too long consider using a service worker
|
|
242
|
-
|
|
229
|
+
vid: stringifyJSON(this.eventBuffer),
|
|
243
230
|
// Send the sequence number but don't send the expected length since that is sent as
|
|
244
231
|
// part of the last stored metrics data
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
232
|
+
seq: this.vfCounter,
|
|
233
|
+
len: totalVideoTime,
|
|
234
|
+
css_urls: [],
|
|
248
235
|
}, false);
|
|
249
236
|
StoredMetrics.getInstance().addVideoFragData(this.vfCounter, totalVideoTime);
|
|
250
237
|
// constructing a client message that metroplex knows how to handle.
|
|
251
|
-
yield MetroplexSocket.getInstance().sendMessage(
|
|
252
|
-
|
|
238
|
+
yield MetroplexSocket.getInstance().sendMessage({
|
|
239
|
+
type: WebsocketMessageType.PageVisitVideoFile,
|
|
240
|
+
payload: videoFragment,
|
|
253
241
|
});
|
|
254
242
|
this.lastFragPostTimestamp = Date.now();
|
|
255
243
|
}
|
|
256
244
|
catch (err) {
|
|
257
245
|
// letting collect know we are closing the rrweb listener
|
|
258
|
-
ClientConfig.getInstance().
|
|
246
|
+
ClientConfig.getInstance().postInternalError({ msg: `video frag socket closed with err: ${err.message}` }, false, SEVERITY.error);
|
|
259
247
|
// if we detect an error in the frag posting, we stop recording
|
|
260
248
|
// the video
|
|
261
249
|
this.freeze();
|
|
@@ -282,7 +270,7 @@ class SessionRecorder {
|
|
|
282
270
|
this.recordStopper();
|
|
283
271
|
}
|
|
284
272
|
catch (e) {
|
|
285
|
-
ClientConfig.getInstance().
|
|
273
|
+
ClientConfig.getInstance().postInternalError({ msg: `Error during handleFragPost in recordStopper: ${e}` }, false, SEVERITY.error);
|
|
286
274
|
}
|
|
287
275
|
}
|
|
288
276
|
}
|
|
@@ -8,9 +8,7 @@ const LINKING_ERROR = `The package 'noibu-session-replay' doesn't seem to be lin
|
|
|
8
8
|
const { NativeSessionRecorder } = NativeModules;
|
|
9
9
|
let nativeModuleEmitter;
|
|
10
10
|
const SupportedPlatforms = ['android'];
|
|
11
|
-
/**
|
|
12
|
-
* The level of logging to show in the device logcat stream.
|
|
13
|
-
*/
|
|
11
|
+
/** The level of logging to show in the device logcat stream. */
|
|
14
12
|
// eslint-disable-next-line no-shadow
|
|
15
13
|
var LogLevel;
|
|
16
14
|
(function (LogLevel) {
|
|
@@ -53,10 +51,10 @@ function initialize(projectId, config) {
|
|
|
53
51
|
* and invokes the provided callback whenever the event occurs. If the platform is not Android,
|
|
54
52
|
* the function will do nothing and return a no-op unsubscribe function.
|
|
55
53
|
*
|
|
56
|
-
* @param {function(RecorderEvent): void} callback -
|
|
54
|
+
* @param {function(RecorderEvent): void} callback - Target callback function that will be invoked with
|
|
57
55
|
* the event data whenever the `noibuRecordingEvent` is emitted.
|
|
58
56
|
*
|
|
59
|
-
* @returns {UnsubscribeFn}
|
|
57
|
+
* @returns {UnsubscribeFn} Target function to unsubscribe from the event. On Android, this will remove
|
|
60
58
|
* the event listener. On other platforms, it will be a no-op.
|
|
61
59
|
*
|
|
62
60
|
* @throws {Error} If the Noibu Session Recorder is not initialized before calling this function.
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
|
-
import StorageProvider from './
|
|
3
|
+
import StorageProvider from './StorageProvider.js';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* React native storage provider implementation
|
|
7
|
-
*/
|
|
5
|
+
/** React native storage provider implementation */
|
|
8
6
|
class RNStorageProvider extends StorageProvider {
|
|
9
|
-
/**
|
|
10
|
-
* Creates new instance
|
|
11
|
-
*/
|
|
7
|
+
/** Creates new instance */
|
|
12
8
|
constructor() {
|
|
13
9
|
super(AsyncStorage);
|
|
14
10
|
}
|
|
@@ -1,41 +1,29 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import RNStorageProvider from './
|
|
2
|
+
import RNStorageProvider from './RNStorageProvider.js';
|
|
3
|
+
import { Singleton } from '../monitors/BaseMonitor.js';
|
|
3
4
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
class Storage {
|
|
8
|
-
/**
|
|
9
|
-
* Creates new instance assessing available options
|
|
10
|
-
*/
|
|
5
|
+
/** Encapsulates storage api */
|
|
6
|
+
class Storage extends Singleton {
|
|
7
|
+
/** Creates new instance assessing available options */
|
|
11
8
|
constructor() {
|
|
9
|
+
super();
|
|
12
10
|
// todo replace with promise all if more storage available
|
|
13
11
|
const rnStorageAvailability = RNStorageProvider.isAvailable();
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Singleton
|
|
21
|
-
* @returns {Storage}
|
|
22
|
-
*/
|
|
23
|
-
static getInstance() {
|
|
24
|
-
if (!this._instance) {
|
|
25
|
-
this._instance = new Storage();
|
|
26
|
-
}
|
|
27
|
-
return this._instance;
|
|
12
|
+
this.provider = rnStorageAvailability.then(({ result }) => (result ? new RNStorageProvider() : null));
|
|
13
|
+
this.type = rnStorageAvailability.then(({ result }) => (result ? 'RNStorage' : 'unavailable'));
|
|
14
|
+
this.isRNStorageAvailable = rnStorageAvailability.then(({ result }) => result);
|
|
15
|
+
this.rnStorageError = rnStorageAvailability.then(({ error }) => error);
|
|
28
16
|
}
|
|
29
17
|
/** Checks if storage is available */
|
|
30
18
|
isAvailable() {
|
|
31
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
return (yield this.
|
|
20
|
+
return (yield this.provider) !== null;
|
|
33
21
|
});
|
|
34
22
|
}
|
|
35
23
|
/** Loads value from storage */
|
|
36
24
|
load(key) {
|
|
37
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
-
const provider = yield this.
|
|
26
|
+
const provider = yield this.provider;
|
|
39
27
|
if (provider !== null) {
|
|
40
28
|
return provider.load(key);
|
|
41
29
|
}
|
|
@@ -45,7 +33,7 @@ class Storage {
|
|
|
45
33
|
/** Saves value to storage */
|
|
46
34
|
save(key, value) {
|
|
47
35
|
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
const provider = yield this.
|
|
36
|
+
const provider = yield this.provider;
|
|
49
37
|
if (provider !== null) {
|
|
50
38
|
return provider.save(key, value);
|
|
51
39
|
}
|
|
@@ -58,7 +46,7 @@ class Storage {
|
|
|
58
46
|
*/
|
|
59
47
|
remove(key) {
|
|
60
48
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
const provider = yield this.
|
|
49
|
+
const provider = yield this.provider;
|
|
62
50
|
if (provider !== null) {
|
|
63
51
|
return provider.remove(key);
|
|
64
52
|
}
|
|
@@ -68,7 +56,7 @@ class Storage {
|
|
|
68
56
|
/** Calculates used scape */
|
|
69
57
|
calculateUsedSize() {
|
|
70
58
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
-
const provider = yield this.
|
|
59
|
+
const provider = yield this.provider;
|
|
72
60
|
if (provider !== null) {
|
|
73
61
|
return provider.calculateUsedSize();
|
|
74
62
|
}
|
|
@@ -82,9 +70,8 @@ class Storage {
|
|
|
82
70
|
*/
|
|
83
71
|
getDiagnoseInfo() {
|
|
84
72
|
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
-
return `storage provider: ${yield this
|
|
86
|
-
.
|
|
87
|
-
._isRNStorageAvailable}, error: ${yield this._rnStorageError})`;
|
|
73
|
+
return `storage provider: ${yield this.type} (rnStorage available: ${yield this
|
|
74
|
+
.isRNStorageAvailable}, error: ${yield this.rnStorageError})`;
|
|
88
75
|
});
|
|
89
76
|
}
|
|
90
77
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import { NOIBU_LOCAL_STORAGE_TEST_KEY } from '../constants.js';
|
|
3
2
|
|
|
3
|
+
// The local storage key used to test whether writing to local storage is supported
|
|
4
|
+
const NOIBU_LOCAL_STORAGE_TEST_KEY = 'n_key';
|
|
4
5
|
/**
|
|
5
6
|
* Base implementation for LocalStorage and SessionStorage
|
|
6
7
|
*/
|
|
7
8
|
class StorageProvider {
|
|
8
9
|
/** Creates new instance based on provided provider type */
|
|
9
10
|
constructor(provider) {
|
|
10
|
-
this.
|
|
11
|
+
this.provider = provider;
|
|
11
12
|
}
|
|
12
13
|
/** Checks if provider is available */
|
|
13
14
|
static isAvailable(resolver) {
|
|
@@ -26,12 +27,10 @@ class StorageProvider {
|
|
|
26
27
|
return { result, error };
|
|
27
28
|
});
|
|
28
29
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Loads value from storage
|
|
31
|
-
*/
|
|
30
|
+
/** Loads value from storage */
|
|
32
31
|
load(key) {
|
|
33
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
-
const value = yield this.
|
|
33
|
+
const value = yield this.provider.getItem(key);
|
|
35
34
|
if (value !== null) {
|
|
36
35
|
return value;
|
|
37
36
|
}
|
|
@@ -40,14 +39,14 @@ class StorageProvider {
|
|
|
40
39
|
}
|
|
41
40
|
/** Saves value to storage */
|
|
42
41
|
save(key, value) {
|
|
43
|
-
return this.
|
|
42
|
+
return this.provider.setItem(key, `${value}`);
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
45
|
* Removes value from storage
|
|
47
46
|
* @param {String} key
|
|
48
47
|
*/
|
|
49
48
|
remove(key) {
|
|
50
|
-
return this.
|
|
49
|
+
return this.provider.removeItem(key);
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
|
package/dist/utils/date.js
CHANGED
|
@@ -1,62 +1,51 @@
|
|
|
1
|
-
import ClientConfig from '../api/
|
|
1
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
2
2
|
import { SEVERITY } from '../constants.js';
|
|
3
3
|
|
|
4
4
|
/** @module Date */
|
|
5
|
-
|
|
6
5
|
/** Checks to see if the necessary Date functions that we use have been overwritten */
|
|
7
6
|
function isDateOverwritten() {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// If none of the above checks return true, we assume that the Date function
|
|
29
|
-
// has not been overwritten
|
|
30
|
-
return false;
|
|
7
|
+
// Check to see if Date.now() exists
|
|
8
|
+
if (!('now' in Date)) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
// Check to ensure that Date.now() returns a number
|
|
12
|
+
if (typeof Date.now() !== 'number') {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
// Check to see if new Date().toISOString() exists
|
|
16
|
+
if (!('toISOString' in new Date())) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
// Check to ensure new Date().toISOString() returns a string
|
|
20
|
+
if (typeof new Date().toISOString() !== 'string') {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
// If none of the above checks return true, we assume that the Date function
|
|
24
|
+
// has not been overwritten
|
|
25
|
+
return false;
|
|
31
26
|
}
|
|
32
|
-
|
|
33
27
|
/** Timestamp wrapper to properly handle timestamps
|
|
34
|
-
* @param {} timestamp
|
|
35
28
|
*/
|
|
36
29
|
function timestampWrapper(timestamp) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
ClientConfig.getInstance().postNoibuErrorAndOptionallyDisableClient(
|
|
51
|
-
`The date object has been overwritten and can't be processed properly.
|
|
30
|
+
var _a;
|
|
31
|
+
// If the Date object has been overwritten and the timestamp is not a number,
|
|
32
|
+
// we use the valueOf property to try to retrieve the actual timestamp.
|
|
33
|
+
// If valueOf is not available, we disable client and log the error.
|
|
34
|
+
if (typeof timestamp === 'object' && isDateOverwritten()) {
|
|
35
|
+
const value = (_a = timestamp === null || timestamp === void 0 ? void 0 : timestamp.valueOf) === null || _a === void 0 ? void 0 : _a.call(timestamp);
|
|
36
|
+
if (typeof value === 'number') {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
ClientConfig.getInstance().postInternalError({
|
|
40
|
+
msg: `The date object has been overwritten and can't be processed properly.
|
|
52
41
|
Client has been disabled.`,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
42
|
+
}, true, SEVERITY.error, true);
|
|
43
|
+
}
|
|
44
|
+
return timestamp;
|
|
45
|
+
}
|
|
46
|
+
/** Get the current time in ISO format */
|
|
47
|
+
function getOccurredNow() {
|
|
48
|
+
return new Date(timestampWrapper(Date.now())).toISOString();
|
|
60
49
|
}
|
|
61
50
|
|
|
62
|
-
export { isDateOverwritten, timestampWrapper };
|
|
51
|
+
export { getOccurredNow, isDateOverwritten, timestampWrapper };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SEVERITY } from '../constants.js';
|
|
2
|
-
import ClientConfig from '../api/
|
|
2
|
+
import ClientConfig from '../api/ClientConfig.js';
|
|
3
3
|
|
|
4
4
|
/** addSafeEventListener will add an event listener for the specified event
|
|
5
5
|
* but will catch and log any errors encountered
|
|
@@ -21,7 +21,7 @@ function addSafeEventListener(object, event, callback, capture = false) {
|
|
|
21
21
|
try {
|
|
22
22
|
callback(eventReceived);
|
|
23
23
|
} catch (e) {
|
|
24
|
-
ClientConfig.getInstance().
|
|
24
|
+
ClientConfig.getInstance().postInternalError(
|
|
25
25
|
`addEventListener callback error: ${e.message}`,
|
|
26
26
|
false,
|
|
27
27
|
SEVERITY.error,
|
|
@@ -29,17 +29,14 @@ function addSafeEventListener(object, event, callback, capture = false) {
|
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
* tries to add an event listener to a Proxy object
|
|
34
|
-
*/
|
|
32
|
+
/** tries to add an event listener to a Proxy object */
|
|
35
33
|
const tryAddEventListenerForProxy = () => {
|
|
36
34
|
if (!Reflect) {
|
|
37
35
|
return false;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
try {
|
|
41
|
-
const addEventListener =
|
|
42
|
-
Reflect.get(object, 'addEventListener') || (() => {});
|
|
39
|
+
const addEventListener = Reflect.get(object, 'addEventListener') || (() => {});
|
|
43
40
|
addEventListener(event, safeCallback, capture);
|
|
44
41
|
} catch (e) {
|
|
45
42
|
return false;
|
|
@@ -56,11 +53,7 @@ function addSafeEventListener(object, event, callback, capture = false) {
|
|
|
56
53
|
return;
|
|
57
54
|
}
|
|
58
55
|
}
|
|
59
|
-
ClientConfig.getInstance().
|
|
60
|
-
`addEventListener error: ${e.message}`,
|
|
61
|
-
false,
|
|
62
|
-
SEVERITY.error,
|
|
63
|
-
);
|
|
56
|
+
ClientConfig.getInstance().postInternalError(`addEventListener error: ${e.message}`, false, SEVERITY.error);
|
|
64
57
|
}
|
|
65
58
|
}
|
|
66
59
|
|