noibu-react-native 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/.gitignore +13 -0
- package/android/build.gradle +79 -0
- package/android/gradle.properties +7 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayModule.kt +107 -0
- package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayPackage.kt +17 -0
- package/dist/api/clientConfig.d.ts +2 -2
- package/dist/api/clientConfig.js +1 -1
- package/dist/api/helpCode.d.ts +29 -0
- package/dist/api/inputManager.d.ts +87 -0
- package/dist/api/metroplexSocket.d.ts +7 -6
- package/dist/api/metroplexSocket.js +14 -18
- package/dist/api/storedMetrics.d.ts +73 -0
- package/dist/api/storedPageVisit.d.ts +49 -0
- package/dist/const_matchers.d.ts +1 -0
- package/dist/constants.d.ts +6 -1
- package/dist/constants.js +13 -2
- package/dist/entry/index.d.ts +1 -1
- package/dist/entry/init.js +8 -4
- package/dist/monitors/clickMonitor.d.ts +44 -0
- package/dist/monitors/gqlErrorValidator.d.ts +82 -0
- package/dist/monitors/httpDataBundler.d.ts +161 -0
- package/dist/monitors/inputMonitor.d.ts +34 -0
- package/dist/monitors/keyboardInputMonitor.d.ts +17 -0
- package/dist/monitors/pageMonitor.d.ts +22 -0
- package/dist/monitors/requestMonitor.d.ts +10 -0
- package/dist/pageVisit/pageVisit.d.ts +52 -0
- package/dist/pageVisit/pageVisit.js +4 -2
- package/dist/pageVisit/pageVisitEventError.d.ts +15 -0
- package/dist/pageVisit/pageVisitEventHTTP.d.ts +18 -0
- package/dist/pageVisit/userStep.d.ts +5 -0
- package/dist/react/ErrorBoundary.js +17 -9
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.d.ts +64 -0
- package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +58 -0
- package/dist/sessionRecorder/sessionRecorder.d.ts +60 -0
- package/dist/sessionRecorder/sessionRecorder.js +287 -0
- package/dist/sessionRecorder/types.d.ts +91 -0
- package/dist/types/StoredPageVisit.types.d.ts +54 -0
- package/dist/types/globals.d.ts +0 -1
- package/dist/utils/date.d.ts +6 -0
- package/dist/utils/eventlistener.d.ts +8 -0
- package/dist/utils/eventlistener.js +2 -2
- package/dist/utils/function.d.ts +4 -0
- package/dist/utils/function.js +13 -1
- package/dist/utils/log.d.ts +0 -1
- package/dist/utils/log.js +3 -5
- package/dist/utils/object.d.ts +2 -2
- package/package.json +11 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
|
|
3
|
+
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["Noibu_kotlinVersion"]
|
|
4
|
+
|
|
5
|
+
repositories {
|
|
6
|
+
google()
|
|
7
|
+
mavenCentral()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
dependencies {
|
|
11
|
+
classpath "com.android.tools.build:gradle:8.5.1"
|
|
12
|
+
// noinspection DifferentKotlinGradleVersion
|
|
13
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def isNewArchitectureEnabled() {
|
|
18
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
apply plugin: "com.android.library"
|
|
22
|
+
apply plugin: "kotlin-android"
|
|
23
|
+
|
|
24
|
+
if (isNewArchitectureEnabled()) {
|
|
25
|
+
apply plugin: "com.facebook.react"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
def getExtOrDefault(name) {
|
|
29
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Noibu_" + name]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def getExtOrIntegerDefault(name) {
|
|
33
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Noibu_" + name]).toInteger()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
android {
|
|
37
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
38
|
+
|
|
39
|
+
defaultConfig {
|
|
40
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
41
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
42
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
43
|
+
}
|
|
44
|
+
buildTypes {
|
|
45
|
+
release {
|
|
46
|
+
minifyEnabled false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
lintOptions {
|
|
51
|
+
disable "GradleCompatible"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
compileOptions {
|
|
55
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
56
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
repositories {
|
|
61
|
+
mavenCentral()
|
|
62
|
+
google()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
66
|
+
|
|
67
|
+
dependencies {
|
|
68
|
+
implementation "com.facebook.react:react-native:+"
|
|
69
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
70
|
+
implementation "com.noibu:sessionreplay-recorder:0.1.0"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (isNewArchitectureEnabled()) {
|
|
74
|
+
react {
|
|
75
|
+
jsRootDir = file("../src/")
|
|
76
|
+
libraryName = "noibusessionreplay"
|
|
77
|
+
codegenJavaPackageName = "com.noibu.sessionreplay.reactnative"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
package com.noibu.sessionreplay.reactnative
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import com.facebook.react.bridge.*
|
|
7
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
|
+
|
|
9
|
+
import com.noibu.sessionreplay.SessionReplayConfig
|
|
10
|
+
import com.noibu.sessionreplay.models.ApplicationFramework
|
|
11
|
+
import com.noibu.sessionreplay.models.LogLevel
|
|
12
|
+
|
|
13
|
+
import com.noibu.sessionreplay.SessionReplay
|
|
14
|
+
|
|
15
|
+
class NoibuSessionReplayModule(reactContext: ReactApplicationContext) :
|
|
16
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
17
|
+
|
|
18
|
+
init {
|
|
19
|
+
NoibuSessionReplayModule.reactContext = reactContext
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override fun getName(): String {
|
|
23
|
+
return NAME
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private fun sendEvent(eventName: String, params: WritableMap?) {
|
|
27
|
+
Log.d("SessionReplayModule", "will send event: ${params}")
|
|
28
|
+
reactContext?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit(eventName, params)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@ReactMethod
|
|
32
|
+
fun initialize(
|
|
33
|
+
projectId: String,
|
|
34
|
+
userId: String?,
|
|
35
|
+
logLevel: String,
|
|
36
|
+
allowMeteredNetworkUsage: Boolean,
|
|
37
|
+
enableWebViewCapture: Boolean,
|
|
38
|
+
allowedDomains: ReadableArray,
|
|
39
|
+
disableOnLowEndDevices: Boolean,
|
|
40
|
+
enableDailyNetworkUsageLimit: Boolean,
|
|
41
|
+
maximumDailyNetworkUsageInMB: Double,
|
|
42
|
+
promise: Promise
|
|
43
|
+
) {
|
|
44
|
+
val allowedActivities = listOf<String>(); // not supported
|
|
45
|
+
val disallowedActivities = listOf<String>(); // not supported
|
|
46
|
+
|
|
47
|
+
// We use two parameters because the react method parameters do not accept nullable primitive types.
|
|
48
|
+
// Moreover, the Long data type is not supported. Js numbers are translated into doubles.
|
|
49
|
+
val maximumDailyNetworkUsageInMBLong =
|
|
50
|
+
if (enableDailyNetworkUsageLimit) maximumDailyNetworkUsageInMB.toLong() else null
|
|
51
|
+
|
|
52
|
+
val config = SessionReplayConfig(
|
|
53
|
+
projectId,
|
|
54
|
+
userId,
|
|
55
|
+
LogLevel.valueOf(logLevel),
|
|
56
|
+
allowMeteredNetworkUsage,
|
|
57
|
+
enableWebViewCapture,
|
|
58
|
+
readableArrayToList(allowedDomains),
|
|
59
|
+
ApplicationFramework.ReactNative,
|
|
60
|
+
allowedActivities,
|
|
61
|
+
disallowedActivities,
|
|
62
|
+
disableOnLowEndDevices,
|
|
63
|
+
maximumDailyNetworkUsageInMBLong
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
Handler(Looper.getMainLooper()).post {
|
|
67
|
+
promise.resolve(
|
|
68
|
+
SessionReplay.initialize(
|
|
69
|
+
currentActivity!!.getApplicationContext(),
|
|
70
|
+
config,
|
|
71
|
+
currentActivity
|
|
72
|
+
) { param ->
|
|
73
|
+
Handler(Looper.getMainLooper()).post {
|
|
74
|
+
val params = Arguments.createMap()
|
|
75
|
+
params.putString("message", param)
|
|
76
|
+
sendEvent("noibuRecordingEvent", params)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@ReactMethod
|
|
84
|
+
fun setCustomUserId(customUserId: String, promise: Promise) {
|
|
85
|
+
promise.resolve(SessionReplay.setCustomUserId(customUserId))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@ReactMethod
|
|
89
|
+
fun setCustomSessionId(customSessionId: String, promise: Promise) {
|
|
90
|
+
promise.resolve(SessionReplay.setCustomSessionId(customSessionId))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private fun readableArrayToList(arr: ReadableArray): List<String> {
|
|
94
|
+
val ret = mutableListOf<String>()
|
|
95
|
+
|
|
96
|
+
for (i in 0 until arr.size()) {
|
|
97
|
+
ret.add(arr.getString(i))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return ret
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
companion object {
|
|
104
|
+
const val NAME = "NativeSessionRecorder"
|
|
105
|
+
private var reactContext: ReactApplicationContext? = null
|
|
106
|
+
}
|
|
107
|
+
}
|
package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayPackage.kt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.noibu.sessionreplay.reactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.JavaScriptModule
|
|
5
|
+
import com.facebook.react.bridge.NativeModule
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.uimanager.ViewManager
|
|
8
|
+
|
|
9
|
+
class NoibuSessionReplayPackage : ReactPackage {
|
|
10
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
11
|
+
return listOf(NoibuSessionReplayModule(reactContext))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
15
|
+
return emptyList()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -10,7 +10,7 @@ export default class ClientConfig {
|
|
|
10
10
|
readonly pageVisitId: string;
|
|
11
11
|
browserId: StoredConfig['BrowserId'];
|
|
12
12
|
private pageVisitSeq;
|
|
13
|
-
|
|
13
|
+
lastActiveTime: Date;
|
|
14
14
|
private readonly noibuErrorURL;
|
|
15
15
|
private cltErrorPostCounter;
|
|
16
16
|
private readonly maxSocketInactiveTime;
|
|
@@ -97,7 +97,7 @@ export default class ClientConfig {
|
|
|
97
97
|
* and disable the client if required
|
|
98
98
|
* severity expects one of the SEVERITY_x level constants, or else error will be used
|
|
99
99
|
*/
|
|
100
|
-
postNoibuErrorAndOptionallyDisableClient(errorMsg:
|
|
100
|
+
postNoibuErrorAndOptionallyDisableClient(errorMsg: any, disableClient: boolean, severity: (typeof SEVERITY)[keyof typeof SEVERITY], keepAlive?: boolean): Promise<void>;
|
|
101
101
|
/**
|
|
102
102
|
* Returns true if the page visit is considered to be inactive
|
|
103
103
|
*/
|
package/dist/api/clientConfig.js
CHANGED
|
@@ -313,7 +313,7 @@ class ClientConfig {
|
|
|
313
313
|
scriptId: GET_SCRIPT_ID(),
|
|
314
314
|
ua: await getUserAgent(),
|
|
315
315
|
deviceEnv: GET_DEVICE_ENV(),
|
|
316
|
-
error: errorMsg,
|
|
316
|
+
error: stringifyJSON(errorMsg),
|
|
317
317
|
};
|
|
318
318
|
// if the page visits sends more errors than the
|
|
319
319
|
// allowed threshold we disable the client
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelpCode class is responsible for help code feature related functionality
|
|
3
|
+
*/
|
|
4
|
+
export default class HelpCode {
|
|
5
|
+
/**
|
|
6
|
+
* Singleton instance
|
|
7
|
+
* @returns {HelpCode}
|
|
8
|
+
*/
|
|
9
|
+
static getInstance(): HelpCode;
|
|
10
|
+
requestContext: {
|
|
11
|
+
resolve: null;
|
|
12
|
+
reject: null;
|
|
13
|
+
promise: null;
|
|
14
|
+
} | null;
|
|
15
|
+
/**
|
|
16
|
+
* Handles the received help code event.
|
|
17
|
+
* @param {CustomEvent<string>} event - The event object with string detail property.
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
20
|
+
receiveHelpCode(event: CustomEvent<string>): void;
|
|
21
|
+
/**
|
|
22
|
+
* Requests a help code and returns a Promise that resolves when the help code is obtained
|
|
23
|
+
* or rejects if the noibu connection is unavailable.
|
|
24
|
+
|
|
25
|
+
* @returns {Promise<string>} Promise object representing the help code request.
|
|
26
|
+
* @throws {string} Throws an error if the noibu connection is unavailable.
|
|
27
|
+
*/
|
|
28
|
+
requestHelpCode(): Promise<string>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** this class controls the input that customers can inject into
|
|
2
|
+
* our script via the NoibuJS SDK
|
|
3
|
+
*/
|
|
4
|
+
export default class InputManager {
|
|
5
|
+
/** gets the singleton instance */
|
|
6
|
+
static getInstance(): InputManager;
|
|
7
|
+
customIDs: {};
|
|
8
|
+
customErrorsCount: number;
|
|
9
|
+
TOO_MANY_IDS_ADDED_MSG: string;
|
|
10
|
+
ID_NAME_ALREADY_ADDED_MSG: string;
|
|
11
|
+
NAME_TOO_LONG_MSG: string;
|
|
12
|
+
VALUE_TOO_LONG_MSG: string;
|
|
13
|
+
INVALID_NAME_TYPE_MSG: string;
|
|
14
|
+
INVALID_VALUE_TYPE_MSG: string;
|
|
15
|
+
NAME_HAS_NO_LENGTH_MSG: string;
|
|
16
|
+
VALUE_HAS_NO_LENGTH_MSG: string;
|
|
17
|
+
SUCCESS_MSG: string;
|
|
18
|
+
ERROR_HAS_NO_MSG_MSG: string;
|
|
19
|
+
ERROR_HAS_NO_STACK_MSG: string;
|
|
20
|
+
NULL_CUSTOM_ERR_MSG: string;
|
|
21
|
+
ERROR_ALREADY_RECEIVED_MSG: string;
|
|
22
|
+
INVALID_ERROR_SOURCE_MSG: string;
|
|
23
|
+
TOO_MANY_ERRORS_RECEIVED_PER_PAGEVISIT_MSG: string;
|
|
24
|
+
/** exposes functions to the window of the browser for the clients
|
|
25
|
+
* to interact with on their end
|
|
26
|
+
*/
|
|
27
|
+
exposeFunctions(): {
|
|
28
|
+
requestHelpCode: (alert?: boolean) => Promise<string>;
|
|
29
|
+
addCustomAttribute: (name: string, value: string) => Promise<string>;
|
|
30
|
+
addError: (customError: Error) => string;
|
|
31
|
+
addJsSdkError: (customError: string, errorSource: string) => string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* gets the sdk object that will be assigned to a window variable
|
|
35
|
+
* @returns {{
|
|
36
|
+
* requestHelpCode: (alert?: boolean) => Promise<string>,
|
|
37
|
+
* addCustomAttribute: (name: string, value: string) => Promise<string>,
|
|
38
|
+
* addError: (customError: Error) => string,
|
|
39
|
+
* addJsSdkError: (customError: string, errorSource: string) => string
|
|
40
|
+
* }}
|
|
41
|
+
*/
|
|
42
|
+
_getSDKWindowObject(): {
|
|
43
|
+
requestHelpCode: (alert?: boolean) => Promise<string>;
|
|
44
|
+
addCustomAttribute: (name: string, value: string) => Promise<string>;
|
|
45
|
+
addError: (customError: Error) => string;
|
|
46
|
+
addJsSdkError: (customError: string, errorSource: string) => string;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* validates the custom error that was passed
|
|
50
|
+
* @param {} customError
|
|
51
|
+
*/
|
|
52
|
+
_validateCustomError(customError: any): string;
|
|
53
|
+
/**
|
|
54
|
+
* Validates and sets the custom error to our internal trackers
|
|
55
|
+
* @param {} customError
|
|
56
|
+
*/
|
|
57
|
+
_validateAndSetCustomError(customError: any): string;
|
|
58
|
+
/**
|
|
59
|
+
* adds an error from a JS Sdk to the session
|
|
60
|
+
* @param {} customError
|
|
61
|
+
* @param {string} errorSource
|
|
62
|
+
*/
|
|
63
|
+
_addErrorFromJSSdk(customError: any, errorSource: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* adds a custom Error to the session
|
|
66
|
+
* @param {} customError
|
|
67
|
+
*/
|
|
68
|
+
_addCustomError(customError: any): string;
|
|
69
|
+
/**
|
|
70
|
+
* adds a custom id to the session
|
|
71
|
+
* @param {} name
|
|
72
|
+
* @param {} value
|
|
73
|
+
*/
|
|
74
|
+
_addCustomAttribute(name: any, value: any): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* validation function for customer input
|
|
77
|
+
* @param {} name
|
|
78
|
+
* @param {} value
|
|
79
|
+
*/
|
|
80
|
+
_validateCustomIDInput(name: any, value: any): string;
|
|
81
|
+
/**
|
|
82
|
+
* Requests a help code from the HelpCode instance.
|
|
83
|
+
* @param {boolean} [alertUser=true] - Whether to alert the user about the help code request.
|
|
84
|
+
* @returns {Promise<string>} A promise that resolves with the requested help code.
|
|
85
|
+
*/
|
|
86
|
+
_requestHelpCode(): Promise<string>;
|
|
87
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { END_AT_ATT_NAME } from '../constants';
|
|
2
2
|
/** Manages the socket to Metroplex */
|
|
3
3
|
export default class MetroplexSocket {
|
|
4
4
|
_initialURL: string;
|
|
5
5
|
ackedOnce: boolean;
|
|
6
6
|
connectionCount: number;
|
|
7
|
-
connectionPromise: Promise<any
|
|
7
|
+
connectionPromise: Promise<any>;
|
|
8
8
|
connectionURL: string;
|
|
9
9
|
currentConnectionAttempts: number;
|
|
10
10
|
forceClosed: boolean;
|
|
@@ -41,8 +41,6 @@ export default class MetroplexSocket {
|
|
|
41
41
|
* @returns {MetroplexSocket}
|
|
42
42
|
*/
|
|
43
43
|
static getInstance(scriptInstanceId?: string | number[]): MetroplexSocket;
|
|
44
|
-
/** Starts off the socket connection */
|
|
45
|
-
start(): void;
|
|
46
44
|
/**
|
|
47
45
|
* Adds the seq num field to the given payload depending on whether its
|
|
48
46
|
* a page visit part or video frag
|
|
@@ -77,12 +75,14 @@ export default class MetroplexSocket {
|
|
|
77
75
|
* connectSocket will establish a websocket connection to the metroplex
|
|
78
76
|
* service
|
|
79
77
|
*/
|
|
80
|
-
connectSocket(): Promise<any
|
|
78
|
+
connectSocket(): Promise<any>;
|
|
81
79
|
/** Calculates and sets the end_at field of the payload
|
|
82
80
|
* @param {} payload
|
|
83
81
|
* @param {} isPageVisit
|
|
84
82
|
*/
|
|
85
|
-
addEndTimeToPayload(payload: any, isPageVisit: boolean):
|
|
83
|
+
addEndTimeToPayload(payload: any, isPageVisit: boolean): typeof payload & {
|
|
84
|
+
[END_AT_ATT_NAME]: string;
|
|
85
|
+
};
|
|
86
86
|
/** open handler for socket */
|
|
87
87
|
_onSocketOpen(): Promise<void>;
|
|
88
88
|
/** message handler for socket
|
|
@@ -146,6 +146,7 @@ export default class MetroplexSocket {
|
|
|
146
146
|
script_inst_id: string | number[] | undefined;
|
|
147
147
|
mp_sock_inst_id: string | number[];
|
|
148
148
|
sock_inst_id: string | number[] | null;
|
|
149
|
+
video_recorder: string;
|
|
149
150
|
}>;
|
|
150
151
|
/**
|
|
151
152
|
* Try to parse help code response and fire custom event
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import uuid from 'react-native-uuid';
|
|
2
|
-
import { getUserAgent, stringifyJSON } from '../utils/function.js';
|
|
2
|
+
import { getUserAgent, stringifyJSON, getVideoRecorderType } from '../utils/function.js';
|
|
3
3
|
import { addSafeEventListener } from '../utils/eventlistener.js';
|
|
4
|
-
import { GET_METROPLEX_BASE_SOCKET_URL, METROPLEX_FRAG_ROUTE, GET_METROPLEX_POST_URL, METROPLEX_RETRY_FREQUENCY, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_METROPLEX_TYPE, PAGE_VISIT_PART_ATT_NAME, SEQ_NUM_ATT_NAME, WORK_REQUEST_ATT_NAME, HELP_CODE_ATT_NAME, PV_EVENTS_ATT_NAME, TYPE_ATT_NAME, USERSTEP_EVENT_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, MAX_METROPLEX_CONNECTION_COUNT, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, END_AT_ATT_NAME, SEVERITY, OK_SOCKET_MESSAGE, CLOSE_CONNECTION_FORCEFULLY, BLOCK_SOCKET_MESSAGE, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, MAX_BEACON_PAYLOAD_SIZE, PAGE_VISIT_INFORMATION_ATT_NAME, VIDEO_PART_COUNT_ATT_NAME, IS_LAST_ATT_NAME, BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, VER_ATT_NAME, CURRENT_PV_VERSION, PV_SEQ_ATT_NAME, ON_URL_ATT_NAME, REF_URL_ATT_NAME, STARTED_AT_ATT_NAME, CONN_COUNT_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, SCRIPT_ID_ATT_NAME, GET_SCRIPT_ID, SCRIPT_INSTANCE_ID_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME } from '../constants.js';
|
|
4
|
+
import { GET_METROPLEX_BASE_SOCKET_URL, METROPLEX_FRAG_ROUTE, GET_METROPLEX_POST_URL, METROPLEX_RETRY_FREQUENCY, META_DATA_METROPLEX_TYPE, PAGE_VISIT_META_DATA_ATT_NAME, HTTP_DATA_METROPLEX_TYPE, PAGE_VISIT_HTTP_DATA_ATT_NAME, VIDEO_METROPLEX_TYPE, PAGE_VISIT_VID_FRAG_ATT_NAME, PV_METROPLEX_TYPE, PAGE_VISIT_PART_ATT_NAME, SEQ_NUM_ATT_NAME, WORK_REQUEST_ATT_NAME, HELP_CODE_ATT_NAME, PV_EVENTS_ATT_NAME, TYPE_ATT_NAME, USERSTEP_EVENT_TYPE, GET_MAX_METROPLEX_RECONNECTION_NUMBER, MAX_METROPLEX_CONNECTION_COUNT, GET_METROPLEX_CONSECUTIVE_CONNECTION_DELAY, END_AT_ATT_NAME, SEVERITY, OK_SOCKET_MESSAGE, CLOSE_CONNECTION_FORCEFULLY, BLOCK_SOCKET_MESSAGE, STOP_STORING_PV_SOCKET_MESSAGE, STOP_STORING_VID_SOCKET_MESSAGE, MAX_BEACON_PAYLOAD_SIZE, PAGE_VISIT_INFORMATION_ATT_NAME, VIDEO_PART_COUNT_ATT_NAME, IS_LAST_ATT_NAME, BROWSER_ID_ATT_NAME, PV_ID_ATT_NAME, VER_ATT_NAME, CURRENT_PV_VERSION, PV_SEQ_ATT_NAME, ON_URL_ATT_NAME, REF_URL_ATT_NAME, STARTED_AT_ATT_NAME, CONN_COUNT_ATT_NAME, COLLECT_VER_ATT_NAME, CURRENT_NOIBUJS_VERSION, SCRIPT_ID_ATT_NAME, GET_SCRIPT_ID, SCRIPT_INSTANCE_ID_ATT_NAME, METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME, SOCKET_INSTANCE_ID_ATT_NAME, VIDEO_RECORDER_ATT_NAME } from '../constants.js';
|
|
5
5
|
import ClientConfig from './clientConfig.js';
|
|
6
6
|
import StoredMetrics from './storedMetrics.js';
|
|
7
7
|
import StoredPageVisit from './storedPageVisit.js';
|
|
@@ -16,7 +16,8 @@ class MetroplexSocket {
|
|
|
16
16
|
_initialURL;
|
|
17
17
|
ackedOnce;
|
|
18
18
|
connectionCount;
|
|
19
|
-
|
|
19
|
+
// promise that will resolve once the socket is connected and metroplex has acknowledged
|
|
20
|
+
connectionPromise;
|
|
20
21
|
connectionURL;
|
|
21
22
|
currentConnectionAttempts;
|
|
22
23
|
forceClosed;
|
|
@@ -65,8 +66,6 @@ class MetroplexSocket {
|
|
|
65
66
|
this.connectionCount = 0;
|
|
66
67
|
// sessiont start time, used to calculate accurate end time
|
|
67
68
|
this.sessionStartTime = safePerformanceNow();
|
|
68
|
-
// promise that will resolve once the socket is connected and metroplex has acknowledged
|
|
69
|
-
this.connectionPromise = null;
|
|
70
69
|
// Whether or not we have sent the page visit information after connecting the socket
|
|
71
70
|
this.pageVisitInfoSent = false;
|
|
72
71
|
// socket connection url
|
|
@@ -110,6 +109,10 @@ class MetroplexSocket {
|
|
|
110
109
|
this.metroRetryFrequencyMS = METROPLEX_RETRY_FREQUENCY;
|
|
111
110
|
this.helpCodeCb = null;
|
|
112
111
|
this.retryMetroplexInterval = null;
|
|
112
|
+
// Connect the WS
|
|
113
|
+
this.connectionPromise = this.connectSocket();
|
|
114
|
+
// Set up the offload events immediately
|
|
115
|
+
this._setupOffloadEvents();
|
|
113
116
|
}
|
|
114
117
|
/**
|
|
115
118
|
* gets the singleton instance
|
|
@@ -118,17 +121,9 @@ class MetroplexSocket {
|
|
|
118
121
|
static getInstance(scriptInstanceId) {
|
|
119
122
|
if (!this.instance) {
|
|
120
123
|
this.instance = new MetroplexSocket(scriptInstanceId);
|
|
121
|
-
this.instance.start();
|
|
122
124
|
}
|
|
123
125
|
return this.instance;
|
|
124
126
|
}
|
|
125
|
-
/** Starts off the socket connection */
|
|
126
|
-
start() {
|
|
127
|
-
// Connect the WS
|
|
128
|
-
this.connectSocket();
|
|
129
|
-
// Set up the offload events immediately
|
|
130
|
-
this._setupOffloadEvents();
|
|
131
|
-
}
|
|
132
127
|
/**
|
|
133
128
|
* Adds the seq num field to the given payload depending on whether its
|
|
134
129
|
* a page visit part or video frag
|
|
@@ -321,8 +316,7 @@ class MetroplexSocket {
|
|
|
321
316
|
}
|
|
322
317
|
// we return a promisified socket resolver to be able to chain the
|
|
323
318
|
// opening of the socket
|
|
324
|
-
|
|
325
|
-
return this.connectionPromise;
|
|
319
|
+
return this.handleConnect(false);
|
|
326
320
|
}
|
|
327
321
|
/** Calculates and sets the end_at field of the payload
|
|
328
322
|
* @param {} payload
|
|
@@ -334,9 +328,10 @@ class MetroplexSocket {
|
|
|
334
328
|
if (isPageVisit) {
|
|
335
329
|
this.sessionLength = delta;
|
|
336
330
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
331
|
+
return {
|
|
332
|
+
...payload,
|
|
333
|
+
[END_AT_ATT_NAME]: new Date(this.sessionTimestamp.getTime() + delta).toISOString(),
|
|
334
|
+
};
|
|
340
335
|
}
|
|
341
336
|
/** open handler for socket */
|
|
342
337
|
async _onSocketOpen() {
|
|
@@ -686,6 +681,7 @@ class MetroplexSocket {
|
|
|
686
681
|
[SCRIPT_INSTANCE_ID_ATT_NAME]: this.scriptInstanceId,
|
|
687
682
|
[METROPLEX_SOCKET_INSTANCE_ID_ATT_NAME]: this.instanceId,
|
|
688
683
|
[SOCKET_INSTANCE_ID_ATT_NAME]: this.socketInstanceId,
|
|
684
|
+
[VIDEO_RECORDER_ATT_NAME]: await getVideoRecorderType(),
|
|
689
685
|
};
|
|
690
686
|
}
|
|
691
687
|
/**
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This class holds the final page visit and video frag metrics. It flushes
|
|
3
|
+
* them to storage and then finally sends them to Metroplex via the post
|
|
4
|
+
* route when the next page is loaded
|
|
5
|
+
*/
|
|
6
|
+
export default class StoredMetrics {
|
|
7
|
+
/**
|
|
8
|
+
* gets the singleton instance
|
|
9
|
+
* @returns {StoredMetrics}
|
|
10
|
+
*/
|
|
11
|
+
static getInstance(): StoredMetrics;
|
|
12
|
+
expectedVideoLength: number;
|
|
13
|
+
expectedVfSeq: number;
|
|
14
|
+
httpSequenceNumber: number;
|
|
15
|
+
httpOverLimitCount: number;
|
|
16
|
+
httpDroppedPayloadByTypeCount: number;
|
|
17
|
+
httpDroppedPayloadByLengthCount: number;
|
|
18
|
+
httpPayloadCount: number;
|
|
19
|
+
expectedPvPart: number;
|
|
20
|
+
videoClicks: number;
|
|
21
|
+
pvClicks: number;
|
|
22
|
+
errCount: number;
|
|
23
|
+
httpCount: number;
|
|
24
|
+
didCutPv: boolean;
|
|
25
|
+
didCutVideo: boolean;
|
|
26
|
+
writeTimeout: any;
|
|
27
|
+
didStartVideo: boolean;
|
|
28
|
+
/** Add video frag payload data to the stored metrics
|
|
29
|
+
* @param {} expectedVfSeq
|
|
30
|
+
* @param {} expectedVideoLength
|
|
31
|
+
*/
|
|
32
|
+
addVideoFragData(expectedVfSeq: any, expectedVideoLength: any): void;
|
|
33
|
+
/** Set the amount of page visit parts
|
|
34
|
+
* @param {} expectedPvPart
|
|
35
|
+
*/
|
|
36
|
+
setPvPart(expectedPvPart: any): void;
|
|
37
|
+
/** Increase the amount of video clicks seen in the session */
|
|
38
|
+
addVideoClick(): void;
|
|
39
|
+
/** Increase the amount of page visit clicks */
|
|
40
|
+
addPvClick(): void;
|
|
41
|
+
/** Increments the error count by 1 */
|
|
42
|
+
addError(): void;
|
|
43
|
+
/** Increments the http count by 1 */
|
|
44
|
+
addHttpEvent(): void;
|
|
45
|
+
/** Increments the http data sequence count by 1 */
|
|
46
|
+
addHttpData(): void;
|
|
47
|
+
/** Increments the http data over limit count by 1 */
|
|
48
|
+
addHttpDataOverLimit(): void;
|
|
49
|
+
/** Increments the http data drop count by content type */
|
|
50
|
+
addHttpDataDropByType(): void;
|
|
51
|
+
/** Increments the http data drop count by content length */
|
|
52
|
+
addHttpDataDropByLength(): void;
|
|
53
|
+
/** Increments the http data payload collected count */
|
|
54
|
+
addHttpDataPayloadCount(): void;
|
|
55
|
+
/** Set that the video was cut/blocked due to size constraints */
|
|
56
|
+
setDidCutVideo(): void;
|
|
57
|
+
/** Set that the video was started */
|
|
58
|
+
setDidStartVideo(): void;
|
|
59
|
+
/** Set that the page visit was cut/blocked due to size constraints */
|
|
60
|
+
setDidCutPv(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Sets up all the listeners that noibujs should listen to before storing
|
|
63
|
+
* our metrics to localstorage
|
|
64
|
+
*/
|
|
65
|
+
_setupListeners(): void;
|
|
66
|
+
/** posts the metrics to metroplex if client is active
|
|
67
|
+
* @param {} eventName
|
|
68
|
+
*/
|
|
69
|
+
_postMetricsIfActive(eventName: any): void;
|
|
70
|
+
/** posts the metrics to metroplex using the beacon API
|
|
71
|
+
*/
|
|
72
|
+
postMetrics(): Promise<void>;
|
|
73
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This class holds the final page visit. It flushes it to storage and then
|
|
3
|
+
* finally sends it to Metroplex via the post route when the next page is loaded
|
|
4
|
+
*/
|
|
5
|
+
export default class StoredPageVisit {
|
|
6
|
+
/** gets the singleton instance */
|
|
7
|
+
static getInstance(): StoredPageVisit;
|
|
8
|
+
latestPageVisitFrag: any;
|
|
9
|
+
writeTimeout: any;
|
|
10
|
+
flushedStorage: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Check if the events contain a click or location change. If they do then write the retry
|
|
13
|
+
* queue (which contains the metroplex msg sent above) to storage
|
|
14
|
+
* @param {} retryMessageQueue
|
|
15
|
+
* @param {} pvInfo
|
|
16
|
+
*/
|
|
17
|
+
checkAndStoreRetryQueue(retryMessageQueue: any, pvInfo: any): void;
|
|
18
|
+
/** Writes the page visit frags in the retry queue to storage
|
|
19
|
+
* @param {} retryMessageQueue
|
|
20
|
+
* @param {} pvInfo
|
|
21
|
+
*/
|
|
22
|
+
writePageVisitsFromRetryQueue(retryMessageQueue: any, pvInfo: any): void;
|
|
23
|
+
/** Write the given page visit frags to storage
|
|
24
|
+
* @param {} pageVisitFrags
|
|
25
|
+
* @param {} pvInfo
|
|
26
|
+
*/
|
|
27
|
+
_writePageVisitFrags(pageVisitFrags: any, pvInfo: any): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Read the stored page visit from storage, create a complete page visit object
|
|
30
|
+
* and then post that to Metroplex
|
|
31
|
+
*/
|
|
32
|
+
_getPostData(): Promise<{
|
|
33
|
+
pvi: any;
|
|
34
|
+
pvp: never[];
|
|
35
|
+
pvvf: never[];
|
|
36
|
+
} | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Creates and tries to resolve a promise that posts the previous page visit
|
|
39
|
+
* to Metroplex from storage
|
|
40
|
+
*/
|
|
41
|
+
_postPreviousPageVisit(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Remove the storage item and set flushed to true after they have
|
|
44
|
+
* been posted to metroplex
|
|
45
|
+
*/
|
|
46
|
+
_updateStorageFlushed(): void;
|
|
47
|
+
/** Returns a promise that resolves to post the page visit in storage to Metroplex */
|
|
48
|
+
_getPostPageVisitPromise(): Promise<any>;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function WHITELIST_TEXT_REGEX_STRING(): string;
|
package/dist/constants.d.ts
CHANGED
|
@@ -33,7 +33,6 @@ export declare const SEVERITY: {
|
|
|
33
33
|
readonly info: "info";
|
|
34
34
|
readonly debug: "debug";
|
|
35
35
|
};
|
|
36
|
-
export declare const UNFREEZE_TAG: "unfreeze";
|
|
37
36
|
export declare const MAX_METROPLEX_SOCKET_INNACTIVE_TIME: number;
|
|
38
37
|
export declare const MAX_PAGEVISIT_VISITED: 300;
|
|
39
38
|
export declare const IMG_EXTENSIONS: readonly ["jpg", "jpeg", "bmp", "gif", "png"];
|
|
@@ -59,7 +58,10 @@ export declare const BROWSER_ID_ATT_NAME: "br_id";
|
|
|
59
58
|
export declare const PV_ID_ATT_NAME: "pv_id";
|
|
60
59
|
export declare const VER_ATT_NAME: "v";
|
|
61
60
|
export declare const PV_SEQ_ATT_NAME: "seq";
|
|
61
|
+
export declare const VIDEO_RECORDER_ATT_NAME: "video_recorder";
|
|
62
62
|
export declare const ON_URL_ATT_NAME: "on_url";
|
|
63
|
+
export declare const PAGE_GROUPS_ATT_NAME = "page_groups";
|
|
64
|
+
export declare const PAGE_TITLE_ATT_NAME = "page_title";
|
|
63
65
|
export declare const URL_ATT_NAME: "url";
|
|
64
66
|
export declare const REF_URL_ATT_NAME: "ref_url";
|
|
65
67
|
export declare const STARTED_AT_ATT_NAME: "start_at";
|
|
@@ -238,3 +240,6 @@ export declare const BLOCKLISTED_DOMAINS: {
|
|
|
238
240
|
'vf.staging.noibu.com': boolean;
|
|
239
241
|
'cdn.noibu.com': boolean;
|
|
240
242
|
};
|
|
243
|
+
export declare const MAX_RECORDER_EVENT_BUFFER = 10;
|
|
244
|
+
export declare const MAX_TIME_FOR_RECORDER_USER_EVENTS = 2000;
|
|
245
|
+
export declare const POST_METRICS_EVENT_NAME = "noibuPostMetrics";
|