@multiplayer-app/session-recorder-react-native 1.0.1-beta.4 → 1.0.1-beta.5
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/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModule.kt +2 -2
- package/lib/module/components/SessionRecorderWidget/ErrorBanner.js.map +1 -1
- package/lib/module/components/SessionRecorderWidget/ModalHeader.js.map +1 -1
- package/lib/module/components/SessionRecorderWidget/SessionRecorderWidget.js.map +1 -1
- package/lib/module/components/SessionRecorderWidget/icons.js.map +1 -1
- package/lib/module/components/SessionRecorderWidget/styles.js.map +1 -1
- package/lib/module/config/constants.js.map +1 -1
- package/lib/module/config/defaults.js.map +1 -1
- package/lib/module/config/masking.js.map +1 -1
- package/lib/module/config/session-recorder.js.map +1 -1
- package/lib/module/config/validators.js.map +1 -1
- package/lib/module/config/widget.js.map +1 -1
- package/lib/module/context/SessionRecorderStore.js.map +1 -1
- package/lib/module/context/useSessionRecorderStore.js.map +1 -1
- package/lib/module/context/useStoreSelector.js.map +1 -1
- package/lib/module/native/SessionRecorderNative.js.map +1 -1
- package/lib/module/native/index.js.map +1 -1
- package/lib/module/otel/helpers.js +1 -1
- package/lib/module/otel/helpers.js.map +1 -1
- package/lib/module/otel/index.js.map +1 -1
- package/lib/module/otel/instrumentations/index.js.map +1 -1
- package/lib/module/patch/xhr.js.map +1 -1
- package/lib/module/recorder/eventExporter.js.map +1 -1
- package/lib/module/recorder/gestureRecorder.js.map +1 -1
- package/lib/module/recorder/index.js.map +1 -1
- package/lib/module/recorder/navigationTracker.js.map +1 -1
- package/lib/module/recorder/screenRecorder.js.map +1 -1
- package/lib/module/services/api.service.js.map +1 -1
- package/lib/module/services/network.service.js.map +1 -1
- package/lib/module/services/screenMaskingService.js.map +1 -1
- package/lib/module/services/storage.service.js.map +1 -1
- package/lib/module/session-recorder.js.map +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/types/session-recorder.js.map +1 -1
- package/lib/module/utils/app-metadata.js +2 -2
- package/lib/module/utils/constants.optional.js.map +1 -1
- package/lib/module/utils/createStore.js.map +1 -1
- package/lib/module/utils/logger.js +0 -8
- package/lib/module/utils/logger.js.map +1 -1
- package/lib/module/utils/platform.js +1 -1
- package/lib/module/utils/platform.js.map +1 -1
- package/lib/module/utils/rrweb-events.js.map +1 -1
- package/lib/module/utils/session.js.map +1 -1
- package/lib/module/utils/shallowEqual.js.map +1 -1
- package/lib/module/utils/time.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/components/ScreenRecorderView/index.d.ts +1 -1
- package/lib/typescript/src/components/SessionRecorderWidget/ErrorBanner.d.ts.map +1 -1
- package/lib/typescript/src/components/SessionRecorderWidget/ModalHeader.d.ts.map +1 -1
- package/lib/typescript/src/components/SessionRecorderWidget/SessionRecorderWidget.d.ts.map +1 -1
- package/lib/typescript/src/components/SessionRecorderWidget/icons.d.ts.map +1 -1
- package/lib/typescript/src/components/SessionRecorderWidget/index.d.ts +1 -1
- package/lib/typescript/src/components/SessionRecorderWidget/styles.d.ts.map +1 -1
- package/lib/typescript/src/components/index.d.ts.map +1 -1
- package/lib/typescript/src/config/constants.d.ts.map +1 -1
- package/lib/typescript/src/config/defaults.d.ts.map +1 -1
- package/lib/typescript/src/config/index.d.ts.map +1 -1
- package/lib/typescript/src/config/masking.d.ts.map +1 -1
- package/lib/typescript/src/config/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/config/validators.d.ts.map +1 -1
- package/lib/typescript/src/config/widget.d.ts +1 -1
- package/lib/typescript/src/config/widget.d.ts.map +1 -1
- package/lib/typescript/src/context/SessionRecorderStore.d.ts.map +1 -1
- package/lib/typescript/src/context/useSessionRecorderStore.d.ts +3 -3
- package/lib/typescript/src/context/useSessionRecorderStore.d.ts.map +1 -1
- package/lib/typescript/src/context/useStoreSelector.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/SessionRecorderNative.d.ts.map +1 -1
- package/lib/typescript/src/native/index.d.ts +1 -1
- package/lib/typescript/src/native/index.d.ts.map +1 -1
- package/lib/typescript/src/otel/helpers.d.ts.map +1 -1
- package/lib/typescript/src/otel/index.d.ts.map +1 -1
- package/lib/typescript/src/otel/instrumentations/index.d.ts.map +1 -1
- package/lib/typescript/src/patch/index.d.ts.map +1 -1
- package/lib/typescript/src/patch/xhr.d.ts.map +1 -1
- package/lib/typescript/src/recorder/eventExporter.d.ts.map +1 -1
- package/lib/typescript/src/recorder/gestureRecorder.d.ts.map +1 -1
- package/lib/typescript/src/recorder/index.d.ts.map +1 -1
- package/lib/typescript/src/recorder/navigationTracker.d.ts.map +1 -1
- package/lib/typescript/src/recorder/screenRecorder.d.ts.map +1 -1
- package/lib/typescript/src/services/api.service.d.ts.map +1 -1
- package/lib/typescript/src/services/network.service.d.ts.map +1 -1
- package/lib/typescript/src/services/screenMaskingService.d.ts.map +1 -1
- package/lib/typescript/src/services/storage.service.d.ts.map +1 -1
- package/lib/typescript/src/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/types/configs.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/types/session-recorder.d.ts +4 -4
- package/lib/typescript/src/types/session-recorder.d.ts.map +1 -1
- package/lib/typescript/src/types/session.d.ts.map +1 -1
- package/lib/typescript/src/utils/app-metadata.d.ts.map +1 -1
- package/lib/typescript/src/utils/constants.optional.d.ts.map +1 -1
- package/lib/typescript/src/utils/constants.optional.expo.d.ts.map +1 -1
- package/lib/typescript/src/utils/createStore.d.ts.map +1 -1
- package/lib/typescript/src/utils/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/logger.d.ts +1 -1
- package/lib/typescript/src/utils/logger.d.ts.map +1 -1
- package/lib/typescript/src/utils/platform.d.ts.map +1 -1
- package/lib/typescript/src/utils/request-utils.d.ts.map +1 -1
- package/lib/typescript/src/utils/rrweb-events.d.ts.map +1 -1
- package/lib/typescript/src/utils/session.d.ts.map +1 -1
- package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -1
- package/lib/typescript/src/utils/time.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-utils.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/ScreenRecorderView/index.ts +1 -1
- package/src/components/SessionRecorderWidget/ErrorBanner.tsx +14 -14
- package/src/components/SessionRecorderWidget/ModalHeader.tsx +11 -9
- package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +70 -56
- package/src/components/SessionRecorderWidget/icons.tsx +58 -30
- package/src/components/SessionRecorderWidget/index.ts +1 -1
- package/src/components/SessionRecorderWidget/styles.ts +17 -18
- package/src/components/index.ts +2 -2
- package/src/config/constants.ts +19 -20
- package/src/config/defaults.ts +35 -31
- package/src/config/index.ts +5 -5
- package/src/config/masking.ts +44 -18
- package/src/config/session-recorder.ts +54 -26
- package/src/config/validators.ts +43 -20
- package/src/config/widget.ts +24 -15
- package/src/context/SessionRecorderStore.ts +19 -18
- package/src/context/useSessionRecorderStore.ts +17 -10
- package/src/context/useStoreSelector.ts +20 -18
- package/src/index.ts +7 -7
- package/src/native/SessionRecorderNative.ts +83 -67
- package/src/native/index.ts +5 -1
- package/src/otel/helpers.ts +109 -93
- package/src/otel/index.ts +46 -49
- package/src/otel/instrumentations/index.ts +44 -41
- package/src/patch/index.ts +1 -1
- package/src/patch/xhr.ts +77 -78
- package/src/recorder/eventExporter.ts +63 -68
- package/src/recorder/gestureRecorder.ts +359 -212
- package/src/recorder/index.ts +75 -62
- package/src/recorder/navigationTracker.ts +120 -97
- package/src/recorder/screenRecorder.ts +214 -163
- package/src/services/api.service.ts +49 -48
- package/src/services/network.service.ts +67 -58
- package/src/services/screenMaskingService.ts +81 -50
- package/src/services/storage.service.ts +99 -70
- package/src/session-recorder.ts +270 -214
- package/src/types/configs.ts +53 -31
- package/src/types/expo-constants.d.ts +2 -2
- package/src/types/index.ts +16 -18
- package/src/types/session-recorder.ts +106 -111
- package/src/types/session.ts +45 -45
- package/src/utils/app-metadata.ts +9 -9
- package/src/utils/constants.optional.expo.ts +3 -3
- package/src/utils/constants.optional.ts +14 -12
- package/src/utils/createStore.ts +23 -20
- package/src/utils/index.ts +7 -7
- package/src/utils/logger.ts +87 -58
- package/src/utils/platform.ts +149 -118
- package/src/utils/request-utils.ts +15 -15
- package/src/utils/rrweb-events.ts +47 -34
- package/src/utils/session.ts +15 -12
- package/src/utils/shallowEqual.ts +16 -10
- package/src/utils/time.ts +7 -4
- package/src/utils/type-utils.ts +36 -36
- package/src/version.ts +1 -1
- package/android/src/main/java/com/multiplayer/sessionrecordernative/SessionRecorderNativeModuleSpec.kt +0 -51
- package/android/src/main/java/com/xxx/XxxModule.kt +0 -23
- package/ios/Xxx.h +0 -5
- package/ios/Xxx.mm +0 -21
package/src/config/defaults.ts
CHANGED
|
@@ -2,18 +2,18 @@ import {
|
|
|
2
2
|
SessionRecorderSdk,
|
|
3
3
|
MULTIPLAYER_BASE_API_URL,
|
|
4
4
|
MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL,
|
|
5
|
-
} from '@multiplayer-app/session-recorder-common'
|
|
5
|
+
} from '@multiplayer-app/session-recorder-common';
|
|
6
6
|
import {
|
|
7
7
|
LogLevel,
|
|
8
8
|
WidgetButtonPlacement,
|
|
9
9
|
type SessionRecorderConfigs,
|
|
10
|
-
} from '../types'
|
|
10
|
+
} from '../types';
|
|
11
11
|
import {
|
|
12
12
|
OTEL_MP_SAMPLE_TRACE_RATIO,
|
|
13
13
|
DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE,
|
|
14
|
-
} from './constants'
|
|
14
|
+
} from './constants';
|
|
15
15
|
|
|
16
|
-
const { mask, sensitiveFields, sensitiveHeaders } = SessionRecorderSdk
|
|
16
|
+
const { mask, sensitiveFields, sensitiveHeaders } = SessionRecorderSdk;
|
|
17
17
|
|
|
18
18
|
export const DEFAULT_MASKING_CONFIG: SessionRecorderConfigs['masking'] = {
|
|
19
19
|
isContentMaskingEnabled: true,
|
|
@@ -30,30 +30,36 @@ export const DEFAULT_MASKING_CONFIG: SessionRecorderConfigs['masking'] = {
|
|
|
30
30
|
maskWebViews: false,
|
|
31
31
|
maskTextInputs: true,
|
|
32
32
|
maskSandboxedViews: false,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const DEFAULT_WIDGET_TEXT_CONFIG: SessionRecorderConfigs['widget']['textOverrides'] =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const DEFAULT_WIDGET_TEXT_CONFIG: SessionRecorderConfigs['widget']['textOverrides'] =
|
|
36
|
+
{
|
|
37
|
+
initialTitleWithContinuous: 'Encountered an issue?',
|
|
38
|
+
initialTitleWithoutContinuous: 'Encountered an issue?',
|
|
39
|
+
initialDescriptionWithContinuous:
|
|
40
|
+
'Record your session so we can see the problem and fix it faster.',
|
|
41
|
+
initialDescriptionWithoutContinuous:
|
|
42
|
+
'Record your session so we can see the problem and fix it faster.',
|
|
43
|
+
continuousRecordingLabel: 'Continuous recording',
|
|
44
|
+
startRecordingButtonText: 'Start recording',
|
|
45
|
+
finalTitle: 'Done recording?',
|
|
46
|
+
finalDescription:
|
|
47
|
+
'You can also add a quick note with extra context, expectations, or questions. Thank you!',
|
|
48
|
+
commentPlaceholder: 'Add a message...',
|
|
49
|
+
saveButtonText: 'Submit recording',
|
|
50
|
+
cancelButtonText: 'Cancel recording',
|
|
51
|
+
continuousOverlayTitle: 'Save time, skip the reproductions',
|
|
52
|
+
continuousOverlayDescription:
|
|
53
|
+
'We keep a rolling record of your recent activity. If something doesn’t work as expected, just save the recording and continue working. No need to worry about exceptions and errors - we automatically save recordings for those!',
|
|
54
|
+
saveLastSnapshotButtonText: 'Save recording',
|
|
55
|
+
submitDialogTitle: 'Save recording',
|
|
56
|
+
submitDialogSubtitle:
|
|
57
|
+
'This full-stack session recording will be saved directly to your selected Multiplayer project. All data is automatically correlated end-to-end.',
|
|
58
|
+
submitDialogCommentLabel: 'You can also add context, comments, or notes.',
|
|
59
|
+
submitDialogCommentPlaceholder: 'Add a message...',
|
|
60
|
+
submitDialogSubmitText: 'Save',
|
|
61
|
+
submitDialogCancelText: 'Cancel',
|
|
62
|
+
};
|
|
57
63
|
|
|
58
64
|
export const BASE_CONFIG: SessionRecorderConfigs = {
|
|
59
65
|
apiKey: '',
|
|
@@ -73,7 +79,6 @@ export const BASE_CONFIG: SessionRecorderConfigs = {
|
|
|
73
79
|
textOverrides: DEFAULT_WIDGET_TEXT_CONFIG,
|
|
74
80
|
},
|
|
75
81
|
|
|
76
|
-
|
|
77
82
|
apiBaseUrl: MULTIPLAYER_BASE_API_URL,
|
|
78
83
|
exporterEndpoint: MULTIPLAYER_OTEL_DEFAULT_TRACES_EXPORTER_HTTP_URL,
|
|
79
84
|
|
|
@@ -89,7 +94,6 @@ export const BASE_CONFIG: SessionRecorderConfigs = {
|
|
|
89
94
|
captureHeaders: true,
|
|
90
95
|
masking: DEFAULT_MASKING_CONFIG,
|
|
91
96
|
|
|
92
|
-
|
|
93
97
|
recordScreen: true,
|
|
94
98
|
recordGestures: true,
|
|
95
99
|
recordNavigation: true,
|
|
@@ -98,4 +102,4 @@ export const BASE_CONFIG: SessionRecorderConfigs = {
|
|
|
98
102
|
enabled: false,
|
|
99
103
|
level: LogLevel.INFO,
|
|
100
104
|
},
|
|
101
|
-
}
|
|
105
|
+
};
|
package/src/config/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Export all config-related functions and constants
|
|
2
|
-
export * from './constants'
|
|
3
|
-
export * from './defaults'
|
|
4
|
-
export * from './validators'
|
|
5
|
-
export * from './masking'
|
|
6
|
-
export * from './session-recorder'
|
|
2
|
+
export * from './constants';
|
|
3
|
+
export * from './defaults';
|
|
4
|
+
export * from './validators';
|
|
5
|
+
export * from './masking';
|
|
6
|
+
export * from './session-recorder';
|
package/src/config/masking.ts
CHANGED
|
@@ -1,34 +1,60 @@
|
|
|
1
|
-
import { type MaskingOptions, type SessionRecorderConfigs } from '../types'
|
|
2
|
-
import { DEFAULT_MASKING_CONFIG } from './defaults'
|
|
3
|
-
import { isValidArray, isValidBoolean, isValidFunction } from './validators'
|
|
4
|
-
import { SessionRecorderSdk } from '@multiplayer-app/session-recorder-common'
|
|
1
|
+
import { type MaskingOptions, type SessionRecorderConfigs } from '../types';
|
|
2
|
+
import { DEFAULT_MASKING_CONFIG } from './defaults';
|
|
3
|
+
import { isValidArray, isValidBoolean, isValidFunction } from './validators';
|
|
4
|
+
import { SessionRecorderSdk } from '@multiplayer-app/session-recorder-common';
|
|
5
5
|
|
|
6
|
-
const { mask, sensitiveFields, sensitiveHeaders } = SessionRecorderSdk
|
|
6
|
+
const { mask, sensitiveFields, sensitiveHeaders } = SessionRecorderSdk;
|
|
7
7
|
|
|
8
|
-
export const getMaskingConfig = (
|
|
9
|
-
|
|
8
|
+
export const getMaskingConfig = (
|
|
9
|
+
masking?: MaskingOptions
|
|
10
|
+
): SessionRecorderConfigs['masking'] => {
|
|
11
|
+
const baseMasking = DEFAULT_MASKING_CONFIG;
|
|
10
12
|
|
|
11
13
|
if (typeof masking !== 'object') {
|
|
12
|
-
return baseMasking
|
|
14
|
+
return baseMasking;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
const maskHeadersList = isValidArray(
|
|
16
|
-
|
|
17
|
+
const maskHeadersList = isValidArray(
|
|
18
|
+
masking.maskHeadersList,
|
|
19
|
+
sensitiveHeaders
|
|
20
|
+
);
|
|
21
|
+
const maskBodyFieldsList = isValidArray(
|
|
22
|
+
masking.maskBodyFieldsList,
|
|
23
|
+
sensitiveFields
|
|
24
|
+
);
|
|
17
25
|
|
|
18
26
|
return {
|
|
19
27
|
maskHeadersList,
|
|
20
28
|
maskBodyFieldsList,
|
|
21
|
-
headersToInclude: isValidArray(
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
headersToInclude: isValidArray(
|
|
30
|
+
masking.headersToInclude,
|
|
31
|
+
baseMasking.headersToInclude
|
|
32
|
+
),
|
|
33
|
+
headersToExclude: isValidArray(
|
|
34
|
+
masking.headersToExclude,
|
|
35
|
+
baseMasking.headersToExclude
|
|
36
|
+
),
|
|
37
|
+
isContentMaskingEnabled: isValidBoolean(
|
|
38
|
+
masking.isContentMaskingEnabled,
|
|
39
|
+
baseMasking.isContentMaskingEnabled
|
|
40
|
+
),
|
|
24
41
|
maskBody: isValidFunction(masking.maskBody, mask(maskBodyFieldsList)),
|
|
25
42
|
maskHeaders: isValidFunction(masking.maskHeaders, mask(maskHeadersList)),
|
|
26
43
|
// Screen masking options
|
|
27
|
-
maskTextInputs: isValidBoolean(
|
|
44
|
+
maskTextInputs: isValidBoolean(
|
|
45
|
+
masking.maskTextInputs,
|
|
46
|
+
baseMasking.maskTextInputs
|
|
47
|
+
),
|
|
28
48
|
maskImages: isValidBoolean(masking.maskImages, baseMasking.maskImages),
|
|
29
49
|
maskButtons: isValidBoolean(masking.maskButtons, baseMasking.maskButtons),
|
|
30
50
|
maskLabels: isValidBoolean(masking.maskLabels, baseMasking.maskLabels),
|
|
31
|
-
maskWebViews: isValidBoolean(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
maskWebViews: isValidBoolean(
|
|
52
|
+
masking.maskWebViews,
|
|
53
|
+
baseMasking.maskWebViews
|
|
54
|
+
),
|
|
55
|
+
maskSandboxedViews: isValidBoolean(
|
|
56
|
+
masking.maskSandboxedViews,
|
|
57
|
+
baseMasking.maskSandboxedViews
|
|
58
|
+
),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
LogLevel,
|
|
3
|
+
type SessionRecorderConfigs,
|
|
4
|
+
type SessionRecorderOptions,
|
|
5
|
+
} from '../types';
|
|
2
6
|
|
|
3
|
-
import { BASE_CONFIG } from './defaults'
|
|
4
|
-
import { getMaskingConfig } from './masking'
|
|
7
|
+
import { BASE_CONFIG } from './defaults';
|
|
8
|
+
import { getMaskingConfig } from './masking';
|
|
5
9
|
import {
|
|
6
10
|
isValidString,
|
|
7
11
|
isValidNumber,
|
|
8
12
|
isValidBoolean,
|
|
9
|
-
isValidArray
|
|
10
|
-
} from './validators'
|
|
11
|
-
import { getWidgetConfig } from './widget'
|
|
12
|
-
|
|
13
|
+
isValidArray,
|
|
14
|
+
} from './validators';
|
|
15
|
+
import { getWidgetConfig } from './widget';
|
|
13
16
|
|
|
14
17
|
const getLoggerConfig = (config: any) => {
|
|
15
18
|
if (!config || typeof config !== 'object') {
|
|
16
|
-
return BASE_CONFIG.logger
|
|
19
|
+
return BASE_CONFIG.logger;
|
|
17
20
|
}
|
|
18
21
|
return {
|
|
19
22
|
level: isValidNumber(config.level, LogLevel.INFO),
|
|
20
23
|
enabled: isValidBoolean(config.enabled, false),
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
+
};
|
|
25
|
+
};
|
|
24
26
|
|
|
25
|
-
export const getSessionRecorderConfig = (
|
|
27
|
+
export const getSessionRecorderConfig = (
|
|
28
|
+
c: SessionRecorderOptions
|
|
29
|
+
): SessionRecorderConfigs => {
|
|
26
30
|
if (!c) {
|
|
27
|
-
return BASE_CONFIG
|
|
31
|
+
return BASE_CONFIG;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
return {
|
|
@@ -33,27 +37,51 @@ export const getSessionRecorderConfig = (c: SessionRecorderOptions): SessionReco
|
|
|
33
37
|
application: isValidString(c.application, BASE_CONFIG.application),
|
|
34
38
|
environment: isValidString(c.environment, BASE_CONFIG.environment),
|
|
35
39
|
|
|
36
|
-
exporterEndpoint: isValidString(
|
|
40
|
+
exporterEndpoint: isValidString(
|
|
41
|
+
c.exporterEndpoint,
|
|
42
|
+
BASE_CONFIG.exporterEndpoint
|
|
43
|
+
),
|
|
37
44
|
apiBaseUrl: isValidString(c.apiBaseUrl, BASE_CONFIG.apiBaseUrl),
|
|
38
45
|
|
|
39
|
-
showContinuousRecording: isValidBoolean(
|
|
46
|
+
showContinuousRecording: isValidBoolean(
|
|
47
|
+
c.showContinuousRecording,
|
|
48
|
+
BASE_CONFIG.showContinuousRecording
|
|
49
|
+
),
|
|
40
50
|
ignoreUrls: isValidArray(c.ignoreUrls, BASE_CONFIG.ignoreUrls),
|
|
41
|
-
sampleTraceRatio: isValidNumber(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
sampleTraceRatio: isValidNumber(
|
|
52
|
+
c.sampleTraceRatio,
|
|
53
|
+
BASE_CONFIG.sampleTraceRatio
|
|
54
|
+
),
|
|
55
|
+
propagateTraceHeaderCorsUrls:
|
|
56
|
+
c.propagateTraceHeaderCorsUrls ||
|
|
57
|
+
BASE_CONFIG.propagateTraceHeaderCorsUrls,
|
|
58
|
+
schemifyDocSpanPayload: isValidBoolean(
|
|
59
|
+
c.schemifyDocSpanPayload,
|
|
60
|
+
BASE_CONFIG.schemifyDocSpanPayload
|
|
61
|
+
),
|
|
62
|
+
maxCapturingHttpPayloadSize: isValidNumber(
|
|
63
|
+
c.maxCapturingHttpPayloadSize,
|
|
64
|
+
BASE_CONFIG.maxCapturingHttpPayloadSize
|
|
65
|
+
),
|
|
46
66
|
|
|
47
67
|
captureBody: isValidBoolean(c.captureBody, BASE_CONFIG.captureBody),
|
|
48
|
-
captureHeaders: isValidBoolean(
|
|
49
|
-
|
|
68
|
+
captureHeaders: isValidBoolean(
|
|
69
|
+
c.captureHeaders,
|
|
70
|
+
BASE_CONFIG.captureHeaders
|
|
71
|
+
),
|
|
50
72
|
|
|
51
73
|
recordScreen: isValidBoolean(c.recordScreen, BASE_CONFIG.recordScreen),
|
|
52
|
-
recordGestures: isValidBoolean(
|
|
53
|
-
|
|
74
|
+
recordGestures: isValidBoolean(
|
|
75
|
+
c.recordGestures,
|
|
76
|
+
BASE_CONFIG.recordGestures
|
|
77
|
+
),
|
|
78
|
+
recordNavigation: isValidBoolean(
|
|
79
|
+
c.recordNavigation,
|
|
80
|
+
BASE_CONFIG.recordNavigation
|
|
81
|
+
),
|
|
54
82
|
|
|
55
83
|
masking: getMaskingConfig(c.masking),
|
|
56
84
|
widget: getWidgetConfig(c.widget),
|
|
57
85
|
logger: getLoggerConfig(c.logger),
|
|
58
|
-
}
|
|
59
|
-
}
|
|
86
|
+
};
|
|
87
|
+
};
|
package/src/config/validators.ts
CHANGED
|
@@ -2,30 +2,53 @@
|
|
|
2
2
|
* Validation helper functions for configuration objects
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export const isValidStringOrRegExp = (
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export const isValidStringOrRegExp = (
|
|
6
|
+
value: string | RegExp | undefined,
|
|
7
|
+
defaultValue: string | RegExp
|
|
8
|
+
) => {
|
|
9
|
+
return typeof value === 'string' || value instanceof RegExp
|
|
10
|
+
? value
|
|
11
|
+
: defaultValue;
|
|
12
|
+
};
|
|
8
13
|
|
|
9
|
-
export const isValidString = <T extends string>(
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
export const isValidString = <T extends string>(
|
|
15
|
+
value: string | undefined | T,
|
|
16
|
+
defaultValue: string
|
|
17
|
+
) => {
|
|
18
|
+
return typeof value === 'string' ? value.trim() : defaultValue;
|
|
19
|
+
};
|
|
12
20
|
|
|
13
|
-
export const isValidNumber = (
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
export const isValidNumber = (
|
|
22
|
+
value: number | undefined,
|
|
23
|
+
defaultValue: number
|
|
24
|
+
) => {
|
|
25
|
+
return typeof value === 'number' ? value : defaultValue;
|
|
26
|
+
};
|
|
16
27
|
|
|
17
|
-
export const isValidBoolean = (
|
|
18
|
-
|
|
19
|
-
|
|
28
|
+
export const isValidBoolean = (
|
|
29
|
+
value: boolean | undefined,
|
|
30
|
+
defaultValue: boolean
|
|
31
|
+
) => {
|
|
32
|
+
return typeof value === 'boolean' ? value : defaultValue;
|
|
33
|
+
};
|
|
20
34
|
|
|
21
|
-
export const isValidArray = <T>(
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
export const isValidArray = <T>(
|
|
36
|
+
value: ReadonlyArray<T> | undefined,
|
|
37
|
+
defaultValue: ReadonlyArray<T>
|
|
38
|
+
): T[] => {
|
|
39
|
+
return Array.isArray(value)
|
|
40
|
+
? ([...value] as T[])
|
|
41
|
+
: ([...defaultValue] as T[]);
|
|
42
|
+
};
|
|
24
43
|
|
|
25
|
-
export const isValidEnum = <T>(
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
export const isValidEnum = <T>(
|
|
45
|
+
value: any | T,
|
|
46
|
+
defaultValue: T,
|
|
47
|
+
enumValues: T[]
|
|
48
|
+
): T => {
|
|
49
|
+
return enumValues.includes(value as T) ? (value as T) : defaultValue;
|
|
50
|
+
};
|
|
28
51
|
|
|
29
52
|
export const isValidFunction = (value: any, defaultValue: any) => {
|
|
30
|
-
return typeof value === 'function' ? value : defaultValue
|
|
31
|
-
}
|
|
53
|
+
return typeof value === 'function' ? value : defaultValue;
|
|
54
|
+
};
|
package/src/config/widget.ts
CHANGED
|
@@ -1,38 +1,47 @@
|
|
|
1
|
-
import { type SessionRecorderOptions, WidgetButtonPlacement } from
|
|
2
|
-
import { BASE_CONFIG } from
|
|
3
|
-
import { isValidBoolean, isValidEnum, isValidString } from
|
|
1
|
+
import { type SessionRecorderOptions, WidgetButtonPlacement } from '../types';
|
|
2
|
+
import { BASE_CONFIG } from './defaults';
|
|
3
|
+
import { isValidBoolean, isValidEnum, isValidString } from './validators';
|
|
4
4
|
|
|
5
5
|
export const getWidgetConfig = (config: SessionRecorderOptions['widget']) => {
|
|
6
|
-
const textOverrides = getTextOverridesConfig(
|
|
6
|
+
const textOverrides = getTextOverridesConfig(
|
|
7
|
+
config?.textOverrides,
|
|
8
|
+
BASE_CONFIG.widget.textOverrides
|
|
9
|
+
);
|
|
7
10
|
|
|
8
11
|
const def = {
|
|
9
12
|
enabled: true,
|
|
10
13
|
button: { visible: true, placement: WidgetButtonPlacement.bottomRight },
|
|
11
14
|
textOverrides,
|
|
12
|
-
}
|
|
15
|
+
};
|
|
13
16
|
|
|
14
|
-
const placementCandidate = config?.button?.placement || def.button.placement
|
|
17
|
+
const placementCandidate = config?.button?.placement || def.button.placement;
|
|
15
18
|
|
|
16
19
|
return {
|
|
17
20
|
textOverrides,
|
|
18
21
|
enabled: isValidBoolean(config && config.enabled, def.enabled),
|
|
19
22
|
button: {
|
|
20
|
-
visible: isValidBoolean(
|
|
23
|
+
visible: isValidBoolean(
|
|
24
|
+
config && config.button && config.button.visible,
|
|
25
|
+
def.button.visible
|
|
26
|
+
),
|
|
21
27
|
placement: isValidEnum<WidgetButtonPlacement>(
|
|
22
28
|
placementCandidate,
|
|
23
29
|
def.button.placement,
|
|
24
30
|
Object.values(WidgetButtonPlacement)
|
|
25
31
|
),
|
|
26
32
|
},
|
|
27
|
-
}
|
|
28
|
-
}
|
|
33
|
+
};
|
|
34
|
+
};
|
|
29
35
|
|
|
30
36
|
const getTextOverridesConfig = (config: any, defaultConfig: any) => {
|
|
31
37
|
if (!config || typeof config !== 'object') {
|
|
32
|
-
return defaultConfig
|
|
38
|
+
return defaultConfig;
|
|
33
39
|
}
|
|
34
|
-
return Object.keys(defaultConfig).reduce(
|
|
35
|
-
acc
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
40
|
+
return Object.keys(defaultConfig).reduce(
|
|
41
|
+
(acc, key) => {
|
|
42
|
+
acc[key] = isValidString(config[key], defaultConfig[key]);
|
|
43
|
+
return acc;
|
|
44
|
+
},
|
|
45
|
+
{} as Record<string, unknown>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { createStore, type Store } from '../utils/createStore'
|
|
2
|
-
import { SessionType } from '@multiplayer-app/session-recorder-common'
|
|
3
|
-
import { SessionState } from '../types'
|
|
1
|
+
import { createStore, type Store } from '../utils/createStore';
|
|
2
|
+
import { SessionType } from '@multiplayer-app/session-recorder-common';
|
|
3
|
+
import { SessionState } from '../types';
|
|
4
4
|
|
|
5
5
|
export type SessionRecorderState = {
|
|
6
|
-
isInitialized: boolean
|
|
7
|
-
sessionType: SessionType | null
|
|
8
|
-
sessionState: SessionState | null
|
|
9
|
-
isWidgetModalVisible: boolean
|
|
10
|
-
isOnline: boolean
|
|
11
|
-
error: string | null
|
|
12
|
-
}
|
|
6
|
+
isInitialized: boolean;
|
|
7
|
+
sessionType: SessionType | null;
|
|
8
|
+
sessionState: SessionState | null;
|
|
9
|
+
isWidgetModalVisible: boolean;
|
|
10
|
+
isOnline: boolean;
|
|
11
|
+
error: string | null;
|
|
12
|
+
};
|
|
13
13
|
|
|
14
|
-
export const sessionRecorderStore: Store<SessionRecorderState> =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
export const sessionRecorderStore: Store<SessionRecorderState> =
|
|
15
|
+
createStore<SessionRecorderState>({
|
|
16
|
+
isInitialized: false,
|
|
17
|
+
sessionType: null,
|
|
18
|
+
sessionState: null,
|
|
19
|
+
isWidgetModalVisible: false,
|
|
20
|
+
isOnline: true,
|
|
21
|
+
error: null,
|
|
22
|
+
});
|
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
import { SessionType } from
|
|
2
|
-
import { SessionState } from
|
|
3
|
-
import { useStoreSelector } from
|
|
4
|
-
import {
|
|
1
|
+
import { SessionType } from '@multiplayer-app/session-recorder-common';
|
|
2
|
+
import { SessionState } from '../types';
|
|
3
|
+
import { useStoreSelector } from './useStoreSelector';
|
|
4
|
+
import {
|
|
5
|
+
type SessionRecorderState,
|
|
6
|
+
sessionRecorderStore,
|
|
7
|
+
} from './SessionRecorderStore';
|
|
5
8
|
|
|
6
9
|
export function useSessionRecorderStore<TSlice>(
|
|
7
10
|
selector: (s: SessionRecorderState) => TSlice,
|
|
8
11
|
equalityFn?: (a: TSlice, b: TSlice) => boolean
|
|
9
12
|
): TSlice {
|
|
10
|
-
return useStoreSelector<SessionRecorderState, TSlice>(
|
|
13
|
+
return useStoreSelector<SessionRecorderState, TSlice>(
|
|
14
|
+
sessionRecorderStore,
|
|
15
|
+
selector,
|
|
16
|
+
equalityFn
|
|
17
|
+
);
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
export function useSessionRecordingState() {
|
|
14
|
-
return useSessionRecorderStore<SessionState | null>((s) => s.sessionState)
|
|
21
|
+
return useSessionRecorderStore<SessionState | null>((s) => s.sessionState);
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export function useSessionType() {
|
|
18
|
-
return useSessionRecorderStore<SessionType | null>((s) => s.sessionType)
|
|
25
|
+
return useSessionRecorderStore<SessionType | null>((s) => s.sessionType);
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export function useIsInitialized() {
|
|
22
|
-
return useSessionRecorderStore<boolean>((s) => s.isInitialized)
|
|
29
|
+
return useSessionRecorderStore<boolean>((s) => s.isInitialized);
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
export function useWidgetModalVisible() {
|
|
26
|
-
return useSessionRecorderStore<boolean>((s) => s.isWidgetModalVisible)
|
|
27
|
-
}
|
|
33
|
+
return useSessionRecorderStore<boolean>((s) => s.isWidgetModalVisible);
|
|
34
|
+
}
|
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'react'
|
|
2
|
-
import { type Store } from '../utils/createStore'
|
|
3
|
-
import { shallowEqual } from '../utils/shallowEqual'
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { type Store } from '../utils/createStore';
|
|
3
|
+
import { shallowEqual } from '../utils/shallowEqual';
|
|
4
4
|
|
|
5
5
|
export function useStoreSelector<TState extends object, TSlice>(
|
|
6
6
|
store: Store<TState>,
|
|
7
7
|
selector: (state: TState) => TSlice,
|
|
8
|
-
equalityFn: (a: TSlice, b: TSlice) => boolean = Object.is
|
|
8
|
+
equalityFn: (a: TSlice, b: TSlice) => boolean = Object.is
|
|
9
9
|
): TSlice {
|
|
10
|
-
const latestSelectorRef = useRef(selector)
|
|
11
|
-
const latestEqualityRef = useRef(equalityFn)
|
|
12
|
-
latestSelectorRef.current = selector
|
|
13
|
-
latestEqualityRef.current = equalityFn
|
|
10
|
+
const latestSelectorRef = useRef(selector);
|
|
11
|
+
const latestEqualityRef = useRef(equalityFn);
|
|
12
|
+
latestSelectorRef.current = selector;
|
|
13
|
+
latestEqualityRef.current = equalityFn;
|
|
14
14
|
|
|
15
|
-
const [slice, setSlice] = useState<TSlice>(() =>
|
|
15
|
+
const [slice, setSlice] = useState<TSlice>(() =>
|
|
16
|
+
latestSelectorRef.current(store.getState())
|
|
17
|
+
);
|
|
16
18
|
|
|
17
19
|
useEffect(() => {
|
|
18
20
|
function handleChange(nextState: TState, prevState: TState) {
|
|
19
|
-
const nextSlice = latestSelectorRef.current(nextState)
|
|
20
|
-
const prevSlice = latestSelectorRef.current(prevState)
|
|
21
|
+
const nextSlice = latestSelectorRef.current(nextState);
|
|
22
|
+
const prevSlice = latestSelectorRef.current(prevState);
|
|
21
23
|
if (!latestEqualityRef.current(nextSlice, prevSlice)) {
|
|
22
|
-
setSlice(nextSlice)
|
|
24
|
+
setSlice(nextSlice);
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
|
-
const unsubscribe = store.subscribe(handleChange)
|
|
27
|
+
const unsubscribe = store.subscribe(handleChange);
|
|
26
28
|
// Sync once in case changed between render and effect
|
|
27
|
-
handleChange(store.getState(), store.getState())
|
|
28
|
-
return unsubscribe
|
|
29
|
-
}, [store])
|
|
29
|
+
handleChange(store.getState(), store.getState());
|
|
30
|
+
return unsubscribe;
|
|
31
|
+
}, [store]);
|
|
30
32
|
|
|
31
|
-
return slice
|
|
33
|
+
return slice;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export const shallow = shallowEqual
|
|
36
|
+
export const shallow = shallowEqual;
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import './patch'
|
|
2
|
-
import SessionRecorder from './session-recorder'
|
|
3
|
-
export * from '@multiplayer-app/session-recorder-common'
|
|
4
|
-
export * from './context/SessionRecorderContext'
|
|
5
|
-
export * from './context/useSessionRecorderStore'
|
|
1
|
+
import './patch';
|
|
2
|
+
import SessionRecorder from './session-recorder';
|
|
3
|
+
export * from '@multiplayer-app/session-recorder-common';
|
|
4
|
+
export * from './context/SessionRecorderContext';
|
|
5
|
+
export * from './context/useSessionRecorderStore';
|
|
6
6
|
|
|
7
7
|
// Export the class for type checking
|
|
8
|
-
export { SessionRecorder }
|
|
8
|
+
export { SessionRecorder };
|
|
9
9
|
// Export the instance as default
|
|
10
|
-
export default SessionRecorder
|
|
10
|
+
export default SessionRecorder;
|