@qontinui/ui-bridge-native 0.1.3 → 0.1.4
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/debug/index.js.map +1 -1
- package/dist/debug/index.mjs.map +1 -1
- package/dist/index.js +59 -47
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59 -47
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.js +59 -47
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +59 -47
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/debug/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/design-handlers.ts","../../src/react/UIBridgeNativeProvider.tsx","../../src/debug/inspector.tsx"],"names":["createContext","useContext","jsxs","TouchableOpacity","View","jsx","Text","ScrollView","Fragment","useState","useMemo","useCallback","Modal","Dimensions","StyleSheet"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * UI Bridge Native Design Review Handlers\n *\n * HTTP handlers for the 8 design review endpoints.\n * Maps registered element styles to the web SDK's design data format.\n */\n\nimport type { NativeUIBridgeRegistry } from '../core/registry';\nimport type { APIResponse, HandlerContext } from './types';\nimport type { ElementDesignData, StateStyles, ResponsiveSnapshot } from '../design/design-types';\nimport {\n mapNativeStyleToExtended,\n getNativeElementDesignData,\n captureNativeStateVariations,\n captureNativeResponsiveSnapshot,\n} from '../design/design-inspector-native';\n\n// Style guide and baseline stored in closure (same pattern as web SDK)\nlet loadedStyleGuide: unknown = null;\nlet savedBaseline: unknown = null;\n\n// Try to load the style validator from the web SDK (optional peer dep)\nlet styleValidator: {\n runStyleAudit: (\n elements: Array<{ elementId: string; styles: Record<string, string> }>,\n guide: unknown\n ) => unknown;\n} | null = null;\n\n// Try to load quality evaluator from the web SDK (optional peer dep)\nlet qualityEvaluator: {\n evaluateQuality: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n context?: unknown\n ) => unknown;\n listContexts: () => Array<{ name: string; description: string }>;\n createBaseline: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n label?: string\n ) => unknown;\n diffSnapshots: (baseline: unknown, current: ElementDesignData[]) => unknown;\n} | null = null;\n\ntry {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const specs = require('@qontinui/ui-bridge/specs');\n styleValidator = specs;\n qualityEvaluator = specs;\n} catch {\n // Optional dependency not installed — audit/evaluate endpoints will return an error\n}\n\nfunction success<T>(data: T): APIResponse<T> {\n return { success: true, data, timestamp: Date.now() };\n}\n\nfunction error<T = unknown>(message: string, code?: string): APIResponse<T> {\n return { success: false, error: message, code, timestamp: Date.now() };\n}\n\n/**\n * Design handler interface (subset of NativeServerHandlers)\n */\nexport interface NativeDesignHandlers {\n getElementStyles: (ctx: HandlerContext) => Promise<APIResponse<ElementDesignData>>;\n getElementStateStyles: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elementId: string; stateStyles: StateStyles[] }>>;\n getDesignSnapshot: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elements: ElementDesignData[]; timestamp: number }>>;\n getResponsiveSnapshots: (ctx: HandlerContext) => Promise<APIResponse<ResponsiveSnapshot[]>>;\n runDesignAudit: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n loadStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ loaded: boolean }>>;\n getStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n clearStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ cleared: boolean }>>;\n evaluateQuality: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n getQualityContexts: (\n ctx: HandlerContext\n ) => Promise<APIResponse<Array<{ name: string; description: string }>>>;\n saveBaseline: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ saved: boolean; elementCount: number }>>;\n diffBaseline: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n}\n\n/**\n * Create design review handlers.\n */\nexport function createDesignHandlers(registry: NativeUIBridgeRegistry): NativeDesignHandlers {\n // Helper to get screen dimensions (React Native's Dimensions API must be\n // called at handler time, not import time, so we use a lazy getter).\n function getScreenDimensions(): { width: number; height: number } {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { Dimensions } = require('react-native');\n const screen = Dimensions.get('screen');\n return { width: screen.width, height: screen.height };\n } catch {\n return { width: 0, height: 0 };\n }\n }\n\n return {\n // 1. GET /design/element/:id/styles\n getElementStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const state = element.getState();\n const data = getNativeElementDesignData(\n id,\n element.label,\n element.type,\n element.flatStyle,\n state.layout\n );\n\n return success(data);\n },\n\n // 2. POST /design/element/:id/state-styles\n getElementStateStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const stateStyles = captureNativeStateVariations(element.flatStyle, element.stateStyles);\n\n return success({ elementId: id, stateStyles });\n },\n\n // 3. POST /design/snapshot\n getDesignSnapshot: async (ctx) => {\n const body = ctx.body as\n | {\n elementIds?: string[];\n includePseudoElements?: boolean;\n }\n | undefined;\n\n let elements = registry.getAllElements();\n\n // Filter to requested IDs if specified\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n return success({ elements: designData, timestamp: Date.now() });\n },\n\n // 4. POST /design/responsive\n getResponsiveSnapshots: async () => {\n // Platform limitation: RN cannot constrain screen width at runtime.\n // Returns a single snapshot at current device dimensions.\n const elements = registry.getAllElements();\n const elementData = elements.map((el) => {\n const state = el.getState();\n return {\n id: el.id,\n label: el.label,\n type: el.type,\n flatStyle: el.flatStyle,\n layout: state.layout,\n };\n });\n\n const snapshots = captureNativeResponsiveSnapshot(elementData, getScreenDimensions());\n return success(snapshots);\n },\n\n // 5. POST /design/audit\n runDesignAudit: async (ctx) => {\n const body = ctx.body as\n | {\n guide?: unknown;\n elementIds?: string[];\n }\n | undefined;\n\n const guide = body?.guide ?? loadedStyleGuide;\n\n if (!guide) {\n return error('No style guide loaded or provided', 'NO_STYLE_GUIDE');\n }\n\n if (!styleValidator) {\n return error(\n 'Install @qontinui/ui-bridge for style audit support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'VALIDATOR_NOT_AVAILABLE'\n );\n }\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n // Map elements to the format expected by the validator\n const auditElements = elements.map((el) => ({\n elementId: el.id,\n styles: mapNativeStyleToExtended(el.flatStyle) as unknown as Record<string, string>,\n }));\n\n try {\n const report = styleValidator.runStyleAudit(auditElements, guide);\n return success(report);\n } catch (err) {\n return error(\n 'Audit failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DESIGN_AUDIT_ERROR'\n );\n }\n },\n\n // 6. POST /design/style-guide/load\n loadStyleGuide: async (ctx) => {\n const body = ctx.body as { guide?: unknown } | undefined;\n\n if (!body?.guide) {\n return error('Style guide is required in request body', 'INVALID_REQUEST');\n }\n\n loadedStyleGuide = body.guide;\n return success({ loaded: true });\n },\n\n // 7. GET /design/style-guide\n getStyleGuide: async () => {\n return success(loadedStyleGuide);\n },\n\n // 8. DELETE /design/style-guide\n clearStyleGuide: async () => {\n loadedStyleGuide = null;\n return success({ cleared: true });\n },\n\n // 9. POST /design/evaluate\n evaluateQuality: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n context?: string;\n customContext?: unknown;\n elementIds?: string[];\n viewport?: { width: number; height: number };\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = body?.viewport ?? getScreenDimensions();\n\n // Resolve context: custom object > style guide context > built-in name\n let context: unknown = body?.customContext ?? body?.context ?? 'general';\n if (typeof context === 'string' && loadedStyleGuide) {\n const guide = loadedStyleGuide as { qualityContexts?: Record<string, unknown> };\n if (guide.qualityContexts?.[context]) {\n context = guide.qualityContexts[context];\n }\n }\n\n try {\n const report = qualityEvaluator.evaluateQuality(designData, viewport, context);\n return success(report);\n } catch (err) {\n return error(\n 'Evaluation failed: ' + (err instanceof Error ? err.message : String(err)),\n 'QUALITY_EVALUATION_ERROR'\n );\n }\n },\n\n // 10. GET /design/evaluate/contexts\n getQualityContexts: async () => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n return success(qualityEvaluator.listContexts());\n },\n\n // 11. POST /design/evaluate/baseline\n saveBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n label?: string;\n elementIds?: string[];\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = getScreenDimensions();\n savedBaseline = qualityEvaluator.createBaseline(designData, viewport, body?.label);\n return success({ saved: true, elementCount: designData.length });\n },\n\n // 12. POST /design/evaluate/diff\n diffBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n if (!savedBaseline) {\n return error('No baseline saved. Call saveBaseline first.', 'NO_BASELINE');\n }\n\n const body = ctx.body as { elementIds?: string[] } | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n try {\n const report = qualityEvaluator.diffSnapshots(savedBaseline, designData);\n return success(report);\n } catch (err) {\n return error(\n 'Diff failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DIFF_BASELINE_ERROR'\n );\n }\n },\n };\n}\n","/**\n * UI Bridge Native Provider\n *\n * React context provider for UI Bridge Native functionality.\n */\n\nimport React, {\n createContext,\n useContext,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n useState,\n} from 'react';\nimport type {\n NativeUIBridgeFeatures,\n NativeUIBridgeConfig,\n RegisteredNativeElement,\n RegisteredNativeComponent,\n NativeBridgeSnapshot,\n BridgeEventType,\n BridgeEventListener,\n} from '../core/types';\nimport { NativeUIBridgeRegistry, setGlobalRegistry, resetGlobalRegistry } from '../core/registry';\nimport { createNativeActionExecutor } from '../control/action-executor';\nimport type { NativeActionExecutor } from '../control/types';\nimport {\n createNativeServer,\n type NativeUIBridgeServer,\n type ServerAdapter,\n type WebSocketServerAdapter,\n} from '../server/http-server';\nimport type { RouteProvider } from '../server/types';\nimport { WebSocketEventBridge } from '../server/ws-event-bridge';\nimport { DeviceAnnouncer } from '../transport/DeviceAnnouncer';\nimport { CloudRelayClient, type CloudRelayConfig } from '../transport/CloudRelayClient';\n\n/**\n * UI Bridge Native context value\n */\nexport interface UIBridgeNativeContextValue {\n /** Feature flags */\n features: NativeUIBridgeFeatures;\n /** Configuration */\n config: NativeUIBridgeConfig;\n /** Element registry */\n registry: NativeUIBridgeRegistry;\n /** Action executor */\n executor: NativeActionExecutor;\n /** Get all registered elements */\n getElements: () => RegisteredNativeElement[];\n /** Get all registered components */\n getComponents: () => RegisteredNativeComponent[];\n /** Create a snapshot */\n createSnapshot: () => NativeBridgeSnapshot;\n /** Subscribe to events */\n on: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => () => void;\n /** Unsubscribe from events */\n off: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => void;\n /** Whether the provider is initialized */\n initialized: boolean;\n /** Server running status */\n serverRunning: boolean;\n /** Start the HTTP server */\n startServer: () => Promise<void>;\n /** Stop the HTTP server */\n stopServer: () => void;\n /** Get the current navigation route (if a RouteProvider is configured) */\n getCurrentRoute: () => string | null;\n}\n\n/**\n * UI Bridge Native context\n */\nconst UIBridgeNativeContext = createContext<UIBridgeNativeContextValue | null>(null);\n\n/**\n * UI Bridge Native provider props\n */\nexport interface UIBridgeNativeProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Feature flags */\n features?: NativeUIBridgeFeatures;\n /** Configuration */\n config?: NativeUIBridgeConfig;\n /** Event handler */\n onEvent?: BridgeEventListener;\n /**\n * A ServerAdapter instance for the HTTP server.\n * The app is responsible for creating this using its preferred native TCP/HTTP library.\n * @see ServerAdapter interface in server/http-server.ts\n */\n serverAdapter?: ServerAdapter;\n /**\n * Navigation provider for programmatic route navigation via UI Bridge.\n * Pass Expo Router's push/back functions to enable `control/page/navigate`.\n */\n navigationProvider?: { navigate: (url: string) => void; back?: () => void };\n /**\n * Screenshot provider for native screen capture via UI Bridge.\n * Pass a function that captures the current screen as base64 PNG.\n */\n screenshotProvider?: {\n capture: () => Promise<{ base64: string; width: number; height: number }>;\n };\n /**\n * Route provider for exposing the current navigation route in snapshots.\n * Wire this to Expo Router's `usePathname()` / `useSegments()` via a module-level ref.\n */\n routeProvider?: RouteProvider;\n /**\n * Configuration for the cloud relay tunnel (enables remote device verification\n * when USB/LAN are not available). Omit `uiBridgeServer` — the provider wires\n * that automatically after the server starts.\n */\n cloudRelayConfig?: Omit<CloudRelayConfig, 'uiBridgeServer'>;\n /**\n * Enable mDNS advertisement so that runners on the same LAN can discover this\n * device automatically (requires react-native-zeroconf).\n */\n enableMdnsAnnounce?: boolean;\n /**\n * Stable device identifier used for mDNS TXT records and cloud relay\n * registration. Typically sourced from expo-device or a UUID stored in\n * AsyncStorage.\n */\n deviceId?: string;\n}\n\n/**\n * UI Bridge Native Provider\n *\n * Provides UI Bridge Native context to child components.\n *\n * @example\n * ```tsx\n * // app/_layout.tsx\n * import { UIBridgeNativeProvider } from 'ui-bridge-native';\n *\n * export default function RootLayout() {\n * return (\n * <UIBridgeNativeProvider\n * features={{ server: __DEV__, debug: __DEV__ }}\n * config={{ serverPort: 8087 }}\n * >\n * <Stack>{children}</Stack>\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeNativeProvider({\n children,\n features = {},\n config = {},\n onEvent,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n cloudRelayConfig,\n enableMdnsAnnounce,\n deviceId,\n}: UIBridgeNativeProviderProps) {\n const registryRef = useRef<NativeUIBridgeRegistry | null>(null);\n const executorRef = useRef<NativeActionExecutor | null>(null);\n const [serverRunning, setServerRunning] = useState(false);\n\n // Initialize on first render\n if (!registryRef.current) {\n registryRef.current = new NativeUIBridgeRegistry({\n verbose: config.verbose,\n onEvent,\n });\n setGlobalRegistry(registryRef.current);\n }\n\n const registry = registryRef.current;\n\n // Create executor (memoized)\n if (!executorRef.current) {\n executorRef.current = createNativeActionExecutor(registry);\n }\n\n const executor = executorRef.current;\n\n // Server instance (persisted across renders)\n const serverRef = useRef<NativeUIBridgeServer | null>(null);\n const eventBridgeRef = useRef<WebSocketEventBridge | null>(null);\n\n // Cloud / mDNS transport references\n const announcerRef = useRef<DeviceAnnouncer | null>(null);\n const cloudRelayRef = useRef<CloudRelayClient | null>(null);\n\n // Server management — uses injected serverAdapter if provided\n const startServer = useCallback(async () => {\n if (!features.server) return;\n\n if (!serverAdapter) {\n console.warn(\n `[ui-bridge-native] HTTP server not available: no serverAdapter prop provided. ` +\n `Pass a serverAdapter to UIBridgeNativeProvider to enable the HTTP server.`\n );\n return;\n }\n\n const server = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n\n server.setAdapter(serverAdapter);\n\n // Wire navigation provider if supplied\n if (navigationProvider) {\n server.setNavigationProvider(navigationProvider);\n }\n\n // Wire screenshot provider if supplied\n if (screenshotProvider) {\n server.setScreenshotProvider(screenshotProvider);\n }\n\n // Wire route provider if supplied (must be set AFTER navigationProvider\n // since both may override getSnapshot / pageNavigate handlers)\n if (routeProvider) {\n server.setRouteProvider(routeProvider);\n }\n\n // Wire up WebSocket event bridge if adapter supports it\n const wsAdapter = serverAdapter as WebSocketServerAdapter;\n if (typeof wsAdapter.broadcast === 'function') {\n const eventBridge = new WebSocketEventBridge(registry);\n server.setEventBridge(eventBridge);\n\n wsAdapter.onWebSocketConnect = (connId: string) => {\n // Create a lightweight connection proxy for the event bridge\n // The actual WebSocketConnection lives in the adapter\n eventBridge.addConnection({\n id: connId,\n subscriptions: new Set(),\n alive: true,\n isOpen: true,\n send: (msg: string) => wsAdapter.sendToConnection?.(connId, msg),\n sendEvent: (event: { event: string }) => {\n if (!eventBridge.isSubscribed(connId, event.event)) return;\n wsAdapter.sendToConnection?.(connId, JSON.stringify(event));\n },\n ping: () => {\n /* adapter handles heartbeat */\n },\n close: () => {\n /* adapter handles close */\n },\n destroy: () => {\n /* adapter handles destroy */\n },\n } as any); // eslint-disable-line @typescript-eslint/no-explicit-any\n };\n\n wsAdapter.onWebSocketDisconnect = (connId: string) => {\n // Abort any pending waiters (waitForElement / waitForCondition)\n // for this connection BEFORE removing it — stops leaked timers\n // and registry listeners.\n server.abortWaitersForConnection(connId);\n eventBridge.removeConnection(connId);\n };\n\n wsAdapter.onWebSocketMessage = async (connId: string, message: string) => {\n return server.handleWebSocketMessage(connId, message);\n };\n\n eventBridge.start();\n eventBridgeRef.current = eventBridge;\n }\n\n try {\n await server.start();\n serverRef.current = server;\n setServerRunning(true);\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start HTTP server:', err);\n }\n }, [\n features.server,\n config.serverPort,\n registry,\n executor,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n ]);\n\n const stopServer = useCallback(() => {\n if (eventBridgeRef.current) {\n eventBridgeRef.current.stop();\n eventBridgeRef.current = null;\n }\n if (serverRef.current) {\n serverRef.current.stop().catch(() => {});\n serverRef.current = null;\n }\n setServerRunning(false);\n }, []);\n\n // Auto-start server if enabled\n useEffect(() => {\n if (features.server) {\n startServer();\n return () => stopServer();\n }\n }, [features.server, startServer, stopServer]);\n\n // Start mDNS announcement and cloud relay.\n //\n // The cloud relay path does NOT require the HTTP server to be running —\n // it calls `server.handleRequest()` directly, bypassing HTTP. This matters\n // for preview/production builds where `features.server` is typically\n // false (no native TCP server adapter available). We still need a\n // NativeUIBridgeServer instance to handle tunneled requests, so we create\n // a bare instance here if startServer() didn't already make one.\n //\n // mDNS also doesn't need the HTTP server — it just advertises on the\n // network so remote devices can discover this phone's address.\n useEffect(() => {\n const needsBareServer = !serverRef.current && !!cloudRelayConfig;\n if (needsBareServer) {\n // Create a server instance for handleRequest() use only; no adapter,\n // no HTTP listener. This is safe without features.server.\n const bareServer = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n if (navigationProvider) bareServer.setNavigationProvider(navigationProvider);\n if (screenshotProvider) bareServer.setScreenshotProvider(screenshotProvider);\n if (routeProvider) bareServer.setRouteProvider(routeProvider);\n serverRef.current = bareServer;\n }\n\n // mDNS advertisement\n if (enableMdnsAnnounce && deviceId) {\n const announcer = new DeviceAnnouncer({\n deviceId,\n appId: config.appInfo?.appId ?? 'unknown',\n port: config.serverPort ?? 8087,\n cloudRelayUrl: cloudRelayConfig?.relayUrl,\n cloudToken: cloudRelayConfig?.authToken,\n });\n announcerRef.current = announcer;\n void announcer.startMdnsAdvertise();\n }\n\n // Cloud relay tunnel (works without HTTP server)\n if (cloudRelayConfig && serverRef.current) {\n const relayClient = new CloudRelayClient({\n ...cloudRelayConfig,\n uiBridgeServer: serverRef.current,\n });\n cloudRelayRef.current = relayClient;\n relayClient.start();\n }\n\n return () => {\n if (announcerRef.current) {\n void announcerRef.current.stop();\n announcerRef.current = null;\n }\n if (cloudRelayRef.current) {\n cloudRelayRef.current.stop();\n cloudRelayRef.current = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n serverRunning,\n cloudRelayConfig?.relayUrl,\n cloudRelayConfig?.authToken,\n enableMdnsAnnounce,\n deviceId,\n ]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n stopServer();\n resetGlobalRegistry();\n };\n }, [stopServer]);\n\n // Context methods\n const getElements = useCallback(() => registry.getAllElements(), [registry]);\n\n const getComponents = useCallback(() => registry.getAllComponents(), [registry]);\n\n const createSnapshot = useCallback(() => registry.createSnapshot(), [registry]);\n\n const getCurrentRoute = useCallback(() => {\n return routeProvider?.getCurrentRoute() ?? null;\n }, [routeProvider]);\n\n // Mark the previous route's elements offscreen when the active route changes.\n // Without this, React Navigation's persistent-mount behavior leaves stale\n // layouts in the registry for tabs the user has left. Elements on the new\n // route re-fire `onLayout` and repopulate their layout.\n useEffect(() => {\n if (!routeProvider) return;\n\n let lastRoute: string | null = routeProvider.getCurrentRoute();\n\n return routeProvider.subscribe((current: string | null) => {\n if (current !== lastRoute && lastRoute != null) {\n registry.markRouteOffscreen(lastRoute);\n }\n lastRoute = current;\n });\n }, [routeProvider, registry]);\n\n const on = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.on(type, listener),\n [registry]\n );\n\n const off = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.off(type, listener),\n [registry]\n );\n\n const contextValue = useMemo<UIBridgeNativeContextValue>(\n () => ({\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n initialized: true,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n }),\n [\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n ]\n );\n\n return (\n <UIBridgeNativeContext.Provider value={contextValue}>{children}</UIBridgeNativeContext.Provider>\n );\n}\n\n/**\n * useUIBridgeNative hook\n *\n * Access the UI Bridge Native context. Throws if used outside provider.\n */\nexport function useUIBridgeNative(): UIBridgeNativeContextValue {\n const context = useContext(UIBridgeNativeContext);\n if (!context) {\n throw new Error('useUIBridgeNative must be used within a UIBridgeNativeProvider');\n }\n return context;\n}\n\n/**\n * useUIBridgeNativeOptional hook\n *\n * Access the UI Bridge Native context, returning null if outside provider.\n */\nexport function useUIBridgeNativeOptional(): UIBridgeNativeContextValue | null {\n return useContext(UIBridgeNativeContext);\n}\n\n/**\n * useUIBridgeNativeRequired hook\n *\n * Alias for useUIBridgeNative (throws if outside provider).\n */\nexport const useUIBridgeNativeRequired = useUIBridgeNative;\n","/**\n * UI Bridge Native Debug Inspector\n *\n * An overlay component that shows registered elements and allows\n * inspection of the UI Bridge state.\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport {\n View,\n Text,\n StyleSheet,\n TouchableOpacity,\n ScrollView,\n Modal,\n Dimensions,\n} from 'react-native';\nimport { useUIBridgeNativeOptional } from '../react/UIBridgeNativeProvider';\nimport type { RegisteredNativeElement } from '../core/types';\n\n/**\n * Inspector props\n */\nexport interface UIBridgeInspectorProps {\n /** Whether to show the inspector */\n visible?: boolean;\n /** Callback when inspector is closed */\n onClose?: () => void;\n /** Position of the inspector toggle button */\n togglePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n}\n\n/**\n * Element info card\n */\nfunction ElementCard({\n element,\n onPress,\n}: {\n element: RegisteredNativeElement;\n onPress: (element: RegisteredNativeElement) => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <TouchableOpacity style={styles.elementCard} onPress={() => onPress(element)}>\n <View style={styles.elementHeader}>\n <Text style={styles.elementId}>{element.id}</Text>\n <Text style={styles.elementType}>{element.type}</Text>\n </View>\n {element.label && <Text style={styles.elementLabel}>{element.label}</Text>}\n <View style={styles.stateRow}>\n <StateIndicator label=\"Mounted\" value={state.mounted} />\n <StateIndicator label=\"Visible\" value={state.visible} />\n <StateIndicator label=\"Enabled\" value={state.enabled} />\n </View>\n {identifier.testId && <Text style={styles.testId}>testID: {identifier.testId}</Text>}\n </TouchableOpacity>\n );\n}\n\n/**\n * State indicator\n */\nfunction StateIndicator({ label, value }: { label: string; value: boolean }) {\n return (\n <View style={styles.stateIndicator}>\n <View style={[styles.stateDot, { backgroundColor: value ? '#4CAF50' : '#F44336' }]} />\n <Text style={styles.stateLabel}>{label}</Text>\n </View>\n );\n}\n\n/**\n * Element detail view\n */\nfunction ElementDetail({\n element,\n onClose,\n}: {\n element: RegisteredNativeElement;\n onClose: () => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <View style={styles.detailContainer}>\n <View style={styles.detailHeader}>\n <Text style={styles.detailTitle}>{element.id}</Text>\n <TouchableOpacity onPress={onClose}>\n <Text style={styles.closeButton}>Close</Text>\n </TouchableOpacity>\n </View>\n\n <ScrollView style={styles.detailContent}>\n <Text style={styles.sectionTitle}>Type</Text>\n <Text style={styles.sectionValue}>{element.type}</Text>\n\n {element.label && (\n <>\n <Text style={styles.sectionTitle}>Label</Text>\n <Text style={styles.sectionValue}>{element.label}</Text>\n </>\n )}\n\n <Text style={styles.sectionTitle}>State</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>Mounted: {String(state.mounted)}</Text>\n <Text style={styles.stateText}>Visible: {String(state.visible)}</Text>\n <Text style={styles.stateText}>Enabled: {String(state.enabled)}</Text>\n <Text style={styles.stateText}>Focused: {String(state.focused)}</Text>\n {state.value !== undefined && <Text style={styles.stateText}>Value: {state.value}</Text>}\n </View>\n\n {state.layout && (\n <>\n <Text style={styles.sectionTitle}>Layout</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>\n Position: ({state.layout.x}, {state.layout.y})\n </Text>\n <Text style={styles.stateText}>\n Size: {state.layout.width} x {state.layout.height}\n </Text>\n <Text style={styles.stateText}>\n Page: ({state.layout.pageX}, {state.layout.pageY})\n </Text>\n </View>\n </>\n )}\n\n <Text style={styles.sectionTitle}>Identifier</Text>\n <View style={styles.stateSection}>\n {identifier.uiId && <Text style={styles.stateText}>uiId: {identifier.uiId}</Text>}\n {identifier.testId && <Text style={styles.stateText}>testId: {identifier.testId}</Text>}\n {identifier.accessibilityLabel && (\n <Text style={styles.stateText}>a11yLabel: {identifier.accessibilityLabel}</Text>\n )}\n <Text style={styles.stateText}>treePath: {identifier.treePath}</Text>\n </View>\n\n <Text style={styles.sectionTitle}>Actions</Text>\n <View style={styles.actionsSection}>\n {element.actions.map((action) => (\n <View key={action} style={styles.actionBadge}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n\n {element.customActions && Object.keys(element.customActions).length > 0 && (\n <>\n <Text style={styles.sectionTitle}>Custom Actions</Text>\n <View style={styles.actionsSection}>\n {Object.keys(element.customActions).map((action) => (\n <View key={action} style={[styles.actionBadge, styles.customActionBadge]}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n </>\n )}\n </ScrollView>\n </View>\n );\n}\n\n/**\n * UI Bridge Inspector component\n *\n * Shows an overlay with information about registered elements.\n * Useful for debugging and development.\n *\n * @example\n * ```tsx\n * function App() {\n * const [showInspector, setShowInspector] = useState(false);\n *\n * return (\n * <UIBridgeNativeProvider features={{ debug: __DEV__ }}>\n * <MainContent />\n * {__DEV__ && (\n * <UIBridgeInspector\n * visible={showInspector}\n * onClose={() => setShowInspector(false)}\n * />\n * )}\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeInspector({\n visible = false,\n onClose,\n togglePosition = 'bottom-right',\n}: UIBridgeInspectorProps) {\n const bridge = useUIBridgeNativeOptional();\n const [showInspector, setShowInspector] = useState(visible);\n const [selectedElement, setSelectedElement] = useState<RegisteredNativeElement | null>(null);\n\n const elements = useMemo(() => (bridge ? bridge.getElements() : []), [bridge, showInspector]);\n\n const components = useMemo(() => (bridge ? bridge.getComponents() : []), [bridge, showInspector]);\n\n const handleToggle = useCallback(() => {\n setShowInspector((prev) => !prev);\n }, []);\n\n const handleClose = useCallback(() => {\n setShowInspector(false);\n onClose?.();\n }, [onClose]);\n\n const handleSelectElement = useCallback((element: RegisteredNativeElement) => {\n setSelectedElement(element);\n }, []);\n\n const handleCloseDetail = useCallback(() => {\n setSelectedElement(null);\n }, []);\n\n // Position style for toggle button\n const toggleStyle = useMemo(() => {\n switch (togglePosition) {\n case 'top-left':\n return { top: 50, left: 10 };\n case 'top-right':\n return { top: 50, right: 10 };\n case 'bottom-left':\n return { bottom: 50, left: 10 };\n case 'bottom-right':\n default:\n return { bottom: 50, right: 10 };\n }\n }, [togglePosition]);\n\n if (!bridge) {\n return null;\n }\n\n return (\n <>\n {/* Toggle button */}\n <TouchableOpacity style={[styles.toggleButton, toggleStyle]} onPress={handleToggle}>\n <Text style={styles.toggleText}>UI</Text>\n </TouchableOpacity>\n\n {/* Inspector modal */}\n <Modal\n visible={showInspector}\n animationType=\"slide\"\n transparent={true}\n onRequestClose={handleClose}\n >\n <View style={styles.modalContainer}>\n <View style={styles.inspectorContainer}>\n {/* Header */}\n <View style={styles.header}>\n <Text style={styles.headerTitle}>UI Bridge Inspector</Text>\n <TouchableOpacity onPress={handleClose}>\n <Text style={styles.closeButton}>X</Text>\n </TouchableOpacity>\n </View>\n\n {/* Stats */}\n <View style={styles.statsRow}>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{elements.length}</Text>\n <Text style={styles.statLabel}>Elements</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{components.length}</Text>\n <Text style={styles.statLabel}>Components</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{bridge.serverRunning ? 'ON' : 'OFF'}</Text>\n <Text style={styles.statLabel}>Server</Text>\n </View>\n </View>\n\n {/* Element list or detail */}\n {selectedElement ? (\n <ElementDetail element={selectedElement} onClose={handleCloseDetail} />\n ) : (\n <ScrollView style={styles.elementList}>\n {elements.map((element) => (\n <ElementCard key={element.id} element={element} onPress={handleSelectElement} />\n ))}\n {elements.length === 0 && (\n <Text style={styles.emptyText}>No elements registered yet</Text>\n )}\n </ScrollView>\n )}\n </View>\n </View>\n </Modal>\n </>\n );\n}\n\nconst { height: screenHeight } = Dimensions.get('window');\n\nconst styles = StyleSheet.create({\n toggleButton: {\n position: 'absolute',\n width: 44,\n height: 44,\n borderRadius: 22,\n backgroundColor: '#2196F3',\n justifyContent: 'center',\n alignItems: 'center',\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.25,\n shadowRadius: 4,\n elevation: 5,\n zIndex: 1000,\n },\n toggleText: {\n color: '#fff',\n fontWeight: 'bold',\n fontSize: 14,\n },\n modalContainer: {\n flex: 1,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n justifyContent: 'flex-end',\n },\n inspectorContainer: {\n backgroundColor: '#1e1e1e',\n borderTopLeftRadius: 16,\n borderTopRightRadius: 16,\n maxHeight: screenHeight * 0.8,\n },\n header: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 16,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n headerTitle: {\n color: '#fff',\n fontSize: 18,\n fontWeight: 'bold',\n },\n closeButton: {\n color: '#2196F3',\n fontSize: 16,\n fontWeight: 'bold',\n },\n statsRow: {\n flexDirection: 'row',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n stat: {\n flex: 1,\n alignItems: 'center',\n },\n statValue: {\n color: '#fff',\n fontSize: 20,\n fontWeight: 'bold',\n },\n statLabel: {\n color: '#888',\n fontSize: 12,\n marginTop: 2,\n },\n elementList: {\n padding: 12,\n },\n elementCard: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 12,\n marginBottom: 8,\n },\n elementHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n elementId: {\n color: '#fff',\n fontSize: 14,\n fontWeight: 'bold',\n },\n elementType: {\n color: '#888',\n fontSize: 12,\n backgroundColor: '#444',\n paddingHorizontal: 8,\n paddingVertical: 2,\n borderRadius: 4,\n },\n elementLabel: {\n color: '#aaa',\n fontSize: 12,\n marginTop: 4,\n },\n stateRow: {\n flexDirection: 'row',\n marginTop: 8,\n },\n stateIndicator: {\n flexDirection: 'row',\n alignItems: 'center',\n marginRight: 12,\n },\n stateDot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginRight: 4,\n },\n stateLabel: {\n color: '#888',\n fontSize: 10,\n },\n testId: {\n color: '#666',\n fontSize: 10,\n marginTop: 4,\n fontFamily: 'monospace',\n },\n emptyText: {\n color: '#888',\n textAlign: 'center',\n marginTop: 20,\n },\n detailContainer: {\n flex: 1,\n },\n detailHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n detailTitle: {\n color: '#fff',\n fontSize: 16,\n fontWeight: 'bold',\n },\n detailContent: {\n padding: 12,\n },\n sectionTitle: {\n color: '#888',\n fontSize: 12,\n marginTop: 12,\n marginBottom: 4,\n textTransform: 'uppercase',\n },\n sectionValue: {\n color: '#fff',\n fontSize: 14,\n },\n stateSection: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 8,\n },\n stateText: {\n color: '#ddd',\n fontSize: 12,\n fontFamily: 'monospace',\n marginBottom: 2,\n },\n actionsSection: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n },\n actionBadge: {\n backgroundColor: '#2196F3',\n paddingHorizontal: 8,\n paddingVertical: 4,\n borderRadius: 4,\n marginRight: 6,\n marginBottom: 6,\n },\n customActionBadge: {\n backgroundColor: '#9C27B0',\n },\n actionText: {\n color: '#fff',\n fontSize: 12,\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/design-handlers.ts","../../src/react/UIBridgeNativeProvider.tsx","../../src/debug/inspector.tsx"],"names":["createContext","useContext","jsxs","TouchableOpacity","View","jsx","Text","ScrollView","Fragment","useState","useMemo","useCallback","Modal","Dimensions","StyleSheet"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * UI Bridge Native Design Review Handlers\n *\n * HTTP handlers for the 8 design review endpoints.\n * Maps registered element styles to the web SDK's design data format.\n */\n\nimport type { NativeUIBridgeRegistry } from '../core/registry';\nimport type { APIResponse, HandlerContext } from './types';\nimport type { ElementDesignData, StateStyles, ResponsiveSnapshot } from '../design/design-types';\nimport {\n mapNativeStyleToExtended,\n getNativeElementDesignData,\n captureNativeStateVariations,\n captureNativeResponsiveSnapshot,\n} from '../design/design-inspector-native';\n\n// Style guide and baseline stored in closure (same pattern as web SDK)\nlet loadedStyleGuide: unknown = null;\nlet savedBaseline: unknown = null;\n\n// Try to load the style validator from the web SDK (optional peer dep)\nlet styleValidator: {\n runStyleAudit: (\n elements: Array<{ elementId: string; styles: Record<string, string> }>,\n guide: unknown\n ) => unknown;\n} | null = null;\n\n// Try to load quality evaluator from the web SDK (optional peer dep)\nlet qualityEvaluator: {\n evaluateQuality: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n context?: unknown\n ) => unknown;\n listContexts: () => Array<{ name: string; description: string }>;\n createBaseline: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n label?: string\n ) => unknown;\n diffSnapshots: (baseline: unknown, current: ElementDesignData[]) => unknown;\n} | null = null;\n\ntry {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const specs = require('@qontinui/ui-bridge/specs');\n styleValidator = specs;\n qualityEvaluator = specs;\n} catch {\n // Optional dependency not installed — audit/evaluate endpoints will return an error\n}\n\nfunction success<T>(data: T): APIResponse<T> {\n return { success: true, data, timestamp: Date.now() };\n}\n\nfunction error<T = unknown>(message: string, code?: string): APIResponse<T> {\n return { success: false, error: message, code, timestamp: Date.now() };\n}\n\n/**\n * Design handler interface (subset of NativeServerHandlers)\n */\nexport interface NativeDesignHandlers {\n getElementStyles: (ctx: HandlerContext) => Promise<APIResponse<ElementDesignData>>;\n getElementStateStyles: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elementId: string; stateStyles: StateStyles[] }>>;\n getDesignSnapshot: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elements: ElementDesignData[]; timestamp: number }>>;\n getResponsiveSnapshots: (ctx: HandlerContext) => Promise<APIResponse<ResponsiveSnapshot[]>>;\n runDesignAudit: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n loadStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ loaded: boolean }>>;\n getStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n clearStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ cleared: boolean }>>;\n evaluateQuality: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n getQualityContexts: (\n ctx: HandlerContext\n ) => Promise<APIResponse<Array<{ name: string; description: string }>>>;\n saveBaseline: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ saved: boolean; elementCount: number }>>;\n diffBaseline: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n}\n\n/**\n * Create design review handlers.\n */\nexport function createDesignHandlers(registry: NativeUIBridgeRegistry): NativeDesignHandlers {\n // Helper to get screen dimensions (React Native's Dimensions API must be\n // called at handler time, not import time, so we use a lazy getter).\n function getScreenDimensions(): { width: number; height: number } {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { Dimensions } = require('react-native');\n const screen = Dimensions.get('screen');\n return { width: screen.width, height: screen.height };\n } catch {\n return { width: 0, height: 0 };\n }\n }\n\n return {\n // 1. GET /design/element/:id/styles\n getElementStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const state = element.getState();\n const data = getNativeElementDesignData(\n id,\n element.label,\n element.type,\n element.flatStyle,\n state.layout\n );\n\n return success(data);\n },\n\n // 2. POST /design/element/:id/state-styles\n getElementStateStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const stateStyles = captureNativeStateVariations(element.flatStyle, element.stateStyles);\n\n return success({ elementId: id, stateStyles });\n },\n\n // 3. POST /design/snapshot\n getDesignSnapshot: async (ctx) => {\n const body = ctx.body as\n | {\n elementIds?: string[];\n includePseudoElements?: boolean;\n }\n | undefined;\n\n let elements = registry.getAllElements();\n\n // Filter to requested IDs if specified\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n return success({ elements: designData, timestamp: Date.now() });\n },\n\n // 4. POST /design/responsive\n getResponsiveSnapshots: async () => {\n // Platform limitation: RN cannot constrain screen width at runtime.\n // Returns a single snapshot at current device dimensions.\n const elements = registry.getAllElements();\n const elementData = elements.map((el) => {\n const state = el.getState();\n return {\n id: el.id,\n label: el.label,\n type: el.type,\n flatStyle: el.flatStyle,\n layout: state.layout,\n };\n });\n\n const snapshots = captureNativeResponsiveSnapshot(elementData, getScreenDimensions());\n return success(snapshots);\n },\n\n // 5. POST /design/audit\n runDesignAudit: async (ctx) => {\n const body = ctx.body as\n | {\n guide?: unknown;\n elementIds?: string[];\n }\n | undefined;\n\n const guide = body?.guide ?? loadedStyleGuide;\n\n if (!guide) {\n return error('No style guide loaded or provided', 'NO_STYLE_GUIDE');\n }\n\n if (!styleValidator) {\n return error(\n 'Install @qontinui/ui-bridge for style audit support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'VALIDATOR_NOT_AVAILABLE'\n );\n }\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n // Map elements to the format expected by the validator\n const auditElements = elements.map((el) => ({\n elementId: el.id,\n styles: mapNativeStyleToExtended(el.flatStyle) as unknown as Record<string, string>,\n }));\n\n try {\n const report = styleValidator.runStyleAudit(auditElements, guide);\n return success(report);\n } catch (err) {\n return error(\n 'Audit failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DESIGN_AUDIT_ERROR'\n );\n }\n },\n\n // 6. POST /design/style-guide/load\n loadStyleGuide: async (ctx) => {\n const body = ctx.body as { guide?: unknown } | undefined;\n\n if (!body?.guide) {\n return error('Style guide is required in request body', 'INVALID_REQUEST');\n }\n\n loadedStyleGuide = body.guide;\n return success({ loaded: true });\n },\n\n // 7. GET /design/style-guide\n getStyleGuide: async () => {\n return success(loadedStyleGuide);\n },\n\n // 8. DELETE /design/style-guide\n clearStyleGuide: async () => {\n loadedStyleGuide = null;\n return success({ cleared: true });\n },\n\n // 9. POST /design/evaluate\n evaluateQuality: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n context?: string;\n customContext?: unknown;\n elementIds?: string[];\n viewport?: { width: number; height: number };\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = body?.viewport ?? getScreenDimensions();\n\n // Resolve context: custom object > style guide context > built-in name\n let context: unknown = body?.customContext ?? body?.context ?? 'general';\n if (typeof context === 'string' && loadedStyleGuide) {\n const guide = loadedStyleGuide as { qualityContexts?: Record<string, unknown> };\n if (guide.qualityContexts?.[context]) {\n context = guide.qualityContexts[context];\n }\n }\n\n try {\n const report = qualityEvaluator.evaluateQuality(designData, viewport, context);\n return success(report);\n } catch (err) {\n return error(\n 'Evaluation failed: ' + (err instanceof Error ? err.message : String(err)),\n 'QUALITY_EVALUATION_ERROR'\n );\n }\n },\n\n // 10. GET /design/evaluate/contexts\n getQualityContexts: async () => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n return success(qualityEvaluator.listContexts());\n },\n\n // 11. POST /design/evaluate/baseline\n saveBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n label?: string;\n elementIds?: string[];\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = getScreenDimensions();\n savedBaseline = qualityEvaluator.createBaseline(designData, viewport, body?.label);\n return success({ saved: true, elementCount: designData.length });\n },\n\n // 12. POST /design/evaluate/diff\n diffBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n if (!savedBaseline) {\n return error('No baseline saved. Call saveBaseline first.', 'NO_BASELINE');\n }\n\n const body = ctx.body as { elementIds?: string[] } | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n try {\n const report = qualityEvaluator.diffSnapshots(savedBaseline, designData);\n return success(report);\n } catch (err) {\n return error(\n 'Diff failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DIFF_BASELINE_ERROR'\n );\n }\n },\n };\n}\n","/**\n * UI Bridge Native Provider\n *\n * React context provider for UI Bridge Native functionality.\n */\n\nimport React, {\n createContext,\n useContext,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n useState,\n} from 'react';\nimport type {\n NativeUIBridgeFeatures,\n NativeUIBridgeConfig,\n RegisteredNativeElement,\n RegisteredNativeComponent,\n NativeBridgeSnapshot,\n BridgeEventType,\n BridgeEventListener,\n} from '../core/types';\nimport { NativeUIBridgeRegistry, setGlobalRegistry, resetGlobalRegistry } from '../core/registry';\nimport { createNativeActionExecutor } from '../control/action-executor';\nimport type { NativeActionExecutor } from '../control/types';\nimport {\n createNativeServer,\n type NativeUIBridgeServer,\n type ServerAdapter,\n type WebSocketServerAdapter,\n} from '../server/http-server';\nimport type { RouteProvider } from '../server/types';\nimport { WebSocketEventBridge } from '../server/ws-event-bridge';\nimport { DeviceAnnouncer } from '../transport/DeviceAnnouncer';\nimport { CloudRelayClient, type CloudRelayConfig } from '../transport/CloudRelayClient';\n\n/**\n * UI Bridge Native context value\n */\nexport interface UIBridgeNativeContextValue {\n /** Feature flags */\n features: NativeUIBridgeFeatures;\n /** Configuration */\n config: NativeUIBridgeConfig;\n /** Element registry */\n registry: NativeUIBridgeRegistry;\n /** Action executor */\n executor: NativeActionExecutor;\n /** Get all registered elements */\n getElements: () => RegisteredNativeElement[];\n /** Get all registered components */\n getComponents: () => RegisteredNativeComponent[];\n /** Create a snapshot */\n createSnapshot: () => NativeBridgeSnapshot;\n /** Subscribe to events */\n on: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => () => void;\n /** Unsubscribe from events */\n off: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => void;\n /** Whether the provider is initialized */\n initialized: boolean;\n /** Server running status */\n serverRunning: boolean;\n /** Start the HTTP server */\n startServer: () => Promise<void>;\n /** Stop the HTTP server */\n stopServer: () => void;\n /** Get the current navigation route (if a RouteProvider is configured) */\n getCurrentRoute: () => string | null;\n}\n\n/**\n * UI Bridge Native context\n */\nconst UIBridgeNativeContext = createContext<UIBridgeNativeContextValue | null>(null);\n\n/**\n * UI Bridge Native provider props\n */\nexport interface UIBridgeNativeProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Feature flags */\n features?: NativeUIBridgeFeatures;\n /** Configuration */\n config?: NativeUIBridgeConfig;\n /** Event handler */\n onEvent?: BridgeEventListener;\n /**\n * A ServerAdapter instance for the HTTP server.\n * The app is responsible for creating this using its preferred native TCP/HTTP library.\n * @see ServerAdapter interface in server/http-server.ts\n */\n serverAdapter?: ServerAdapter;\n /**\n * Navigation provider for programmatic route navigation via UI Bridge.\n * Pass Expo Router's push/back functions to enable `control/page/navigate`.\n */\n navigationProvider?: { navigate: (url: string) => void; back?: () => void };\n /**\n * Screenshot provider for native screen capture via UI Bridge.\n * Pass a function that captures the current screen as base64 PNG.\n */\n screenshotProvider?: {\n capture: () => Promise<{ base64: string; width: number; height: number }>;\n };\n /**\n * Route provider for exposing the current navigation route in snapshots.\n * Wire this to Expo Router's `usePathname()` / `useSegments()` via a module-level ref.\n */\n routeProvider?: RouteProvider;\n /**\n * Configuration for the cloud relay tunnel (enables remote device verification\n * when USB/LAN are not available). Omit `uiBridgeServer` — the provider wires\n * that automatically after the server starts.\n */\n cloudRelayConfig?: Omit<CloudRelayConfig, 'uiBridgeServer'>;\n /**\n * Enable mDNS advertisement so that runners on the same LAN can discover this\n * device automatically (requires react-native-zeroconf).\n */\n enableMdnsAnnounce?: boolean;\n /**\n * Stable device identifier used for mDNS TXT records and cloud relay\n * registration. Typically sourced from expo-device or a UUID stored in\n * AsyncStorage.\n */\n deviceId?: string;\n}\n\n/**\n * UI Bridge Native Provider\n *\n * Provides UI Bridge Native context to child components.\n *\n * @example\n * ```tsx\n * // app/_layout.tsx\n * import { UIBridgeNativeProvider } from 'ui-bridge-native';\n *\n * export default function RootLayout() {\n * return (\n * <UIBridgeNativeProvider\n * features={{ server: __DEV__, debug: __DEV__ }}\n * config={{ serverPort: 8087 }}\n * >\n * <Stack>{children}</Stack>\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeNativeProvider({\n children,\n features = {},\n config = {},\n onEvent,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n cloudRelayConfig,\n enableMdnsAnnounce,\n deviceId,\n}: UIBridgeNativeProviderProps) {\n const registryRef = useRef<NativeUIBridgeRegistry | null>(null);\n const executorRef = useRef<NativeActionExecutor | null>(null);\n const [serverRunning, setServerRunning] = useState(false);\n\n // Initialize on first render\n if (!registryRef.current) {\n registryRef.current = new NativeUIBridgeRegistry({\n verbose: config.verbose,\n onEvent,\n });\n setGlobalRegistry(registryRef.current);\n }\n\n const registry = registryRef.current;\n\n // Create executor (memoized)\n if (!executorRef.current) {\n executorRef.current = createNativeActionExecutor(registry);\n }\n\n const executor = executorRef.current;\n\n // Server instance (persisted across renders)\n const serverRef = useRef<NativeUIBridgeServer | null>(null);\n const eventBridgeRef = useRef<WebSocketEventBridge | null>(null);\n\n // Cloud / mDNS transport references\n const announcerRef = useRef<DeviceAnnouncer | null>(null);\n const cloudRelayRef = useRef<CloudRelayClient | null>(null);\n\n // Server management — uses injected serverAdapter if provided\n const startServer = useCallback(async () => {\n if (!features.server) return;\n\n if (!serverAdapter) {\n console.warn(\n `[ui-bridge-native] HTTP server not available: no serverAdapter prop provided. ` +\n `Pass a serverAdapter to UIBridgeNativeProvider to enable the HTTP server.`\n );\n return;\n }\n\n const server = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n\n server.setAdapter(serverAdapter);\n\n // Wire navigation provider if supplied\n if (navigationProvider) {\n server.setNavigationProvider(navigationProvider);\n }\n\n // Wire screenshot provider if supplied\n if (screenshotProvider) {\n server.setScreenshotProvider(screenshotProvider);\n }\n\n // Wire route provider if supplied (must be set AFTER navigationProvider\n // since both may override getSnapshot / pageNavigate handlers)\n if (routeProvider) {\n server.setRouteProvider(routeProvider);\n }\n\n // Wire up WebSocket event bridge if adapter supports it\n const wsAdapter = serverAdapter as WebSocketServerAdapter;\n if (typeof wsAdapter.broadcast === 'function') {\n const eventBridge = new WebSocketEventBridge(registry);\n server.setEventBridge(eventBridge);\n\n wsAdapter.onWebSocketConnect = (connId: string) => {\n // Create a lightweight connection proxy for the event bridge\n // The actual WebSocketConnection lives in the adapter\n eventBridge.addConnection({\n id: connId,\n subscriptions: new Set(),\n alive: true,\n isOpen: true,\n send: (msg: string) => wsAdapter.sendToConnection?.(connId, msg),\n sendEvent: (event: { event: string }) => {\n if (!eventBridge.isSubscribed(connId, event.event)) return;\n wsAdapter.sendToConnection?.(connId, JSON.stringify(event));\n },\n ping: () => {\n /* adapter handles heartbeat */\n },\n close: () => {\n /* adapter handles close */\n },\n destroy: () => {\n /* adapter handles destroy */\n },\n } as any); // eslint-disable-line @typescript-eslint/no-explicit-any\n };\n\n wsAdapter.onWebSocketDisconnect = (connId: string) => {\n // Abort any pending waiters (waitForElement / waitForCondition)\n // for this connection BEFORE removing it — stops leaked timers\n // and registry listeners.\n server.abortWaitersForConnection(connId);\n eventBridge.removeConnection(connId);\n };\n\n wsAdapter.onWebSocketMessage = async (connId: string, message: string) => {\n return server.handleWebSocketMessage(connId, message);\n };\n\n eventBridge.start();\n eventBridgeRef.current = eventBridge;\n }\n\n try {\n await server.start();\n serverRef.current = server;\n setServerRunning(true);\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start HTTP server:', err);\n }\n }, [\n features.server,\n config.serverPort,\n registry,\n executor,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n ]);\n\n const stopServer = useCallback(() => {\n if (eventBridgeRef.current) {\n eventBridgeRef.current.stop();\n eventBridgeRef.current = null;\n }\n if (serverRef.current) {\n serverRef.current.stop().catch(() => {});\n serverRef.current = null;\n }\n setServerRunning(false);\n }, []);\n\n // Auto-start server if enabled\n useEffect(() => {\n if (features.server) {\n startServer();\n return () => stopServer();\n }\n }, [features.server, startServer, stopServer]);\n\n // Start mDNS announcement and cloud relay.\n //\n // The cloud relay path does NOT require the HTTP server to be running —\n // it calls `server.handleRequest()` directly, bypassing HTTP. This matters\n // for preview/production builds where `features.server` is typically\n // false (no native TCP server adapter available). We still need a\n // NativeUIBridgeServer instance to handle tunneled requests, so we create\n // a bare instance here if startServer() didn't already make one.\n //\n // mDNS also doesn't need the HTTP server — it just advertises on the\n // network so remote devices can discover this phone's address.\n useEffect(() => {\n // Everything here is best-effort — any exception must not crash the app.\n try {\n const needsBareServer = !serverRef.current && !!cloudRelayConfig;\n if (needsBareServer) {\n try {\n // Create a server instance for handleRequest() use only; no adapter,\n // no HTTP listener. This is safe without features.server.\n const bareServer = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n if (navigationProvider) bareServer.setNavigationProvider(navigationProvider);\n if (screenshotProvider) bareServer.setScreenshotProvider(screenshotProvider);\n if (routeProvider) bareServer.setRouteProvider(routeProvider);\n serverRef.current = bareServer;\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to create bare server:', err);\n }\n }\n\n // mDNS advertisement\n if (enableMdnsAnnounce && deviceId) {\n try {\n const announcer = new DeviceAnnouncer({\n deviceId,\n appId: config.appInfo?.appId ?? 'unknown',\n port: config.serverPort ?? 8087,\n cloudRelayUrl: cloudRelayConfig?.relayUrl,\n cloudToken: cloudRelayConfig?.authToken,\n });\n announcerRef.current = announcer;\n void announcer.startMdnsAdvertise().catch((err) => {\n console.warn('[ui-bridge-native] mDNS advertise failed:', err);\n });\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start DeviceAnnouncer:', err);\n }\n }\n\n // Cloud relay tunnel (works without HTTP server)\n if (cloudRelayConfig && serverRef.current) {\n try {\n const relayClient = new CloudRelayClient({\n ...cloudRelayConfig,\n uiBridgeServer: serverRef.current,\n });\n cloudRelayRef.current = relayClient;\n relayClient.start();\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start CloudRelayClient:', err);\n }\n }\n } catch (err) {\n console.warn('[ui-bridge-native] Transport effect failed:', err);\n }\n\n return () => {\n try {\n if (announcerRef.current) {\n void announcerRef.current.stop().catch(() => {});\n announcerRef.current = null;\n }\n if (cloudRelayRef.current) {\n cloudRelayRef.current.stop();\n cloudRelayRef.current = null;\n }\n } catch {\n // cleanup must never throw\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n serverRunning,\n cloudRelayConfig?.relayUrl,\n cloudRelayConfig?.authToken,\n enableMdnsAnnounce,\n deviceId,\n ]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n stopServer();\n resetGlobalRegistry();\n };\n }, [stopServer]);\n\n // Context methods\n const getElements = useCallback(() => registry.getAllElements(), [registry]);\n\n const getComponents = useCallback(() => registry.getAllComponents(), [registry]);\n\n const createSnapshot = useCallback(() => registry.createSnapshot(), [registry]);\n\n const getCurrentRoute = useCallback(() => {\n return routeProvider?.getCurrentRoute() ?? null;\n }, [routeProvider]);\n\n // Mark the previous route's elements offscreen when the active route changes.\n // Without this, React Navigation's persistent-mount behavior leaves stale\n // layouts in the registry for tabs the user has left. Elements on the new\n // route re-fire `onLayout` and repopulate their layout.\n useEffect(() => {\n if (!routeProvider) return;\n\n let lastRoute: string | null = routeProvider.getCurrentRoute();\n\n return routeProvider.subscribe((current: string | null) => {\n if (current !== lastRoute && lastRoute != null) {\n registry.markRouteOffscreen(lastRoute);\n }\n lastRoute = current;\n });\n }, [routeProvider, registry]);\n\n const on = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.on(type, listener),\n [registry]\n );\n\n const off = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.off(type, listener),\n [registry]\n );\n\n const contextValue = useMemo<UIBridgeNativeContextValue>(\n () => ({\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n initialized: true,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n }),\n [\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n ]\n );\n\n return (\n <UIBridgeNativeContext.Provider value={contextValue}>{children}</UIBridgeNativeContext.Provider>\n );\n}\n\n/**\n * useUIBridgeNative hook\n *\n * Access the UI Bridge Native context. Throws if used outside provider.\n */\nexport function useUIBridgeNative(): UIBridgeNativeContextValue {\n const context = useContext(UIBridgeNativeContext);\n if (!context) {\n throw new Error('useUIBridgeNative must be used within a UIBridgeNativeProvider');\n }\n return context;\n}\n\n/**\n * useUIBridgeNativeOptional hook\n *\n * Access the UI Bridge Native context, returning null if outside provider.\n */\nexport function useUIBridgeNativeOptional(): UIBridgeNativeContextValue | null {\n return useContext(UIBridgeNativeContext);\n}\n\n/**\n * useUIBridgeNativeRequired hook\n *\n * Alias for useUIBridgeNative (throws if outside provider).\n */\nexport const useUIBridgeNativeRequired = useUIBridgeNative;\n","/**\n * UI Bridge Native Debug Inspector\n *\n * An overlay component that shows registered elements and allows\n * inspection of the UI Bridge state.\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport {\n View,\n Text,\n StyleSheet,\n TouchableOpacity,\n ScrollView,\n Modal,\n Dimensions,\n} from 'react-native';\nimport { useUIBridgeNativeOptional } from '../react/UIBridgeNativeProvider';\nimport type { RegisteredNativeElement } from '../core/types';\n\n/**\n * Inspector props\n */\nexport interface UIBridgeInspectorProps {\n /** Whether to show the inspector */\n visible?: boolean;\n /** Callback when inspector is closed */\n onClose?: () => void;\n /** Position of the inspector toggle button */\n togglePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n}\n\n/**\n * Element info card\n */\nfunction ElementCard({\n element,\n onPress,\n}: {\n element: RegisteredNativeElement;\n onPress: (element: RegisteredNativeElement) => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <TouchableOpacity style={styles.elementCard} onPress={() => onPress(element)}>\n <View style={styles.elementHeader}>\n <Text style={styles.elementId}>{element.id}</Text>\n <Text style={styles.elementType}>{element.type}</Text>\n </View>\n {element.label && <Text style={styles.elementLabel}>{element.label}</Text>}\n <View style={styles.stateRow}>\n <StateIndicator label=\"Mounted\" value={state.mounted} />\n <StateIndicator label=\"Visible\" value={state.visible} />\n <StateIndicator label=\"Enabled\" value={state.enabled} />\n </View>\n {identifier.testId && <Text style={styles.testId}>testID: {identifier.testId}</Text>}\n </TouchableOpacity>\n );\n}\n\n/**\n * State indicator\n */\nfunction StateIndicator({ label, value }: { label: string; value: boolean }) {\n return (\n <View style={styles.stateIndicator}>\n <View style={[styles.stateDot, { backgroundColor: value ? '#4CAF50' : '#F44336' }]} />\n <Text style={styles.stateLabel}>{label}</Text>\n </View>\n );\n}\n\n/**\n * Element detail view\n */\nfunction ElementDetail({\n element,\n onClose,\n}: {\n element: RegisteredNativeElement;\n onClose: () => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <View style={styles.detailContainer}>\n <View style={styles.detailHeader}>\n <Text style={styles.detailTitle}>{element.id}</Text>\n <TouchableOpacity onPress={onClose}>\n <Text style={styles.closeButton}>Close</Text>\n </TouchableOpacity>\n </View>\n\n <ScrollView style={styles.detailContent}>\n <Text style={styles.sectionTitle}>Type</Text>\n <Text style={styles.sectionValue}>{element.type}</Text>\n\n {element.label && (\n <>\n <Text style={styles.sectionTitle}>Label</Text>\n <Text style={styles.sectionValue}>{element.label}</Text>\n </>\n )}\n\n <Text style={styles.sectionTitle}>State</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>Mounted: {String(state.mounted)}</Text>\n <Text style={styles.stateText}>Visible: {String(state.visible)}</Text>\n <Text style={styles.stateText}>Enabled: {String(state.enabled)}</Text>\n <Text style={styles.stateText}>Focused: {String(state.focused)}</Text>\n {state.value !== undefined && <Text style={styles.stateText}>Value: {state.value}</Text>}\n </View>\n\n {state.layout && (\n <>\n <Text style={styles.sectionTitle}>Layout</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>\n Position: ({state.layout.x}, {state.layout.y})\n </Text>\n <Text style={styles.stateText}>\n Size: {state.layout.width} x {state.layout.height}\n </Text>\n <Text style={styles.stateText}>\n Page: ({state.layout.pageX}, {state.layout.pageY})\n </Text>\n </View>\n </>\n )}\n\n <Text style={styles.sectionTitle}>Identifier</Text>\n <View style={styles.stateSection}>\n {identifier.uiId && <Text style={styles.stateText}>uiId: {identifier.uiId}</Text>}\n {identifier.testId && <Text style={styles.stateText}>testId: {identifier.testId}</Text>}\n {identifier.accessibilityLabel && (\n <Text style={styles.stateText}>a11yLabel: {identifier.accessibilityLabel}</Text>\n )}\n <Text style={styles.stateText}>treePath: {identifier.treePath}</Text>\n </View>\n\n <Text style={styles.sectionTitle}>Actions</Text>\n <View style={styles.actionsSection}>\n {element.actions.map((action) => (\n <View key={action} style={styles.actionBadge}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n\n {element.customActions && Object.keys(element.customActions).length > 0 && (\n <>\n <Text style={styles.sectionTitle}>Custom Actions</Text>\n <View style={styles.actionsSection}>\n {Object.keys(element.customActions).map((action) => (\n <View key={action} style={[styles.actionBadge, styles.customActionBadge]}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n </>\n )}\n </ScrollView>\n </View>\n );\n}\n\n/**\n * UI Bridge Inspector component\n *\n * Shows an overlay with information about registered elements.\n * Useful for debugging and development.\n *\n * @example\n * ```tsx\n * function App() {\n * const [showInspector, setShowInspector] = useState(false);\n *\n * return (\n * <UIBridgeNativeProvider features={{ debug: __DEV__ }}>\n * <MainContent />\n * {__DEV__ && (\n * <UIBridgeInspector\n * visible={showInspector}\n * onClose={() => setShowInspector(false)}\n * />\n * )}\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeInspector({\n visible = false,\n onClose,\n togglePosition = 'bottom-right',\n}: UIBridgeInspectorProps) {\n const bridge = useUIBridgeNativeOptional();\n const [showInspector, setShowInspector] = useState(visible);\n const [selectedElement, setSelectedElement] = useState<RegisteredNativeElement | null>(null);\n\n const elements = useMemo(() => (bridge ? bridge.getElements() : []), [bridge, showInspector]);\n\n const components = useMemo(() => (bridge ? bridge.getComponents() : []), [bridge, showInspector]);\n\n const handleToggle = useCallback(() => {\n setShowInspector((prev) => !prev);\n }, []);\n\n const handleClose = useCallback(() => {\n setShowInspector(false);\n onClose?.();\n }, [onClose]);\n\n const handleSelectElement = useCallback((element: RegisteredNativeElement) => {\n setSelectedElement(element);\n }, []);\n\n const handleCloseDetail = useCallback(() => {\n setSelectedElement(null);\n }, []);\n\n // Position style for toggle button\n const toggleStyle = useMemo(() => {\n switch (togglePosition) {\n case 'top-left':\n return { top: 50, left: 10 };\n case 'top-right':\n return { top: 50, right: 10 };\n case 'bottom-left':\n return { bottom: 50, left: 10 };\n case 'bottom-right':\n default:\n return { bottom: 50, right: 10 };\n }\n }, [togglePosition]);\n\n if (!bridge) {\n return null;\n }\n\n return (\n <>\n {/* Toggle button */}\n <TouchableOpacity style={[styles.toggleButton, toggleStyle]} onPress={handleToggle}>\n <Text style={styles.toggleText}>UI</Text>\n </TouchableOpacity>\n\n {/* Inspector modal */}\n <Modal\n visible={showInspector}\n animationType=\"slide\"\n transparent={true}\n onRequestClose={handleClose}\n >\n <View style={styles.modalContainer}>\n <View style={styles.inspectorContainer}>\n {/* Header */}\n <View style={styles.header}>\n <Text style={styles.headerTitle}>UI Bridge Inspector</Text>\n <TouchableOpacity onPress={handleClose}>\n <Text style={styles.closeButton}>X</Text>\n </TouchableOpacity>\n </View>\n\n {/* Stats */}\n <View style={styles.statsRow}>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{elements.length}</Text>\n <Text style={styles.statLabel}>Elements</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{components.length}</Text>\n <Text style={styles.statLabel}>Components</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{bridge.serverRunning ? 'ON' : 'OFF'}</Text>\n <Text style={styles.statLabel}>Server</Text>\n </View>\n </View>\n\n {/* Element list or detail */}\n {selectedElement ? (\n <ElementDetail element={selectedElement} onClose={handleCloseDetail} />\n ) : (\n <ScrollView style={styles.elementList}>\n {elements.map((element) => (\n <ElementCard key={element.id} element={element} onPress={handleSelectElement} />\n ))}\n {elements.length === 0 && (\n <Text style={styles.emptyText}>No elements registered yet</Text>\n )}\n </ScrollView>\n )}\n </View>\n </View>\n </Modal>\n </>\n );\n}\n\nconst { height: screenHeight } = Dimensions.get('window');\n\nconst styles = StyleSheet.create({\n toggleButton: {\n position: 'absolute',\n width: 44,\n height: 44,\n borderRadius: 22,\n backgroundColor: '#2196F3',\n justifyContent: 'center',\n alignItems: 'center',\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.25,\n shadowRadius: 4,\n elevation: 5,\n zIndex: 1000,\n },\n toggleText: {\n color: '#fff',\n fontWeight: 'bold',\n fontSize: 14,\n },\n modalContainer: {\n flex: 1,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n justifyContent: 'flex-end',\n },\n inspectorContainer: {\n backgroundColor: '#1e1e1e',\n borderTopLeftRadius: 16,\n borderTopRightRadius: 16,\n maxHeight: screenHeight * 0.8,\n },\n header: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 16,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n headerTitle: {\n color: '#fff',\n fontSize: 18,\n fontWeight: 'bold',\n },\n closeButton: {\n color: '#2196F3',\n fontSize: 16,\n fontWeight: 'bold',\n },\n statsRow: {\n flexDirection: 'row',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n stat: {\n flex: 1,\n alignItems: 'center',\n },\n statValue: {\n color: '#fff',\n fontSize: 20,\n fontWeight: 'bold',\n },\n statLabel: {\n color: '#888',\n fontSize: 12,\n marginTop: 2,\n },\n elementList: {\n padding: 12,\n },\n elementCard: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 12,\n marginBottom: 8,\n },\n elementHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n elementId: {\n color: '#fff',\n fontSize: 14,\n fontWeight: 'bold',\n },\n elementType: {\n color: '#888',\n fontSize: 12,\n backgroundColor: '#444',\n paddingHorizontal: 8,\n paddingVertical: 2,\n borderRadius: 4,\n },\n elementLabel: {\n color: '#aaa',\n fontSize: 12,\n marginTop: 4,\n },\n stateRow: {\n flexDirection: 'row',\n marginTop: 8,\n },\n stateIndicator: {\n flexDirection: 'row',\n alignItems: 'center',\n marginRight: 12,\n },\n stateDot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginRight: 4,\n },\n stateLabel: {\n color: '#888',\n fontSize: 10,\n },\n testId: {\n color: '#666',\n fontSize: 10,\n marginTop: 4,\n fontFamily: 'monospace',\n },\n emptyText: {\n color: '#888',\n textAlign: 'center',\n marginTop: 20,\n },\n detailContainer: {\n flex: 1,\n },\n detailHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n detailTitle: {\n color: '#fff',\n fontSize: 16,\n fontWeight: 'bold',\n },\n detailContent: {\n padding: 12,\n },\n sectionTitle: {\n color: '#888',\n fontSize: 12,\n marginTop: 12,\n marginBottom: 4,\n textTransform: 'uppercase',\n },\n sectionValue: {\n color: '#fff',\n fontSize: 14,\n },\n stateSection: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 8,\n },\n stateText: {\n color: '#ddd',\n fontSize: 12,\n fontFamily: 'monospace',\n marginBottom: 2,\n },\n actionsSection: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n },\n actionBadge: {\n backgroundColor: '#2196F3',\n paddingHorizontal: 8,\n paddingVertical: 4,\n borderRadius: 4,\n marginRight: 6,\n marginBottom: 6,\n },\n customActionBadge: {\n backgroundColor: '#9C27B0',\n },\n actionText: {\n color: '#fff',\n fontSize: 12,\n },\n});\n"]}
|
package/dist/debug/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/design-handlers.ts","../../src/react/UIBridgeNativeProvider.tsx","../../src/debug/inspector.tsx"],"names":["jsx","useState","useMemo","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * UI Bridge Native Design Review Handlers\n *\n * HTTP handlers for the 8 design review endpoints.\n * Maps registered element styles to the web SDK's design data format.\n */\n\nimport type { NativeUIBridgeRegistry } from '../core/registry';\nimport type { APIResponse, HandlerContext } from './types';\nimport type { ElementDesignData, StateStyles, ResponsiveSnapshot } from '../design/design-types';\nimport {\n mapNativeStyleToExtended,\n getNativeElementDesignData,\n captureNativeStateVariations,\n captureNativeResponsiveSnapshot,\n} from '../design/design-inspector-native';\n\n// Style guide and baseline stored in closure (same pattern as web SDK)\nlet loadedStyleGuide: unknown = null;\nlet savedBaseline: unknown = null;\n\n// Try to load the style validator from the web SDK (optional peer dep)\nlet styleValidator: {\n runStyleAudit: (\n elements: Array<{ elementId: string; styles: Record<string, string> }>,\n guide: unknown\n ) => unknown;\n} | null = null;\n\n// Try to load quality evaluator from the web SDK (optional peer dep)\nlet qualityEvaluator: {\n evaluateQuality: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n context?: unknown\n ) => unknown;\n listContexts: () => Array<{ name: string; description: string }>;\n createBaseline: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n label?: string\n ) => unknown;\n diffSnapshots: (baseline: unknown, current: ElementDesignData[]) => unknown;\n} | null = null;\n\ntry {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const specs = require('@qontinui/ui-bridge/specs');\n styleValidator = specs;\n qualityEvaluator = specs;\n} catch {\n // Optional dependency not installed — audit/evaluate endpoints will return an error\n}\n\nfunction success<T>(data: T): APIResponse<T> {\n return { success: true, data, timestamp: Date.now() };\n}\n\nfunction error<T = unknown>(message: string, code?: string): APIResponse<T> {\n return { success: false, error: message, code, timestamp: Date.now() };\n}\n\n/**\n * Design handler interface (subset of NativeServerHandlers)\n */\nexport interface NativeDesignHandlers {\n getElementStyles: (ctx: HandlerContext) => Promise<APIResponse<ElementDesignData>>;\n getElementStateStyles: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elementId: string; stateStyles: StateStyles[] }>>;\n getDesignSnapshot: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elements: ElementDesignData[]; timestamp: number }>>;\n getResponsiveSnapshots: (ctx: HandlerContext) => Promise<APIResponse<ResponsiveSnapshot[]>>;\n runDesignAudit: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n loadStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ loaded: boolean }>>;\n getStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n clearStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ cleared: boolean }>>;\n evaluateQuality: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n getQualityContexts: (\n ctx: HandlerContext\n ) => Promise<APIResponse<Array<{ name: string; description: string }>>>;\n saveBaseline: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ saved: boolean; elementCount: number }>>;\n diffBaseline: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n}\n\n/**\n * Create design review handlers.\n */\nexport function createDesignHandlers(registry: NativeUIBridgeRegistry): NativeDesignHandlers {\n // Helper to get screen dimensions (React Native's Dimensions API must be\n // called at handler time, not import time, so we use a lazy getter).\n function getScreenDimensions(): { width: number; height: number } {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { Dimensions } = require('react-native');\n const screen = Dimensions.get('screen');\n return { width: screen.width, height: screen.height };\n } catch {\n return { width: 0, height: 0 };\n }\n }\n\n return {\n // 1. GET /design/element/:id/styles\n getElementStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const state = element.getState();\n const data = getNativeElementDesignData(\n id,\n element.label,\n element.type,\n element.flatStyle,\n state.layout\n );\n\n return success(data);\n },\n\n // 2. POST /design/element/:id/state-styles\n getElementStateStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const stateStyles = captureNativeStateVariations(element.flatStyle, element.stateStyles);\n\n return success({ elementId: id, stateStyles });\n },\n\n // 3. POST /design/snapshot\n getDesignSnapshot: async (ctx) => {\n const body = ctx.body as\n | {\n elementIds?: string[];\n includePseudoElements?: boolean;\n }\n | undefined;\n\n let elements = registry.getAllElements();\n\n // Filter to requested IDs if specified\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n return success({ elements: designData, timestamp: Date.now() });\n },\n\n // 4. POST /design/responsive\n getResponsiveSnapshots: async () => {\n // Platform limitation: RN cannot constrain screen width at runtime.\n // Returns a single snapshot at current device dimensions.\n const elements = registry.getAllElements();\n const elementData = elements.map((el) => {\n const state = el.getState();\n return {\n id: el.id,\n label: el.label,\n type: el.type,\n flatStyle: el.flatStyle,\n layout: state.layout,\n };\n });\n\n const snapshots = captureNativeResponsiveSnapshot(elementData, getScreenDimensions());\n return success(snapshots);\n },\n\n // 5. POST /design/audit\n runDesignAudit: async (ctx) => {\n const body = ctx.body as\n | {\n guide?: unknown;\n elementIds?: string[];\n }\n | undefined;\n\n const guide = body?.guide ?? loadedStyleGuide;\n\n if (!guide) {\n return error('No style guide loaded or provided', 'NO_STYLE_GUIDE');\n }\n\n if (!styleValidator) {\n return error(\n 'Install @qontinui/ui-bridge for style audit support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'VALIDATOR_NOT_AVAILABLE'\n );\n }\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n // Map elements to the format expected by the validator\n const auditElements = elements.map((el) => ({\n elementId: el.id,\n styles: mapNativeStyleToExtended(el.flatStyle) as unknown as Record<string, string>,\n }));\n\n try {\n const report = styleValidator.runStyleAudit(auditElements, guide);\n return success(report);\n } catch (err) {\n return error(\n 'Audit failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DESIGN_AUDIT_ERROR'\n );\n }\n },\n\n // 6. POST /design/style-guide/load\n loadStyleGuide: async (ctx) => {\n const body = ctx.body as { guide?: unknown } | undefined;\n\n if (!body?.guide) {\n return error('Style guide is required in request body', 'INVALID_REQUEST');\n }\n\n loadedStyleGuide = body.guide;\n return success({ loaded: true });\n },\n\n // 7. GET /design/style-guide\n getStyleGuide: async () => {\n return success(loadedStyleGuide);\n },\n\n // 8. DELETE /design/style-guide\n clearStyleGuide: async () => {\n loadedStyleGuide = null;\n return success({ cleared: true });\n },\n\n // 9. POST /design/evaluate\n evaluateQuality: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n context?: string;\n customContext?: unknown;\n elementIds?: string[];\n viewport?: { width: number; height: number };\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = body?.viewport ?? getScreenDimensions();\n\n // Resolve context: custom object > style guide context > built-in name\n let context: unknown = body?.customContext ?? body?.context ?? 'general';\n if (typeof context === 'string' && loadedStyleGuide) {\n const guide = loadedStyleGuide as { qualityContexts?: Record<string, unknown> };\n if (guide.qualityContexts?.[context]) {\n context = guide.qualityContexts[context];\n }\n }\n\n try {\n const report = qualityEvaluator.evaluateQuality(designData, viewport, context);\n return success(report);\n } catch (err) {\n return error(\n 'Evaluation failed: ' + (err instanceof Error ? err.message : String(err)),\n 'QUALITY_EVALUATION_ERROR'\n );\n }\n },\n\n // 10. GET /design/evaluate/contexts\n getQualityContexts: async () => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n return success(qualityEvaluator.listContexts());\n },\n\n // 11. POST /design/evaluate/baseline\n saveBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n label?: string;\n elementIds?: string[];\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = getScreenDimensions();\n savedBaseline = qualityEvaluator.createBaseline(designData, viewport, body?.label);\n return success({ saved: true, elementCount: designData.length });\n },\n\n // 12. POST /design/evaluate/diff\n diffBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n if (!savedBaseline) {\n return error('No baseline saved. Call saveBaseline first.', 'NO_BASELINE');\n }\n\n const body = ctx.body as { elementIds?: string[] } | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n try {\n const report = qualityEvaluator.diffSnapshots(savedBaseline, designData);\n return success(report);\n } catch (err) {\n return error(\n 'Diff failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DIFF_BASELINE_ERROR'\n );\n }\n },\n };\n}\n","/**\n * UI Bridge Native Provider\n *\n * React context provider for UI Bridge Native functionality.\n */\n\nimport React, {\n createContext,\n useContext,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n useState,\n} from 'react';\nimport type {\n NativeUIBridgeFeatures,\n NativeUIBridgeConfig,\n RegisteredNativeElement,\n RegisteredNativeComponent,\n NativeBridgeSnapshot,\n BridgeEventType,\n BridgeEventListener,\n} from '../core/types';\nimport { NativeUIBridgeRegistry, setGlobalRegistry, resetGlobalRegistry } from '../core/registry';\nimport { createNativeActionExecutor } from '../control/action-executor';\nimport type { NativeActionExecutor } from '../control/types';\nimport {\n createNativeServer,\n type NativeUIBridgeServer,\n type ServerAdapter,\n type WebSocketServerAdapter,\n} from '../server/http-server';\nimport type { RouteProvider } from '../server/types';\nimport { WebSocketEventBridge } from '../server/ws-event-bridge';\nimport { DeviceAnnouncer } from '../transport/DeviceAnnouncer';\nimport { CloudRelayClient, type CloudRelayConfig } from '../transport/CloudRelayClient';\n\n/**\n * UI Bridge Native context value\n */\nexport interface UIBridgeNativeContextValue {\n /** Feature flags */\n features: NativeUIBridgeFeatures;\n /** Configuration */\n config: NativeUIBridgeConfig;\n /** Element registry */\n registry: NativeUIBridgeRegistry;\n /** Action executor */\n executor: NativeActionExecutor;\n /** Get all registered elements */\n getElements: () => RegisteredNativeElement[];\n /** Get all registered components */\n getComponents: () => RegisteredNativeComponent[];\n /** Create a snapshot */\n createSnapshot: () => NativeBridgeSnapshot;\n /** Subscribe to events */\n on: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => () => void;\n /** Unsubscribe from events */\n off: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => void;\n /** Whether the provider is initialized */\n initialized: boolean;\n /** Server running status */\n serverRunning: boolean;\n /** Start the HTTP server */\n startServer: () => Promise<void>;\n /** Stop the HTTP server */\n stopServer: () => void;\n /** Get the current navigation route (if a RouteProvider is configured) */\n getCurrentRoute: () => string | null;\n}\n\n/**\n * UI Bridge Native context\n */\nconst UIBridgeNativeContext = createContext<UIBridgeNativeContextValue | null>(null);\n\n/**\n * UI Bridge Native provider props\n */\nexport interface UIBridgeNativeProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Feature flags */\n features?: NativeUIBridgeFeatures;\n /** Configuration */\n config?: NativeUIBridgeConfig;\n /** Event handler */\n onEvent?: BridgeEventListener;\n /**\n * A ServerAdapter instance for the HTTP server.\n * The app is responsible for creating this using its preferred native TCP/HTTP library.\n * @see ServerAdapter interface in server/http-server.ts\n */\n serverAdapter?: ServerAdapter;\n /**\n * Navigation provider for programmatic route navigation via UI Bridge.\n * Pass Expo Router's push/back functions to enable `control/page/navigate`.\n */\n navigationProvider?: { navigate: (url: string) => void; back?: () => void };\n /**\n * Screenshot provider for native screen capture via UI Bridge.\n * Pass a function that captures the current screen as base64 PNG.\n */\n screenshotProvider?: {\n capture: () => Promise<{ base64: string; width: number; height: number }>;\n };\n /**\n * Route provider for exposing the current navigation route in snapshots.\n * Wire this to Expo Router's `usePathname()` / `useSegments()` via a module-level ref.\n */\n routeProvider?: RouteProvider;\n /**\n * Configuration for the cloud relay tunnel (enables remote device verification\n * when USB/LAN are not available). Omit `uiBridgeServer` — the provider wires\n * that automatically after the server starts.\n */\n cloudRelayConfig?: Omit<CloudRelayConfig, 'uiBridgeServer'>;\n /**\n * Enable mDNS advertisement so that runners on the same LAN can discover this\n * device automatically (requires react-native-zeroconf).\n */\n enableMdnsAnnounce?: boolean;\n /**\n * Stable device identifier used for mDNS TXT records and cloud relay\n * registration. Typically sourced from expo-device or a UUID stored in\n * AsyncStorage.\n */\n deviceId?: string;\n}\n\n/**\n * UI Bridge Native Provider\n *\n * Provides UI Bridge Native context to child components.\n *\n * @example\n * ```tsx\n * // app/_layout.tsx\n * import { UIBridgeNativeProvider } from 'ui-bridge-native';\n *\n * export default function RootLayout() {\n * return (\n * <UIBridgeNativeProvider\n * features={{ server: __DEV__, debug: __DEV__ }}\n * config={{ serverPort: 8087 }}\n * >\n * <Stack>{children}</Stack>\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeNativeProvider({\n children,\n features = {},\n config = {},\n onEvent,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n cloudRelayConfig,\n enableMdnsAnnounce,\n deviceId,\n}: UIBridgeNativeProviderProps) {\n const registryRef = useRef<NativeUIBridgeRegistry | null>(null);\n const executorRef = useRef<NativeActionExecutor | null>(null);\n const [serverRunning, setServerRunning] = useState(false);\n\n // Initialize on first render\n if (!registryRef.current) {\n registryRef.current = new NativeUIBridgeRegistry({\n verbose: config.verbose,\n onEvent,\n });\n setGlobalRegistry(registryRef.current);\n }\n\n const registry = registryRef.current;\n\n // Create executor (memoized)\n if (!executorRef.current) {\n executorRef.current = createNativeActionExecutor(registry);\n }\n\n const executor = executorRef.current;\n\n // Server instance (persisted across renders)\n const serverRef = useRef<NativeUIBridgeServer | null>(null);\n const eventBridgeRef = useRef<WebSocketEventBridge | null>(null);\n\n // Cloud / mDNS transport references\n const announcerRef = useRef<DeviceAnnouncer | null>(null);\n const cloudRelayRef = useRef<CloudRelayClient | null>(null);\n\n // Server management — uses injected serverAdapter if provided\n const startServer = useCallback(async () => {\n if (!features.server) return;\n\n if (!serverAdapter) {\n console.warn(\n `[ui-bridge-native] HTTP server not available: no serverAdapter prop provided. ` +\n `Pass a serverAdapter to UIBridgeNativeProvider to enable the HTTP server.`\n );\n return;\n }\n\n const server = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n\n server.setAdapter(serverAdapter);\n\n // Wire navigation provider if supplied\n if (navigationProvider) {\n server.setNavigationProvider(navigationProvider);\n }\n\n // Wire screenshot provider if supplied\n if (screenshotProvider) {\n server.setScreenshotProvider(screenshotProvider);\n }\n\n // Wire route provider if supplied (must be set AFTER navigationProvider\n // since both may override getSnapshot / pageNavigate handlers)\n if (routeProvider) {\n server.setRouteProvider(routeProvider);\n }\n\n // Wire up WebSocket event bridge if adapter supports it\n const wsAdapter = serverAdapter as WebSocketServerAdapter;\n if (typeof wsAdapter.broadcast === 'function') {\n const eventBridge = new WebSocketEventBridge(registry);\n server.setEventBridge(eventBridge);\n\n wsAdapter.onWebSocketConnect = (connId: string) => {\n // Create a lightweight connection proxy for the event bridge\n // The actual WebSocketConnection lives in the adapter\n eventBridge.addConnection({\n id: connId,\n subscriptions: new Set(),\n alive: true,\n isOpen: true,\n send: (msg: string) => wsAdapter.sendToConnection?.(connId, msg),\n sendEvent: (event: { event: string }) => {\n if (!eventBridge.isSubscribed(connId, event.event)) return;\n wsAdapter.sendToConnection?.(connId, JSON.stringify(event));\n },\n ping: () => {\n /* adapter handles heartbeat */\n },\n close: () => {\n /* adapter handles close */\n },\n destroy: () => {\n /* adapter handles destroy */\n },\n } as any); // eslint-disable-line @typescript-eslint/no-explicit-any\n };\n\n wsAdapter.onWebSocketDisconnect = (connId: string) => {\n // Abort any pending waiters (waitForElement / waitForCondition)\n // for this connection BEFORE removing it — stops leaked timers\n // and registry listeners.\n server.abortWaitersForConnection(connId);\n eventBridge.removeConnection(connId);\n };\n\n wsAdapter.onWebSocketMessage = async (connId: string, message: string) => {\n return server.handleWebSocketMessage(connId, message);\n };\n\n eventBridge.start();\n eventBridgeRef.current = eventBridge;\n }\n\n try {\n await server.start();\n serverRef.current = server;\n setServerRunning(true);\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start HTTP server:', err);\n }\n }, [\n features.server,\n config.serverPort,\n registry,\n executor,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n ]);\n\n const stopServer = useCallback(() => {\n if (eventBridgeRef.current) {\n eventBridgeRef.current.stop();\n eventBridgeRef.current = null;\n }\n if (serverRef.current) {\n serverRef.current.stop().catch(() => {});\n serverRef.current = null;\n }\n setServerRunning(false);\n }, []);\n\n // Auto-start server if enabled\n useEffect(() => {\n if (features.server) {\n startServer();\n return () => stopServer();\n }\n }, [features.server, startServer, stopServer]);\n\n // Start mDNS announcement and cloud relay.\n //\n // The cloud relay path does NOT require the HTTP server to be running —\n // it calls `server.handleRequest()` directly, bypassing HTTP. This matters\n // for preview/production builds where `features.server` is typically\n // false (no native TCP server adapter available). We still need a\n // NativeUIBridgeServer instance to handle tunneled requests, so we create\n // a bare instance here if startServer() didn't already make one.\n //\n // mDNS also doesn't need the HTTP server — it just advertises on the\n // network so remote devices can discover this phone's address.\n useEffect(() => {\n const needsBareServer = !serverRef.current && !!cloudRelayConfig;\n if (needsBareServer) {\n // Create a server instance for handleRequest() use only; no adapter,\n // no HTTP listener. This is safe without features.server.\n const bareServer = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n if (navigationProvider) bareServer.setNavigationProvider(navigationProvider);\n if (screenshotProvider) bareServer.setScreenshotProvider(screenshotProvider);\n if (routeProvider) bareServer.setRouteProvider(routeProvider);\n serverRef.current = bareServer;\n }\n\n // mDNS advertisement\n if (enableMdnsAnnounce && deviceId) {\n const announcer = new DeviceAnnouncer({\n deviceId,\n appId: config.appInfo?.appId ?? 'unknown',\n port: config.serverPort ?? 8087,\n cloudRelayUrl: cloudRelayConfig?.relayUrl,\n cloudToken: cloudRelayConfig?.authToken,\n });\n announcerRef.current = announcer;\n void announcer.startMdnsAdvertise();\n }\n\n // Cloud relay tunnel (works without HTTP server)\n if (cloudRelayConfig && serverRef.current) {\n const relayClient = new CloudRelayClient({\n ...cloudRelayConfig,\n uiBridgeServer: serverRef.current,\n });\n cloudRelayRef.current = relayClient;\n relayClient.start();\n }\n\n return () => {\n if (announcerRef.current) {\n void announcerRef.current.stop();\n announcerRef.current = null;\n }\n if (cloudRelayRef.current) {\n cloudRelayRef.current.stop();\n cloudRelayRef.current = null;\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n serverRunning,\n cloudRelayConfig?.relayUrl,\n cloudRelayConfig?.authToken,\n enableMdnsAnnounce,\n deviceId,\n ]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n stopServer();\n resetGlobalRegistry();\n };\n }, [stopServer]);\n\n // Context methods\n const getElements = useCallback(() => registry.getAllElements(), [registry]);\n\n const getComponents = useCallback(() => registry.getAllComponents(), [registry]);\n\n const createSnapshot = useCallback(() => registry.createSnapshot(), [registry]);\n\n const getCurrentRoute = useCallback(() => {\n return routeProvider?.getCurrentRoute() ?? null;\n }, [routeProvider]);\n\n // Mark the previous route's elements offscreen when the active route changes.\n // Without this, React Navigation's persistent-mount behavior leaves stale\n // layouts in the registry for tabs the user has left. Elements on the new\n // route re-fire `onLayout` and repopulate their layout.\n useEffect(() => {\n if (!routeProvider) return;\n\n let lastRoute: string | null = routeProvider.getCurrentRoute();\n\n return routeProvider.subscribe((current: string | null) => {\n if (current !== lastRoute && lastRoute != null) {\n registry.markRouteOffscreen(lastRoute);\n }\n lastRoute = current;\n });\n }, [routeProvider, registry]);\n\n const on = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.on(type, listener),\n [registry]\n );\n\n const off = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.off(type, listener),\n [registry]\n );\n\n const contextValue = useMemo<UIBridgeNativeContextValue>(\n () => ({\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n initialized: true,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n }),\n [\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n ]\n );\n\n return (\n <UIBridgeNativeContext.Provider value={contextValue}>{children}</UIBridgeNativeContext.Provider>\n );\n}\n\n/**\n * useUIBridgeNative hook\n *\n * Access the UI Bridge Native context. Throws if used outside provider.\n */\nexport function useUIBridgeNative(): UIBridgeNativeContextValue {\n const context = useContext(UIBridgeNativeContext);\n if (!context) {\n throw new Error('useUIBridgeNative must be used within a UIBridgeNativeProvider');\n }\n return context;\n}\n\n/**\n * useUIBridgeNativeOptional hook\n *\n * Access the UI Bridge Native context, returning null if outside provider.\n */\nexport function useUIBridgeNativeOptional(): UIBridgeNativeContextValue | null {\n return useContext(UIBridgeNativeContext);\n}\n\n/**\n * useUIBridgeNativeRequired hook\n *\n * Alias for useUIBridgeNative (throws if outside provider).\n */\nexport const useUIBridgeNativeRequired = useUIBridgeNative;\n","/**\n * UI Bridge Native Debug Inspector\n *\n * An overlay component that shows registered elements and allows\n * inspection of the UI Bridge state.\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport {\n View,\n Text,\n StyleSheet,\n TouchableOpacity,\n ScrollView,\n Modal,\n Dimensions,\n} from 'react-native';\nimport { useUIBridgeNativeOptional } from '../react/UIBridgeNativeProvider';\nimport type { RegisteredNativeElement } from '../core/types';\n\n/**\n * Inspector props\n */\nexport interface UIBridgeInspectorProps {\n /** Whether to show the inspector */\n visible?: boolean;\n /** Callback when inspector is closed */\n onClose?: () => void;\n /** Position of the inspector toggle button */\n togglePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n}\n\n/**\n * Element info card\n */\nfunction ElementCard({\n element,\n onPress,\n}: {\n element: RegisteredNativeElement;\n onPress: (element: RegisteredNativeElement) => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <TouchableOpacity style={styles.elementCard} onPress={() => onPress(element)}>\n <View style={styles.elementHeader}>\n <Text style={styles.elementId}>{element.id}</Text>\n <Text style={styles.elementType}>{element.type}</Text>\n </View>\n {element.label && <Text style={styles.elementLabel}>{element.label}</Text>}\n <View style={styles.stateRow}>\n <StateIndicator label=\"Mounted\" value={state.mounted} />\n <StateIndicator label=\"Visible\" value={state.visible} />\n <StateIndicator label=\"Enabled\" value={state.enabled} />\n </View>\n {identifier.testId && <Text style={styles.testId}>testID: {identifier.testId}</Text>}\n </TouchableOpacity>\n );\n}\n\n/**\n * State indicator\n */\nfunction StateIndicator({ label, value }: { label: string; value: boolean }) {\n return (\n <View style={styles.stateIndicator}>\n <View style={[styles.stateDot, { backgroundColor: value ? '#4CAF50' : '#F44336' }]} />\n <Text style={styles.stateLabel}>{label}</Text>\n </View>\n );\n}\n\n/**\n * Element detail view\n */\nfunction ElementDetail({\n element,\n onClose,\n}: {\n element: RegisteredNativeElement;\n onClose: () => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <View style={styles.detailContainer}>\n <View style={styles.detailHeader}>\n <Text style={styles.detailTitle}>{element.id}</Text>\n <TouchableOpacity onPress={onClose}>\n <Text style={styles.closeButton}>Close</Text>\n </TouchableOpacity>\n </View>\n\n <ScrollView style={styles.detailContent}>\n <Text style={styles.sectionTitle}>Type</Text>\n <Text style={styles.sectionValue}>{element.type}</Text>\n\n {element.label && (\n <>\n <Text style={styles.sectionTitle}>Label</Text>\n <Text style={styles.sectionValue}>{element.label}</Text>\n </>\n )}\n\n <Text style={styles.sectionTitle}>State</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>Mounted: {String(state.mounted)}</Text>\n <Text style={styles.stateText}>Visible: {String(state.visible)}</Text>\n <Text style={styles.stateText}>Enabled: {String(state.enabled)}</Text>\n <Text style={styles.stateText}>Focused: {String(state.focused)}</Text>\n {state.value !== undefined && <Text style={styles.stateText}>Value: {state.value}</Text>}\n </View>\n\n {state.layout && (\n <>\n <Text style={styles.sectionTitle}>Layout</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>\n Position: ({state.layout.x}, {state.layout.y})\n </Text>\n <Text style={styles.stateText}>\n Size: {state.layout.width} x {state.layout.height}\n </Text>\n <Text style={styles.stateText}>\n Page: ({state.layout.pageX}, {state.layout.pageY})\n </Text>\n </View>\n </>\n )}\n\n <Text style={styles.sectionTitle}>Identifier</Text>\n <View style={styles.stateSection}>\n {identifier.uiId && <Text style={styles.stateText}>uiId: {identifier.uiId}</Text>}\n {identifier.testId && <Text style={styles.stateText}>testId: {identifier.testId}</Text>}\n {identifier.accessibilityLabel && (\n <Text style={styles.stateText}>a11yLabel: {identifier.accessibilityLabel}</Text>\n )}\n <Text style={styles.stateText}>treePath: {identifier.treePath}</Text>\n </View>\n\n <Text style={styles.sectionTitle}>Actions</Text>\n <View style={styles.actionsSection}>\n {element.actions.map((action) => (\n <View key={action} style={styles.actionBadge}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n\n {element.customActions && Object.keys(element.customActions).length > 0 && (\n <>\n <Text style={styles.sectionTitle}>Custom Actions</Text>\n <View style={styles.actionsSection}>\n {Object.keys(element.customActions).map((action) => (\n <View key={action} style={[styles.actionBadge, styles.customActionBadge]}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n </>\n )}\n </ScrollView>\n </View>\n );\n}\n\n/**\n * UI Bridge Inspector component\n *\n * Shows an overlay with information about registered elements.\n * Useful for debugging and development.\n *\n * @example\n * ```tsx\n * function App() {\n * const [showInspector, setShowInspector] = useState(false);\n *\n * return (\n * <UIBridgeNativeProvider features={{ debug: __DEV__ }}>\n * <MainContent />\n * {__DEV__ && (\n * <UIBridgeInspector\n * visible={showInspector}\n * onClose={() => setShowInspector(false)}\n * />\n * )}\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeInspector({\n visible = false,\n onClose,\n togglePosition = 'bottom-right',\n}: UIBridgeInspectorProps) {\n const bridge = useUIBridgeNativeOptional();\n const [showInspector, setShowInspector] = useState(visible);\n const [selectedElement, setSelectedElement] = useState<RegisteredNativeElement | null>(null);\n\n const elements = useMemo(() => (bridge ? bridge.getElements() : []), [bridge, showInspector]);\n\n const components = useMemo(() => (bridge ? bridge.getComponents() : []), [bridge, showInspector]);\n\n const handleToggle = useCallback(() => {\n setShowInspector((prev) => !prev);\n }, []);\n\n const handleClose = useCallback(() => {\n setShowInspector(false);\n onClose?.();\n }, [onClose]);\n\n const handleSelectElement = useCallback((element: RegisteredNativeElement) => {\n setSelectedElement(element);\n }, []);\n\n const handleCloseDetail = useCallback(() => {\n setSelectedElement(null);\n }, []);\n\n // Position style for toggle button\n const toggleStyle = useMemo(() => {\n switch (togglePosition) {\n case 'top-left':\n return { top: 50, left: 10 };\n case 'top-right':\n return { top: 50, right: 10 };\n case 'bottom-left':\n return { bottom: 50, left: 10 };\n case 'bottom-right':\n default:\n return { bottom: 50, right: 10 };\n }\n }, [togglePosition]);\n\n if (!bridge) {\n return null;\n }\n\n return (\n <>\n {/* Toggle button */}\n <TouchableOpacity style={[styles.toggleButton, toggleStyle]} onPress={handleToggle}>\n <Text style={styles.toggleText}>UI</Text>\n </TouchableOpacity>\n\n {/* Inspector modal */}\n <Modal\n visible={showInspector}\n animationType=\"slide\"\n transparent={true}\n onRequestClose={handleClose}\n >\n <View style={styles.modalContainer}>\n <View style={styles.inspectorContainer}>\n {/* Header */}\n <View style={styles.header}>\n <Text style={styles.headerTitle}>UI Bridge Inspector</Text>\n <TouchableOpacity onPress={handleClose}>\n <Text style={styles.closeButton}>X</Text>\n </TouchableOpacity>\n </View>\n\n {/* Stats */}\n <View style={styles.statsRow}>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{elements.length}</Text>\n <Text style={styles.statLabel}>Elements</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{components.length}</Text>\n <Text style={styles.statLabel}>Components</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{bridge.serverRunning ? 'ON' : 'OFF'}</Text>\n <Text style={styles.statLabel}>Server</Text>\n </View>\n </View>\n\n {/* Element list or detail */}\n {selectedElement ? (\n <ElementDetail element={selectedElement} onClose={handleCloseDetail} />\n ) : (\n <ScrollView style={styles.elementList}>\n {elements.map((element) => (\n <ElementCard key={element.id} element={element} onPress={handleSelectElement} />\n ))}\n {elements.length === 0 && (\n <Text style={styles.emptyText}>No elements registered yet</Text>\n )}\n </ScrollView>\n )}\n </View>\n </View>\n </Modal>\n </>\n );\n}\n\nconst { height: screenHeight } = Dimensions.get('window');\n\nconst styles = StyleSheet.create({\n toggleButton: {\n position: 'absolute',\n width: 44,\n height: 44,\n borderRadius: 22,\n backgroundColor: '#2196F3',\n justifyContent: 'center',\n alignItems: 'center',\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.25,\n shadowRadius: 4,\n elevation: 5,\n zIndex: 1000,\n },\n toggleText: {\n color: '#fff',\n fontWeight: 'bold',\n fontSize: 14,\n },\n modalContainer: {\n flex: 1,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n justifyContent: 'flex-end',\n },\n inspectorContainer: {\n backgroundColor: '#1e1e1e',\n borderTopLeftRadius: 16,\n borderTopRightRadius: 16,\n maxHeight: screenHeight * 0.8,\n },\n header: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 16,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n headerTitle: {\n color: '#fff',\n fontSize: 18,\n fontWeight: 'bold',\n },\n closeButton: {\n color: '#2196F3',\n fontSize: 16,\n fontWeight: 'bold',\n },\n statsRow: {\n flexDirection: 'row',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n stat: {\n flex: 1,\n alignItems: 'center',\n },\n statValue: {\n color: '#fff',\n fontSize: 20,\n fontWeight: 'bold',\n },\n statLabel: {\n color: '#888',\n fontSize: 12,\n marginTop: 2,\n },\n elementList: {\n padding: 12,\n },\n elementCard: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 12,\n marginBottom: 8,\n },\n elementHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n elementId: {\n color: '#fff',\n fontSize: 14,\n fontWeight: 'bold',\n },\n elementType: {\n color: '#888',\n fontSize: 12,\n backgroundColor: '#444',\n paddingHorizontal: 8,\n paddingVertical: 2,\n borderRadius: 4,\n },\n elementLabel: {\n color: '#aaa',\n fontSize: 12,\n marginTop: 4,\n },\n stateRow: {\n flexDirection: 'row',\n marginTop: 8,\n },\n stateIndicator: {\n flexDirection: 'row',\n alignItems: 'center',\n marginRight: 12,\n },\n stateDot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginRight: 4,\n },\n stateLabel: {\n color: '#888',\n fontSize: 10,\n },\n testId: {\n color: '#666',\n fontSize: 10,\n marginTop: 4,\n fontFamily: 'monospace',\n },\n emptyText: {\n color: '#888',\n textAlign: 'center',\n marginTop: 20,\n },\n detailContainer: {\n flex: 1,\n },\n detailHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n detailTitle: {\n color: '#fff',\n fontSize: 16,\n fontWeight: 'bold',\n },\n detailContent: {\n padding: 12,\n },\n sectionTitle: {\n color: '#888',\n fontSize: 12,\n marginTop: 12,\n marginBottom: 4,\n textTransform: 'uppercase',\n },\n sectionValue: {\n color: '#fff',\n fontSize: 14,\n },\n stateSection: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 8,\n },\n stateText: {\n color: '#ddd',\n fontSize: 12,\n fontFamily: 'monospace',\n marginBottom: 2,\n },\n actionsSection: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n },\n actionBadge: {\n backgroundColor: '#2196F3',\n paddingHorizontal: 8,\n paddingVertical: 4,\n borderRadius: 4,\n marginRight: 6,\n marginBottom: 6,\n },\n customActionBadge: {\n backgroundColor: '#9C27B0',\n },\n actionText: {\n color: '#fff',\n fontSize: 12,\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/design-handlers.ts","../../src/react/UIBridgeNativeProvider.tsx","../../src/debug/inspector.tsx"],"names":["jsx","useState","useMemo","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * UI Bridge Native Design Review Handlers\n *\n * HTTP handlers for the 8 design review endpoints.\n * Maps registered element styles to the web SDK's design data format.\n */\n\nimport type { NativeUIBridgeRegistry } from '../core/registry';\nimport type { APIResponse, HandlerContext } from './types';\nimport type { ElementDesignData, StateStyles, ResponsiveSnapshot } from '../design/design-types';\nimport {\n mapNativeStyleToExtended,\n getNativeElementDesignData,\n captureNativeStateVariations,\n captureNativeResponsiveSnapshot,\n} from '../design/design-inspector-native';\n\n// Style guide and baseline stored in closure (same pattern as web SDK)\nlet loadedStyleGuide: unknown = null;\nlet savedBaseline: unknown = null;\n\n// Try to load the style validator from the web SDK (optional peer dep)\nlet styleValidator: {\n runStyleAudit: (\n elements: Array<{ elementId: string; styles: Record<string, string> }>,\n guide: unknown\n ) => unknown;\n} | null = null;\n\n// Try to load quality evaluator from the web SDK (optional peer dep)\nlet qualityEvaluator: {\n evaluateQuality: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n context?: unknown\n ) => unknown;\n listContexts: () => Array<{ name: string; description: string }>;\n createBaseline: (\n elements: ElementDesignData[],\n viewport: { width: number; height: number },\n label?: string\n ) => unknown;\n diffSnapshots: (baseline: unknown, current: ElementDesignData[]) => unknown;\n} | null = null;\n\ntry {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const specs = require('@qontinui/ui-bridge/specs');\n styleValidator = specs;\n qualityEvaluator = specs;\n} catch {\n // Optional dependency not installed — audit/evaluate endpoints will return an error\n}\n\nfunction success<T>(data: T): APIResponse<T> {\n return { success: true, data, timestamp: Date.now() };\n}\n\nfunction error<T = unknown>(message: string, code?: string): APIResponse<T> {\n return { success: false, error: message, code, timestamp: Date.now() };\n}\n\n/**\n * Design handler interface (subset of NativeServerHandlers)\n */\nexport interface NativeDesignHandlers {\n getElementStyles: (ctx: HandlerContext) => Promise<APIResponse<ElementDesignData>>;\n getElementStateStyles: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elementId: string; stateStyles: StateStyles[] }>>;\n getDesignSnapshot: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ elements: ElementDesignData[]; timestamp: number }>>;\n getResponsiveSnapshots: (ctx: HandlerContext) => Promise<APIResponse<ResponsiveSnapshot[]>>;\n runDesignAudit: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n loadStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ loaded: boolean }>>;\n getStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n clearStyleGuide: (ctx: HandlerContext) => Promise<APIResponse<{ cleared: boolean }>>;\n evaluateQuality: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n getQualityContexts: (\n ctx: HandlerContext\n ) => Promise<APIResponse<Array<{ name: string; description: string }>>>;\n saveBaseline: (\n ctx: HandlerContext\n ) => Promise<APIResponse<{ saved: boolean; elementCount: number }>>;\n diffBaseline: (ctx: HandlerContext) => Promise<APIResponse<unknown>>;\n}\n\n/**\n * Create design review handlers.\n */\nexport function createDesignHandlers(registry: NativeUIBridgeRegistry): NativeDesignHandlers {\n // Helper to get screen dimensions (React Native's Dimensions API must be\n // called at handler time, not import time, so we use a lazy getter).\n function getScreenDimensions(): { width: number; height: number } {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { Dimensions } = require('react-native');\n const screen = Dimensions.get('screen');\n return { width: screen.width, height: screen.height };\n } catch {\n return { width: 0, height: 0 };\n }\n }\n\n return {\n // 1. GET /design/element/:id/styles\n getElementStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const state = element.getState();\n const data = getNativeElementDesignData(\n id,\n element.label,\n element.type,\n element.flatStyle,\n state.layout\n );\n\n return success(data);\n },\n\n // 2. POST /design/element/:id/state-styles\n getElementStateStyles: async (ctx) => {\n const { id } = ctx.params;\n const element = registry.getElement(id);\n\n if (!element) {\n return error('Element not found: ' + id, 'ELEMENT_NOT_FOUND');\n }\n\n const stateStyles = captureNativeStateVariations(element.flatStyle, element.stateStyles);\n\n return success({ elementId: id, stateStyles });\n },\n\n // 3. POST /design/snapshot\n getDesignSnapshot: async (ctx) => {\n const body = ctx.body as\n | {\n elementIds?: string[];\n includePseudoElements?: boolean;\n }\n | undefined;\n\n let elements = registry.getAllElements();\n\n // Filter to requested IDs if specified\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n return success({ elements: designData, timestamp: Date.now() });\n },\n\n // 4. POST /design/responsive\n getResponsiveSnapshots: async () => {\n // Platform limitation: RN cannot constrain screen width at runtime.\n // Returns a single snapshot at current device dimensions.\n const elements = registry.getAllElements();\n const elementData = elements.map((el) => {\n const state = el.getState();\n return {\n id: el.id,\n label: el.label,\n type: el.type,\n flatStyle: el.flatStyle,\n layout: state.layout,\n };\n });\n\n const snapshots = captureNativeResponsiveSnapshot(elementData, getScreenDimensions());\n return success(snapshots);\n },\n\n // 5. POST /design/audit\n runDesignAudit: async (ctx) => {\n const body = ctx.body as\n | {\n guide?: unknown;\n elementIds?: string[];\n }\n | undefined;\n\n const guide = body?.guide ?? loadedStyleGuide;\n\n if (!guide) {\n return error('No style guide loaded or provided', 'NO_STYLE_GUIDE');\n }\n\n if (!styleValidator) {\n return error(\n 'Install @qontinui/ui-bridge for style audit support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'VALIDATOR_NOT_AVAILABLE'\n );\n }\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n // Map elements to the format expected by the validator\n const auditElements = elements.map((el) => ({\n elementId: el.id,\n styles: mapNativeStyleToExtended(el.flatStyle) as unknown as Record<string, string>,\n }));\n\n try {\n const report = styleValidator.runStyleAudit(auditElements, guide);\n return success(report);\n } catch (err) {\n return error(\n 'Audit failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DESIGN_AUDIT_ERROR'\n );\n }\n },\n\n // 6. POST /design/style-guide/load\n loadStyleGuide: async (ctx) => {\n const body = ctx.body as { guide?: unknown } | undefined;\n\n if (!body?.guide) {\n return error('Style guide is required in request body', 'INVALID_REQUEST');\n }\n\n loadedStyleGuide = body.guide;\n return success({ loaded: true });\n },\n\n // 7. GET /design/style-guide\n getStyleGuide: async () => {\n return success(loadedStyleGuide);\n },\n\n // 8. DELETE /design/style-guide\n clearStyleGuide: async () => {\n loadedStyleGuide = null;\n return success({ cleared: true });\n },\n\n // 9. POST /design/evaluate\n evaluateQuality: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support. ' +\n 'Add it as a dependency: npm install @qontinui/ui-bridge',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n context?: string;\n customContext?: unknown;\n elementIds?: string[];\n viewport?: { width: number; height: number };\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = body?.viewport ?? getScreenDimensions();\n\n // Resolve context: custom object > style guide context > built-in name\n let context: unknown = body?.customContext ?? body?.context ?? 'general';\n if (typeof context === 'string' && loadedStyleGuide) {\n const guide = loadedStyleGuide as { qualityContexts?: Record<string, unknown> };\n if (guide.qualityContexts?.[context]) {\n context = guide.qualityContexts[context];\n }\n }\n\n try {\n const report = qualityEvaluator.evaluateQuality(designData, viewport, context);\n return success(report);\n } catch (err) {\n return error(\n 'Evaluation failed: ' + (err instanceof Error ? err.message : String(err)),\n 'QUALITY_EVALUATION_ERROR'\n );\n }\n },\n\n // 10. GET /design/evaluate/contexts\n getQualityContexts: async () => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n return success(qualityEvaluator.listContexts());\n },\n\n // 11. POST /design/evaluate/baseline\n saveBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n const body = ctx.body as\n | {\n label?: string;\n elementIds?: string[];\n }\n | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n const viewport = getScreenDimensions();\n savedBaseline = qualityEvaluator.createBaseline(designData, viewport, body?.label);\n return success({ saved: true, elementCount: designData.length });\n },\n\n // 12. POST /design/evaluate/diff\n diffBaseline: async (ctx) => {\n if (!qualityEvaluator) {\n return error(\n 'Install @qontinui/ui-bridge for quality evaluation support.',\n 'EVALUATOR_NOT_AVAILABLE'\n );\n }\n\n if (!savedBaseline) {\n return error('No baseline saved. Call saveBaseline first.', 'NO_BASELINE');\n }\n\n const body = ctx.body as { elementIds?: string[] } | undefined;\n\n let elements = registry.getAllElements();\n if (body?.elementIds && body.elementIds.length > 0) {\n const idSet = new Set(body.elementIds);\n elements = elements.filter((e) => idSet.has(e.id));\n }\n\n const designData: ElementDesignData[] = elements.map((el) => {\n const state = el.getState();\n return getNativeElementDesignData(el.id, el.label, el.type, el.flatStyle, state.layout);\n });\n\n try {\n const report = qualityEvaluator.diffSnapshots(savedBaseline, designData);\n return success(report);\n } catch (err) {\n return error(\n 'Diff failed: ' + (err instanceof Error ? err.message : String(err)),\n 'DIFF_BASELINE_ERROR'\n );\n }\n },\n };\n}\n","/**\n * UI Bridge Native Provider\n *\n * React context provider for UI Bridge Native functionality.\n */\n\nimport React, {\n createContext,\n useContext,\n useMemo,\n useEffect,\n useCallback,\n useRef,\n useState,\n} from 'react';\nimport type {\n NativeUIBridgeFeatures,\n NativeUIBridgeConfig,\n RegisteredNativeElement,\n RegisteredNativeComponent,\n NativeBridgeSnapshot,\n BridgeEventType,\n BridgeEventListener,\n} from '../core/types';\nimport { NativeUIBridgeRegistry, setGlobalRegistry, resetGlobalRegistry } from '../core/registry';\nimport { createNativeActionExecutor } from '../control/action-executor';\nimport type { NativeActionExecutor } from '../control/types';\nimport {\n createNativeServer,\n type NativeUIBridgeServer,\n type ServerAdapter,\n type WebSocketServerAdapter,\n} from '../server/http-server';\nimport type { RouteProvider } from '../server/types';\nimport { WebSocketEventBridge } from '../server/ws-event-bridge';\nimport { DeviceAnnouncer } from '../transport/DeviceAnnouncer';\nimport { CloudRelayClient, type CloudRelayConfig } from '../transport/CloudRelayClient';\n\n/**\n * UI Bridge Native context value\n */\nexport interface UIBridgeNativeContextValue {\n /** Feature flags */\n features: NativeUIBridgeFeatures;\n /** Configuration */\n config: NativeUIBridgeConfig;\n /** Element registry */\n registry: NativeUIBridgeRegistry;\n /** Action executor */\n executor: NativeActionExecutor;\n /** Get all registered elements */\n getElements: () => RegisteredNativeElement[];\n /** Get all registered components */\n getComponents: () => RegisteredNativeComponent[];\n /** Create a snapshot */\n createSnapshot: () => NativeBridgeSnapshot;\n /** Subscribe to events */\n on: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => () => void;\n /** Unsubscribe from events */\n off: <T = unknown>(type: BridgeEventType, listener: BridgeEventListener<T>) => void;\n /** Whether the provider is initialized */\n initialized: boolean;\n /** Server running status */\n serverRunning: boolean;\n /** Start the HTTP server */\n startServer: () => Promise<void>;\n /** Stop the HTTP server */\n stopServer: () => void;\n /** Get the current navigation route (if a RouteProvider is configured) */\n getCurrentRoute: () => string | null;\n}\n\n/**\n * UI Bridge Native context\n */\nconst UIBridgeNativeContext = createContext<UIBridgeNativeContextValue | null>(null);\n\n/**\n * UI Bridge Native provider props\n */\nexport interface UIBridgeNativeProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Feature flags */\n features?: NativeUIBridgeFeatures;\n /** Configuration */\n config?: NativeUIBridgeConfig;\n /** Event handler */\n onEvent?: BridgeEventListener;\n /**\n * A ServerAdapter instance for the HTTP server.\n * The app is responsible for creating this using its preferred native TCP/HTTP library.\n * @see ServerAdapter interface in server/http-server.ts\n */\n serverAdapter?: ServerAdapter;\n /**\n * Navigation provider for programmatic route navigation via UI Bridge.\n * Pass Expo Router's push/back functions to enable `control/page/navigate`.\n */\n navigationProvider?: { navigate: (url: string) => void; back?: () => void };\n /**\n * Screenshot provider for native screen capture via UI Bridge.\n * Pass a function that captures the current screen as base64 PNG.\n */\n screenshotProvider?: {\n capture: () => Promise<{ base64: string; width: number; height: number }>;\n };\n /**\n * Route provider for exposing the current navigation route in snapshots.\n * Wire this to Expo Router's `usePathname()` / `useSegments()` via a module-level ref.\n */\n routeProvider?: RouteProvider;\n /**\n * Configuration for the cloud relay tunnel (enables remote device verification\n * when USB/LAN are not available). Omit `uiBridgeServer` — the provider wires\n * that automatically after the server starts.\n */\n cloudRelayConfig?: Omit<CloudRelayConfig, 'uiBridgeServer'>;\n /**\n * Enable mDNS advertisement so that runners on the same LAN can discover this\n * device automatically (requires react-native-zeroconf).\n */\n enableMdnsAnnounce?: boolean;\n /**\n * Stable device identifier used for mDNS TXT records and cloud relay\n * registration. Typically sourced from expo-device or a UUID stored in\n * AsyncStorage.\n */\n deviceId?: string;\n}\n\n/**\n * UI Bridge Native Provider\n *\n * Provides UI Bridge Native context to child components.\n *\n * @example\n * ```tsx\n * // app/_layout.tsx\n * import { UIBridgeNativeProvider } from 'ui-bridge-native';\n *\n * export default function RootLayout() {\n * return (\n * <UIBridgeNativeProvider\n * features={{ server: __DEV__, debug: __DEV__ }}\n * config={{ serverPort: 8087 }}\n * >\n * <Stack>{children}</Stack>\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeNativeProvider({\n children,\n features = {},\n config = {},\n onEvent,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n cloudRelayConfig,\n enableMdnsAnnounce,\n deviceId,\n}: UIBridgeNativeProviderProps) {\n const registryRef = useRef<NativeUIBridgeRegistry | null>(null);\n const executorRef = useRef<NativeActionExecutor | null>(null);\n const [serverRunning, setServerRunning] = useState(false);\n\n // Initialize on first render\n if (!registryRef.current) {\n registryRef.current = new NativeUIBridgeRegistry({\n verbose: config.verbose,\n onEvent,\n });\n setGlobalRegistry(registryRef.current);\n }\n\n const registry = registryRef.current;\n\n // Create executor (memoized)\n if (!executorRef.current) {\n executorRef.current = createNativeActionExecutor(registry);\n }\n\n const executor = executorRef.current;\n\n // Server instance (persisted across renders)\n const serverRef = useRef<NativeUIBridgeServer | null>(null);\n const eventBridgeRef = useRef<WebSocketEventBridge | null>(null);\n\n // Cloud / mDNS transport references\n const announcerRef = useRef<DeviceAnnouncer | null>(null);\n const cloudRelayRef = useRef<CloudRelayClient | null>(null);\n\n // Server management — uses injected serverAdapter if provided\n const startServer = useCallback(async () => {\n if (!features.server) return;\n\n if (!serverAdapter) {\n console.warn(\n `[ui-bridge-native] HTTP server not available: no serverAdapter prop provided. ` +\n `Pass a serverAdapter to UIBridgeNativeProvider to enable the HTTP server.`\n );\n return;\n }\n\n const server = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n\n server.setAdapter(serverAdapter);\n\n // Wire navigation provider if supplied\n if (navigationProvider) {\n server.setNavigationProvider(navigationProvider);\n }\n\n // Wire screenshot provider if supplied\n if (screenshotProvider) {\n server.setScreenshotProvider(screenshotProvider);\n }\n\n // Wire route provider if supplied (must be set AFTER navigationProvider\n // since both may override getSnapshot / pageNavigate handlers)\n if (routeProvider) {\n server.setRouteProvider(routeProvider);\n }\n\n // Wire up WebSocket event bridge if adapter supports it\n const wsAdapter = serverAdapter as WebSocketServerAdapter;\n if (typeof wsAdapter.broadcast === 'function') {\n const eventBridge = new WebSocketEventBridge(registry);\n server.setEventBridge(eventBridge);\n\n wsAdapter.onWebSocketConnect = (connId: string) => {\n // Create a lightweight connection proxy for the event bridge\n // The actual WebSocketConnection lives in the adapter\n eventBridge.addConnection({\n id: connId,\n subscriptions: new Set(),\n alive: true,\n isOpen: true,\n send: (msg: string) => wsAdapter.sendToConnection?.(connId, msg),\n sendEvent: (event: { event: string }) => {\n if (!eventBridge.isSubscribed(connId, event.event)) return;\n wsAdapter.sendToConnection?.(connId, JSON.stringify(event));\n },\n ping: () => {\n /* adapter handles heartbeat */\n },\n close: () => {\n /* adapter handles close */\n },\n destroy: () => {\n /* adapter handles destroy */\n },\n } as any); // eslint-disable-line @typescript-eslint/no-explicit-any\n };\n\n wsAdapter.onWebSocketDisconnect = (connId: string) => {\n // Abort any pending waiters (waitForElement / waitForCondition)\n // for this connection BEFORE removing it — stops leaked timers\n // and registry listeners.\n server.abortWaitersForConnection(connId);\n eventBridge.removeConnection(connId);\n };\n\n wsAdapter.onWebSocketMessage = async (connId: string, message: string) => {\n return server.handleWebSocketMessage(connId, message);\n };\n\n eventBridge.start();\n eventBridgeRef.current = eventBridge;\n }\n\n try {\n await server.start();\n serverRef.current = server;\n setServerRunning(true);\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start HTTP server:', err);\n }\n }, [\n features.server,\n config.serverPort,\n registry,\n executor,\n serverAdapter,\n navigationProvider,\n screenshotProvider,\n routeProvider,\n ]);\n\n const stopServer = useCallback(() => {\n if (eventBridgeRef.current) {\n eventBridgeRef.current.stop();\n eventBridgeRef.current = null;\n }\n if (serverRef.current) {\n serverRef.current.stop().catch(() => {});\n serverRef.current = null;\n }\n setServerRunning(false);\n }, []);\n\n // Auto-start server if enabled\n useEffect(() => {\n if (features.server) {\n startServer();\n return () => stopServer();\n }\n }, [features.server, startServer, stopServer]);\n\n // Start mDNS announcement and cloud relay.\n //\n // The cloud relay path does NOT require the HTTP server to be running —\n // it calls `server.handleRequest()` directly, bypassing HTTP. This matters\n // for preview/production builds where `features.server` is typically\n // false (no native TCP server adapter available). We still need a\n // NativeUIBridgeServer instance to handle tunneled requests, so we create\n // a bare instance here if startServer() didn't already make one.\n //\n // mDNS also doesn't need the HTTP server — it just advertises on the\n // network so remote devices can discover this phone's address.\n useEffect(() => {\n // Everything here is best-effort — any exception must not crash the app.\n try {\n const needsBareServer = !serverRef.current && !!cloudRelayConfig;\n if (needsBareServer) {\n try {\n // Create a server instance for handleRequest() use only; no adapter,\n // no HTTP listener. This is safe without features.server.\n const bareServer = createNativeServer(registry, executor, {\n serverPort: config.serverPort || 8087,\n cors: true,\n });\n if (navigationProvider) bareServer.setNavigationProvider(navigationProvider);\n if (screenshotProvider) bareServer.setScreenshotProvider(screenshotProvider);\n if (routeProvider) bareServer.setRouteProvider(routeProvider);\n serverRef.current = bareServer;\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to create bare server:', err);\n }\n }\n\n // mDNS advertisement\n if (enableMdnsAnnounce && deviceId) {\n try {\n const announcer = new DeviceAnnouncer({\n deviceId,\n appId: config.appInfo?.appId ?? 'unknown',\n port: config.serverPort ?? 8087,\n cloudRelayUrl: cloudRelayConfig?.relayUrl,\n cloudToken: cloudRelayConfig?.authToken,\n });\n announcerRef.current = announcer;\n void announcer.startMdnsAdvertise().catch((err) => {\n console.warn('[ui-bridge-native] mDNS advertise failed:', err);\n });\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start DeviceAnnouncer:', err);\n }\n }\n\n // Cloud relay tunnel (works without HTTP server)\n if (cloudRelayConfig && serverRef.current) {\n try {\n const relayClient = new CloudRelayClient({\n ...cloudRelayConfig,\n uiBridgeServer: serverRef.current,\n });\n cloudRelayRef.current = relayClient;\n relayClient.start();\n } catch (err) {\n console.warn('[ui-bridge-native] Failed to start CloudRelayClient:', err);\n }\n }\n } catch (err) {\n console.warn('[ui-bridge-native] Transport effect failed:', err);\n }\n\n return () => {\n try {\n if (announcerRef.current) {\n void announcerRef.current.stop().catch(() => {});\n announcerRef.current = null;\n }\n if (cloudRelayRef.current) {\n cloudRelayRef.current.stop();\n cloudRelayRef.current = null;\n }\n } catch {\n // cleanup must never throw\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n serverRunning,\n cloudRelayConfig?.relayUrl,\n cloudRelayConfig?.authToken,\n enableMdnsAnnounce,\n deviceId,\n ]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n stopServer();\n resetGlobalRegistry();\n };\n }, [stopServer]);\n\n // Context methods\n const getElements = useCallback(() => registry.getAllElements(), [registry]);\n\n const getComponents = useCallback(() => registry.getAllComponents(), [registry]);\n\n const createSnapshot = useCallback(() => registry.createSnapshot(), [registry]);\n\n const getCurrentRoute = useCallback(() => {\n return routeProvider?.getCurrentRoute() ?? null;\n }, [routeProvider]);\n\n // Mark the previous route's elements offscreen when the active route changes.\n // Without this, React Navigation's persistent-mount behavior leaves stale\n // layouts in the registry for tabs the user has left. Elements on the new\n // route re-fire `onLayout` and repopulate their layout.\n useEffect(() => {\n if (!routeProvider) return;\n\n let lastRoute: string | null = routeProvider.getCurrentRoute();\n\n return routeProvider.subscribe((current: string | null) => {\n if (current !== lastRoute && lastRoute != null) {\n registry.markRouteOffscreen(lastRoute);\n }\n lastRoute = current;\n });\n }, [routeProvider, registry]);\n\n const on = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.on(type, listener),\n [registry]\n );\n\n const off = useCallback(\n <T = unknown,>(type: BridgeEventType, listener: BridgeEventListener<T>) =>\n registry.off(type, listener),\n [registry]\n );\n\n const contextValue = useMemo<UIBridgeNativeContextValue>(\n () => ({\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n initialized: true,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n }),\n [\n features,\n config,\n registry,\n executor,\n getElements,\n getComponents,\n createSnapshot,\n on,\n off,\n serverRunning,\n startServer,\n stopServer,\n getCurrentRoute,\n ]\n );\n\n return (\n <UIBridgeNativeContext.Provider value={contextValue}>{children}</UIBridgeNativeContext.Provider>\n );\n}\n\n/**\n * useUIBridgeNative hook\n *\n * Access the UI Bridge Native context. Throws if used outside provider.\n */\nexport function useUIBridgeNative(): UIBridgeNativeContextValue {\n const context = useContext(UIBridgeNativeContext);\n if (!context) {\n throw new Error('useUIBridgeNative must be used within a UIBridgeNativeProvider');\n }\n return context;\n}\n\n/**\n * useUIBridgeNativeOptional hook\n *\n * Access the UI Bridge Native context, returning null if outside provider.\n */\nexport function useUIBridgeNativeOptional(): UIBridgeNativeContextValue | null {\n return useContext(UIBridgeNativeContext);\n}\n\n/**\n * useUIBridgeNativeRequired hook\n *\n * Alias for useUIBridgeNative (throws if outside provider).\n */\nexport const useUIBridgeNativeRequired = useUIBridgeNative;\n","/**\n * UI Bridge Native Debug Inspector\n *\n * An overlay component that shows registered elements and allows\n * inspection of the UI Bridge state.\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport {\n View,\n Text,\n StyleSheet,\n TouchableOpacity,\n ScrollView,\n Modal,\n Dimensions,\n} from 'react-native';\nimport { useUIBridgeNativeOptional } from '../react/UIBridgeNativeProvider';\nimport type { RegisteredNativeElement } from '../core/types';\n\n/**\n * Inspector props\n */\nexport interface UIBridgeInspectorProps {\n /** Whether to show the inspector */\n visible?: boolean;\n /** Callback when inspector is closed */\n onClose?: () => void;\n /** Position of the inspector toggle button */\n togglePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n}\n\n/**\n * Element info card\n */\nfunction ElementCard({\n element,\n onPress,\n}: {\n element: RegisteredNativeElement;\n onPress: (element: RegisteredNativeElement) => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <TouchableOpacity style={styles.elementCard} onPress={() => onPress(element)}>\n <View style={styles.elementHeader}>\n <Text style={styles.elementId}>{element.id}</Text>\n <Text style={styles.elementType}>{element.type}</Text>\n </View>\n {element.label && <Text style={styles.elementLabel}>{element.label}</Text>}\n <View style={styles.stateRow}>\n <StateIndicator label=\"Mounted\" value={state.mounted} />\n <StateIndicator label=\"Visible\" value={state.visible} />\n <StateIndicator label=\"Enabled\" value={state.enabled} />\n </View>\n {identifier.testId && <Text style={styles.testId}>testID: {identifier.testId}</Text>}\n </TouchableOpacity>\n );\n}\n\n/**\n * State indicator\n */\nfunction StateIndicator({ label, value }: { label: string; value: boolean }) {\n return (\n <View style={styles.stateIndicator}>\n <View style={[styles.stateDot, { backgroundColor: value ? '#4CAF50' : '#F44336' }]} />\n <Text style={styles.stateLabel}>{label}</Text>\n </View>\n );\n}\n\n/**\n * Element detail view\n */\nfunction ElementDetail({\n element,\n onClose,\n}: {\n element: RegisteredNativeElement;\n onClose: () => void;\n}) {\n const state = element.getState();\n const identifier = element.getIdentifier();\n\n return (\n <View style={styles.detailContainer}>\n <View style={styles.detailHeader}>\n <Text style={styles.detailTitle}>{element.id}</Text>\n <TouchableOpacity onPress={onClose}>\n <Text style={styles.closeButton}>Close</Text>\n </TouchableOpacity>\n </View>\n\n <ScrollView style={styles.detailContent}>\n <Text style={styles.sectionTitle}>Type</Text>\n <Text style={styles.sectionValue}>{element.type}</Text>\n\n {element.label && (\n <>\n <Text style={styles.sectionTitle}>Label</Text>\n <Text style={styles.sectionValue}>{element.label}</Text>\n </>\n )}\n\n <Text style={styles.sectionTitle}>State</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>Mounted: {String(state.mounted)}</Text>\n <Text style={styles.stateText}>Visible: {String(state.visible)}</Text>\n <Text style={styles.stateText}>Enabled: {String(state.enabled)}</Text>\n <Text style={styles.stateText}>Focused: {String(state.focused)}</Text>\n {state.value !== undefined && <Text style={styles.stateText}>Value: {state.value}</Text>}\n </View>\n\n {state.layout && (\n <>\n <Text style={styles.sectionTitle}>Layout</Text>\n <View style={styles.stateSection}>\n <Text style={styles.stateText}>\n Position: ({state.layout.x}, {state.layout.y})\n </Text>\n <Text style={styles.stateText}>\n Size: {state.layout.width} x {state.layout.height}\n </Text>\n <Text style={styles.stateText}>\n Page: ({state.layout.pageX}, {state.layout.pageY})\n </Text>\n </View>\n </>\n )}\n\n <Text style={styles.sectionTitle}>Identifier</Text>\n <View style={styles.stateSection}>\n {identifier.uiId && <Text style={styles.stateText}>uiId: {identifier.uiId}</Text>}\n {identifier.testId && <Text style={styles.stateText}>testId: {identifier.testId}</Text>}\n {identifier.accessibilityLabel && (\n <Text style={styles.stateText}>a11yLabel: {identifier.accessibilityLabel}</Text>\n )}\n <Text style={styles.stateText}>treePath: {identifier.treePath}</Text>\n </View>\n\n <Text style={styles.sectionTitle}>Actions</Text>\n <View style={styles.actionsSection}>\n {element.actions.map((action) => (\n <View key={action} style={styles.actionBadge}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n\n {element.customActions && Object.keys(element.customActions).length > 0 && (\n <>\n <Text style={styles.sectionTitle}>Custom Actions</Text>\n <View style={styles.actionsSection}>\n {Object.keys(element.customActions).map((action) => (\n <View key={action} style={[styles.actionBadge, styles.customActionBadge]}>\n <Text style={styles.actionText}>{action}</Text>\n </View>\n ))}\n </View>\n </>\n )}\n </ScrollView>\n </View>\n );\n}\n\n/**\n * UI Bridge Inspector component\n *\n * Shows an overlay with information about registered elements.\n * Useful for debugging and development.\n *\n * @example\n * ```tsx\n * function App() {\n * const [showInspector, setShowInspector] = useState(false);\n *\n * return (\n * <UIBridgeNativeProvider features={{ debug: __DEV__ }}>\n * <MainContent />\n * {__DEV__ && (\n * <UIBridgeInspector\n * visible={showInspector}\n * onClose={() => setShowInspector(false)}\n * />\n * )}\n * </UIBridgeNativeProvider>\n * );\n * }\n * ```\n */\nexport function UIBridgeInspector({\n visible = false,\n onClose,\n togglePosition = 'bottom-right',\n}: UIBridgeInspectorProps) {\n const bridge = useUIBridgeNativeOptional();\n const [showInspector, setShowInspector] = useState(visible);\n const [selectedElement, setSelectedElement] = useState<RegisteredNativeElement | null>(null);\n\n const elements = useMemo(() => (bridge ? bridge.getElements() : []), [bridge, showInspector]);\n\n const components = useMemo(() => (bridge ? bridge.getComponents() : []), [bridge, showInspector]);\n\n const handleToggle = useCallback(() => {\n setShowInspector((prev) => !prev);\n }, []);\n\n const handleClose = useCallback(() => {\n setShowInspector(false);\n onClose?.();\n }, [onClose]);\n\n const handleSelectElement = useCallback((element: RegisteredNativeElement) => {\n setSelectedElement(element);\n }, []);\n\n const handleCloseDetail = useCallback(() => {\n setSelectedElement(null);\n }, []);\n\n // Position style for toggle button\n const toggleStyle = useMemo(() => {\n switch (togglePosition) {\n case 'top-left':\n return { top: 50, left: 10 };\n case 'top-right':\n return { top: 50, right: 10 };\n case 'bottom-left':\n return { bottom: 50, left: 10 };\n case 'bottom-right':\n default:\n return { bottom: 50, right: 10 };\n }\n }, [togglePosition]);\n\n if (!bridge) {\n return null;\n }\n\n return (\n <>\n {/* Toggle button */}\n <TouchableOpacity style={[styles.toggleButton, toggleStyle]} onPress={handleToggle}>\n <Text style={styles.toggleText}>UI</Text>\n </TouchableOpacity>\n\n {/* Inspector modal */}\n <Modal\n visible={showInspector}\n animationType=\"slide\"\n transparent={true}\n onRequestClose={handleClose}\n >\n <View style={styles.modalContainer}>\n <View style={styles.inspectorContainer}>\n {/* Header */}\n <View style={styles.header}>\n <Text style={styles.headerTitle}>UI Bridge Inspector</Text>\n <TouchableOpacity onPress={handleClose}>\n <Text style={styles.closeButton}>X</Text>\n </TouchableOpacity>\n </View>\n\n {/* Stats */}\n <View style={styles.statsRow}>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{elements.length}</Text>\n <Text style={styles.statLabel}>Elements</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{components.length}</Text>\n <Text style={styles.statLabel}>Components</Text>\n </View>\n <View style={styles.stat}>\n <Text style={styles.statValue}>{bridge.serverRunning ? 'ON' : 'OFF'}</Text>\n <Text style={styles.statLabel}>Server</Text>\n </View>\n </View>\n\n {/* Element list or detail */}\n {selectedElement ? (\n <ElementDetail element={selectedElement} onClose={handleCloseDetail} />\n ) : (\n <ScrollView style={styles.elementList}>\n {elements.map((element) => (\n <ElementCard key={element.id} element={element} onPress={handleSelectElement} />\n ))}\n {elements.length === 0 && (\n <Text style={styles.emptyText}>No elements registered yet</Text>\n )}\n </ScrollView>\n )}\n </View>\n </View>\n </Modal>\n </>\n );\n}\n\nconst { height: screenHeight } = Dimensions.get('window');\n\nconst styles = StyleSheet.create({\n toggleButton: {\n position: 'absolute',\n width: 44,\n height: 44,\n borderRadius: 22,\n backgroundColor: '#2196F3',\n justifyContent: 'center',\n alignItems: 'center',\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.25,\n shadowRadius: 4,\n elevation: 5,\n zIndex: 1000,\n },\n toggleText: {\n color: '#fff',\n fontWeight: 'bold',\n fontSize: 14,\n },\n modalContainer: {\n flex: 1,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n justifyContent: 'flex-end',\n },\n inspectorContainer: {\n backgroundColor: '#1e1e1e',\n borderTopLeftRadius: 16,\n borderTopRightRadius: 16,\n maxHeight: screenHeight * 0.8,\n },\n header: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 16,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n headerTitle: {\n color: '#fff',\n fontSize: 18,\n fontWeight: 'bold',\n },\n closeButton: {\n color: '#2196F3',\n fontSize: 16,\n fontWeight: 'bold',\n },\n statsRow: {\n flexDirection: 'row',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n stat: {\n flex: 1,\n alignItems: 'center',\n },\n statValue: {\n color: '#fff',\n fontSize: 20,\n fontWeight: 'bold',\n },\n statLabel: {\n color: '#888',\n fontSize: 12,\n marginTop: 2,\n },\n elementList: {\n padding: 12,\n },\n elementCard: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 12,\n marginBottom: 8,\n },\n elementHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n elementId: {\n color: '#fff',\n fontSize: 14,\n fontWeight: 'bold',\n },\n elementType: {\n color: '#888',\n fontSize: 12,\n backgroundColor: '#444',\n paddingHorizontal: 8,\n paddingVertical: 2,\n borderRadius: 4,\n },\n elementLabel: {\n color: '#aaa',\n fontSize: 12,\n marginTop: 4,\n },\n stateRow: {\n flexDirection: 'row',\n marginTop: 8,\n },\n stateIndicator: {\n flexDirection: 'row',\n alignItems: 'center',\n marginRight: 12,\n },\n stateDot: {\n width: 8,\n height: 8,\n borderRadius: 4,\n marginRight: 4,\n },\n stateLabel: {\n color: '#888',\n fontSize: 10,\n },\n testId: {\n color: '#666',\n fontSize: 10,\n marginTop: 4,\n fontFamily: 'monospace',\n },\n emptyText: {\n color: '#888',\n textAlign: 'center',\n marginTop: 20,\n },\n detailContainer: {\n flex: 1,\n },\n detailHeader: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n padding: 12,\n borderBottomWidth: 1,\n borderBottomColor: '#333',\n },\n detailTitle: {\n color: '#fff',\n fontSize: 16,\n fontWeight: 'bold',\n },\n detailContent: {\n padding: 12,\n },\n sectionTitle: {\n color: '#888',\n fontSize: 12,\n marginTop: 12,\n marginBottom: 4,\n textTransform: 'uppercase',\n },\n sectionValue: {\n color: '#fff',\n fontSize: 14,\n },\n stateSection: {\n backgroundColor: '#2d2d2d',\n borderRadius: 8,\n padding: 8,\n },\n stateText: {\n color: '#ddd',\n fontSize: 12,\n fontFamily: 'monospace',\n marginBottom: 2,\n },\n actionsSection: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n },\n actionBadge: {\n backgroundColor: '#2196F3',\n paddingHorizontal: 8,\n paddingVertical: 4,\n borderRadius: 4,\n marginRight: 6,\n marginBottom: 6,\n },\n customActionBadge: {\n backgroundColor: '#9C27B0',\n },\n actionText: {\n color: '#fff',\n fontSize: 12,\n },\n});\n"]}
|