noibu-react-native 0.2.18 → 0.2.20
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/CHANGELOG.md +14 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayModule.kt +15 -77
- package/dist/api/ClientConfig.js +1 -1
- package/dist/api/MetroplexSocket.d.ts +1 -1
- package/dist/api/MetroplexSocket.js +2 -6
- package/dist/api/StoredMetrics.js +2 -2
- package/dist/constants.js +1 -1
- package/dist/entry/init.js +1 -1
- package/dist/mobileTransformer/mobile-replay/index.js +16 -2
- package/dist/mobileTransformer/mobile-replay/mobile.types.d.ts +7 -0
- package/dist/mobileTransformer/mobile-replay/schema/mobile/rr-mobile-schema.json.js +12 -0
- package/dist/mobileTransformer/mobile-replay/transformer/screen-chrome.js +1 -1
- package/dist/mobileTransformer/mobile-replay/transformer/transformers.d.ts +1 -0
- package/dist/mobileTransformer/mobile-replay/transformer/transformers.js +18 -8
- package/dist/mobileTransformer/mobile-replay/transformer/webview-transformer.d.ts +9 -0
- package/dist/mobileTransformer/mobile-replay/transformer/webview-transformer.js +124 -0
- package/dist/monitors/ErrorMonitor.js +1 -1
- package/dist/monitors/KeyboardInputMonitor.js +1 -1
- package/dist/pageVisit/HttpEventManager.js +2 -2
- package/dist/pageVisit/pageVisitEventError.js +1 -1
- package/dist/sessionRecorder/SessionRecorder.d.ts +0 -4
- package/dist/sessionRecorder/SessionRecorder.js +4 -28
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.d.ts +1 -22
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +17 -18
- package/dist/sessionRecorder/types.d.ts +1 -88
- package/package.json +3 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes of the noibu-react-native SDK release series are documented in this file using
|
|
4
4
|
the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
|
|
5
5
|
|
|
6
|
+
## 0.2.20
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- ** ANDROID: WebView replay support (mobile transformer)**
|
|
10
|
+
- Integrates a WebView-specific transformer to convert rrweb full/incremental snapshots from WebViews into web events.
|
|
11
|
+
- Snapshots generated during transformation are now included at the top level of the transformed output, emitted immediately after the event that produced them.
|
|
12
|
+
- **Live subscription emits multiple events when applicable**
|
|
13
|
+
- The native subscription path now routes events through `transformToWeb`, allowing multiple transformed events (e.g., WebView snapshots) to be emitted per native event.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **`transformToWeb`** now drains a small internal buffer of WebView snapshots produced during transformation and appends them to the resulting array in order.
|
|
17
|
+
- **`nativeSessionRecorderSubscription`** (Android and iOS) now uses `transformToWeb([event])` and forwards each resulting event via the provided callback.
|
|
18
|
+
|
|
19
|
+
|
|
6
20
|
## 0.2.13
|
|
7
21
|
|
|
8
22
|
### Alpha support for iOS Session Replay in React Native
|
package/android/build.gradle
CHANGED
|
@@ -67,7 +67,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
|
67
67
|
dependencies {
|
|
68
68
|
implementation "com.facebook.react:react-native:+"
|
|
69
69
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
70
|
-
implementation "com.noibu:sessionreplay-recorder:0.
|
|
70
|
+
implementation "com.noibu:sessionreplay-recorder:1.0.1"
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
if (isNewArchitectureEnabled()) {
|
|
@@ -76,4 +76,4 @@ if (isNewArchitectureEnabled()) {
|
|
|
76
76
|
libraryName = "noibusessionreplay"
|
|
77
77
|
codegenJavaPackageName = "com.noibu.sessionreplay.reactnative"
|
|
78
78
|
}
|
|
79
|
-
}
|
|
79
|
+
}
|
package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayModule.kt
CHANGED
|
@@ -6,11 +6,9 @@ import android.util.Log
|
|
|
6
6
|
import com.facebook.react.bridge.*
|
|
7
7
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
import com.noibu.sessionreplay.
|
|
11
|
-
import com.noibu.sessionreplay.
|
|
12
|
-
|
|
13
|
-
import com.noibu.sessionreplay.SessionReplay
|
|
9
|
+
// Update the import statements to point to the KMP shared module's package
|
|
10
|
+
import com.noibu.mobile.android.sessionreplay.Noibu
|
|
11
|
+
import com.noibu.mobile.android.sessionreplay.NoibuConfig
|
|
14
12
|
|
|
15
13
|
class NoibuSessionReplayModule(reactContext: ReactApplicationContext) :
|
|
16
14
|
ReactContextBaseJavaModule(reactContext) {
|
|
@@ -28,79 +26,19 @@ class NoibuSessionReplayModule(reactContext: ReactApplicationContext) :
|
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
@ReactMethod
|
|
31
|
-
fun initialize(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
enableWebViewCapture: Boolean,
|
|
37
|
-
allowedDomains: ReadableArray,
|
|
38
|
-
disableOnLowEndDevices: Boolean,
|
|
39
|
-
enableDailyNetworkUsageLimit: Boolean,
|
|
40
|
-
maximumDailyNetworkUsageInMB: Double,
|
|
41
|
-
promise: Promise
|
|
42
|
-
) {
|
|
43
|
-
val allowedActivities = listOf<String>(); // not supported
|
|
44
|
-
val disallowedActivities = listOf<String>(); // not supported
|
|
45
|
-
|
|
46
|
-
// We use two parameters because the react method parameters do not accept nullable primitive types.
|
|
47
|
-
// Moreover, the Long data type is not supported. Js numbers are translated into doubles.
|
|
48
|
-
val maximumDailyNetworkUsageInMBLong =
|
|
49
|
-
if (enableDailyNetworkUsageLimit) maximumDailyNetworkUsageInMB.toLong() else null
|
|
50
|
-
|
|
51
|
-
val config = SessionReplayConfig(
|
|
52
|
-
projectId,
|
|
53
|
-
userId,
|
|
54
|
-
LogLevel.valueOf(logLevel),
|
|
55
|
-
allowMeteredNetworkUsage,
|
|
56
|
-
enableWebViewCapture,
|
|
57
|
-
readableArrayToList(allowedDomains),
|
|
58
|
-
ApplicationFramework.ReactNative,
|
|
59
|
-
allowedActivities,
|
|
60
|
-
disallowedActivities,
|
|
61
|
-
disableOnLowEndDevices,
|
|
62
|
-
maximumDailyNetworkUsageInMBLong
|
|
29
|
+
fun initialize( promise: Promise ) {
|
|
30
|
+
val context = currentActivity?.applicationContext ?: reactContext?.applicationContext ?: return
|
|
31
|
+
val config = NoibuConfig(
|
|
32
|
+
sessionReplayEnabled = true,
|
|
33
|
+
maskAllTextInputs = false,
|
|
63
34
|
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
promise.resolve(
|
|
71
|
-
SessionReplay.initialize(
|
|
72
|
-
context,
|
|
73
|
-
config,
|
|
74
|
-
currentActivity
|
|
75
|
-
) { param ->
|
|
76
|
-
Handler(Looper.getMainLooper()).post {
|
|
77
|
-
val params = Arguments.createMap()
|
|
78
|
-
params.putString("message", param)
|
|
79
|
-
sendEvent("noibuRecordingEvent", params)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
)
|
|
35
|
+
Noibu.setup(context, config){ param ->
|
|
36
|
+
val params = Arguments.createMap()
|
|
37
|
+
params.putString("message", param)
|
|
38
|
+
sendEvent("noibuRecordingEvent", params)
|
|
39
|
+
true
|
|
83
40
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@ReactMethod
|
|
87
|
-
fun setCustomUserId(customUserId: String, promise: Promise) {
|
|
88
|
-
promise.resolve(SessionReplay.setCustomUserId(customUserId))
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
@ReactMethod
|
|
92
|
-
fun setCustomSessionId(customSessionId: String, promise: Promise) {
|
|
93
|
-
promise.resolve(SessionReplay.setCustomSessionId(customSessionId))
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private fun readableArrayToList(arr: ReadableArray): List<String> {
|
|
97
|
-
val ret = mutableListOf<String>()
|
|
98
|
-
|
|
99
|
-
for (i in 0 until arr.size()) {
|
|
100
|
-
ret.add(arr.getString(i))
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return ret
|
|
41
|
+
promise.resolve(true)
|
|
104
42
|
}
|
|
105
43
|
|
|
106
44
|
@ReactMethod
|
|
@@ -117,4 +55,4 @@ class NoibuSessionReplayModule(reactContext: ReactApplicationContext) :
|
|
|
117
55
|
const val NAME = "NativeSessionRecorder"
|
|
118
56
|
private var reactContext: ReactApplicationContext? = null
|
|
119
57
|
}
|
|
120
|
-
}
|
|
58
|
+
}
|
package/dist/api/ClientConfig.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import uuid from 'react-native-uuid';
|
|
3
3
|
import { Severity } from 'noibu-metroplex-ts-bindings';
|
|
4
|
-
import { MAX_METROPLEX_SOCKET_INNACTIVE_TIME,
|
|
4
|
+
import { MAX_METROPLEX_SOCKET_INNACTIVE_TIME, GET_DEVICE_ENV, GET_SCRIPT_ID } from '../constants.js';
|
|
5
5
|
import { stringifyJSON, getMaxSubstringAllowed, getUserAgent, postRequest } from '../utils/function.js';
|
|
6
6
|
import Storage from '../storage/Storage.js';
|
|
7
7
|
import { noibuLog } from '../utils/log.js';
|
|
@@ -4,7 +4,7 @@ import { NoSeqNumSlidingMessage, RetryQueueWSMessage } from '../types/Metroplex'
|
|
|
4
4
|
/**
|
|
5
5
|
* Grab the video recorder type based on the device we run the app on.
|
|
6
6
|
*/
|
|
7
|
-
export declare function getVideoRecorderType(): Promise<VideoRecorder.RRWeb
|
|
7
|
+
export declare function getVideoRecorderType(): Promise<VideoRecorder.RRWeb>;
|
|
8
8
|
/**
|
|
9
9
|
* Implements rolling window of specified size,
|
|
10
10
|
* but only makes a cut once array length exceeds 150%.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
2
|
import uuid from 'react-native-uuid';
|
|
3
|
-
import {
|
|
4
|
-
import { MetroplexRoute, MetroplexMessageType, WorkRequestMessageType, EventType, Severity, InboundMessageType } from 'noibu-metroplex-ts-bindings';
|
|
3
|
+
import { MetroplexRoute, WorkRequestMessageType, MetroplexMessageType, EventType, Severity, InboundMessageType } from 'noibu-metroplex-ts-bindings';
|
|
5
4
|
import { getUserAgent, stringifyJSON } from '../utils/function.js';
|
|
6
5
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
7
|
-
import { GET_METROPLEX_BASE_SOCKET_URL, GET_METROPLEX_POST_URL, GET_MAX_METROPLEX_RECONNECTION_NUMBER, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, MAX_BEACON_PAYLOAD_SIZE,
|
|
6
|
+
import { GET_METROPLEX_BASE_SOCKET_URL, GET_METROPLEX_POST_URL, GET_MAX_METROPLEX_RECONNECTION_NUMBER, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, MAX_BEACON_PAYLOAD_SIZE, GET_SCRIPT_ID, CURRENT_NOIBUJS_VERSION } from '../constants.js';
|
|
8
7
|
import ClientConfig from './ClientConfig.js';
|
|
9
8
|
import StoredMetrics from './StoredMetrics.js';
|
|
10
9
|
import StoredPageVisit from './StoredPageVisit.js';
|
|
@@ -19,9 +18,6 @@ import { Singleton } from '../monitors/BaseMonitor.js';
|
|
|
19
18
|
*/
|
|
20
19
|
function getVideoRecorderType() {
|
|
21
20
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
if (Platform.OS === 'android') {
|
|
23
|
-
return 'AndroidNative';
|
|
24
|
-
}
|
|
25
21
|
return 'RRWeb'; // should never happen
|
|
26
22
|
});
|
|
27
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import {
|
|
2
|
+
import { GET_METROPLEX_METRICS_URL, CURRENT_NOIBUJS_VERSION } from '../constants.js';
|
|
3
3
|
import ClientConfig from './ClientConfig.js';
|
|
4
|
-
import {
|
|
4
|
+
import { stringifyJSON, getUserAgent } from '../utils/function.js';
|
|
5
5
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
6
6
|
import { unwrapNoibuWrapped } from '../utils/object.js';
|
|
7
7
|
import { Singleton } from '../monitors/BaseMonitor.js';
|
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.
|
|
27
|
+
return "1.0.104-rn-sdk-0.2.20" ;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Gets the max metro recon number
|
package/dist/entry/init.js
CHANGED
|
@@ -3,7 +3,7 @@ import uuid from 'react-native-uuid';
|
|
|
3
3
|
import { MetroplexRoute, Severity } from 'noibu-metroplex-ts-bindings';
|
|
4
4
|
import { KeyboardInputMonitor } from '../monitors/KeyboardInputMonitor.js';
|
|
5
5
|
import { PageMonitor } from '../monitors/PageMonitor.js';
|
|
6
|
-
import {
|
|
6
|
+
import { GET_METROPLEX_BASE_HTTP_URL, GET_METROPLEX_BASE_SOCKET_URL } from '../constants.js';
|
|
7
7
|
import ClientConfig from '../api/ClientConfig.js';
|
|
8
8
|
import { isNoibuJSAlreadyLoaded } from '../utils/function.js';
|
|
9
9
|
import { PageVisitManager } from '../pageVisit/PageVisitManager.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Ajv from 'ajv';
|
|
2
2
|
import mobileSchema from './schema/mobile/rr-mobile-schema.json.js';
|
|
3
3
|
import webSchema from './schema/web/rr-web-schema.json.js';
|
|
4
|
-
import {
|
|
4
|
+
import { _drainWebViewSnapshots, makeCustomEvent, makeMetaEvent, makeIncrementalEvent, makeFullEvent } from './transformer/transformers.js';
|
|
5
5
|
|
|
6
6
|
//import { captureException, captureMessage } from '@sentry/react'
|
|
7
7
|
//@ts-ignore
|
|
@@ -41,6 +41,20 @@ function transformEventToWeb(event, validateTransformation) {
|
|
|
41
41
|
}
|
|
42
42
|
return event;
|
|
43
43
|
}
|
|
44
|
+
function transformToWeb(mobileData) {
|
|
45
|
+
return mobileData.reduce((acc, event) => {
|
|
46
|
+
const transformed = transformEventToWeb(event);
|
|
47
|
+
const finalEvent = transformed ? transformed : event;
|
|
48
|
+
acc.push(finalEvent);
|
|
49
|
+
// Append any snapshots generated during this event's transformation
|
|
50
|
+
const snapshots = _drainWebViewSnapshots();
|
|
51
|
+
if (snapshots.length > 0) {
|
|
52
|
+
// Ensure snapshots have required fields; push as-is to preserve timestamps/order
|
|
53
|
+
snapshots.forEach((s) => acc.push(s));
|
|
54
|
+
}
|
|
55
|
+
return acc;
|
|
56
|
+
}, []);
|
|
57
|
+
}
|
|
44
58
|
function validateAgainstWebSchema(data) {
|
|
45
59
|
const validationResult = webSchemaValidator(data);
|
|
46
60
|
if (!validationResult) {
|
|
@@ -54,4 +68,4 @@ function validateAgainstWebSchema(data) {
|
|
|
54
68
|
return validationResult;
|
|
55
69
|
}
|
|
56
70
|
|
|
57
|
-
export { transformEventToWeb, validateAgainstWebSchema };
|
|
71
|
+
export { transformEventToWeb, transformToWeb, validateAgainstWebSchema };
|
|
@@ -216,6 +216,13 @@ export type wireframeRectangle = wireframeBase & {
|
|
|
216
216
|
export type wireframeWebView = wireframeBase & {
|
|
217
217
|
type: 'web_view';
|
|
218
218
|
url?: string;
|
|
219
|
+
/**
|
|
220
|
+
* @description Contains the rrweb meta and full snapshot events for the webview content, as a JSON string.
|
|
221
|
+
* The string is an array of two events: [metaEvent, fullSnapshotEvent].
|
|
222
|
+
*/
|
|
223
|
+
rrwebFullSnapshot: {
|
|
224
|
+
node: any[];
|
|
225
|
+
};
|
|
219
226
|
};
|
|
220
227
|
export type wireframePlaceholder = wireframeBase & {
|
|
221
228
|
type: 'placeholder';
|
|
@@ -1539,6 +1539,18 @@ var definitions = {
|
|
|
1539
1539
|
},
|
|
1540
1540
|
y: {
|
|
1541
1541
|
type: "number"
|
|
1542
|
+
},
|
|
1543
|
+
rrwebFullSnapshot: {
|
|
1544
|
+
description: "Contains the rrweb meta and full snapshot events for the webview content, as a JSON string. The string is an array of two events: [metaEvent, fullSnapshotEvent].",
|
|
1545
|
+
type: "object",
|
|
1546
|
+
properties: {
|
|
1547
|
+
node: {
|
|
1548
|
+
type: "string"
|
|
1549
|
+
}
|
|
1550
|
+
},
|
|
1551
|
+
required: [
|
|
1552
|
+
"node"
|
|
1553
|
+
]
|
|
1542
1554
|
}
|
|
1543
1555
|
},
|
|
1544
1556
|
required: [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NodeType } from '../mobile.types.js';
|
|
2
2
|
import { isLight } from './colors.js';
|
|
3
|
-
import { _isPositiveInteger, makePlaceholderElement,
|
|
3
|
+
import { _isPositiveInteger, makePlaceholderElement, NAVIGATION_BAR_ID, STATUS_BAR_ID, BACKGROUND, KEYBOARD_ID } from './transformers.js';
|
|
4
4
|
import { asStyleString, makeStylesString } from './wireframeStyle.js';
|
|
5
5
|
|
|
6
6
|
let navigationBackgroundColor = undefined;
|
|
@@ -2,6 +2,7 @@ import { customEvent, fullSnapshotEvent, incrementalSnapshotEvent, metaEvent } f
|
|
|
2
2
|
import { fullSnapshotEvent as MobileFullSnapshotEvent, keyboardEvent, metaEvent as MobileMetaEvent, MobileIncrementalSnapshotEvent, serializedNodeWithId, wireframe, wireframeDiv, wireframeNavigationBar, wireframeStatusBar } from '../mobile.types';
|
|
3
3
|
import { ConversionContext, ConversionResult } from './types';
|
|
4
4
|
export declare const BACKGROUND = "#f3f4ef";
|
|
5
|
+
export declare function _drainWebViewSnapshots(): any[];
|
|
5
6
|
export declare const NAVIGATION_BAR_ID = 8;
|
|
6
7
|
export declare const KEYBOARD_ID = 10;
|
|
7
8
|
export declare const STATUS_BAR_PARENT_ID = 11;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EventType, IncrementalSource } from '../rrweb.js';
|
|
2
2
|
import { isObject } from '../../utils.js';
|
|
3
3
|
import { NodeType } from '../mobile.types.js';
|
|
4
|
-
import { makeOpenKeyboardPlaceholder,
|
|
5
|
-
import {
|
|
4
|
+
import { makeOpenKeyboardPlaceholder, makeNavigationBar, makeStatusBar } from './screen-chrome.js';
|
|
5
|
+
import { makeBodyStyles, makeHTMLStyles, makeStylesString, asStyleString, makeDeterminateProgressStyles, makeIndeterminateProgressStyles, makeMinimalStyles, makePositionStyles, makeColorStyles } from './wireframeStyle.js';
|
|
6
|
+
import { transform } from './webview-transformer.js';
|
|
6
7
|
|
|
7
8
|
const BACKGROUND = '#f3f4ef';
|
|
8
9
|
const FOREGROUND = '#35373e';
|
|
10
|
+
// Buffer to collect snapshots generated during element transformations (e.g., WebView)
|
|
11
|
+
// These are later drained and appended to the top-level transformed JSON.
|
|
12
|
+
let __pendingWebViewSnapshots = [];
|
|
13
|
+
function _drainWebViewSnapshots() {
|
|
14
|
+
const out = __pendingWebViewSnapshots;
|
|
15
|
+
__pendingWebViewSnapshots = [];
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
9
18
|
/**
|
|
10
19
|
* generates a sequence of ids
|
|
11
20
|
* from 100 to 9,999,999
|
|
@@ -183,11 +192,12 @@ function makeTextElement(wireframe, children, context) {
|
|
|
183
192
|
};
|
|
184
193
|
}
|
|
185
194
|
function makeWebViewElement(wireframe, children, context) {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
195
|
+
const webViewWireframe = wireframe;
|
|
196
|
+
const { frame, snapshots } = transform(webViewWireframe);
|
|
197
|
+
if (Array.isArray(snapshots) && snapshots.length > 0) {
|
|
198
|
+
__pendingWebViewSnapshots.push(...snapshots);
|
|
189
199
|
}
|
|
190
|
-
return
|
|
200
|
+
return { result: frame, context };
|
|
191
201
|
}
|
|
192
202
|
function makePlaceholderElement(wireframe, children, context) {
|
|
193
203
|
var _a, _b;
|
|
@@ -1151,4 +1161,4 @@ function makeCSSReset(context) {
|
|
|
1151
1161
|
};
|
|
1152
1162
|
}
|
|
1153
1163
|
|
|
1154
|
-
export { BACKGROUND, KEYBOARD_ID, NAVIGATION_BAR_ID, STATUS_BAR_ID, STATUS_BAR_PARENT_ID, _isPositiveInteger, dataURIOrPNG, makeCustomEvent, makeDivElement, makeFullEvent, makeIncrementalEvent, makeMetaEvent, makePlaceholderElement, stripBarsFromWireframes };
|
|
1164
|
+
export { BACKGROUND, KEYBOARD_ID, NAVIGATION_BAR_ID, STATUS_BAR_ID, STATUS_BAR_PARENT_ID, _drainWebViewSnapshots, _isPositiveInteger, dataURIOrPNG, makeCustomEvent, makeDivElement, makeFullEvent, makeIncrementalEvent, makeMetaEvent, makePlaceholderElement, stripBarsFromWireframes };
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
function transform(webView) {
|
|
2
|
+
const frameId = 999999999;
|
|
3
|
+
const rootId = frameId + 1;
|
|
4
|
+
const result = { frame: null, snapshots: [] };
|
|
5
|
+
try {
|
|
6
|
+
const snapshots = webView.rrwebFullSnapshot.node;
|
|
7
|
+
const fullSnapshotIndex = snapshots.findIndex((event) => event.type === 2);
|
|
8
|
+
const fullSnapshot = snapshots[fullSnapshotIndex];
|
|
9
|
+
const incrementalSnapshots = snapshots.filter((snapshot, index) => snapshot.type === 3 && index > fullSnapshotIndex);
|
|
10
|
+
const syntheticSnapshot = createSyntheticSnapshot(fullSnapshot, frameId, rootId);
|
|
11
|
+
incrementalSnapshots.forEach((snapshot) => patchIncrementalSnapshot(snapshot, rootId));
|
|
12
|
+
result.frame = createFrameNode(frameId);
|
|
13
|
+
;
|
|
14
|
+
result.snapshots.push(syntheticSnapshot, ...incrementalSnapshots);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
console.error(error);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function createSyntheticSnapshot(snapshot, frameId, rootId) {
|
|
22
|
+
const childNodes = snapshot.data.node.childNodes;
|
|
23
|
+
const htmlNodeIndex = childNodes.findIndex((node) => node.type === 2 && node.tagName === "html");
|
|
24
|
+
const htmlNode = childNodes[htmlNodeIndex];
|
|
25
|
+
patch(htmlNode);
|
|
26
|
+
return {
|
|
27
|
+
type: 3,
|
|
28
|
+
data: {
|
|
29
|
+
source: 0,
|
|
30
|
+
adds: [
|
|
31
|
+
{
|
|
32
|
+
parentId: frameId,
|
|
33
|
+
nextId: null,
|
|
34
|
+
node: {
|
|
35
|
+
type: 0,
|
|
36
|
+
childNodes: [htmlNode],
|
|
37
|
+
id: rootId,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
removes: [],
|
|
42
|
+
texts: [],
|
|
43
|
+
attributes: [],
|
|
44
|
+
isAttachIframe: true,
|
|
45
|
+
},
|
|
46
|
+
timestamp: snapshot.timestamp,
|
|
47
|
+
};
|
|
48
|
+
function patch(node) {
|
|
49
|
+
node.rootId = rootId;
|
|
50
|
+
if (node.id) {
|
|
51
|
+
node.id = rootId + node.id;
|
|
52
|
+
}
|
|
53
|
+
if (node.childNodes) {
|
|
54
|
+
node.childNodes.forEach(patch);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function patchIncrementalSnapshot(snapshot, rootId) {
|
|
59
|
+
const { data } = snapshot;
|
|
60
|
+
const { adds, removes, attributes, positions } = data;
|
|
61
|
+
if (data.id) {
|
|
62
|
+
data.id = rootId + data.id;
|
|
63
|
+
}
|
|
64
|
+
if (adds === null || adds === void 0 ? void 0 : adds.length) {
|
|
65
|
+
adds.forEach(patchAdd);
|
|
66
|
+
}
|
|
67
|
+
if (removes === null || removes === void 0 ? void 0 : removes.length) {
|
|
68
|
+
removes.forEach(patchRemove);
|
|
69
|
+
}
|
|
70
|
+
if (attributes === null || attributes === void 0 ? void 0 : attributes.length) {
|
|
71
|
+
attributes.forEach(patchAttribute);
|
|
72
|
+
}
|
|
73
|
+
if (positions === null || positions === void 0 ? void 0 : positions.length) {
|
|
74
|
+
positions.forEach(patchAttribute);
|
|
75
|
+
}
|
|
76
|
+
function patchNode(node) {
|
|
77
|
+
if (node.id) {
|
|
78
|
+
node.id = rootId + node.id;
|
|
79
|
+
}
|
|
80
|
+
if (node.rootId) {
|
|
81
|
+
node.rootId = rootId + node.rootId;
|
|
82
|
+
}
|
|
83
|
+
if (node.childNodes) {
|
|
84
|
+
node.childNodes.forEach(patchNode);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function patchAdd(add) {
|
|
88
|
+
if (add.parentId) {
|
|
89
|
+
add.parentId = rootId + add.parentId;
|
|
90
|
+
}
|
|
91
|
+
if (add.nextId) {
|
|
92
|
+
add.nextId = rootId + add.nextId;
|
|
93
|
+
}
|
|
94
|
+
if (add.node) {
|
|
95
|
+
patchNode(add.node);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function patchRemove(remove) {
|
|
99
|
+
if (remove.parentId) {
|
|
100
|
+
remove.parentId = rootId + remove.parentId;
|
|
101
|
+
}
|
|
102
|
+
if (remove.id) {
|
|
103
|
+
remove.id = rootId + remove.id;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function patchAttribute(attribute) {
|
|
107
|
+
if (attribute.id) {
|
|
108
|
+
attribute.id = rootId + attribute.id;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function createFrameNode(id) {
|
|
113
|
+
return {
|
|
114
|
+
type: 2,
|
|
115
|
+
tagName: "iframe",
|
|
116
|
+
attributes: {
|
|
117
|
+
style: "width: 100%; height: 100%;"
|
|
118
|
+
},
|
|
119
|
+
childNodes: [],
|
|
120
|
+
id: id,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export { transform };
|
|
@@ -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';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventDebouncer } from '../pageVisit/EventDebouncer.js';
|
|
2
2
|
import { TextInput } from 'react-native';
|
|
3
3
|
import { Singleton } from './BaseMonitor.js';
|
|
4
|
-
import {
|
|
4
|
+
import { UserStepType, EventType } from 'noibu-metroplex-ts-bindings';
|
|
5
5
|
|
|
6
6
|
/** @module KeyboardInputMonitor */
|
|
7
7
|
/**
|
|
@@ -8,9 +8,9 @@ import { MetroplexMessageType, EventType } from 'noibu-metroplex-ts-bindings';
|
|
|
8
8
|
/** @module PageVisitEventHTTP */
|
|
9
9
|
/** http event manager */
|
|
10
10
|
// maximum number of HTTP data events including errors to collect per page visit
|
|
11
|
-
const MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT =
|
|
11
|
+
const MAX_HTTP_DATA_IF_ERROR_EVENT_COUNT = 5000;
|
|
12
12
|
// maximum number of HTTP data events to collect per page visit
|
|
13
|
-
const MAX_HTTP_DATA_EVENT_COUNT =
|
|
13
|
+
const MAX_HTTP_DATA_EVENT_COUNT = 5000;
|
|
14
14
|
/** if no value or it's less than 0, fallback to 0 */
|
|
15
15
|
const validate = (value) => (!value || value < 0 ? 0 : value);
|
|
16
16
|
/** Saves the HTTP event to the pageVisit Queue */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import { isValidURL,
|
|
2
|
+
import { isValidURL, stringifyJSON, getMaxSubstringAllowed, getJSStack, asString } from '../utils/function.js';
|
|
3
3
|
import ClientConfig from '../api/ClientConfig.js';
|
|
4
4
|
import StoredMetrics from '../api/StoredMetrics.js';
|
|
5
5
|
import { EventDebouncer } from './EventDebouncer.js';
|
|
@@ -27,10 +27,6 @@ export default class SessionRecorder extends Singleton {
|
|
|
27
27
|
* of the buffer if it exceeds max size
|
|
28
28
|
*/
|
|
29
29
|
handleRecorderEvent(recorderEvent: RecorderEvent): Promise<void>;
|
|
30
|
-
/** Compress event */
|
|
31
|
-
private pack;
|
|
32
|
-
/** Compresses the snapshot */
|
|
33
|
-
private static compress;
|
|
34
30
|
/** builds a log message with debug info */
|
|
35
31
|
buildDebugMessage(eventName: string, totalVideoTime: number, sessionLength: number): string;
|
|
36
32
|
/**
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { __awaiter } from 'tslib';
|
|
2
|
-
import {
|
|
3
|
-
import { LogLevel, initialize, subscribeToNativeEvent } from './nativeSessionRecorderSubscription.js';
|
|
2
|
+
import { initialize, subscribeToNativeEvent } from './nativeSessionRecorderSubscription.js';
|
|
4
3
|
import StoredMetrics from '../api/StoredMetrics.js';
|
|
5
4
|
import ClientConfig from '../api/ClientConfig.js';
|
|
6
5
|
import { stringifyJSON } from '../utils/function.js';
|
|
@@ -8,7 +7,6 @@ import { MAX_TIME_FOR_UNSENT_DATA_MILLIS } from '../constants.js';
|
|
|
8
7
|
import MetroplexSocket from '../api/MetroplexSocket.js';
|
|
9
8
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
10
9
|
import { noibuLog } from '../utils/log.js';
|
|
11
|
-
import { Platform } from 'react-native';
|
|
12
10
|
import { Singleton } from '../monitors/BaseMonitor.js';
|
|
13
11
|
import { Severity, MetroplexMessageType } from 'noibu-metroplex-ts-bindings';
|
|
14
12
|
|
|
@@ -36,10 +34,7 @@ class SessionRecorder extends Singleton {
|
|
|
36
34
|
this.freezingEvents = false;
|
|
37
35
|
this.setupUnloadHandler();
|
|
38
36
|
this.setupPostMetricsHandler();
|
|
39
|
-
|
|
40
|
-
logLevel: LogLevel.Verbose,
|
|
41
|
-
};
|
|
42
|
-
initialize('abc1234', nativeSessionRecorderConfig);
|
|
37
|
+
initialize();
|
|
43
38
|
addSafeEventListener(window, 'click', () => this.handleFragPost());
|
|
44
39
|
}
|
|
45
40
|
/** Sets up the page hide handler to try to push remaining video events */
|
|
@@ -147,9 +142,9 @@ class SessionRecorder extends Singleton {
|
|
|
147
142
|
ClientConfig.getInstance().postInternalError({ msg: `Detected time rewind. Client has been disabled.` }, true, Severity.ERROR, true);
|
|
148
143
|
return;
|
|
149
144
|
}
|
|
150
|
-
|
|
145
|
+
//
|
|
151
146
|
// Buffer the event for sending to metroplex
|
|
152
|
-
this.eventBuffer.push(
|
|
147
|
+
this.eventBuffer.push(recorderEvent.message);
|
|
153
148
|
// Check if the event was a click or a double click. This is true if the root type is
|
|
154
149
|
// incremental snapshot (3) and the data source is mouse interaction data (2).
|
|
155
150
|
// Finally, we capture a click (2) or double click (4) event.
|
|
@@ -161,25 +156,6 @@ class SessionRecorder extends Singleton {
|
|
|
161
156
|
}
|
|
162
157
|
});
|
|
163
158
|
}
|
|
164
|
-
/** Compress event */
|
|
165
|
-
pack(recorderEvent) {
|
|
166
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
167
|
-
// return JSON.stringify(recorderEvent);
|
|
168
|
-
if (Platform.OS === 'ios') {
|
|
169
|
-
return recorderEvent;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
return SessionRecorder.compress(recorderEvent);
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
/** Compresses the snapshot */
|
|
177
|
-
static compress(snapshot) {
|
|
178
|
-
const uncompressedString = stringifyJSON(snapshot);
|
|
179
|
-
const uncompressedData = strToU8(uncompressedString);
|
|
180
|
-
const compressedData = zlibSync(uncompressedData, { level: 1 });
|
|
181
|
-
return strFromU8(compressedData, true);
|
|
182
|
-
}
|
|
183
159
|
/** builds a log message with debug info */
|
|
184
160
|
buildDebugMessage(eventName, totalVideoTime, sessionLength) {
|
|
185
161
|
return JSON.stringify({ eventName, totalVideoTime, sessionLength });
|
|
@@ -34,29 +34,8 @@ export interface SessionRecorderConfig {
|
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Initializes the Noibu - Session recording SDK if the API level is supported.
|
|
37
|
-
* param projectId [REQUIRED] The session recording project id to send data to.
|
|
38
|
-
* param config [OPTIONAL] The sessionreplay config, if not provided default values are used.
|
|
39
37
|
*/
|
|
40
|
-
export declare function initialize(
|
|
41
|
-
/**
|
|
42
|
-
* Sets a custom user id that can be used to identify the user. It has less
|
|
43
|
-
* restrictions than the userId parameter. You can pass any string and
|
|
44
|
-
* you can filter on it on the dashboard side. If you need the most efficient
|
|
45
|
-
* filtering on the dashboard, use the userId parameter if possible.
|
|
46
|
-
* <p>
|
|
47
|
-
* Note: custom user id cannot be null or empty, or consists only of whitespaces.
|
|
48
|
-
* </p>
|
|
49
|
-
* @param customUserId The custom user id to set.
|
|
50
|
-
*/
|
|
51
|
-
export declare function setCustomUserId(customUserId: string): void;
|
|
52
|
-
/**
|
|
53
|
-
* Sets a custom session id that can be used to identify the session.
|
|
54
|
-
* <p>
|
|
55
|
-
* Note: custom session id cannot be null or empty, or consists only of whitespaces.
|
|
56
|
-
* </p>
|
|
57
|
-
* @param customSessionId The custom session id to set.
|
|
58
|
-
*/
|
|
59
|
-
export declare function setCustomSessionId(customSessionId: string): void;
|
|
38
|
+
export declare function initialize(): void;
|
|
60
39
|
export type RecorderEvent = import('./types').RecorderEvent;
|
|
61
40
|
export type UnsubscribeFn = import('./types').UnsubscribeFn;
|
|
62
41
|
export declare function subscribeToNativeEvent(callback: (event: RecorderEvent) => void): UnsubscribeFn;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { __rest } from 'tslib';
|
|
2
|
+
import { NativeModules, Platform, NativeEventEmitter } from 'react-native';
|
|
2
3
|
import { noibuLog } from '../utils/log.js';
|
|
3
|
-
import {
|
|
4
|
+
import { transformToWeb } from '../mobileTransformer/mobile-replay/index.js';
|
|
4
5
|
|
|
5
6
|
const LINKING_ERROR = `The package 'noibu-session-replay' doesn't seem to be linked. Make sure: \n\n` +
|
|
6
7
|
// Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) + TODO: add back when iOS is supported.
|
|
@@ -22,19 +23,12 @@ var LogLevel;
|
|
|
22
23
|
})(LogLevel || (LogLevel = {}));
|
|
23
24
|
/**
|
|
24
25
|
* Initializes the Noibu - Session recording SDK if the API level is supported.
|
|
25
|
-
* param projectId [REQUIRED] The session recording project id to send data to.
|
|
26
|
-
* param config [OPTIONAL] The sessionreplay config, if not provided default values are used.
|
|
27
26
|
*/
|
|
28
|
-
function initialize(
|
|
27
|
+
function initialize() {
|
|
29
28
|
if (Platform.OS === 'ios') {
|
|
30
29
|
return;
|
|
31
30
|
}
|
|
32
|
-
if (!(typeof config === 'object' || typeof config === 'undefined')) {
|
|
33
|
-
throw Error('Invalid session recording initialization arguments. Please check the docs for assitance.');
|
|
34
|
-
}
|
|
35
31
|
nativeModuleEmitter = new NativeEventEmitter(NativeSessionRecorder);
|
|
36
|
-
// applying default values
|
|
37
|
-
const { userId = null, logLevel = LogLevel.None, allowMeteredNetworkUsage = false, enableWebViewCapture = true, allowedDomains = ['*'], disableOnLowEndDevices = false, maximumDailyNetworkUsageInMB = null, } = config !== null && config !== void 0 ? config : {};
|
|
38
32
|
if (!SupportedPlatforms.includes(Platform.OS)) {
|
|
39
33
|
noibuLog(`Noibu - Session recording supports ${SupportedPlatforms.join(', ')} only for now.`);
|
|
40
34
|
return;
|
|
@@ -43,10 +37,7 @@ function initialize(projectId, config) {
|
|
|
43
37
|
noibuLog('Noibu - Session recording did not initialize properly.', LINKING_ERROR);
|
|
44
38
|
return;
|
|
45
39
|
}
|
|
46
|
-
|
|
47
|
-
const enableDailyNetworkUsageLimit = maximumDailyNetworkUsageInMB != null;
|
|
48
|
-
const refinedMaximumDailyNetworkUsageInMB = maximumDailyNetworkUsageInMB !== null && maximumDailyNetworkUsageInMB !== void 0 ? maximumDailyNetworkUsageInMB : 0;
|
|
49
|
-
NativeSessionRecorder.initialize(projectId, userId, logLevel, allowMeteredNetworkUsage, enableWebViewCapture, allowedDomains, disableOnLowEndDevices, enableDailyNetworkUsageLimit, refinedMaximumDailyNetworkUsageInMB);
|
|
40
|
+
NativeSessionRecorder.initialize();
|
|
50
41
|
}
|
|
51
42
|
/**
|
|
52
43
|
* Subscribes to a native event emitted by the Noibu Session Recorder.
|
|
@@ -70,7 +61,15 @@ function subscribeToNativeEvent(callback) {
|
|
|
70
61
|
throw new Error('You have to initialize Noibu Session Recorder first');
|
|
71
62
|
}
|
|
72
63
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
73
|
-
nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
|
|
64
|
+
// const subscription = nativeModuleEmitter.addListener('noibuRecordingEvent', callback);
|
|
65
|
+
nativeModuleEmitter.addListener('noibuRecordingEvent', event => {
|
|
66
|
+
const message = event.message;
|
|
67
|
+
const _a = JSON.parse(message), { data } = _a, rest = __rest(_a, ["data"]);
|
|
68
|
+
noibuLog('New noibu recording event', rest);
|
|
69
|
+
const transformedEvents = transformToWeb([Object.assign(Object.assign({}, rest), { data })]);
|
|
70
|
+
noibuLog('after transformation: ', transformedEvents);
|
|
71
|
+
transformedEvents.forEach((e) => callback({ message: e }));
|
|
72
|
+
});
|
|
74
73
|
// return () => subscription.remove();
|
|
75
74
|
}
|
|
76
75
|
if (Platform.OS === 'ios') {
|
|
@@ -80,11 +79,11 @@ function subscribeToNativeEvent(callback) {
|
|
|
80
79
|
}
|
|
81
80
|
nativeModuleEmitter.addListener('iosPOCRecordingEvent', event => {
|
|
82
81
|
try {
|
|
83
|
-
const
|
|
84
|
-
callback({ message:
|
|
82
|
+
const transformedEvents = transformToWeb([event.message]);
|
|
83
|
+
transformedEvents.forEach((e) => callback({ message: e }));
|
|
85
84
|
}
|
|
86
85
|
catch (e) {
|
|
87
|
-
noibuLog(`[Error]
|
|
86
|
+
noibuLog(`[Error] transformToWeb failed: ${e.message}`);
|
|
88
87
|
}
|
|
89
88
|
});
|
|
90
89
|
if (!isIOSInitialized) {
|
|
@@ -1,91 +1,4 @@
|
|
|
1
|
-
type Color = {
|
|
2
|
-
a: number;
|
|
3
|
-
b: number;
|
|
4
|
-
r: number;
|
|
5
|
-
g: number;
|
|
6
|
-
};
|
|
7
|
-
type Paint = {
|
|
8
|
-
strokeJoin: number;
|
|
9
|
-
strokeWidth: number;
|
|
10
|
-
strokeCap: number;
|
|
11
|
-
color: Color;
|
|
12
|
-
dither: boolean;
|
|
13
|
-
blendMode: number;
|
|
14
|
-
style: number;
|
|
15
|
-
antiAlias: boolean;
|
|
16
|
-
strokeMiter: number;
|
|
17
|
-
};
|
|
18
|
-
type Rect = {
|
|
19
|
-
top: number;
|
|
20
|
-
left: number;
|
|
21
|
-
bottom: number;
|
|
22
|
-
right: number;
|
|
23
|
-
};
|
|
24
|
-
type Command = {
|
|
25
|
-
name?: string;
|
|
26
|
-
id?: number;
|
|
27
|
-
type: string;
|
|
28
|
-
isClipRectSource?: boolean;
|
|
29
|
-
rect?: Rect;
|
|
30
|
-
paintIndex?: number;
|
|
31
|
-
op?: number;
|
|
32
|
-
antiAlias?: boolean;
|
|
33
|
-
matrix?: number[];
|
|
34
|
-
};
|
|
35
|
-
type ViewNode = {
|
|
36
|
-
viewX: number;
|
|
37
|
-
visible: boolean;
|
|
38
|
-
processedText$delegate: {
|
|
39
|
-
_value: any;
|
|
40
|
-
initializer: any;
|
|
41
|
-
};
|
|
42
|
-
viewY: number;
|
|
43
|
-
viewWidth: number;
|
|
44
|
-
clickable: boolean;
|
|
45
|
-
viewHeight: number;
|
|
46
|
-
isMasked: boolean;
|
|
47
|
-
type: string;
|
|
48
|
-
renderNodeId: number;
|
|
49
|
-
isWebView: boolean;
|
|
50
|
-
ignoreClicks: boolean;
|
|
51
|
-
children: ViewNode[];
|
|
52
|
-
width: number;
|
|
53
|
-
x: number;
|
|
54
|
-
y: number;
|
|
55
|
-
id: number;
|
|
56
|
-
text: string;
|
|
57
|
-
height: number;
|
|
58
|
-
backgroundColor?: number;
|
|
59
|
-
};
|
|
60
|
-
type ViewHierarchy = {
|
|
61
|
-
root: ViewNode;
|
|
62
|
-
visibleFragments: any[];
|
|
63
|
-
timestamp: number;
|
|
64
|
-
};
|
|
65
|
-
type SubPicture = {
|
|
66
|
-
subPictures: any[];
|
|
67
|
-
images: any[];
|
|
68
|
-
screenWidth: number;
|
|
69
|
-
textBlobs: any[];
|
|
70
|
-
density: number;
|
|
71
|
-
vertices: any[];
|
|
72
|
-
screenHeight: number;
|
|
73
|
-
activityName: string;
|
|
74
|
-
paints: Paint[];
|
|
75
|
-
typefaces: any[];
|
|
76
|
-
viewHierarchy: ViewHierarchy;
|
|
77
|
-
paths: any[];
|
|
78
|
-
activityHashCode: number;
|
|
79
|
-
commands: Command[];
|
|
80
|
-
timestamp: number;
|
|
81
|
-
};
|
|
82
1
|
export type RecorderEvent = {
|
|
83
|
-
message:
|
|
2
|
+
message: string;
|
|
84
3
|
};
|
|
85
|
-
export type NativeFrames = {
|
|
86
|
-
p: (number | boolean | SubPicture)[][];
|
|
87
|
-
a: (number[] | (number | string | string[])[])[];
|
|
88
|
-
e: (string | number)[];
|
|
89
|
-
} | string;
|
|
90
4
|
export type UnsubscribeFn = () => void;
|
|
91
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noibu-react-native",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
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",
|
|
7
7
|
"types": "dist/entry/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"android",
|
|
10
|
+
"android/settings.gradle",
|
|
10
11
|
"dist/*",
|
|
11
12
|
"README.md",
|
|
12
13
|
"CHANGELOG.md",
|
|
@@ -41,14 +42,12 @@
|
|
|
41
42
|
},
|
|
42
43
|
"optionalDependencies": {
|
|
43
44
|
"@react-native-async-storage/async-storage": "^1.19.0",
|
|
44
|
-
"fflate": "^0.8.2",
|
|
45
45
|
"react-native-navigation": ">=2.29.0",
|
|
46
46
|
"react-native-url-polyfill": "^1.3.0",
|
|
47
47
|
"react-native-uuid": "^2.0.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@react-native-async-storage/async-storage": "^1.19.0",
|
|
51
|
-
"fflate": "^0.8.2",
|
|
52
51
|
"react": ">=16.13.1 <=18",
|
|
53
52
|
"react-native": ">=0.63.0",
|
|
54
53
|
"react-native-navigation": ">=2.29.0",
|
|
@@ -71,7 +70,7 @@
|
|
|
71
70
|
"@tsconfig/react-native": "^3.0.2",
|
|
72
71
|
"@types/jest": "^29.5.14",
|
|
73
72
|
"@types/node": "^20.2.3",
|
|
74
|
-
"@types/react": "
|
|
73
|
+
"@types/react": "18.2.6",
|
|
75
74
|
"@types/react-test-renderer": "^18.0.0",
|
|
76
75
|
"@typescript-eslint/eslint-plugin": "^8.19.1",
|
|
77
76
|
"@typescript-eslint/parser": "^8.19.1",
|
|
@@ -83,7 +82,6 @@
|
|
|
83
82
|
"eslint-plugin-jsdoc": "^50.6.1",
|
|
84
83
|
"eslint-plugin-prettier": "^5.2.1",
|
|
85
84
|
"eslint-plugin-react": "^7.37.3",
|
|
86
|
-
"fflate": "0.8.2",
|
|
87
85
|
"jest": "^29.7.0",
|
|
88
86
|
"prettier": "^3.4.2",
|
|
89
87
|
"react": "16.13.1",
|