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.
Files changed (48) hide show
  1. package/android/.gitignore +13 -0
  2. package/android/build.gradle +79 -0
  3. package/android/gradle.properties +7 -0
  4. package/android/src/main/AndroidManifest.xml +5 -0
  5. package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayModule.kt +107 -0
  6. package/android/src/main/java/com/noibu/sessionreplay/reactnative/NoibuSessionReplayPackage.kt +17 -0
  7. package/dist/api/clientConfig.d.ts +2 -2
  8. package/dist/api/clientConfig.js +1 -1
  9. package/dist/api/helpCode.d.ts +29 -0
  10. package/dist/api/inputManager.d.ts +87 -0
  11. package/dist/api/metroplexSocket.d.ts +7 -6
  12. package/dist/api/metroplexSocket.js +14 -18
  13. package/dist/api/storedMetrics.d.ts +73 -0
  14. package/dist/api/storedPageVisit.d.ts +49 -0
  15. package/dist/const_matchers.d.ts +1 -0
  16. package/dist/constants.d.ts +6 -1
  17. package/dist/constants.js +13 -2
  18. package/dist/entry/index.d.ts +1 -1
  19. package/dist/entry/init.js +8 -4
  20. package/dist/monitors/clickMonitor.d.ts +44 -0
  21. package/dist/monitors/gqlErrorValidator.d.ts +82 -0
  22. package/dist/monitors/httpDataBundler.d.ts +161 -0
  23. package/dist/monitors/inputMonitor.d.ts +34 -0
  24. package/dist/monitors/keyboardInputMonitor.d.ts +17 -0
  25. package/dist/monitors/pageMonitor.d.ts +22 -0
  26. package/dist/monitors/requestMonitor.d.ts +10 -0
  27. package/dist/pageVisit/pageVisit.d.ts +52 -0
  28. package/dist/pageVisit/pageVisit.js +4 -2
  29. package/dist/pageVisit/pageVisitEventError.d.ts +15 -0
  30. package/dist/pageVisit/pageVisitEventHTTP.d.ts +18 -0
  31. package/dist/pageVisit/userStep.d.ts +5 -0
  32. package/dist/react/ErrorBoundary.js +17 -9
  33. package/dist/sessionRecorder/nativeSessionRecorderSubscription.d.ts +64 -0
  34. package/dist/sessionRecorder/nativeSessionRecorderSubscription.js +58 -0
  35. package/dist/sessionRecorder/sessionRecorder.d.ts +60 -0
  36. package/dist/sessionRecorder/sessionRecorder.js +287 -0
  37. package/dist/sessionRecorder/types.d.ts +91 -0
  38. package/dist/types/StoredPageVisit.types.d.ts +54 -0
  39. package/dist/types/globals.d.ts +0 -1
  40. package/dist/utils/date.d.ts +6 -0
  41. package/dist/utils/eventlistener.d.ts +8 -0
  42. package/dist/utils/eventlistener.js +2 -2
  43. package/dist/utils/function.d.ts +4 -0
  44. package/dist/utils/function.js +13 -1
  45. package/dist/utils/log.d.ts +0 -1
  46. package/dist/utils/log.js +3 -5
  47. package/dist/utils/object.d.ts +2 -2
  48. package/package.json +11 -3
@@ -0,0 +1,13 @@
1
+ build/
2
+ .idea
3
+ .gradle
4
+ local.properties
5
+ *.iml
6
+ *.hprof
7
+ .cxx/
8
+ *.keystore
9
+ !debug.keystore
10
+ gradle
11
+ gradle*
12
+ !gradle.properties
13
+ settings.gradle
@@ -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,7 @@
1
+ #make sure these are acutally used
2
+ Noibu_kotlinVersion=1.7.22
3
+ Noibu_minSdkVersion=21
4
+ Noibu_targetSdkVersion=34
5
+ Noibu_compileSdkVersion=34
6
+ Noibu_ndkversion=21.4.7075529
7
+ android.useAndroidX=true
@@ -0,0 +1,5 @@
1
+ <manifest
2
+ xmlns:android="http://schemas.android.com/apk/res/android"
3
+ package="com.noibu.sessionreplay.reactnative">
4
+
5
+ </manifest>
@@ -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
+ }
@@ -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
- private lastActiveTime;
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: string, disableClient: boolean, severity: (typeof SEVERITY)[keyof typeof SEVERITY], keepAlive?: boolean): Promise<void>;
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
  */
@@ -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
- /// <reference types="react-native" />
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> | null;
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> | null;
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): void;
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
- connectionPromise = null;
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
- this.connectionPromise = this.handleConnect(false);
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
- // Assigning this value here is much better than copying the whole object.
338
- // eslint-disable-next-line no-param-reassign
339
- payload[END_AT_ATT_NAME] = new Date(this.sessionTimestamp.getTime() + delta).toISOString();
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;
@@ -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";