@multiplayer-app/session-recorder-react-native 0.0.1-alpha.9 → 0.0.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/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.d.ts +6 -0
- package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js +1 -0
- package/dist/components/GestureCaptureWrapper/GestureCaptureWrapper.js.map +1 -0
- package/dist/components/GestureCaptureWrapper/index.d.ts +1 -0
- package/dist/components/GestureCaptureWrapper/index.js +1 -0
- package/dist/components/GestureCaptureWrapper/index.js.map +1 -0
- package/dist/components/GestureCaptureWrapper.js +1 -1
- package/dist/components/GestureCaptureWrapper.js.map +1 -1
- package/dist/components/ScreenRecorderView/ScreenRecorderView.d.ts +5 -0
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js +1 -0
- package/dist/components/ScreenRecorderView/ScreenRecorderView.js.map +1 -0
- package/dist/components/ScreenRecorderView/index.d.ts +1 -0
- package/dist/components/ScreenRecorderView/index.js +1 -0
- package/dist/components/ScreenRecorderView/index.js.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -0
- package/dist/context/SessionRecorderContext.js +1 -1
- package/dist/context/SessionRecorderContext.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/otel/index.d.ts +0 -2
- package/dist/otel/index.js.map +1 -1
- package/dist/otel/instrumentations/gestureInstrumentation.js +1 -1
- package/dist/otel/instrumentations/gestureInstrumentation.js.map +1 -1
- package/dist/otel/instrumentations/index.d.ts +0 -3
- package/dist/otel/instrumentations/index.js +1 -1
- package/dist/otel/instrumentations/index.js.map +1 -1
- package/dist/recorder/gestureRecorder.d.ts +0 -9
- package/dist/recorder/gestureRecorder.js +1 -1
- package/dist/recorder/gestureRecorder.js.map +1 -1
- package/dist/recorder/index.d.ts +4 -3
- package/dist/recorder/index.js.map +1 -1
- package/dist/recorder/screenRecorder.d.ts +1 -6
- package/dist/recorder/screenRecorder.js +1 -1
- package/dist/recorder/screenRecorder.js.map +1 -1
- package/dist/session-recorder.d.ts +3 -2
- package/dist/session-recorder.js.map +1 -1
- package/dist/types/index.d.ts +2 -16
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/app-metadata.d.ts +16 -0
- package/dist/utils/app-metadata.js +1 -0
- package/dist/utils/app-metadata.js.map +1 -0
- package/dist/utils/platform.d.ts +35 -3
- package/dist/utils/platform.js +1 -1
- package/dist/utils/platform.js.map +1 -1
- package/dist/utils/rrweb-events.d.ts +1 -1
- package/dist/utils/rrweb-events.js +1 -1
- package/dist/utils/rrweb-events.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/AUTO_METADATA_DETECTION.md +108 -0
- package/package.json +6 -9
- package/scripts/generate-app-metadata.js +173 -0
- package/src/components/{GestureCaptureWrapper.tsx → GestureCaptureWrapper/GestureCaptureWrapper.tsx} +1 -25
- package/src/components/GestureCaptureWrapper/index.ts +1 -0
- package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +72 -0
- package/src/components/ScreenRecorderView/index.ts +1 -0
- package/src/components/index.ts +1 -0
- package/src/context/SessionRecorderContext.tsx +21 -89
- package/src/index.ts +8 -0
- package/src/otel/index.ts +1 -12
- package/src/otel/instrumentations/index.ts +1 -6
- package/src/recorder/gestureRecorder.ts +10 -134
- package/src/recorder/index.ts +5 -4
- package/src/recorder/screenRecorder.ts +6 -14
- package/src/session-recorder.ts +2 -3
- package/src/types/index.ts +2 -20
- package/src/utils/app-metadata.ts +31 -0
- package/src/utils/platform.ts +303 -6
- package/src/utils/rrweb-events.ts +2 -4
- package/src/version.ts +1 -1
- package/src/otel/instrumentations/gestureInstrumentation.ts +0 -141
- package/src/otel/instrumentations/reactNativeInstrumentation.ts +0 -77
- package/src/otel/instrumentations/reactNavigationInstrumentation.ts +0 -119
- package/src/recorder/gestureHandlerRecorder.ts +0 -157
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build script to automatically extract app metadata from configuration files
|
|
5
|
+
* This runs without developer intervention and generates app-metadata.ts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs')
|
|
9
|
+
const path = require('path')
|
|
10
|
+
|
|
11
|
+
function findProjectRoot() {
|
|
12
|
+
let currentDir = process.cwd()
|
|
13
|
+
|
|
14
|
+
// Look for package.json going up the directory tree
|
|
15
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
16
|
+
if (fs.existsSync(path.join(currentDir, 'package.json'))) {
|
|
17
|
+
return currentDir
|
|
18
|
+
}
|
|
19
|
+
currentDir = path.dirname(currentDir)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return process.cwd()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function extractAppMetadata(projectRoot) {
|
|
26
|
+
const metadata = {
|
|
27
|
+
name: undefined,
|
|
28
|
+
version: undefined,
|
|
29
|
+
bundleId: undefined,
|
|
30
|
+
buildNumber: undefined,
|
|
31
|
+
displayName: undefined,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
// Method 1: Try app.json
|
|
36
|
+
const appJsonPath = path.join(projectRoot, 'app.json')
|
|
37
|
+
if (fs.existsSync(appJsonPath)) {
|
|
38
|
+
const appConfig = JSON.parse(fs.readFileSync(appJsonPath, 'utf8'))
|
|
39
|
+
|
|
40
|
+
metadata.name = appConfig.name || appConfig.displayName
|
|
41
|
+
metadata.version = appConfig.version
|
|
42
|
+
metadata.displayName = appConfig.displayName
|
|
43
|
+
|
|
44
|
+
// Extract bundle ID from platform-specific configs
|
|
45
|
+
if (appConfig.ios?.bundleIdentifier) {
|
|
46
|
+
metadata.bundleId = appConfig.ios.bundleIdentifier
|
|
47
|
+
} else if (appConfig.android?.package) {
|
|
48
|
+
metadata.bundleId = appConfig.android.package
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (appConfig.ios?.buildNumber) {
|
|
52
|
+
metadata.buildNumber = appConfig.ios.buildNumber.toString()
|
|
53
|
+
} else if (appConfig.android?.versionCode) {
|
|
54
|
+
metadata.buildNumber = appConfig.android.versionCode.toString()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log('✅ Extracted metadata from app.json')
|
|
58
|
+
return metadata
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Method 2: Try app.config.js
|
|
62
|
+
const appConfigJsPath = path.join(projectRoot, 'app.config.js')
|
|
63
|
+
if (fs.existsSync(appConfigJsPath)) {
|
|
64
|
+
try {
|
|
65
|
+
// Clear require cache to get fresh config
|
|
66
|
+
delete require.cache[require.resolve(appConfigJsPath)]
|
|
67
|
+
const appConfig = require(appConfigJsPath)
|
|
68
|
+
|
|
69
|
+
metadata.name = appConfig.name || appConfig.displayName
|
|
70
|
+
metadata.version = appConfig.version
|
|
71
|
+
metadata.displayName = appConfig.displayName
|
|
72
|
+
|
|
73
|
+
// Extract bundle ID from platform-specific configs
|
|
74
|
+
if (appConfig.ios?.bundleIdentifier) {
|
|
75
|
+
metadata.bundleId = appConfig.ios.bundleIdentifier
|
|
76
|
+
} else if (appConfig.android?.package) {
|
|
77
|
+
metadata.bundleId = appConfig.android.package
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (appConfig.ios?.buildNumber) {
|
|
81
|
+
metadata.buildNumber = appConfig.ios.buildNumber.toString()
|
|
82
|
+
} else if (appConfig.android?.versionCode) {
|
|
83
|
+
metadata.buildNumber = appConfig.android.versionCode.toString()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log('✅ Extracted metadata from app.config.js')
|
|
87
|
+
return metadata
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.warn('⚠️ Could not parse app.config.js:', error.message)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Method 3: Fallback to package.json
|
|
94
|
+
const packageJsonPath = path.join(projectRoot, 'package.json')
|
|
95
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
96
|
+
const packageConfig = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
97
|
+
|
|
98
|
+
metadata.name = packageConfig.name
|
|
99
|
+
metadata.version = packageConfig.version
|
|
100
|
+
|
|
101
|
+
console.log('✅ Extracted metadata from package.json')
|
|
102
|
+
return metadata
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.warn('⚠️ Error extracting app metadata:', error.message)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return metadata
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function generateAppMetadataFile(metadata, outputPath) {
|
|
113
|
+
const content = `/**
|
|
114
|
+
* Auto-generated app metadata
|
|
115
|
+
* This file is generated at build time to provide app metadata without developer intervention
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
// This file is automatically generated by the build process
|
|
119
|
+
// It extracts metadata from app.json, app.config.js, or package.json
|
|
120
|
+
|
|
121
|
+
export interface AppMetadata {
|
|
122
|
+
name?: string
|
|
123
|
+
version?: string
|
|
124
|
+
bundleId?: string
|
|
125
|
+
buildNumber?: string
|
|
126
|
+
displayName?: string
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Auto-detected values from project configuration files
|
|
130
|
+
export const APP_METADATA: AppMetadata = {
|
|
131
|
+
name: ${metadata.name ? `"${metadata.name}"` : 'undefined'},
|
|
132
|
+
version: ${metadata.version ? `"${metadata.version}"` : 'undefined'},
|
|
133
|
+
bundleId: ${metadata.bundleId ? `"${metadata.bundleId}"` : 'undefined'},
|
|
134
|
+
buildNumber: ${metadata.buildNumber ? `"${metadata.buildNumber}"` : 'undefined'},
|
|
135
|
+
displayName: ${metadata.displayName ? `"${metadata.displayName}"` : 'undefined'},
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get auto-detected app metadata
|
|
140
|
+
*/
|
|
141
|
+
export function getAutoDetectedAppMetadata(): AppMetadata {
|
|
142
|
+
return { ...APP_METADATA }
|
|
143
|
+
}
|
|
144
|
+
`
|
|
145
|
+
|
|
146
|
+
fs.writeFileSync(outputPath, content, 'utf8')
|
|
147
|
+
console.log(`✅ Generated app-metadata.ts`)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function main() {
|
|
151
|
+
const projectRoot = findProjectRoot()
|
|
152
|
+
console.log(`🔍 Looking for app metadata in: ${projectRoot}`)
|
|
153
|
+
|
|
154
|
+
const metadata = extractAppMetadata(projectRoot)
|
|
155
|
+
|
|
156
|
+
// Show what was detected
|
|
157
|
+
console.log('📋 Detected metadata:')
|
|
158
|
+
Object.entries(metadata).forEach(([key, value]) => {
|
|
159
|
+
if (value) {
|
|
160
|
+
console.log(` ${key}: ${value}`)
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// Generate the TypeScript file
|
|
165
|
+
const outputPath = path.join(__dirname, '../src/utils/app-metadata.ts')
|
|
166
|
+
generateAppMetadataFile(metadata, outputPath)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (require.main === module) {
|
|
170
|
+
main()
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = { extractAppMetadata, generateAppMetadataFile }
|
package/src/components/{GestureCaptureWrapper.tsx → GestureCaptureWrapper/GestureCaptureWrapper.tsx}
RENAMED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import React, { ReactNode, useCallback,
|
|
1
|
+
import React, { ReactNode, useCallback, useMemo } from 'react'
|
|
2
2
|
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
3
|
-
import { GestureInstrumentation } from '../otel/instrumentations/gestureInstrumentation'
|
|
4
|
-
import { logger } from '../utils'
|
|
5
3
|
|
|
6
4
|
export interface GestureCaptureWrapperProps {
|
|
7
5
|
children: ReactNode
|
|
@@ -9,30 +7,8 @@ export interface GestureCaptureWrapperProps {
|
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
export const GestureCaptureWrapper: React.FC<GestureCaptureWrapperProps> = ({ children, onGestureRecord }) => {
|
|
12
|
-
const gestureInstrumentation = useRef(new GestureInstrumentation())
|
|
13
|
-
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
gestureInstrumentation.current.enable()
|
|
16
|
-
}, [])
|
|
17
|
-
|
|
18
10
|
const recordGesture = useCallback(
|
|
19
11
|
(gestureType: string, data: any) => {
|
|
20
|
-
// Record with OpenTelemetry
|
|
21
|
-
logger.debug('GestureCaptureWrapper', 'Recording gesture', { gestureType, data })
|
|
22
|
-
switch (gestureType) {
|
|
23
|
-
case 'tap':
|
|
24
|
-
gestureInstrumentation.current.recordTap(data.x, data.y)
|
|
25
|
-
break
|
|
26
|
-
case 'pan_start':
|
|
27
|
-
case 'pan_update':
|
|
28
|
-
case 'pan_end':
|
|
29
|
-
gestureInstrumentation.current.recordPan(data.translationX || 0, data.translationY || 0)
|
|
30
|
-
break
|
|
31
|
-
case 'long_press':
|
|
32
|
-
gestureInstrumentation.current.recordLongPress(data.duration, undefined)
|
|
33
|
-
break
|
|
34
|
-
}
|
|
35
|
-
|
|
36
12
|
// Record with session recorder
|
|
37
13
|
onGestureRecord(gestureType, data)
|
|
38
14
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./GestureCaptureWrapper";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import SessionRecorder from '@multiplayer-app/session-recorder-react-native'
|
|
2
|
+
import React, { PropsWithChildren, useCallback } from 'react'
|
|
3
|
+
import { View } from 'react-native'
|
|
4
|
+
import { SessionState } from '../../types'
|
|
5
|
+
import { logger } from '../../utils'
|
|
6
|
+
import { GestureCaptureWrapper } from '../GestureCaptureWrapper'
|
|
7
|
+
|
|
8
|
+
interface ScreenRecorderViewProps extends PropsWithChildren {}
|
|
9
|
+
|
|
10
|
+
export const ScreenRecorderView = ({ children }: ScreenRecorderViewProps) => {
|
|
11
|
+
// Set up gesture recording callback
|
|
12
|
+
const handleGestureRecord = useCallback((gestureType: string, data: any) => {
|
|
13
|
+
if (SessionRecorder.sessionState !== SessionState.started) {
|
|
14
|
+
logger.debug('SessionRecorderContext', 'Gesture recording skipped', {
|
|
15
|
+
client: !!SessionRecorder.sessionState,
|
|
16
|
+
sessionState: SessionRecorder.sessionState
|
|
17
|
+
})
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
logger.debug('SessionRecorderContext', 'Gesture recorded', { gestureType, data })
|
|
21
|
+
try {
|
|
22
|
+
// Record gesture as appropriate touch events
|
|
23
|
+
switch (gestureType) {
|
|
24
|
+
case 'tap':
|
|
25
|
+
// For tap, record both touch start and end
|
|
26
|
+
logger.debug('SessionRecorderContext', 'Recording tap as touch start + end')
|
|
27
|
+
SessionRecorder.recordTouchStart?.(data.x, data.y, undefined, 1.0)
|
|
28
|
+
SessionRecorder.recordTouchEnd?.(data.x, data.y, undefined, 1.0)
|
|
29
|
+
break
|
|
30
|
+
|
|
31
|
+
case 'pan_start':
|
|
32
|
+
logger.debug('SessionRecorderContext', 'Recording pan_start as touch start')
|
|
33
|
+
SessionRecorder.recordTouchStart?.(data.x, data.y, undefined, 1.0)
|
|
34
|
+
break
|
|
35
|
+
|
|
36
|
+
case 'pan_update':
|
|
37
|
+
logger.debug('SessionRecorderContext', 'Recording pan_update as touch move')
|
|
38
|
+
SessionRecorder.recordTouchMove?.(data.x, data.y, undefined, 1.0)
|
|
39
|
+
break
|
|
40
|
+
|
|
41
|
+
case 'pan_end':
|
|
42
|
+
logger.debug('SessionRecorderContext', 'Recording pan_end as touch end')
|
|
43
|
+
SessionRecorder.recordTouchEnd?.(data.x, data.y, undefined, 1.0)
|
|
44
|
+
break
|
|
45
|
+
|
|
46
|
+
case 'long_press':
|
|
47
|
+
logger.debug('SessionRecorderContext', 'Recording long_press as touch start + end')
|
|
48
|
+
SessionRecorder.recordTouchStart?.(data.x, data.y, undefined, 1.0)
|
|
49
|
+
SessionRecorder.recordTouchEnd?.(data.x, data.y, undefined, 1.0)
|
|
50
|
+
break
|
|
51
|
+
default:
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logger.error('SessionRecorderContext', 'Failed to record gesture event', error)
|
|
55
|
+
}
|
|
56
|
+
}, [])
|
|
57
|
+
|
|
58
|
+
// Callback ref to set the viewshot ref immediately when available
|
|
59
|
+
const setViewShotRef = (ref: View | null) => {
|
|
60
|
+
if (ref) {
|
|
61
|
+
SessionRecorder.setViewShotRef?.(ref)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<GestureCaptureWrapper onGestureRecord={handleGestureRecord}>
|
|
67
|
+
<View ref={setViewShotRef} style={{ flex: 1 }}>
|
|
68
|
+
{children}
|
|
69
|
+
</View>
|
|
70
|
+
</GestureCaptureWrapper>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./ScreenRecorderView";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './GestureCaptureWrapper'
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import React, { createContext, useContext,
|
|
1
|
+
import React, { createContext, useContext, PropsWithChildren, useState, useEffect, useRef } from 'react'
|
|
2
2
|
import { Pressable, Text, View } from 'react-native'
|
|
3
3
|
import { SessionRecorderOptions, SessionState } from '../types'
|
|
4
4
|
import SessionRecorder from '../session-recorder'
|
|
5
|
-
import { GestureCaptureWrapper } from '../components/GestureCaptureWrapper'
|
|
6
5
|
import sessionRecorder from '../session-recorder'
|
|
7
|
-
import {
|
|
6
|
+
import { ScreenRecorderView } from '../components/ScreenRecorderView'
|
|
8
7
|
|
|
9
8
|
interface SessionRecorderContextType {
|
|
10
9
|
instance: typeof SessionRecorder
|
|
@@ -44,96 +43,29 @@ export const SessionRecorderProvider: React.FC<SessionRecorderProviderProps> = (
|
|
|
44
43
|
|
|
45
44
|
return (
|
|
46
45
|
<SessionRecorderContext.Provider value={{ instance: sessionRecorder }}>
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
</Pressable>
|
|
67
|
-
</GestureEventCapture>
|
|
46
|
+
<ScreenRecorderView>{children}</ScreenRecorderView>
|
|
47
|
+
<Pressable onPress={onToggleSession}>
|
|
48
|
+
<View
|
|
49
|
+
style={{
|
|
50
|
+
position: 'absolute',
|
|
51
|
+
right: 0,
|
|
52
|
+
bottom: 100,
|
|
53
|
+
width: 48,
|
|
54
|
+
height: 48,
|
|
55
|
+
paddingTop: 16,
|
|
56
|
+
paddingLeft: 10,
|
|
57
|
+
backgroundColor: 'red',
|
|
58
|
+
borderTopLeftRadius: 24,
|
|
59
|
+
borderBottomLeftRadius: 24
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
<Text style={{ color: 'white' }}>{sessionState === SessionState.started ? 'Stop' : 'Start'}</Text>
|
|
63
|
+
</View>
|
|
64
|
+
</Pressable>
|
|
68
65
|
</SessionRecorderContext.Provider>
|
|
69
66
|
)
|
|
70
67
|
}
|
|
71
68
|
|
|
72
|
-
// Gesture-based event capture component
|
|
73
|
-
const GestureEventCapture: React.FC<{ children: ReactNode }> = ({ children }) => {
|
|
74
|
-
// Set up gesture recording callback
|
|
75
|
-
const handleGestureRecord = useCallback((gestureType: string, data: any) => {
|
|
76
|
-
if (SessionRecorder.sessionState !== SessionState.started) {
|
|
77
|
-
logger.debug('SessionRecorderContext', 'Gesture recording skipped', {
|
|
78
|
-
client: !!SessionRecorder.sessionState,
|
|
79
|
-
sessionState: SessionRecorder.sessionState
|
|
80
|
-
})
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
logger.debug('SessionRecorderContext', 'Gesture recorded', { gestureType, data })
|
|
84
|
-
try {
|
|
85
|
-
// Record gesture as appropriate touch events
|
|
86
|
-
switch (gestureType) {
|
|
87
|
-
case 'tap':
|
|
88
|
-
// For tap, record both touch start and end
|
|
89
|
-
logger.debug('SessionRecorderContext', 'Recording tap as touch start + end')
|
|
90
|
-
SessionRecorder.recordTouchStart?.(data.x, data.y, undefined, 1.0)
|
|
91
|
-
SessionRecorder.recordTouchEnd?.(data.x, data.y, undefined, 1.0)
|
|
92
|
-
break
|
|
93
|
-
|
|
94
|
-
case 'pan_start':
|
|
95
|
-
logger.debug('SessionRecorderContext', 'Recording pan_start as touch start')
|
|
96
|
-
SessionRecorder.recordTouchStart?.(data.x, data.y, undefined, 1.0)
|
|
97
|
-
break
|
|
98
|
-
|
|
99
|
-
case 'pan_update':
|
|
100
|
-
logger.debug('SessionRecorderContext', 'Recording pan_update as touch move')
|
|
101
|
-
SessionRecorder.recordTouchMove?.(data.x, data.y, undefined, 1.0)
|
|
102
|
-
break
|
|
103
|
-
|
|
104
|
-
case 'pan_end':
|
|
105
|
-
logger.debug('SessionRecorderContext', 'Recording pan_end as touch end')
|
|
106
|
-
SessionRecorder.recordTouchEnd?.(data.x, data.y, undefined, 1.0)
|
|
107
|
-
break
|
|
108
|
-
|
|
109
|
-
case 'long_press':
|
|
110
|
-
logger.debug('SessionRecorderContext', 'Recording long_press as touch start + end')
|
|
111
|
-
SessionRecorder.recordTouchStart?.(data.x, data.y, undefined, 1.0)
|
|
112
|
-
SessionRecorder.recordTouchEnd?.(data.x, data.y, undefined, 1.0)
|
|
113
|
-
break
|
|
114
|
-
default:
|
|
115
|
-
}
|
|
116
|
-
} catch (error) {
|
|
117
|
-
logger.error('SessionRecorderContext', 'Failed to record gesture event', error)
|
|
118
|
-
}
|
|
119
|
-
}, [])
|
|
120
|
-
|
|
121
|
-
// Callback ref to set the viewshot ref immediately when available
|
|
122
|
-
const setViewShotRef = (ref: View | null) => {
|
|
123
|
-
if (ref) {
|
|
124
|
-
SessionRecorder.setViewShotRef?.(ref)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return (
|
|
129
|
-
<GestureCaptureWrapper onGestureRecord={handleGestureRecord}>
|
|
130
|
-
<View ref={setViewShotRef} style={{ flex: 1 }}>
|
|
131
|
-
{children}
|
|
132
|
-
</View>
|
|
133
|
-
</GestureCaptureWrapper>
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
69
|
export const useSessionRecorder = (): SessionRecorderContextType => {
|
|
138
70
|
const context = useContext(SessionRecorderContext)
|
|
139
71
|
if (!context) {
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,14 @@ import SessionRecorder from './session-recorder'
|
|
|
3
3
|
export * from '@multiplayer-app/session-recorder-common'
|
|
4
4
|
export * from './context/SessionRecorderContext'
|
|
5
5
|
|
|
6
|
+
// Export platform utilities including app metadata configuration
|
|
7
|
+
export {
|
|
8
|
+
detectPlatform,
|
|
9
|
+
isExpoEnvironment,
|
|
10
|
+
configureAppMetadata,
|
|
11
|
+
getPlatformAttributes,
|
|
12
|
+
getConfiguredAppMetadata,
|
|
13
|
+
} from './utils/platform'
|
|
6
14
|
|
|
7
15
|
export { SessionRecorder }
|
|
8
16
|
// Export the instance as default
|
package/src/otel/index.ts
CHANGED
|
@@ -13,8 +13,7 @@ import {
|
|
|
13
13
|
import { TracerReactNativeConfig } from '../types'
|
|
14
14
|
import { getInstrumentations } from './instrumentations'
|
|
15
15
|
import { getExporterEndpoint } from './helpers'
|
|
16
|
-
|
|
17
|
-
import { GestureInstrumentation } from './instrumentations/gestureInstrumentation'
|
|
16
|
+
|
|
18
17
|
import { getPlatformAttributes } from '../utils/platform'
|
|
19
18
|
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
|
|
20
19
|
|
|
@@ -28,8 +27,6 @@ export class TracerReactNativeSDK {
|
|
|
28
27
|
private sessionId = ''
|
|
29
28
|
private idGenerator?: SessionRecorderIdGenerator
|
|
30
29
|
private exporter?: any
|
|
31
|
-
private navigationInstrumentation?: ReactNavigationInstrumentation
|
|
32
|
-
private gestureInstrumentation?: GestureInstrumentation
|
|
33
30
|
private isInitialized = false
|
|
34
31
|
|
|
35
32
|
constructor() { }
|
|
@@ -80,14 +77,6 @@ export class TracerReactNativeSDK {
|
|
|
80
77
|
instrumentations: getInstrumentations(this.config),
|
|
81
78
|
})
|
|
82
79
|
|
|
83
|
-
// // Initialize React Native specific instrumentations
|
|
84
|
-
// this.navigationInstrumentation = new ReactNavigationInstrumentation()
|
|
85
|
-
// this.gestureInstrumentation = new GestureInstrumentation()
|
|
86
|
-
|
|
87
|
-
// // Enable the custom instrumentations
|
|
88
|
-
// this.navigationInstrumentation.enable()
|
|
89
|
-
// this.gestureInstrumentation.enable()
|
|
90
|
-
|
|
91
80
|
this.isInitialized = true
|
|
92
81
|
}
|
|
93
82
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'
|
|
2
2
|
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'
|
|
3
3
|
|
|
4
|
+
import { logger } from '../../utils'
|
|
4
5
|
import { OTEL_IGNORE_URLS } from '../../config'
|
|
5
6
|
import { TracerReactNativeConfig } from '../../types'
|
|
6
7
|
import { extractResponseBody, headersToObject, processHttpPayload } from '../helpers'
|
|
7
|
-
import { logger } from '../../utils'
|
|
8
8
|
|
|
9
9
|
export function getInstrumentations(config: TracerReactNativeConfig) {
|
|
10
10
|
|
|
@@ -113,8 +113,3 @@ export function getInstrumentations(config: TracerReactNativeConfig) {
|
|
|
113
113
|
|
|
114
114
|
return instrumentations
|
|
115
115
|
}
|
|
116
|
-
|
|
117
|
-
// Export custom instrumentations for manual use
|
|
118
|
-
export { ReactNativeInstrumentation } from './reactNativeInstrumentation'
|
|
119
|
-
export { ReactNavigationInstrumentation } from './reactNavigationInstrumentation'
|
|
120
|
-
export { GestureInstrumentation } from './gestureInstrumentation'
|