import { NativeModules, NativeEventEmitter, DeviceEventEmitter, } from 'react-native'; import NativeNetworkInspector from './NativeNetworkInspector'; export interface NativeDeviceMetrics { totalRAM?: number; freeRAM?: number; usedRAM?: number; residentMemory?: number; virtualMemory?: number; isLowMemory?: boolean; nativeHeapAllocated?: number; nativeHeapSize?: number; nativeHeapFree?: number; freeStorage?: number; totalStorage?: number; batteryPercent?: number; isCharging?: boolean; deviceModel?: string; deviceBrand?: string; osVersion?: string; apiLevel?: number; cpuAbi?: string; appName?: string; appVersion?: string; appBuild?: string; appBundleId?: string; appPackageName?: string; } export interface NativeCrashEvent { platform: 'android' | 'ios'; error: string; name?: string; stack?: string; threadName?: string; timestamp: number; } // Seamless TurboModule (New Architecture / JSI) & Legacy NativeModules Bridge resolution const NativeModule: any = NativeNetworkInspector || NativeModules.NetworkInspectorModule || NativeModules.NetworkInspector; export const isNativeModuleAvailable = (): boolean => { return !!NativeModule; }; const getNativeEmitter = () => { try { if (NativeModules && NativeModules.NetworkInspectorModule) { return new NativeEventEmitter(NativeModules.NetworkInspectorModule); } } catch (e) {} return null; }; const nativeEmitter = getNativeEmitter(); /** * Retrieves low-level native hardware and system metrics (RAM, Heap, Disk, Battery, CPU). */ export const getNativeDeviceMetrics = async (): Promise => { if (!NativeModule || !NativeModule.getDeviceMetrics) { return null; } try { const metrics: NativeDeviceMetrics = await NativeModule.getDeviceMetrics(); return metrics; } catch (error) { return null; } }; /** * Enables native signal and uncaught exception protection in the iOS / Android runtime. * Automatically ensures the native floating icon is shown and available before UI renders. */ export const enableNativeCrashProtection = async (options?: { showFloatingButton?: boolean; }): Promise => { if (!NativeModule || !NativeModule.enableNativeCrashProtection) { return false; } try { const result = await NativeModule.enableNativeCrashProtection(); if (options?.showFloatingButton === true) { await showNativeFloatingButton(); } return !!result; } catch (error) { return false; } }; /** * Subscribes to fatal native crash events caught by the iOS / Kotlin exception handlers. */ export const subscribeNativeCrashes = ( callback: (event: NativeCrashEvent) => void, ): (() => void) => { const cleanups: Array<() => void> = []; try { const sub1 = DeviceEventEmitter.addListener('onNativeCrash', callback); cleanups.push(() => sub1.remove()); } catch (e) {} if (nativeEmitter) { try { const sub2 = nativeEmitter.addListener('onNativeCrash', callback); cleanups.push(() => sub2.remove()); } catch (e) {} } return () => { cleanups.forEach(fn => { try { fn(); } catch (e) {} }); }; }; export interface FloatingButtonOptions { size?: number; x?: number; y?: number; } /** * Displays the 100% native main-thread floating overlay button. * Dragging & touches run on the native UI thread, completely isolated from JS thread stalls. */ export const showNativeFloatingButton = async ( options?: FloatingButtonOptions, ): Promise => { if (!NativeModule || !NativeModule.showFloatingButton) { return false; } try { const result = await NativeModule.showFloatingButton(options || {}); return !!result; } catch (error) { return false; } }; /** * Hides the native floating overlay button. */ export const hideNativeFloatingButton = async (): Promise => { if (!NativeModule || !NativeModule.hideFloatingButton) { return false; } try { const result = await NativeModule.hideFloatingButton(); return !!result; } catch (error) { return false; } }; /** * Updates the badge/status dot on the native floating overlay button. */ export const setNativeFloatingButtonBadge = async ( hasBadge: boolean, ): Promise => { if (!NativeModule || !NativeModule.setFloatingButtonBadge) { return false; } try { const result = await NativeModule.setFloatingButtonBadge(hasBadge); return !!result; } catch (error) { return false; } }; /** * Subscribes to tap events on the native floating button. */ export const subscribeNativeFloatingButtonPress = ( callback: () => void, ): (() => void) => { const cleanups: Array<() => void> = []; try { const sub1 = DeviceEventEmitter.addListener( 'onFloatingButtonPress', callback, ); cleanups.push(() => sub1.remove()); } catch (e) {} if (nativeEmitter) { try { const sub2 = nativeEmitter.addListener( 'onFloatingButtonPress', callback, ); cleanups.push(() => sub2.remove()); } catch (e) {} } // Active Bridgeless / TurboModule tap detection const interval = setInterval(async () => { if (NativeModule && NativeModule.checkFloatingButtonPress) { try { const pressed = await NativeModule.checkFloatingButtonPress(); if (pressed) { callback(); } } catch (e) {} } }, 180); cleanups.push(() => clearInterval(interval)); return () => { cleanups.forEach(fn => { try { fn(); } catch (e) {} }); }; }; /** * Starts hardware-accurate native UI thread FPS tracking (CADisplayLink / Choreographer). */ export const startNativeFpsMonitoring = async (): Promise => { if (!NativeModule || !NativeModule.startFpsMonitoring) { return false; } try { const result = await NativeModule.startFpsMonitoring(); return !!result; } catch { return false; } }; /** * Stops native FPS tracking. */ export const stopNativeFpsMonitoring = async (): Promise => { if (!NativeModule || !NativeModule.stopFpsMonitoring) { return false; } try { const result = await NativeModule.stopFpsMonitoring(); return !!result; } catch { return false; } }; export interface NativeFpsMetrics { fps: number; targetFps: number; } /** * Reads the latest live hardware FPS from CADisplayLink (iOS) or Choreographer (Android). */ export const getNativeFpsMetrics = async (): Promise => { if (!NativeModule || !NativeModule.getFpsMetrics) { return {fps: 60, targetFps: 60}; } try { const metrics = await NativeModule.getFpsMetrics(); return { fps: typeof metrics?.fps === 'number' ? metrics.fps : 60, targetFps: typeof metrics?.targetFps === 'number' ? metrics.targetFps : 60, }; } catch { return {fps: 60, targetFps: 60}; } }; /** * Subscribes to physical hardware shake events (or Cmd+Ctrl+Z on iOS simulator). */ export const subscribeNativeDeviceShake = ( callback: () => void, ): (() => void) => { if (!nativeEmitter) { return () => {}; } try { const subscription = nativeEmitter.addListener('onDeviceShake', callback); return () => { subscription.remove(); }; } catch { return () => {}; } }; /** * Reads a persisted value synchronously from native NSUserDefaults / SharedPreferences. */ export const getNativeStorageItem = async ( key: string, ): Promise => { if (!NativeModule || !NativeModule.getNativeStorageItem) { return null; } try { const val = await NativeModule.getNativeStorageItem(key); return typeof val === 'string' ? val : null; } catch { return null; } }; /** * Persists a key-value pair to native NSUserDefaults / SharedPreferences with 0ms latency. */ export const setNativeStorageItem = async ( key: string, value: string | null, ): Promise => { if (!NativeModule || !NativeModule.setNativeStorageItem) { return false; } try { const result = await NativeModule.setNativeStorageItem(key, value); return !!result; } catch { return false; } }; export type HapticStyle = 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error'; /** * Triggers hardware native haptic feedback (iOS UIFeedbackGenerator / Android VibrationEffect). */ export const triggerNativeHaptic = async ( style: HapticStyle = 'light', ): Promise => { if (!NativeModule || !NativeModule.triggerHaptic) { return false; } try { const result = await NativeModule.triggerHaptic(style); return !!result; } catch { return false; } }; export interface NativeSystemMetrics { thermalState: 'nominal' | 'fair' | 'serious' | 'critical'; residentRamMb: number; totalPhysicalRamMb: number; fps: number; activeCpuCores: number; } /** * Retrieves live system thermal state and RAM telemetry directly from native layer. */ export const getNativeSystemMetrics = async (): Promise => { if (!NativeModule || !NativeModule.getNativeSystemMetrics) { return null; } try { const metrics = await NativeModule.getNativeSystemMetrics(); return metrics as NativeSystemMetrics; } catch { return null; } }; /** * Pushes a log payload to native background worker queues for instant native page caching. */ export const pushNativeLogRecord = async ( pageKey: 'apis' | 'logs' | 'analytics' | 'crash', jsonPayload: string, ): Promise => { if (!NativeModule || !NativeModule.pushNativeLogRecord) { return false; } try { const result = await NativeModule.pushNativeLogRecord(pageKey, jsonPayload); return !!result; } catch { return false; } }; export interface NativeCachedPageResult { pageKey: string; total: number; offset: number; items: T[]; } /** * Fetches pre-indexed, pre-sliced page data directly from native background memory queues. * Delivers instantaneous 0ms page loading without blocking JS render thread. */ export const fetchNativeCachedPage = async ( pageKey: 'apis' | 'logs' | 'analytics' | 'crash', offset: number = 0, limit: number = 50, query: string = '', ): Promise | null> => { if (!NativeModule || !NativeModule.getNativeCachedPage) { return null; } try { const rawJson: string = await NativeModule.getNativeCachedPage( pageKey, offset, limit, query, ); if (!rawJson) return null; const parsed = JSON.parse(rawJson); const parsedItems = (parsed.items || []).map((item: string | object) => typeof item === 'string' ? JSON.parse(item) : item, ); return { pageKey: parsed.pageKey || pageKey, total: parsed.total || 0, offset: parsed.offset || offset, items: parsedItems, }; } catch { return null; } }; export interface ScreenshotOptions { format?: 'png' | 'jpeg' | 'webp'; quality?: number; // 0.1 to 1.0 scale?: number; // 0.5, 0.75, 1.0 hideInspector?: boolean; includeBase64?: boolean; } export interface ScreenshotResult { uri: string; format: 'png' | 'jpeg' | 'webp'; width: number; height: number; sizeBytes: number; timestamp: number; base64?: string; } export interface RecordingOptions { /** Output format: 'mp4' (H.264) or 'gif' (animated GIF). Default: 'mp4' */ format?: 'mp4' | 'gif'; /** Audio source: 'none' (muted), 'app' (in-app audio), 'mic' (microphone), 'mixed'. Default: 'none' */ audioSource?: 'none' | 'app' | 'mic' | 'mixed'; /** Target frames per second: 5–60. Default: 30 */ fps?: number; /** Resolution scale factor: 0.2–1.0. Lower = smaller file, less CPU. Default: 0.5 */ scale?: number; /** H.264 encoding bitrate in bits/sec. 0 = auto (adaptive to resolution). Default: auto */ bitrate?: number; /** Maximum recording duration in seconds: 5–300. Default: 120 */ maxDurationSeconds?: number; /** Temporarily hide inspector overlay during recording. Default: false */ hideInspector?: boolean; } export interface RecordingResult { uri: string; thumbnailUri?: string; format: 'mp4' | 'gif'; durationMs: number; hasAudio: boolean; width: number; height: number; sizeBytes: number; timestamp: number; } export interface GifConversionOptions { fps?: number; width?: number; maxDurationSeconds?: number; } export interface CapturedMediaItem { id: string; type: 'image' | 'video' | 'gif'; format: string; uri: string; thumbnailUri?: string; filename: string; sizeBytes: number; timestamp: number; durationMs?: number; hasAudio?: boolean; width?: number; height?: number; } /** * Captures a high-resolution native screenshot of the application window. */ export const takeNativeScreenshot = async ( options?: ScreenshotOptions, ): Promise => { if (!NativeModule || !NativeModule.takeScreenshot) { return null; } try { const result = await NativeModule.takeScreenshot(options || {}); return result as ScreenshotResult; } catch { return null; } }; /** * Starts native video or GIF recording of the application. */ export const startNativeVideoRecording = async ( options?: RecordingOptions, ): Promise => { if (!NativeModule || !NativeModule.startVideoRecording) { return false; } try { const result = await NativeModule.startVideoRecording(options || {}); return !!result; } catch { return false; } }; /** * Stops active video or GIF recording and returns the final file metadata. */ export const stopNativeVideoRecording = async (): Promise => { if (!NativeModule || !NativeModule.stopVideoRecording) { return null; } try { const result = await NativeModule.stopVideoRecording(); return result as RecordingResult; } catch { return null; } }; /** * Checks if a recording session is currently active. */ export const isNativeRecordingActive = async (): Promise => { if (!NativeModule || !NativeModule.isRecording) { return false; } try { const result = await NativeModule.isRecording(); return !!result; } catch { return false; } }; /** * Plays a recorded video file using the native system media player. */ export const playNativeVideo = async (videoUri: string): Promise => { if (!NativeModule || !NativeModule.playVideo) { return false; } try { const result = await NativeModule.playVideo(videoUri); return !!result; } catch { return false; } }; /** * Converts a recorded MP4 video to an animated GIF. */ export const convertNativeVideoToGif = async ( videoUri: string, options?: GifConversionOptions, ): Promise => { if (!NativeModule || !NativeModule.convertToGif) { return null; } try { const result = await NativeModule.convertToGif(videoUri, options || {}); return result as RecordingResult; } catch { return null; } }; /** * Fetches all captured screenshots, recordings, and GIFs from disk. */ export const fetchCapturedMediaList = async (): Promise => { if (!NativeModule || !NativeModule.getCapturedMedia) { return []; } try { const raw: any = await NativeModule.getCapturedMedia(); if (!raw) return []; const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw; return Array.isArray(parsed) ? parsed : []; } catch { return []; } }; /** * Deletes a specific media file from disk. */ export const deleteCapturedMediaFile = async (uri: string): Promise => { if (!NativeModule || !NativeModule.deleteCapturedMedia) { return false; } try { const result = await NativeModule.deleteCapturedMedia(uri); return !!result; } catch { return false; } }; /** * Purges all captured media files from disk. */ export const clearAllCapturedMediaFiles = async (): Promise => { if (!NativeModule || !NativeModule.clearAllCapturedMedia) { return false; } try { const result = await NativeModule.clearAllCapturedMedia(); return !!result; } catch { return false; } }; /** * Copies a media file (image/video) to the system clipboard as media data if supported. */ export const copyMediaToClipboard = async (filePath: string): Promise => { if (!filePath) return false; if (!NativeModule || !NativeModule.copyMediaToClipboard) { return false; } try { const result = await NativeModule.copyMediaToClipboard(filePath); return Boolean(result?.success); } catch { return false; } }; /** * 100% Native photo editing (lossless crop, rotate, flip, and GPU color grading). */ export const editNativePhoto = async ( options: import('../types/editor').PhotoEditOptions, ): Promise => { if (!NativeModule || !NativeModule.editPhoto) { return null; } try { const result = await NativeModule.editPhoto(options); return result as import('../types/editor').PhotoEditResult; } catch (err) { return null; } }; /** * 100% Native hardware-accelerated video trimming and export. */ export const trimNativeVideo = async ( options: import('../types/editor').VideoTrimOptions, ): Promise => { if (!NativeModule || !NativeModule.trimVideo) { return null; } try { const result = await NativeModule.trimVideo(options); return result as import('../types/editor').VideoTrimResult; } catch (err) { return null; } }; /** * 100% Native video filmstrip thumbnail generator for timeline scrubbers. */ export const generateNativeFilmstrip = async ( options: import('../types/editor').FilmstripOptions, ): Promise => { if (!NativeModule || !NativeModule.generateFilmstrip) { return null; } try { const result = await NativeModule.generateFilmstrip(options); return result as import('../types/editor').FilmstripResult; } catch (err) { return null; } }; export interface PickMediaOptions { mediaType?: 'image' | 'video' | 'any'; } /** * Opens native system photo/video picker (Camera Roll / Photo Library) * with strict media type filtering (photos only or videos only). */ export const pickNativeMedia = async ( options?: PickMediaOptions, ): Promise => { if (!NativeModule || !NativeModule.pickMedia) { return null; } try { const result = await NativeModule.pickMedia(options || {}); return (result as CapturedMediaItem) || null; } catch { return null; } };