@multiplayer-app/session-recorder-react-native 0.0.1-beta.7 → 0.0.1-beta.9

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 (75) hide show
  1. package/app.plugin.js +42 -0
  2. package/docs/NATIVE_MODULE_SETUP.md +177 -0
  3. package/ios/SessionRecorderNative.podspec +5 -0
  4. package/package.json +10 -1
  5. package/plugin/package.json +20 -0
  6. package/plugin/src/index.js +42 -0
  7. package/android/src/main/AndroidManifest.xml +0 -2
  8. package/android/src/main/java/com/multiplayer/sessionrecorder/ScreenMaskingModule.kt +0 -202
  9. package/android/src/main/java/com/multiplayer/sessionrecorder/ScreenMaskingPackage.kt +0 -16
  10. package/android/src/main/java/com/multiplayer/sessionrecorder/SessionRecorderModule.kt +0 -202
  11. package/android/src/main/java/com/multiplayer/sessionrecorder/SessionRecorderPackage.kt +0 -16
  12. package/babel.config.js +0 -13
  13. package/docs/AUTO_METADATA_DETECTION.md +0 -108
  14. package/docs/TROUBLESHOOTING.md +0 -168
  15. package/ios/ScreenMasking.m +0 -12
  16. package/ios/ScreenMasking.podspec +0 -21
  17. package/ios/ScreenMasking.swift +0 -205
  18. package/ios/SessionRecorder.podspec +0 -21
  19. package/scripts/generate-app-metadata.js +0 -173
  20. package/src/components/GestureCaptureWrapper/GestureCaptureWrapper.tsx +0 -86
  21. package/src/components/GestureCaptureWrapper/index.ts +0 -1
  22. package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +0 -72
  23. package/src/components/ScreenRecorderView/index.ts +0 -1
  24. package/src/components/SessionRecorderWidget/FinalPopover.tsx +0 -62
  25. package/src/components/SessionRecorderWidget/FloatingButton.tsx +0 -136
  26. package/src/components/SessionRecorderWidget/InitialPopover.tsx +0 -89
  27. package/src/components/SessionRecorderWidget/ModalContainer.tsx +0 -128
  28. package/src/components/SessionRecorderWidget/ModalHeader.tsx +0 -24
  29. package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +0 -109
  30. package/src/components/SessionRecorderWidget/icons.tsx +0 -52
  31. package/src/components/SessionRecorderWidget/index.ts +0 -3
  32. package/src/components/SessionRecorderWidget/styles.ts +0 -150
  33. package/src/components/index.ts +0 -3
  34. package/src/config/constants.ts +0 -60
  35. package/src/config/defaults.ts +0 -83
  36. package/src/config/index.ts +0 -6
  37. package/src/config/masking.ts +0 -28
  38. package/src/config/session-recorder.ts +0 -55
  39. package/src/config/validators.ts +0 -31
  40. package/src/context/SessionRecorderContext.tsx +0 -53
  41. package/src/index.ts +0 -9
  42. package/src/native/ScreenMasking.ts +0 -34
  43. package/src/native/SessionRecorderNative.ts +0 -34
  44. package/src/otel/helpers.ts +0 -275
  45. package/src/otel/index.ts +0 -138
  46. package/src/otel/instrumentations/index.ts +0 -115
  47. package/src/patch/index.ts +0 -1
  48. package/src/patch/xhr.ts +0 -141
  49. package/src/recorder/eventExporter.ts +0 -141
  50. package/src/recorder/gestureRecorder.ts +0 -498
  51. package/src/recorder/index.ts +0 -179
  52. package/src/recorder/navigationTracker.ts +0 -449
  53. package/src/recorder/screenRecorder.ts +0 -527
  54. package/src/services/api.service.ts +0 -203
  55. package/src/services/screenMaskingService.ts +0 -118
  56. package/src/services/storage.service.ts +0 -199
  57. package/src/session-recorder.ts +0 -606
  58. package/src/types/expo.d.ts +0 -23
  59. package/src/types/index.ts +0 -28
  60. package/src/types/session-recorder.ts +0 -429
  61. package/src/types/session.ts +0 -65
  62. package/src/utils/app-metadata.ts +0 -31
  63. package/src/utils/index.ts +0 -8
  64. package/src/utils/logger.ts +0 -225
  65. package/src/utils/nativeModuleTest.ts +0 -60
  66. package/src/utils/platform.ts +0 -384
  67. package/src/utils/request-utils.ts +0 -61
  68. package/src/utils/rrweb-events.ts +0 -309
  69. package/src/utils/session.ts +0 -18
  70. package/src/utils/time.ts +0 -17
  71. package/src/utils/type-utils.ts +0 -75
  72. package/src/version.ts +0 -1
  73. package/tsconfig.json +0 -24
  74. /package/ios/{SessionRecorder.m → SessionRecorderNative.m} +0 -0
  75. /package/ios/{SessionRecorder.swift → SessionRecorderNative.swift} +0 -0
@@ -1,225 +0,0 @@
1
- /**
2
- * Centralized logger utility for the session recorder
3
- * Provides consistent logging across all components
4
- */
5
-
6
- export enum LogLevel {
7
- DEBUG = 0,
8
- INFO = 1,
9
- WARN = 2,
10
- ERROR = 3
11
- }
12
-
13
- export interface LoggerConfig {
14
- level: LogLevel
15
- enableConsole: boolean
16
- enablePrefix: boolean
17
- prefix: string
18
- }
19
-
20
- class Logger {
21
- private config: LoggerConfig = {
22
- level: LogLevel.INFO,
23
- enableConsole: true,
24
- enablePrefix: true,
25
- prefix: '[SessionRecorder]',
26
- }
27
-
28
- private componentPrefixes: Map<string, string> = new Map([
29
- ['ScreenRecorder', '📸'],
30
- ['GestureRecorder', '👆'],
31
- ['GestureCaptureWrapper', '📸'],
32
- ['SessionRecorderContext', '🎯'],
33
- ['EventExporter', '📤'],
34
- ['NavigationTracker', '📸'],
35
- ['RecorderReactNativeSDK', '📤'],
36
- ['DEBUGGER_LIB', '🔍'],
37
- ])
38
-
39
- /**
40
- * Configure the logger
41
- * @param config - Logger configuration
42
- */
43
- configure(config: Partial<LoggerConfig>): void {
44
- this.config = { ...this.config, ...config }
45
- }
46
-
47
- /**
48
- * Set the log level
49
- * @param level - Log level to set
50
- */
51
- setLevel(level: LogLevel): void {
52
- this.config.level = level
53
- }
54
-
55
- /**
56
- * Enable or disable console output
57
- * @param enabled - Whether to enable console output
58
- */
59
- setConsoleEnabled(enabled: boolean): void {
60
- this.config.enableConsole = enabled
61
- }
62
-
63
- /**
64
- * Add or update a component prefix
65
- * @param component - Component name
66
- * @param emoji - Emoji prefix for the component
67
- */
68
- setComponentPrefix(component: string, emoji: string): void {
69
- this.componentPrefixes.set(component, emoji)
70
- }
71
-
72
- /**
73
- * Get the formatted prefix for a component
74
- * @param component - Component name
75
- * @returns Formatted prefix string
76
- */
77
- private getPrefix(component: string): string {
78
- if (!this.config.enablePrefix) return ''
79
-
80
- const emoji = this.componentPrefixes.get(component) || '📝'
81
- return `${this.config.prefix} ${emoji} [${component}]`
82
- }
83
-
84
- /**
85
- * Check if a log level should be output
86
- * @param level - Log level to check
87
- * @returns True if should output
88
- */
89
- private shouldLog(level: LogLevel): boolean {
90
- return level >= this.config.level && this.config.enableConsole
91
- }
92
-
93
- /**
94
- * Format the log message
95
- * @param component - Component name
96
- * @param level - Log level
97
- * @param message - Log message
98
- * @param data - Additional data to log
99
- * @returns Formatted log message
100
- */
101
- private formatMessage(component: string, level: LogLevel, message: string, data?: any): string {
102
- const prefix = this.getPrefix(component)
103
- const timestamp = new Date().toISOString()
104
- const levelName = LogLevel[level]
105
-
106
- let formattedMessage = `${prefix} ${levelName} ${message}`
107
-
108
- if (data !== undefined) {
109
- formattedMessage += ` ${JSON.stringify(data)}`
110
- }
111
-
112
- return formattedMessage
113
- }
114
-
115
- /**
116
- * Log a debug message
117
- * @param component - Component name
118
- * @param message - Log message
119
- * @param data - Additional data to log
120
- */
121
- debug(component: string, message: string, data?: any): void {
122
- if (!this.shouldLog(LogLevel.DEBUG)) return
123
-
124
- const formattedMessage = this.formatMessage(component, LogLevel.DEBUG, message, data)
125
- // eslint-disable-next-line no-console
126
- console.log(formattedMessage)
127
- }
128
-
129
- /**
130
- * Log an info message
131
- * @param component - Component name
132
- * @param message - Log message
133
- * @param data - Additional data to log
134
- */
135
- info(component: string, message: string, data?: any): void {
136
- if (!this.shouldLog(LogLevel.INFO)) return
137
-
138
- const formattedMessage = this.formatMessage(component, LogLevel.INFO, message, data)
139
- // eslint-disable-next-line no-console
140
- console.log(formattedMessage)
141
- }
142
-
143
- /**
144
- * Log a warning message
145
- * @param component - Component name
146
- * @param message - Log message
147
- * @param data - Additional data to log
148
- */
149
- warn(component: string, message: string, data?: any): void {
150
- if (!this.shouldLog(LogLevel.WARN)) return
151
-
152
- const formattedMessage = this.formatMessage(component, LogLevel.WARN, message, data)
153
- // eslint-disable-next-line no-console
154
- console.warn(formattedMessage)
155
- }
156
-
157
- /**
158
- * Log an error message
159
- * @param component - Component name
160
- * @param message - Log message
161
- * @param data - Additional data to log
162
- */
163
- error(component: string, message: string, data?: any): void {
164
- if (!this.shouldLog(LogLevel.ERROR)) return
165
-
166
- const formattedMessage = this.formatMessage(component, LogLevel.ERROR, message, data)
167
- // eslint-disable-next-line no-console
168
- console.error(formattedMessage)
169
- }
170
-
171
- /**
172
- * Log a success message (info level with success emoji)
173
- * @param component - Component name
174
- * @param message - Log message
175
- * @param data - Additional data to log
176
- */
177
- success(component: string, message: string, data?: any): void {
178
- if (!this.shouldLog(LogLevel.INFO)) return
179
-
180
- const prefix = this.getPrefix(component)
181
- const timestamp = new Date().toISOString()
182
- const formattedMessage = `${prefix} ✅ ${message}`
183
-
184
- let fullMessage = formattedMessage
185
- if (data !== undefined) {
186
- fullMessage += ` ${JSON.stringify(data)}`
187
- }
188
-
189
- // eslint-disable-next-line no-console
190
- console.log(fullMessage)
191
- }
192
-
193
- /**
194
- * Log a failure message (error level with failure emoji)
195
- * @param component - Component name
196
- * @param message - Log message
197
- * @param data - Additional data to log
198
- */
199
- failure(component: string, message: string, data?: any): void {
200
- if (!this.shouldLog(LogLevel.ERROR)) return
201
-
202
- const prefix = this.getPrefix(component)
203
- const timestamp = new Date().toISOString()
204
- const formattedMessage = `${prefix} ❌ ${message}`
205
-
206
- let fullMessage = formattedMessage
207
- if (data !== undefined) {
208
- fullMessage += ` ${JSON.stringify(data)}`
209
- }
210
-
211
- // eslint-disable-next-line no-console
212
- console.error(fullMessage)
213
- }
214
- }
215
-
216
- // Export a singleton instance
217
- export const logger = new Logger()
218
-
219
- // Export convenience functions for common use cases
220
- export const logDebug = (component: string, message: string, data?: any) => logger.debug(component, message, data)
221
- export const logInfo = (component: string, message: string, data?: any) => logger.info(component, message, data)
222
- export const logWarn = (component: string, message: string, data?: any) => logger.warn(component, message, data)
223
- export const logError = (component: string, message: string, data?: any) => logger.error(component, message, data)
224
- export const logSuccess = (component: string, message: string, data?: any) => logger.success(component, message, data)
225
- export const logFailure = (component: string, message: string, data?: any) => logger.failure(component, message, data)
@@ -1,60 +0,0 @@
1
- import { NativeModules } from 'react-native'
2
- import { logger } from './logger'
3
-
4
- /**
5
- * Test function to verify native module availability
6
- */
7
- export function testNativeModuleAvailability(): void {
8
- logger.info('NativeModuleTest', 'Testing native module availability...')
9
-
10
- // Log all available native modules
11
- const availableModules = Object.keys(NativeModules)
12
- logger.info('NativeModuleTest', `Available native modules: ${availableModules.join(', ')}`)
13
-
14
- // Check specifically for SessionRecorderNative
15
- const { SessionRecorderNative } = NativeModules
16
-
17
- if (SessionRecorderNative) {
18
- logger.info('NativeModuleTest', '✅ SessionRecorderNative module is available!')
19
-
20
- // Test if the methods exist
21
- if (typeof SessionRecorderNative.captureAndMask === 'function') {
22
- logger.info('NativeModuleTest', '✅ captureAndMask method is available!')
23
- } else {
24
- logger.warn('NativeModuleTest', '❌ captureAndMask method is not available')
25
- }
26
-
27
- if (typeof SessionRecorderNative.captureAndMaskWithOptions === 'function') {
28
- logger.info('NativeModuleTest', '✅ captureAndMaskWithOptions method is available!')
29
- } else {
30
- logger.warn('NativeModuleTest', '❌ captureAndMaskWithOptions method is not available')
31
- }
32
- } else {
33
- logger.error('NativeModuleTest', '❌ SessionRecorderNative module is not available')
34
- logger.info('NativeModuleTest', 'This could mean:')
35
- logger.info('NativeModuleTest', '1. Auto-linking has not completed yet')
36
- logger.info('NativeModuleTest', '2. The native module was not properly built')
37
- logger.info('NativeModuleTest', '3. The module name does not match')
38
- }
39
- }
40
-
41
- /**
42
- * Test function to verify auto-linking configuration
43
- */
44
- export function testAutoLinkingConfig(): void {
45
- logger.info('NativeModuleTest', 'Testing auto-linking configuration...')
46
-
47
- // Check if react-native.config.js exists and is properly configured
48
- try {
49
- const config = require('../../react-native.config.js')
50
- logger.info('NativeModuleTest', '✅ react-native.config.js found')
51
-
52
- if (config.dependencies && config.dependencies['react-native-session-recorder']) {
53
- logger.info('NativeModuleTest', '✅ Auto-linking configuration found for react-native-session-recorder')
54
- } else {
55
- logger.warn('NativeModuleTest', '❌ Auto-linking configuration not found for react-native-session-recorder')
56
- }
57
- } catch (error) {
58
- logger.warn('NativeModuleTest', '❌ react-native.config.js not found or invalid')
59
- }
60
- }
@@ -1,384 +0,0 @@
1
- import { IResourceAttributes } from '../types'
2
- import Constants from 'expo-constants'
3
- import { Platform, Dimensions, PixelRatio } from 'react-native'
4
- import { version } from '../version'
5
- import { getAutoDetectedAppMetadata } from './app-metadata'
6
-
7
- // Global app metadata configuration for non-Expo apps
8
- let globalAppMetadata: { name?: string; version?: string; bundleId?: string } = {}
9
-
10
- // Cache for auto-detected metadata to avoid repeated file reads
11
- let autoDetectedMetadata: { name?: string; version?: string; bundleId?: string } | null = null
12
-
13
- export interface PlatformInfo {
14
- isExpo: boolean
15
- isReactNative: boolean
16
- platform: 'ios' | 'android' | 'web' | 'unknown'
17
- platformVersion?: string
18
- expoVersion?: string
19
- deviceType: string
20
- }
21
-
22
- export function detectPlatform(): PlatformInfo {
23
- try {
24
- // Check if we're in an Expo environment
25
- const isExpo = !!Constants.default?.expoVersion || !!Constants.expoVersion
26
-
27
- if (isExpo) {
28
- const expoVersion = Constants.default?.expoVersion || Constants.expoVersion
29
- const platform = Constants.default?.platform || Constants.platform
30
-
31
- return {
32
- isExpo: true,
33
- isReactNative: true,
34
- platform: platform?.ios ? 'ios' : platform?.android ? 'android' : 'unknown',
35
- expoVersion,
36
- deviceType: 'expo',
37
- }
38
- }
39
-
40
- // Fallback to React Native detection
41
- return {
42
- isExpo: false,
43
- isReactNative: true,
44
- platform: Platform.OS as 'ios' | 'android' | 'web' | 'unknown',
45
- platformVersion: Platform.Version?.toString(),
46
- deviceType: Platform.OS,
47
- }
48
- } catch (error) {
49
- // Fallback for web or other environments
50
- return {
51
- isExpo: false,
52
- isReactNative: false,
53
- platform: 'unknown',
54
- deviceType: 'unknown',
55
- }
56
- }
57
- }
58
-
59
- export function getPlatformAttributes(): Record<string, any> {
60
- const platformInfo = detectPlatform()
61
-
62
- const attributes: Record<string, any> = {
63
- platform: platformInfo.isExpo ? 'expo' : 'react-native',
64
- 'device.type': platformInfo.deviceType,
65
- }
66
-
67
- if (platformInfo.platformVersion) {
68
- attributes['platform.version'] = platformInfo.platformVersion
69
- }
70
-
71
- if (platformInfo.expoVersion) {
72
- attributes['expo.version'] = platformInfo.expoVersion
73
- }
74
-
75
- return attributes
76
- }
77
-
78
- export function isExpoEnvironment(): boolean {
79
- return detectPlatform().isExpo
80
- }
81
-
82
- export function isReactNativeEnvironment(): boolean {
83
- return detectPlatform().isReactNative
84
- }
85
-
86
- /**
87
- * Configure app metadata for non-Expo React Native apps
88
- * Call this function in your app initialization to provide app information
89
- *
90
- * @example
91
- * ```typescript
92
- * import { configureAppMetadata } from '@multiplayer-app/session-recorder-react-native'
93
- *
94
- * // In your App.tsx or index.js
95
- * configureAppMetadata({
96
- * name: 'My Awesome App',
97
- * version: '1.2.3',
98
- * bundleId: 'com.mycompany.myapp',
99
- * buildNumber: '123',
100
- * displayName: 'My App',
101
- * })
102
- * ```
103
- */
104
- export function configureAppMetadata(metadata: {
105
- name?: string
106
- version?: string
107
- bundleId?: string
108
- buildNumber?: string
109
- displayName?: string
110
- }): void {
111
- globalAppMetadata = { ...globalAppMetadata, ...metadata }
112
- }
113
-
114
- /**
115
- * Get configured app metadata
116
- */
117
- export function getConfiguredAppMetadata(): { name?: string, version?: string, bundleId?: string, buildNumber?: string, displayName?: string, } {
118
- return { ...globalAppMetadata }
119
- }
120
-
121
- /**
122
- * Automatically detect app metadata from common configuration files
123
- * This runs without developer intervention
124
- */
125
- function autoDetectAppMetadata(): { name?: string; version?: string; bundleId?: string } {
126
- if (autoDetectedMetadata) {
127
- return autoDetectedMetadata
128
- }
129
-
130
- try {
131
- // Get auto-detected metadata from build-time generated file
132
- const autoMetadata = getAutoDetectedAppMetadata()
133
-
134
- // Filter out undefined values
135
- const metadata: { name?: string; version?: string; bundleId?: string } = {}
136
- if (autoMetadata.name) metadata.name = autoMetadata.name
137
- if (autoMetadata.version) metadata.version = autoMetadata.version
138
- if (autoMetadata.bundleId) metadata.bundleId = autoMetadata.bundleId
139
-
140
- autoDetectedMetadata = metadata
141
- return metadata
142
- } catch (error) {
143
- // Silently fail - this is optional auto-detection
144
- autoDetectedMetadata = {}
145
- return {}
146
- }
147
- }
148
-
149
- /**
150
- * Enhanced app metadata detection with automatic fallbacks
151
- */
152
- function getAppMetadata(): { name?: string; version?: string; bundleId?: string } {
153
- // Priority order:
154
- // 1. Expo config (if available)
155
- // 2. Manually configured metadata
156
- // 3. Auto-detected metadata
157
- // 4. Fallbacks
158
-
159
- const expoMetadata = getExpoMetadata()
160
- const configuredMetadata = getConfiguredAppMetadata()
161
- const autoMetadata = autoDetectAppMetadata()
162
-
163
- return {
164
- name: expoMetadata.name || configuredMetadata.name || autoMetadata.name,
165
- version: expoMetadata.version || configuredMetadata.version || autoMetadata.version,
166
- bundleId: expoMetadata.bundleId || configuredMetadata.bundleId || autoMetadata.bundleId,
167
- }
168
- }
169
-
170
- /**
171
- * Get metadata from Expo config
172
- */
173
- function getExpoMetadata(): { name?: string; version?: string; bundleId?: string } {
174
- const expoConfig = Constants.default?.expoConfig || Constants.expoConfig
175
- if (!expoConfig) return {}
176
-
177
- return {
178
- name: expoConfig.name,
179
- version: expoConfig.version,
180
- bundleId: expoConfig.ios?.bundleIdentifier || expoConfig.android?.package,
181
- }
182
- }
183
-
184
- export const getNavigatorInfo = (): IResourceAttributes => {
185
- const platformInfo = detectPlatform()
186
- const screenData = Dimensions.get('window')
187
- const screenDataScreen = Dimensions.get('screen')
188
- const pixelRatio = PixelRatio.get()
189
-
190
- // Get device type based on screen dimensions
191
- const getDeviceType = (): string => {
192
- const { width, height } = screenData
193
- const minDimension = Math.min(width, height)
194
- const maxDimension = Math.max(width, height)
195
-
196
- // Rough device type detection based on screen size
197
- if (maxDimension >= 1024) {
198
- return 'Tablet'
199
- } else if (minDimension >= 600) {
200
- return 'Large Phone'
201
- } else {
202
- return 'Phone'
203
- }
204
- }
205
-
206
- // Get orientation
207
- const getOrientation = (): string => {
208
- const { width, height } = screenData
209
- return width > height ? 'Landscape' : 'Portrait'
210
- }
211
-
212
- // Get OS version details
213
- const getOSInfo = (): string => {
214
- if (platformInfo.isExpo) {
215
- const platform = Constants.default?.platform || Constants.platform
216
- if (platform?.ios) {
217
- return `iOS ${Platform.Version}`
218
- } else if (platform?.android) {
219
- return `Android ${Platform.Version}`
220
- }
221
- }
222
-
223
- if (Platform.OS === 'ios') {
224
- return `iOS ${Platform.Version}`
225
- } else if (Platform.OS === 'android') {
226
- return `Android ${Platform.Version}`
227
- }
228
-
229
- return `${Platform.OS} ${Platform.Version || 'Unknown'}`
230
- }
231
-
232
- // Get device info string
233
- const getDeviceInfo = (): string => {
234
- const deviceType = getDeviceType()
235
- const osInfo = getOSInfo()
236
- return `${deviceType} - ${osInfo}`
237
- }
238
-
239
- // Get browser/runtime info
240
- const getBrowserInfo = (): string => {
241
- if (platformInfo.isExpo) {
242
- return `Expo ${platformInfo.expoVersion || 'Unknown'} - React Native`
243
- }
244
- return 'React Native'
245
- }
246
-
247
- // Get screen size string
248
- const getScreenSize = (): string => {
249
- return `${Math.round(screenData.width)}x${Math.round(screenData.height)}`
250
- }
251
-
252
- // Get app info with fallbacks for non-Expo apps
253
- const getAppInfo = (): string => {
254
- const appName = getAppName()
255
- const appVersion = getAppVersion()
256
- return `${appName} v${appVersion}`
257
- }
258
-
259
- // Get app name with automatic detection
260
- const getAppName = (): string => {
261
- const metadata = getAppMetadata()
262
- if (metadata.name) return metadata.name
263
-
264
- // Try configured display name as fallback
265
- const configuredMetadata = getConfiguredAppMetadata()
266
- if (configuredMetadata.displayName) return configuredMetadata.displayName
267
-
268
- // Final fallback
269
- return 'React Native App'
270
- }
271
-
272
- // Get app version with automatic detection
273
- const getAppVersion = (): string => {
274
- const metadata = getAppMetadata()
275
- if (metadata.version) return metadata.version
276
-
277
- // Final fallback
278
- return 'Unknown'
279
- }
280
-
281
- // Get bundle ID with automatic detection
282
- const getBundleId = (): string => {
283
- const metadata = getAppMetadata()
284
- if (metadata.bundleId) return metadata.bundleId
285
-
286
- // Fallback
287
- return 'com.reactnative.app'
288
- }
289
-
290
- // Get build number with multiple fallback strategies
291
- const getBuildNumber = (): string => {
292
- // Try Expo config first
293
- const expoBuildNumber =
294
- Constants.default?.expoConfig?.ios?.buildNumber ||
295
- Constants.expoConfig?.ios?.buildNumber ||
296
- Constants.default?.expoConfig?.android?.versionCode ||
297
- Constants.expoConfig?.android?.versionCode
298
- if (expoBuildNumber) return expoBuildNumber.toString()
299
-
300
- // Try configured metadata for non-Expo apps
301
- const configuredMetadata = getConfiguredAppMetadata()
302
- if (configuredMetadata.buildNumber) return configuredMetadata.buildNumber
303
-
304
- // Fallback
305
- return '1'
306
- }
307
-
308
- // Get network info (basic)
309
- const getNetworkInfo = (): string => {
310
- // This is a basic implementation - in a real app you might want to use @react-native-community/netinfo
311
- return 'Unknown'
312
- }
313
-
314
- // Get hardware info
315
- const getHardwareInfo = (): string => {
316
- const pixelRatioInfo = `Pixel Ratio: ${pixelRatio}`
317
- const screenDensity = PixelRatio.getFontScale()
318
- return `${pixelRatioInfo}, Font Scale: ${screenDensity}`
319
- }
320
-
321
- return {
322
- // Core platform info
323
- platform: platformInfo.isExpo ? 'expo' : 'react-native',
324
- userAgent: getBrowserInfo(),
325
- language: 'en', // Could be enhanced with react-native-localize if available
326
- timestamp: new Date().toISOString(),
327
-
328
- // Device and OS information
329
- deviceInfo: getDeviceInfo(),
330
- osInfo: getOSInfo(),
331
- browserInfo: getBrowserInfo(),
332
-
333
- // Screen information
334
- screenSize: getScreenSize(),
335
- pixelRatio: pixelRatio,
336
- orientation: getOrientation(),
337
- screenWidth: Math.round(screenData.width),
338
- screenHeight: Math.round(screenData.height),
339
- screenScale: pixelRatio,
340
-
341
- // Device capabilities
342
- hardwareConcurrency: 1, // React Native doesn't expose CPU cores directly
343
- cookiesEnabled: 'N/A', // Not applicable in React Native
344
-
345
- // App information
346
- packageVersion: version,
347
- appInfo: getAppInfo(),
348
- appName: getAppName(),
349
- appVersion: getAppVersion(),
350
- bundleId: getBundleId(),
351
- buildNumber: getBuildNumber(),
352
-
353
- // Platform specific
354
- platformType: platformInfo.platform,
355
- platformVersion: platformInfo.platformVersion,
356
- expoVersion: platformInfo.expoVersion,
357
- deviceType: getDeviceType(),
358
-
359
- // Additional device info
360
- deviceModel: Platform.OS === 'ios' ? 'iOS Device' : 'Android Device',
361
- deviceManufacturer: Platform.OS === 'ios' ? 'Apple' : 'Android Manufacturer',
362
- deviceBrand: Platform.OS === 'ios' ? 'Apple' : 'Android Brand',
363
-
364
- // Performance and hardware
365
- hardwareInfo: getHardwareInfo(),
366
- networkInfo: getNetworkInfo(),
367
-
368
- // Screen details
369
- screenDensity: PixelRatio.getFontScale(),
370
- screenScaleFactor: pixelRatio,
371
- windowWidth: Math.round(screenData.width),
372
- windowHeight: Math.round(screenData.height),
373
- fullScreenWidth: Math.round(screenDataScreen.width),
374
- fullScreenHeight: Math.round(screenDataScreen.height),
375
-
376
- // Environment info
377
- isExpo: platformInfo.isExpo,
378
- isReactNative: platformInfo.isReactNative,
379
- environment: platformInfo.isExpo ? 'expo' : 'react-native',
380
-
381
- // Additional platform attributes
382
- ...getPlatformAttributes(),
383
- }
384
- }