catalyst-core 0.1.0-beta.2 → 0.1.0-beta.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.
Files changed (103) hide show
  1. package/README.md +1 -1
  2. package/bin/catalyst.js +8 -1
  3. package/changelog.md +6 -0
  4. package/dist/native/androidProject/app/build.gradle.kts +9 -0
  5. package/dist/native/androidProject/app/src/main/AndroidManifest.xml +2 -1
  6. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/BridgeMessageValidator.kt +1 -1
  7. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +17 -1
  8. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +31 -3
  9. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +148 -0
  10. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeCameraManager.kt +337 -0
  11. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/TransitionManager.kt +202 -0
  12. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/WebCacheManager.kt +3 -3
  13. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/BarcodeDetector.kt +123 -0
  14. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/CameraSessionManager.kt +244 -0
  15. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/HoldController.kt +70 -0
  16. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/TorchController.kt +57 -0
  17. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/VideoStreamState.kt +41 -0
  18. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/VideoStreamStateMachine.kt +40 -0
  19. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/ViewfinderMapper.kt +75 -0
  20. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/ZoomController.kt +156 -0
  21. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/CatalystPlugin.kt +7 -0
  22. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/GeneratedPluginIndex.kt +6 -0
  23. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/PluginBridge.kt +253 -0
  24. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/FridaDetector.kt +16 -5
  25. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +42 -5
  26. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +7 -3
  27. package/dist/native/androidProject/app/src/main/res/drawable/debug_viewfinder_border.xml +8 -0
  28. package/dist/native/androidProject/app/src/main/res/layout/activity_main.xml +37 -0
  29. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/plugins/PluginBridgeTest.kt +139 -0
  30. package/dist/native/androidSetup.js +1 -1
  31. package/dist/native/bridge/WebBridge.js +5 -5
  32. package/dist/native/bridge/constants/NativeInterfaces.js +9 -5
  33. package/dist/native/bridge/hooks/index.js +1 -0
  34. package/dist/native/bridge/hooks/useCamera.js +9 -0
  35. package/dist/native/bridge/hooks/useDataProtection.js +2 -0
  36. package/dist/native/bridge/hooks/useDeviceInfo.js +2 -0
  37. package/dist/native/bridge/hooks/useFilePicker.js +2 -0
  38. package/dist/native/bridge/hooks/useGoogleSignIn.js +1 -0
  39. package/dist/native/bridge/hooks/useHapticFeedback.js +1 -0
  40. package/dist/native/bridge/hooks/useIntent.js +1 -0
  41. package/dist/native/bridge/hooks/useNativeTransition.js +43 -0
  42. package/dist/native/bridge/hooks/useNetworkStatus.js +3 -0
  43. package/dist/native/bridge/hooks/useNotification.js +2 -0
  44. package/dist/native/bridge/hooks/useSafeArea.js +2 -0
  45. package/dist/native/bridge/hooks/useVideoStream.js +6 -0
  46. package/dist/native/bridge/hooks/utils.js +1 -0
  47. package/dist/native/bridge/hooks.js +1 -137
  48. package/dist/native/bridge/useBaseHook.js +12 -7
  49. package/dist/native/bridge/utils/NativeBridge.js +41 -6
  50. package/dist/native/buildAppAndroid.js +7 -9
  51. package/dist/native/buildAppIos.js +14 -22
  52. package/dist/native/internalPluginUtils.js +1 -0
  53. package/dist/native/iosnativeWebView/Package.resolved +36 -0
  54. package/dist/native/iosnativeWebView/Sources/Core/Camera/BarcodeDetector.swift +116 -0
  55. package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraPreviewView.swift +58 -0
  56. package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraSessionManager.swift +308 -0
  57. package/dist/native/iosnativeWebView/Sources/Core/Camera/HoldController.swift +63 -0
  58. package/dist/native/iosnativeWebView/Sources/Core/Camera/NativeCameraManager.swift +194 -0
  59. package/dist/native/iosnativeWebView/Sources/Core/Camera/TorchController.swift +60 -0
  60. package/dist/native/iosnativeWebView/Sources/Core/Camera/VideoStreamState.swift +44 -0
  61. package/dist/native/iosnativeWebView/Sources/Core/Camera/VideoStreamStateMachine.swift +60 -0
  62. package/dist/native/iosnativeWebView/Sources/Core/Camera/ZoomController.swift +130 -0
  63. package/dist/native/iosnativeWebView/Sources/Core/Constants/CatalystConstants.swift +11 -1
  64. package/dist/native/iosnativeWebView/Sources/Core/Plugins/CatalystPlugin.swift +5 -0
  65. package/dist/native/iosnativeWebView/Sources/Core/Plugins/GeneratedPluginIndex.swift +6 -0
  66. package/dist/native/iosnativeWebView/Sources/Core/Plugins/PluginBridge.swift +364 -0
  67. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +4 -1
  68. package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +227 -4
  69. package/dist/native/iosnativeWebView/Sources/Core/WebView/TransitionManager.swift +169 -0
  70. package/dist/native/iosnativeWebView/Sources/Core/WebView/WeakScriptMessageHandler.swift +14 -0
  71. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +38 -7
  72. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +6 -2
  73. package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +15 -4
  74. package/dist/native/iosnativeWebView/iosnativeWebView/Info.plist +11 -17
  75. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +8 -2
  76. package/dist/native/iosnativeWebView/iosnativeWebViewTests/PluginBridgeTests.swift +160 -0
  77. package/dist/native/plugin-bridge/PluginBridge.js +1 -0
  78. package/dist/native/pluginComposerAndroid.js +9 -0
  79. package/dist/native/pluginComposerIos.js +7 -0
  80. package/dist/native/renameAndroidProject.js +3 -3
  81. package/dist/native/setupServer.js +2 -3
  82. package/dist/native/utils.js +4 -1
  83. package/dist/otel.js +70 -2
  84. package/dist/scripts/devServe.js +1 -1
  85. package/dist/scripts/plugins.js +1 -0
  86. package/dist/scripts/registerAliases.js +6 -2
  87. package/dist/scripts/scriptUtils.js +2 -1
  88. package/dist/scripts/serve.js +2 -1
  89. package/dist/scripts/start.js +4 -1
  90. package/dist/server/renderer/extract.js +5 -5
  91. package/dist/server/renderer/handler.js +15 -14
  92. package/dist/server/utils/validator.js +1 -1
  93. package/dist/webpack/base.babel.js +2 -1
  94. package/dist/webpack/development.client.babel.js +6 -2
  95. package/dist/webpack/production.ssr.babel.js +5 -1
  96. package/mcp_v2/knowledge-base.json +1564 -1067
  97. package/mcp_v2/lib/helpers.js +19 -7
  98. package/mcp_v2/tools/build.js +1 -1
  99. package/mcp_v2/tools/config.js +16 -4
  100. package/mcp_v2/tools/conversion.js +11 -11
  101. package/mcp_v2/tools/knowledge.js +16 -3
  102. package/mcp_v2/tools/tasks.js +13 -4
  103. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _NativeInterfaces=require("./constants/NativeInterfaces.js");var _NativeBridge=_interopRequireDefault(require("./utils/NativeBridge.js"));var _CameraUtils=_interopRequireDefault(require("./utils/CameraUtils.js"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}class WebBridge{constructor(){this.handlers=new Map();this.initialized=false;this._logInitialization();}/**
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _NativeInterfaces=require("./constants/NativeInterfaces.js");var _NativeBridge=_interopRequireDefault(require("./utils/NativeBridge.js"));var _CameraUtils=_interopRequireDefault(require("./utils/CameraUtils.js"));var _PluginBridge=_interopRequireDefault(require("../plugin-bridge/PluginBridge.js"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}const DEVICE_INFO_PLUGIN={pluginId:"io.catalyst.device_info",command:"getDeviceInfo",successEvent:"onSuccess",errorEvent:"onError"};const DEVICE_INFO_REQUEST_TIMEOUT_MS=5000;const DEVICE_INFO_PLUGIN_FALLBACK_CODES=new Set(["PLUGIN_NOT_FOUND","COMMAND_NOT_SUPPORTED","PLUGIN_NOT_REGISTERED"]);const DEVICE_INFO_PLUGIN_FALLBACK_MESSAGES=["pluginbridge is not available in this environment","pluginbridge is not available","device info plugin request timed out"];const normalizeDeviceInfoPayload=payload=>{if(typeof payload!=="string"){return payload;}try{return JSON.parse(payload);}catch{return{message:payload};}};const createDeviceInfoError=(payload,fallbackMessage)=>{const parsed=normalizeDeviceInfoPayload(payload);const message=parsed?.message||parsed?.error||fallbackMessage;const error=new Error(message);if(parsed?.code){error.code=parsed.code;}if(parsed?.pluginId){error.pluginId=parsed.pluginId;}if(parsed?.command){error.command=parsed.command;}return error;};class WebBridge{constructor(){this.handlers=new Map();this.initialized=false;this._logInitialization();}/**
2
2
  * Log initialization info
3
3
  */_logInitialization(){console.log("🌉 WebBridge initialized");console.log("🌉 Available callback interfaces:",_NativeInterfaces.ALL_CALLBACKS.length);if(process.env.NODE_ENV==="development"){(0,_NativeInterfaces.debugInterfaces)();}}/**
4
4
  * Static method to initialize WebBridge on window object
@@ -51,9 +51,9 @@ if(this.handlers.has(interfaceName)){console.warn(`🌉 Interface ${interfaceNam
51
51
  * Request camera permission
52
52
  * @param {Object} config - Permission configuration (includeDetails)
53
53
  * @returns {Promise<Object>} - Promise that resolves with permission status or rejects with error
54
- */requestCameraPermission=(config={})=>{return _CameraUtils.default.requestCameraPermission(config,this.register,this.unregister);};/**
54
+ */requestCameraPermission=(config={})=>{return _CameraUtils.default.requestCameraPermission(config,this.register,this.unregister);};getDeviceInfoFromLegacyBridge=parseDeviceInfo=>{return new Promise((resolve,reject)=>{let timeoutId=null;const cleanup=()=>{if(timeoutId!=null){clearTimeout(timeoutId);}this.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_SUCCESS);this.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_ERROR);};this.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_SUCCESS,data=>{cleanup();resolve(parseDeviceInfo(data));});this.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_ERROR,error=>{cleanup();reject(new Error(error));});try{const dispatched=_NativeBridge.default.device.getDeviceInfo();if(dispatched===false){cleanup();reject(new Error("Legacy device info bridge failed to dispatch"));return;}timeoutId=setTimeout(()=>{cleanup();reject(new Error("Legacy device info request timed out"));},DEVICE_INFO_REQUEST_TIMEOUT_MS);}catch(error){cleanup();reject(error);}});};getDeviceInfoFromPluginBridge=parseDeviceInfo=>{return new Promise((resolve,reject)=>{_PluginBridge.default.init();let isSettled=false;let timeoutId=null;const cleanups=[];const cleanup=()=>{if(timeoutId!=null){clearTimeout(timeoutId);}while(cleanups.length>0){const unregister=cleanups.pop();unregister();}};const settle=callback=>{if(isSettled){return;}isSettled=true;cleanup();callback();};cleanups.push(_PluginBridge.default.register({pluginId:DEVICE_INFO_PLUGIN.pluginId,eventName:DEVICE_INFO_PLUGIN.successEvent,command:DEVICE_INFO_PLUGIN.command,handler:payload=>{settle(()=>{try{resolve(parseDeviceInfo(payload));}catch(error){reject(error);}});}}));cleanups.push(_PluginBridge.default.register({pluginId:DEVICE_INFO_PLUGIN.pluginId,eventName:DEVICE_INFO_PLUGIN.errorEvent,command:DEVICE_INFO_PLUGIN.command,handler:payload=>{settle(()=>{reject(createDeviceInfoError(payload,"Device info plugin failed"));});}}));cleanups.push(_PluginBridge.default.register({pluginId:"__bridge__",eventName:"PLUGIN_BRIDGE_ERROR",command:DEVICE_INFO_PLUGIN.command,handler:payload=>{const pluginId=normalizeDeviceInfoPayload(payload)?.pluginId;if(pluginId!==DEVICE_INFO_PLUGIN.pluginId){return;}settle(()=>{reject(createDeviceInfoError(payload,"Device info plugin unavailable"));});}}));try{_PluginBridge.default.emit({pluginId:DEVICE_INFO_PLUGIN.pluginId,command:DEVICE_INFO_PLUGIN.command});timeoutId=setTimeout(()=>{settle(()=>{reject(new Error("Device info plugin request timed out"));});},DEVICE_INFO_REQUEST_TIMEOUT_MS);}catch(error){cleanup();reject(error);}});};shouldFallbackToLegacyDeviceInfo=error=>{if(!error){return false;}if(DEVICE_INFO_PLUGIN_FALLBACK_CODES.has(error.code)){return true;}if(typeof error.message!=="string"){return false;}const normalizedMessage=error.message.toLowerCase();return DEVICE_INFO_PLUGIN_FALLBACK_MESSAGES.some(message=>normalizedMessage.includes(message));};/**
55
55
  * Get device information
56
56
  * @returns {Promise<Object>} - Promise that resolves with device info or rejects with error
57
- */getDeviceInfo=()=>{const{platform,isNativeEnvironment}=_NativeBridge.default.getEnvironmentInfo();// Handle web environment
58
- if(!isNativeEnvironment||platform==="web"){return new Promise(resolve=>{const webDeviceInfo={model:navigator.userAgent,manufacturer:"browser",platform:"web",screenWidth:screen.width,screenHeight:screen.height,screenDensity:window.devicePixelRatio};resolve(webDeviceInfo);});}// Key mapping from native to web keys
59
- const DEVICE_INFO_KEY_MAP={android:{model:"model",manufacturer:"manufacturer",platform:"platform",screenWidth:"screenWidth",screenHeight:"screenHeight",screenDensity:"screenDensity",appInfo:"appInfo"},ios:{model:"model",manufacturer:"manufacturer",platform:"platform",screenWidth:"screenWidth",screenHeight:"screenHeight",screenDensity:"screenDensity",appInfo:"appInfo"}};const parseDeviceInfo=data=>{const rawDeviceInfo=typeof data==="string"?JSON.parse(data):data;const platformMapping=DEVICE_INFO_KEY_MAP[platform]||{};return Object.fromEntries(Object.entries(rawDeviceInfo).map(([key,value])=>[platformMapping[key]||key,value]));};return new Promise((resolve,reject)=>{const cleanup=()=>{this.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_SUCCESS);this.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_ERROR);};this.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_SUCCESS,data=>{cleanup();resolve(parseDeviceInfo(data));});this.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_DEVICE_INFO_ERROR,error=>{cleanup();reject(new Error(error));});try{_NativeBridge.default.device.getDeviceInfo();}catch(error){cleanup();reject(error);}});};}var _default=exports.default=WebBridge;
57
+ */getDeviceInfo=async()=>{const{platform,isNativeEnvironment}=_NativeBridge.default.getEnvironmentInfo();// Handle web environment
58
+ if(!isNativeEnvironment||platform==="web"){return{model:navigator.userAgent,manufacturer:"browser",platform:"web",screenWidth:screen.width,screenHeight:screen.height,screenDensity:window.devicePixelRatio};}// Key mapping from native to web keys
59
+ const DEVICE_INFO_KEY_MAP={android:{model:"model",manufacturer:"manufacturer",platform:"platform",screenWidth:"screenWidth",screenHeight:"screenHeight",screenDensity:"screenDensity",appInfo:"appInfo"},ios:{model:"model",manufacturer:"manufacturer",platform:"platform",screenWidth:"screenWidth",screenHeight:"screenHeight",screenDensity:"screenDensity",appInfo:"appInfo"}};const parseDeviceInfo=data=>{const rawDeviceInfo=typeof data==="string"?JSON.parse(data):data;const platformMapping=DEVICE_INFO_KEY_MAP[platform]||{};return Object.fromEntries(Object.entries(rawDeviceInfo).map(([key,value])=>[platformMapping[key]||key,value]));};try{return await this.getDeviceInfoFromPluginBridge(parseDeviceInfo);}catch(error){if(!this.shouldFallbackToLegacyDeviceInfo(error)){throw error;}return this.getDeviceInfoFromLegacyBridge(parseDeviceInfo);}};}var _default=exports.default=WebBridge;
@@ -2,17 +2,20 @@
2
2
  // Centralized definitions for all native interface communications
3
3
  // Command Interfaces: Web → Native (outgoing commands)
4
4
  const NATIVE_COMMANDS=exports.NATIVE_COMMANDS={// Camera commands
5
- OPEN_CAMERA:"openCamera",REQUEST_CAMERA_PERMISSION:"requestCameraPermission",// File commands
5
+ OPEN_CAMERA:"openCamera",REQUEST_CAMERA_PERMISSION:"requestCameraPermission",// Video stream commands
6
+ START_VIDEO_STREAM:"startVideoStream",STOP_VIDEO_STREAM:"stopVideoStream",SET_VIDEO_STREAM_ZOOM:"setVideoStreamZoom",SET_VIDEO_STREAM_TORCH:"setVideoStreamTorch",SET_VIDEO_STREAM_FPS:"setVideoStreamFps",FLIP_VIDEO_STREAM:"flipVideoStream",// File commands
6
7
  PICK_FILE:"pickFile",OPEN_FILE_WITH_INTENT:"openFileWithIntent",// Haptic feedback commands
7
8
  REQUEST_HAPTIC_FEEDBACK:"requestHapticFeedback",// Notification commands
8
9
  SCHEDULE_LOCAL_NOTIFICATION:"scheduleLocalNotification",CANCEL_LOCAL_NOTIFICATION:"cancelLocalNotification",REQUEST_NOTIFICATION_PERMISSION:"requestNotificationPermission",REGISTER_FOR_PUSH_NOTIFICATIONS:"registerForPushNotifications",UPDATE_BADGE_COUNT:"updateBadgeCount",SUBSCRIBE_TO_TOPIC:"subscribeToTopic",UNSUBSCRIBE_FROM_TOPIC:"unsubscribeFromTopic",GET_SUBSCRIBED_TOPICS:"getSubscribedTopics",// Device info commands
9
10
  GET_DEVICE_INFO:"getDeviceInfo",// Network commands
10
11
  GET_NETWORK_STATUS:"getNetworkStatus",// Auth commands
11
- GOOGLE_SIGN_IN:"googleSignIn",// Safe area commands
12
+ GOOGLE_SIGN_IN:"googleSignIn",// Transition commands
13
+ START_TRANSITION:"startTransition",COMMIT_TRANSITION:"commitTransition",CANCEL_TRANSITION:"cancelTransition",// Safe area commands
12
14
  GET_SAFE_AREA:"getSafeArea",// Security commands
13
15
  SET_SCREEN_SECURE:"setScreenSecure",GET_SCREEN_SECURE:"getScreenSecure",CLEAR_WEB_DATA:"clearWebData"};// Callback Interfaces: Native → Web (incoming events/callbacks)
14
16
  const NATIVE_CALLBACKS=exports.NATIVE_CALLBACKS={// Camera callbacks
15
- CAMERA_PERMISSION_STATUS:"CAMERA_PERMISSION_STATUS",ON_CAMERA_CAPTURE:"ON_CAMERA_CAPTURE",ON_CAMERA_ERROR:"ON_CAMERA_ERROR",// File picker callbacks
17
+ CAMERA_PERMISSION_STATUS:"CAMERA_PERMISSION_STATUS",ON_CAMERA_CAPTURE:"ON_CAMERA_CAPTURE",ON_CAMERA_ERROR:"ON_CAMERA_ERROR",// Video stream callbacks
18
+ ON_VIDEO_STREAM_READY:"ON_VIDEO_STREAM_READY",ON_VIDEO_STREAM_STOPPED:"ON_VIDEO_STREAM_STOPPED",ON_QR_DETECTED:"ON_QR_DETECTED",ON_TORCH_CHANGED:"ON_TORCH_CHANGED",ON_ZOOM_CHANGED:"ON_ZOOM_CHANGED",// File picker callbacks
16
19
  ON_FILE_PICKED:"ON_FILE_PICKED",ON_FILE_PICK_ERROR:"ON_FILE_PICK_ERROR",ON_FILE_PICK_CANCELLED:"ON_FILE_PICK_CANCELLED",ON_FILE_PICK_STATE_UPDATE:"ON_FILE_PICK_STATE_UPDATE",// Intent callbacks
17
20
  ON_INTENT_SUCCESS:"ON_INTENT_SUCCESS",ON_INTENT_ERROR:"ON_INTENT_ERROR",ON_INTENT_CANCELLED:"ON_INTENT_CANCELLED",// Haptic feedback callbacks
18
21
  HAPTIC_FEEDBACK:"HAPTIC_FEEDBACK",// Notification callbacks
@@ -20,9 +23,10 @@ NOTIFICATION_PERMISSION_STATUS:"NOTIFICATION_PERMISSION_STATUS",LOCAL_NOTIFICATI
20
23
  ON_DEVICE_INFO_SUCCESS:"ON_DEVICE_INFO_SUCCESS",ON_DEVICE_INFO_ERROR:"ON_DEVICE_INFO_ERROR",// Auth callbacks
21
24
  ON_GOOGLE_SIGN_IN_SUCCESS:"ON_GOOGLE_SIGN_IN_SUCCESS",ON_GOOGLE_SIGN_IN_ERROR:"ON_GOOGLE_SIGN_IN_ERROR",ON_GOOGLE_SIGN_IN_CANCELLED:"ON_GOOGLE_SIGN_IN_CANCELLED",// Network callbacks
22
25
  NETWORK_STATUS_CHANGED:"NETWORK_STATUS_CHANGED",// Safe area callbacks
23
- ON_SAFE_AREA_INSETS_UPDATED:"ON_SAFE_AREA_INSETS_UPDATED",// Security callbacks
26
+ ON_SAFE_AREA_INSETS_UPDATED:"ON_SAFE_AREA_INSETS_UPDATED",// Transition callbacks
27
+ ON_TRANSITION_COMMITTED:"ON_TRANSITION_COMMITTED",ON_TRANSITION_CANCELLED:"ON_TRANSITION_CANCELLED",ON_TRANSITION_TIMEOUT:"ON_TRANSITION_TIMEOUT",// Security callbacks
24
28
  ON_SCREEN_SECURE_SET:"ON_SCREEN_SECURE_SET",ON_SCREEN_SECURE_STATUS:"ON_SCREEN_SECURE_STATUS",ON_SCREEN_SECURE_ERROR:"ON_SCREEN_SECURE_ERROR",ON_WEB_DATA_CLEARED:"ON_WEB_DATA_CLEARED",ON_WEB_DATA_CLEAR_ERROR:"ON_WEB_DATA_CLEAR_ERROR"};// Interface Categories for easier management
25
- const INTERFACE_CATEGORIES=exports.INTERFACE_CATEGORIES={CAMERA:{commands:[NATIVE_COMMANDS.OPEN_CAMERA,NATIVE_COMMANDS.REQUEST_CAMERA_PERMISSION],callbacks:[NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,NATIVE_CALLBACKS.ON_CAMERA_CAPTURE,NATIVE_CALLBACKS.ON_CAMERA_ERROR]},FILE:{commands:[NATIVE_COMMANDS.PICK_FILE,NATIVE_COMMANDS.OPEN_FILE_WITH_INTENT],callbacks:[NATIVE_CALLBACKS.ON_FILE_PICKED,NATIVE_CALLBACKS.ON_FILE_PICK_ERROR,NATIVE_CALLBACKS.ON_FILE_PICK_CANCELLED,NATIVE_CALLBACKS.ON_FILE_PICK_STATE_UPDATE]},INTENT:{commands:[NATIVE_COMMANDS.OPEN_FILE_WITH_INTENT],callbacks:[NATIVE_CALLBACKS.ON_INTENT_SUCCESS,NATIVE_CALLBACKS.ON_INTENT_ERROR,NATIVE_CALLBACKS.ON_INTENT_CANCELLED]},HAPTIC:{commands:[NATIVE_COMMANDS.REQUEST_HAPTIC_FEEDBACK],callbacks:[NATIVE_CALLBACKS.HAPTIC_FEEDBACK]},NOTIFICATION:{commands:[NATIVE_COMMANDS.SCHEDULE_LOCAL_NOTIFICATION,NATIVE_COMMANDS.CANCEL_LOCAL_NOTIFICATION,NATIVE_COMMANDS.REQUEST_NOTIFICATION_PERMISSION,NATIVE_COMMANDS.REGISTER_FOR_PUSH_NOTIFICATIONS,NATIVE_COMMANDS.UPDATE_BADGE_COUNT,NATIVE_COMMANDS.SUBSCRIBE_TO_TOPIC,NATIVE_COMMANDS.UNSUBSCRIBE_FROM_TOPIC,NATIVE_COMMANDS.GET_SUBSCRIBED_TOPICS],callbacks:[NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS,NATIVE_CALLBACKS.LOCAL_NOTIFICATION_SCHEDULED,NATIVE_CALLBACKS.LOCAL_NOTIFICATION_CANCELLED,NATIVE_CALLBACKS.PUSH_NOTIFICATION_TOKEN,NATIVE_CALLBACKS.NOTIFICATION_RECEIVED,NATIVE_CALLBACKS.NOTIFICATION_ACTION_PERFORMED,NATIVE_CALLBACKS.NOTIFICATION_TAPPED,NATIVE_CALLBACKS.TOPIC_SUBSCRIPTION_RESULT,NATIVE_CALLBACKS.SUBSCRIBED_TOPICS_RESULT]},DEVICE_INFO:{commands:[NATIVE_COMMANDS.GET_DEVICE_INFO],callbacks:[NATIVE_CALLBACKS.ON_DEVICE_INFO_SUCCESS,NATIVE_CALLBACKS.ON_DEVICE_INFO_ERROR]},AUTH:{commands:[NATIVE_COMMANDS.GOOGLE_SIGN_IN],callbacks:[NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_SUCCESS,NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_ERROR,NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_CANCELLED]},NETWORK:{commands:[NATIVE_COMMANDS.GET_NETWORK_STATUS],callbacks:[NATIVE_CALLBACKS.NETWORK_STATUS_CHANGED]},SECURITY:{commands:[NATIVE_COMMANDS.SET_SCREEN_SECURE,NATIVE_COMMANDS.GET_SCREEN_SECURE,NATIVE_COMMANDS.CLEAR_WEB_DATA],callbacks:[NATIVE_CALLBACKS.ON_SCREEN_SECURE_SET,NATIVE_CALLBACKS.ON_SCREEN_SECURE_ERROR,NATIVE_CALLBACKS.ON_WEB_DATA_CLEARED,NATIVE_CALLBACKS.ON_WEB_DATA_CLEAR_ERROR]}};// All available interfaces (for validation)
29
+ const INTERFACE_CATEGORIES=exports.INTERFACE_CATEGORIES={CAMERA:{commands:[NATIVE_COMMANDS.OPEN_CAMERA,NATIVE_COMMANDS.REQUEST_CAMERA_PERMISSION],callbacks:[NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,NATIVE_CALLBACKS.ON_CAMERA_CAPTURE,NATIVE_CALLBACKS.ON_CAMERA_ERROR]},FILE:{commands:[NATIVE_COMMANDS.PICK_FILE,NATIVE_COMMANDS.OPEN_FILE_WITH_INTENT],callbacks:[NATIVE_CALLBACKS.ON_FILE_PICKED,NATIVE_CALLBACKS.ON_FILE_PICK_ERROR,NATIVE_CALLBACKS.ON_FILE_PICK_CANCELLED,NATIVE_CALLBACKS.ON_FILE_PICK_STATE_UPDATE]},INTENT:{commands:[NATIVE_COMMANDS.OPEN_FILE_WITH_INTENT],callbacks:[NATIVE_CALLBACKS.ON_INTENT_SUCCESS,NATIVE_CALLBACKS.ON_INTENT_ERROR,NATIVE_CALLBACKS.ON_INTENT_CANCELLED]},HAPTIC:{commands:[NATIVE_COMMANDS.REQUEST_HAPTIC_FEEDBACK],callbacks:[NATIVE_CALLBACKS.HAPTIC_FEEDBACK]},NOTIFICATION:{commands:[NATIVE_COMMANDS.SCHEDULE_LOCAL_NOTIFICATION,NATIVE_COMMANDS.CANCEL_LOCAL_NOTIFICATION,NATIVE_COMMANDS.REQUEST_NOTIFICATION_PERMISSION,NATIVE_COMMANDS.REGISTER_FOR_PUSH_NOTIFICATIONS,NATIVE_COMMANDS.UPDATE_BADGE_COUNT,NATIVE_COMMANDS.SUBSCRIBE_TO_TOPIC,NATIVE_COMMANDS.UNSUBSCRIBE_FROM_TOPIC,NATIVE_COMMANDS.GET_SUBSCRIBED_TOPICS],callbacks:[NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS,NATIVE_CALLBACKS.LOCAL_NOTIFICATION_SCHEDULED,NATIVE_CALLBACKS.LOCAL_NOTIFICATION_CANCELLED,NATIVE_CALLBACKS.PUSH_NOTIFICATION_TOKEN,NATIVE_CALLBACKS.NOTIFICATION_RECEIVED,NATIVE_CALLBACKS.NOTIFICATION_ACTION_PERFORMED,NATIVE_CALLBACKS.NOTIFICATION_TAPPED,NATIVE_CALLBACKS.TOPIC_SUBSCRIPTION_RESULT,NATIVE_CALLBACKS.SUBSCRIBED_TOPICS_RESULT]},DEVICE_INFO:{commands:[NATIVE_COMMANDS.GET_DEVICE_INFO],callbacks:[NATIVE_CALLBACKS.ON_DEVICE_INFO_SUCCESS,NATIVE_CALLBACKS.ON_DEVICE_INFO_ERROR]},AUTH:{commands:[NATIVE_COMMANDS.GOOGLE_SIGN_IN],callbacks:[NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_SUCCESS,NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_ERROR,NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_CANCELLED]},NETWORK:{commands:[NATIVE_COMMANDS.GET_NETWORK_STATUS],callbacks:[NATIVE_CALLBACKS.NETWORK_STATUS_CHANGED]},SECURITY:{commands:[NATIVE_COMMANDS.SET_SCREEN_SECURE,NATIVE_COMMANDS.GET_SCREEN_SECURE,NATIVE_COMMANDS.CLEAR_WEB_DATA],callbacks:[NATIVE_CALLBACKS.ON_SCREEN_SECURE_SET,NATIVE_CALLBACKS.ON_SCREEN_SECURE_ERROR,NATIVE_CALLBACKS.ON_WEB_DATA_CLEARED,NATIVE_CALLBACKS.ON_WEB_DATA_CLEAR_ERROR]},TRANSITION:{commands:[NATIVE_COMMANDS.START_TRANSITION,NATIVE_COMMANDS.COMMIT_TRANSITION,NATIVE_COMMANDS.CANCEL_TRANSITION],callbacks:[NATIVE_CALLBACKS.ON_TRANSITION_COMMITTED,NATIVE_CALLBACKS.ON_TRANSITION_CANCELLED,NATIVE_CALLBACKS.ON_TRANSITION_TIMEOUT]}};// All available interfaces (for validation)
26
30
  const ALL_COMMANDS=exports.ALL_COMMANDS=Object.values(NATIVE_COMMANDS);const ALL_CALLBACKS=exports.ALL_CALLBACKS=Object.values(NATIVE_CALLBACKS);const ALL_INTERFACES=exports.ALL_INTERFACES=[...ALL_COMMANDS,...ALL_CALLBACKS];// Permission status constants
27
31
  const PERMISSION_STATUS=exports.PERMISSION_STATUS={GRANTED:"GRANTED",DENIED:"DENIED",NOT_DETERMINED:"NOT_DETERMINED",RESTRICTED:"RESTRICTED"};// Haptic feedback types (matching Android implementation)
28
32
  const HAPTIC_FEEDBACK_TYPES=exports.HAPTIC_FEEDBACK_TYPES={VIRTUAL_KEY:"VIRTUAL_KEY",LONG_PRESS:"LONG_PRESS",DEFAULT:"DEFAULT",// Legacy types for backward compatibility
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"requestCameraPermission",{enumerable:true,get:function(){return _useCamera.requestCameraPermission;}});Object.defineProperty(exports,"requestHapticFeedback",{enumerable:true,get:function(){return _useHapticFeedback.requestHapticFeedback;}});Object.defineProperty(exports,"requestNotificationPermission",{enumerable:true,get:function(){return _useNotification.requestNotificationPermission;}});Object.defineProperty(exports,"sanitizeFilePickerOptions",{enumerable:true,get:function(){return _useFilePicker.sanitizeFilePickerOptions;}});Object.defineProperty(exports,"useCamera",{enumerable:true,get:function(){return _useCamera.useCamera;}});Object.defineProperty(exports,"useCameraPermission",{enumerable:true,get:function(){return _useCamera.useCameraPermission;}});Object.defineProperty(exports,"useDataProtection",{enumerable:true,get:function(){return _useDataProtection.useDataProtection;}});Object.defineProperty(exports,"useDeviceInfo",{enumerable:true,get:function(){return _useDeviceInfo.useDeviceInfo;}});Object.defineProperty(exports,"useFilePicker",{enumerable:true,get:function(){return _useFilePicker.useFilePicker;}});Object.defineProperty(exports,"useGoogleSignIn",{enumerable:true,get:function(){return _useGoogleSignIn.useGoogleSignIn;}});Object.defineProperty(exports,"useHapticFeedback",{enumerable:true,get:function(){return _useHapticFeedback.useHapticFeedback;}});Object.defineProperty(exports,"useIntent",{enumerable:true,get:function(){return _useIntent.useIntent;}});Object.defineProperty(exports,"useNativeTransition",{enumerable:true,get:function(){return _useNativeTransition.useNativeTransition;}});Object.defineProperty(exports,"useNetworkStatus",{enumerable:true,get:function(){return _useNetworkStatus.useNetworkStatus;}});Object.defineProperty(exports,"useNotification",{enumerable:true,get:function(){return _useNotification.useNotification;}});Object.defineProperty(exports,"useNotificationPermission",{enumerable:true,get:function(){return _useNotification.useNotificationPermission;}});Object.defineProperty(exports,"useSafeArea",{enumerable:true,get:function(){return _useSafeArea.useSafeArea;}});Object.defineProperty(exports,"useVideoStream",{enumerable:true,get:function(){return _useVideoStream.useVideoStream;}});var _useGoogleSignIn=require("./useGoogleSignIn.js");var _useCamera=require("./useCamera.js");var _useIntent=require("./useIntent.js");var _useFilePicker=require("./useFilePicker.js");var _useHapticFeedback=require("./useHapticFeedback.js");var _useNotification=require("./useNotification.js");var _useNetworkStatus=require("./useNetworkStatus.js");var _useDeviceInfo=require("./useDeviceInfo.js");var _useDataProtection=require("./useDataProtection.js");var _useSafeArea=require("./useSafeArea.js");var _useVideoStream=require("./useVideoStream.js");var _useNativeTransition=require("./useNativeTransition.js");
@@ -0,0 +1,9 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useCameraPermission=exports.useCamera=exports.requestCameraPermission=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useCamera=({webFallback}={})=>{const base=(0,_useBaseHook.useBaseHook)("useCamera",{hasWebFallback:true,webFallback});const[permission,setPermission]=(0,_react.useState)(null);if(typeof window==="undefined"){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:()=>{},execute:()=>{},clear:()=>{},clearError:()=>{},permission:null,photo:null,takePhoto:()=>{},isLoading:false,clearPhoto:()=>{}};}if(base.webFallbackDisabled){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:false,webFallbackDisabled:true,setWebFallback:base.setWebFallback,execute:()=>{},clear:()=>{},clearError:()=>{},permission:null,photo:null,takePhoto:()=>{},isLoading:false,clearPhoto:()=>{}};}// Web fallback callback — always declared (Rules of Hooks)
2
+ const webTakePhoto=(0,_react.useCallback)(()=>{const input=document.createElement("input");input.type="file";input.accept="image/*";input.capture="environment";input.onchange=()=>{const file=input.files?.[0];if(!file)return;const fileSrc=URL.createObjectURL(file);base.setDataAndComplete({fileSrc,fileName:file.name,size:file.size,mimeType:file.type,transport:"OBJECT_URL",source:"camera"});};input.click();},[base]);if(base.webFallbackActive){return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:true,isNative:false,webFallbackActive:true,webFallbackDisabled:false,setWebFallback:base.setWebFallback,execute:webTakePhoto,clear:base.clear,clearError:base.clearError,permission:null,photo:base.data,takePhoto:webTakePhoto,isLoading:base.loading,clearPhoto:base.clear};}(0,_react.useEffect)(()=>{window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_CAPTURE,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;console.log("📷 Camera capture result:",result);const photoData=result.fileSrc?{fileSrc:result.fileSrc,fileName:result.fileName,size:result.size,mimeType:result.mimeType,transport:result.transport,source:result.source}:{fileSrc:result.imageUrl,fileName:"camera_photo.jpg",size:0,mimeType:"image/jpeg",transport:"LEGACY",source:"camera"};base.setDataAndComplete(photoData);if(photoData.transport){base.updateProgress({transport:photoData.transport,bytesTotal:photoData.size||null});}console.log("📷 Photo captured successfully via transport:",photoData.transport);}catch(parseError){console.error("📷 Error parsing camera capture data:",parseError);base.handleNativeError("Failed to process captured photo");}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,data=>{setPermission(data);console.log("📷 Camera permission status:",data);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_ERROR,data=>{console.error("📷 Camera error:",data);base.handleNativeError(data);});return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_CAPTURE);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_ERROR);};},[base.setDataAndComplete,base.handleNativeError,base.updateProgress]);const takePhoto=()=>{console.log("📷 Camera open requested");base.executeOperation(()=>{base.updateProgress({state:"capturing",phase:"requesting",message:"Opening camera..."});_NativeBridge.default.camera.open();},"camera capture");};return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:base.setWebFallback,execute:takePhoto,clear:base.clear,clearError:base.clearError,permission,photo:base.data,takePhoto,isLoading:base.loading,clearPhoto:base.clear};};exports.useCamera=useCamera;const requestCameraPermission=()=>{if(typeof window==="undefined"){return Promise.resolve(null);}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}return new Promise((resolve,reject)=>{try{if(!_NativeBridge.default.isAvailable()){reject(new Error("Native bridge not available"));return;}const handlePermissionStatus=data=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS);if(data===_NativeInterfaces.PERMISSION_STATUS.GRANTED){resolve(data);}else{reject(new Error(`Camera permission ${data.toLowerCase()}`));}};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,handlePermissionStatus);_NativeBridge.default.camera.requestPermission();console.log("📷 Camera permission requested");}catch(error){reject(error);}});};exports.requestCameraPermission=requestCameraPermission;const useCameraPermission=({webFallback}={})=>{const isWeb=typeof window==="undefined"?true:!_NativeBridge.default.isAvailable();// All hooks unconditionally at top level (Rules of Hooks)
3
+ const[webFallbackState,setWebFallback]=(0,_react.useState)(true);const webFallbackResolved=webFallback!==undefined?webFallback!==false:webFallbackState;const webFallbackActive=isWeb&&webFallbackResolved;const webFallbackDisabled=isWeb&&!webFallbackResolved;const[permission,setPermission]=(0,_react.useState)(null);const[isLoading,setIsLoading]=(0,_react.useState)(true);const permResultRef=(0,_react.useRef)(null);(0,_react.useEffect)(()=>{if(typeof window==="undefined"){setIsLoading(false);return;}if(webFallbackDisabled){setIsLoading(false);return;}if(!window.WebBridge){// Web fallback: navigator.permissions API (query only — never prompts)
4
+ if(typeof navigator==="undefined"||!navigator.permissions){setPermission(_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);return;}const PERM_MAP={granted:_NativeInterfaces.PERMISSION_STATUS.GRANTED,denied:_NativeInterfaces.PERMISSION_STATUS.DENIED,prompt:_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED};navigator.permissions.query({name:"camera"}).then(result=>{permResultRef.current=result;setPermission(PERM_MAP[result.state]??_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);result.onchange=()=>{setPermission(PERM_MAP[result.state]??_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);};}).catch(()=>{setPermission(_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);});return;}// Native path
5
+ const requestPermission=async()=>{try{if(!_NativeBridge.default.isAvailable()){setPermission(_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);return;}window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,data=>{setPermission(data);setIsLoading(false);console.log("📷 Camera permission status updated:",data);});_NativeBridge.default.camera.requestPermission();}catch(error){console.error("📷 Error requesting camera permission:",error);setPermission(_NativeInterfaces.PERMISSION_STATUS.DENIED);setIsLoading(false);}};requestPermission();return()=>{if(window.WebBridge&&_NativeBridge.default.isAvailable()){window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS);}};},[webFallbackDisabled]);// Web: navigator.permissions.query() never prompts. request() triggers getUserMedia
6
+ // which causes the browser to show the permission dialog, then re-reads permission state.
7
+ const request=(0,_react.useCallback)(async()=>{if(!isWeb||typeof window==="undefined")return;if(!navigator.mediaDevices?.getUserMedia)return;try{setIsLoading(true);const stream=await navigator.mediaDevices.getUserMedia({video:true,audio:false});stream.getTracks().forEach(t=>t.stop());}catch(_){// Ignore — the permission state change fires via permResultRef.current.onchange
8
+ }// Re-query to get the authoritative state after the prompt
9
+ if(navigator.permissions){try{const result=await navigator.permissions.query({name:"camera"});const PERM_MAP={granted:_NativeInterfaces.PERMISSION_STATUS.GRANTED,denied:_NativeInterfaces.PERMISSION_STATUS.DENIED,prompt:_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED};setPermission(PERM_MAP[result.state]??_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);}catch(_){/* permission query not supported */}}setIsLoading(false);},[isWeb]);if(typeof window==="undefined"){return{permission:null,isLoading:false,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:()=>{},request:()=>{}};}return{permission,isLoading,webFallbackActive,webFallbackDisabled,setWebFallback,request};};exports.useCameraPermission=useCameraPermission;
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useDataProtection=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");var _utils=require("./utils.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useDataProtection=({webFallback}={})=>{const base=(0,_useBaseHook.useBaseHook)("useDataProtection",{hasWebFallback:true,webFallback});const[screenSecure,setScreenSecureState]=(0,_react.useState)(false);// Web fallback state — always declared (Rules of Hooks)
2
+ const[screenSecureWeb,setScreenSecureWeb]=(0,_react.useState)(false);const secureOverlayRef=(0,_react.useRef)(null);(0,_react.useEffect)(()=>{if(!base.webFallbackActive||!screenSecureWeb)return;const overlay=document.createElement("div");overlay.style.cssText="position:fixed;inset:0;background:#000;z-index:2147483647;display:none";document.body.appendChild(overlay);secureOverlayRef.current=overlay;const onVisibilityChange=()=>{overlay.style.display=document.hidden?"block":"none";};document.addEventListener("visibilitychange",onVisibilityChange);return()=>{document.removeEventListener("visibilitychange",onVisibilityChange);overlay.remove();secureOverlayRef.current=null;};},[base.webFallbackActive,screenSecureWeb]);const webSetScreenSecure=(0,_react.useCallback)(enable=>{setScreenSecureWeb(Boolean(enable));},[]);const webClearWebData=(0,_react.useCallback)(async()=>{try{localStorage.clear();sessionStorage.clear();}catch(_){/* storage may be unavailable in restricted contexts */}document.cookie.split(";").forEach(c=>{document.cookie=c.trim().split("=")[0]+"=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";});if(window.indexedDB?.databases){const dbs=await window.indexedDB.databases().catch(()=>[]);await Promise.all(dbs.map(db=>new Promise(res=>{const req=window.indexedDB.deleteDatabase(db.name);req.onsuccess=req.onerror=res;})));}},[]);if(typeof window==="undefined"){return{screenSecure:false,setScreenSecure:()=>{},clearWebData:()=>{},data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:()=>{},clear:()=>{},clearError:()=>{}};}if(base.webFallbackDisabled){return{screenSecure:false,setScreenSecure:()=>{},clearWebData:()=>{},data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:false,webFallbackDisabled:true,setWebFallback:base.setWebFallback,clear:()=>{},clearError:()=>{}};}if(base.webFallbackActive){return{screenSecure:screenSecureWeb,setScreenSecure:webSetScreenSecure,clearWebData:webClearWebData,data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:true,webFallbackDisabled:false,setWebFallback:base.setWebFallback,clear:()=>{},clearError:()=>{}};}(0,_react.useEffect)(()=>{if(!_NativeBridge.default.isAvailable())return;const handleScreenSecureSet=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}setScreenSecureState(Boolean(result?.secure));base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}};const handleScreenSecureError=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;base.handleNativeError(result?.error||"setScreenSecure failed");}catch(error){base.handleNativeError(error);}};const handleWebDataCleared=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}};const handleWebDataClearError=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;base.handleNativeError(result?.error||"clearWebData failed");}catch(error){base.handleNativeError(error);}};const handleScreenSecureStatus=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}setScreenSecureState(Boolean(result?.secure));}catch(error){base.handleNativeError(error);}};const cleanup=(0,_utils.registerNativeHandlers)([[_NativeInterfaces.NATIVE_CALLBACKS.ON_SCREEN_SECURE_SET,handleScreenSecureSet],[_NativeInterfaces.NATIVE_CALLBACKS.ON_SCREEN_SECURE_STATUS,handleScreenSecureStatus],[_NativeInterfaces.NATIVE_CALLBACKS.ON_SCREEN_SECURE_ERROR,handleScreenSecureError],[_NativeInterfaces.NATIVE_CALLBACKS.ON_WEB_DATA_CLEARED,handleWebDataCleared],[_NativeInterfaces.NATIVE_CALLBACKS.ON_WEB_DATA_CLEAR_ERROR,handleWebDataClearError]]);base.callNative(()=>_NativeBridge.default.security.getScreenSecure());return cleanup;},[base.setDataAndComplete,base.handleNativeError]);const setScreenSecure=(0,_react.useCallback)(enable=>{base.callNative(()=>_NativeBridge.default.security.setScreenSecure(enable));},[base.callNative]);const clearWebData=(0,_react.useCallback)(()=>{base.callNative(()=>_NativeBridge.default.security.clearWebData());},[base.callNative]);return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:base.setWebFallback,clear:base.clear,clearError:base.clearError,screenSecure,setScreenSecure,clearWebData};};exports.useDataProtection=useDataProtection;
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useDeviceInfo=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useDeviceInfo=({webFallback}={})=>{const[deviceInfo,setDeviceInfo]=(0,_react.useState)(null);const[loading,setLoading]=(0,_react.useState)(true);const[error,setError]=(0,_react.useState)(null);const isNative=_NativeBridge.default.isAvailable();const[webFallbackState,setWebFallback]=(0,_react.useState)(true);const webFallbackResolved=webFallback!==undefined?webFallback!==false:webFallbackState;const webFallbackActive=!isNative&&webFallbackResolved;const webFallbackDisabled=!isNative&&!webFallbackResolved;(0,_react.useEffect)(()=>{if(typeof window==="undefined"){setLoading(false);return;}if(!_NativeBridge.default.isAvailable()){if(webFallbackDisabled){setLoading(false);return;}// Web fallback: derive info from browser APIs
2
+ const ua=navigator.userAgent||"";setDeviceInfo({model:ua,manufacturer:"browser",platform:"web",screenWidth:screen.width*(window.devicePixelRatio||1),screenHeight:screen.height*(window.devicePixelRatio||1),screenDensity:window.devicePixelRatio||1,appInfo:null});setLoading(false);return;}if(!window.WebBridge){setError("WebBridge not initialized");setLoading(false);return;}window.WebBridge.getDeviceInfo().then(info=>{setDeviceInfo(info);setLoading(false);}).catch(err=>{setError(err.message||"Failed to get device info");setLoading(false);});},[webFallbackDisabled]);return{deviceInfo,loading,error,isNative,isWeb:!isNative,webFallbackActive,webFallbackDisabled,setWebFallback};};exports.useDeviceInfo=useDeviceInfo;
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useFilePicker=exports.sanitizeFilePickerOptions=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");var _FileObjectConverter=require("../utils/FileObjectConverter.js");var _utils=require("./utils.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const SSR_FILE_PICKER_STUB={data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,execute:_utils.noop,clear:_utils.noop,clearError:_utils.noop,getFileObject:(0,_utils.createSSRUnavailable)("getFileObject"),getAllFileObjects:(0,_utils.createSSRUnavailable)("getAllFileObjects"),canCreateFileObject:false,canCreateFileObjects:[],selectedFile:null,selectedFiles:[],pickFile:_utils.noop,isLoading:false,processingState:null,clearFile:_utils.noop};const extractFiles=value=>{if(!value)return[];if(Array.isArray(value))return value.filter(Boolean);if(Array.isArray(value.files))return value.files.filter(Boolean);if(value.files)return[value.files];return[value].filter(Boolean);};const sanitizeFilePickerOptions=input=>{const options={...input};const mime=typeof options.mimeType==="string"?options.mimeType.trim():"";options.mimeType=mime.length>0?mime:"*/*";const coerceInteger=(value,min)=>{if(value==null)return undefined;const numeric=typeof value==="string"?Number(value.trim()):Number(value);if(!Number.isFinite(numeric)){throw new Error("File picker numeric options must be valid numbers");}if(!Number.isInteger(numeric)){throw new Error("File picker numeric options must be integers");}if(numeric<min){throw new Error(`File picker numeric options must be ≥ ${min}`);}return numeric;};const minFiles=coerceInteger(options.minFiles,1);const maxFiles=coerceInteger(options.maxFiles,1);const minFileSize=coerceInteger(options.minFileSize,0);const maxFileSize=coerceInteger(options.maxFileSize,0);if(minFiles!==undefined)options.minFiles=minFiles;if(maxFiles!==undefined)options.maxFiles=maxFiles;if(minFileSize!==undefined)options.minFileSize=minFileSize;if(maxFileSize!==undefined)options.maxFileSize=maxFileSize;if(minFiles!==undefined&&maxFiles!==undefined&&minFiles>maxFiles){throw new Error("minFiles cannot be greater than maxFiles");}if(minFileSize!==undefined&&maxFileSize!==undefined&&minFileSize>maxFileSize){throw new Error("minFileSize cannot be greater than maxFileSize");}const multiple=typeof options.multiple==="boolean"?options.multiple:Boolean(options.multiple);options.multiple=multiple||minFiles&&minFiles>1||maxFiles&&maxFiles>1;return options;};exports.sanitizeFilePickerOptions=sanitizeFilePickerOptions;const resolvePickPayload=input=>{if(input==null)return"*/*";if(typeof input==="string")return input.trim()||"*/*";return sanitizeFilePickerOptions(input);};const normalizeFilePickResult=payload=>{const parsed=(0,_utils.parseNativePayload)(payload);if(!parsed)return null;const files=extractFiles(parsed);if(!files.length)return null;const first=files[0];const rawOptions=!Array.isArray(parsed)&&parsed&&typeof parsed.options==="object"?parsed.options:null;let normalizedOptions=rawOptions||null;if(rawOptions){try{normalizedOptions=sanitizeFilePickerOptions(rawOptions);}catch(_error){normalizedOptions=rawOptions;}}const totalSize=parsed.totalSize??files.reduce((sum,file)=>{const size=typeof file?.size==="number"?file.size:0;return sum+size;},0);const base=Array.isArray(parsed)?{}:parsed;return{...base,files,multiple:parsed.multiple??files.length>1,count:parsed.count??files.length,totalSize,fileName:parsed.fileName??first?.fileName??first?.name??null,fileSrc:parsed.fileSrc??first?.fileSrc??first?.src??null,filePath:parsed.filePath??first?.filePath??null,size:parsed.size??first?.size??null,mimeType:parsed.mimeType??first?.mimeType??first?.type??null,transport:parsed.transport??first?.transport??null,options:normalizedOptions};};const updateProgressFromResult=(updateProgress,result)=>{if(!result)return;const first=result.files?.[0];const transport=result.transport??first?.transport??null;const bytesTotal=result.totalSize??result.size??(typeof first?.size==="number"?first.size:null);if(transport||bytesTotal!=null){updateProgress({transport:transport??null,bytesTotal});}};const mapStateToProgress=state=>{if(state==null){return{state:"starting",phase:null,message:"File picker: starting..."};}const rawState=String(state);const normalized=rawState.toLowerCase();const allowedStates=new Set(["opening","processing","routing"]);const progressState=allowedStates.has(normalized)?normalized:"starting";return{state:progressState,phase:rawState,message:`File picker: ${rawState}...`};};const useFilePicker=({webFallback}={})=>{const base=(0,_useBaseHook.useBaseHook)("useFilePicker",{hasWebFallback:true,webFallback});const fileObjectCache=(0,_react.useRef)(new Map());// Web fallback callbacks — always declared (Rules of Hooks)
2
+ const webPickFile=(0,_react.useCallback)((input=null)=>{let accept="*/*";let multiple=false;if(typeof input==="string"){accept=input.trim()||"*/*";}else if(input&&typeof input==="object"){try{const opts=sanitizeFilePickerOptions(input);accept=opts.mimeType||"*/*";multiple=Boolean(opts.multiple);}catch(err){base.handleNativeError(err instanceof Error?err.message:"Invalid file picker options");return;}}const el=document.createElement("input");el.type="file";el.accept=accept;el.multiple=multiple;el.onchange=()=>{const fileList=Array.from(el.files||[]);if(!fileList.length)return;const files=fileList.map(f=>({fileName:f.name,fileSrc:URL.createObjectURL(f),size:f.size,mimeType:f.type,transport:"OBJECT_URL"}));base.setDataAndComplete({files,multiple:files.length>1,count:files.length,totalSize:files.reduce((sum,f)=>sum+(f.size||0),0),fileName:files[0].fileName,fileSrc:files[0].fileSrc,filePath:null,size:files[0].size,mimeType:files[0].mimeType,transport:"OBJECT_URL",options:null});};el.click();},[base]);const webFiles=(0,_react.useMemo)(()=>extractFiles(base.data),[base.data]);if(typeof window==="undefined"){return SSR_FILE_PICKER_STUB;}if(base.webFallbackDisabled){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:false,webFallbackDisabled:true,setWebFallback:base.setWebFallback,execute:_utils.noop,clear:_utils.noop,clearError:_utils.noop,getFileObject:(0,_utils.createSSRUnavailable)("getFileObject"),getAllFileObjects:(0,_utils.createSSRUnavailable)("getAllFileObjects"),canCreateFileObject:false,canCreateFileObjects:[],selectedFile:null,selectedFiles:[],pickFile:_utils.noop,isLoading:false,processingState:null,clearFile:_utils.noop};}if(base.webFallbackActive){return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:true,isNative:false,webFallbackActive:true,webFallbackDisabled:false,setWebFallback:base.setWebFallback,execute:webPickFile,clear:base.clear,clearError:base.clearError,getFileObject:(0,_utils.createSSRUnavailable)("getFileObject"),getAllFileObjects:(0,_utils.createSSRUnavailable)("getAllFileObjects"),canCreateFileObject:false,canCreateFileObjects:[],selectedFile:webFiles[0]||null,selectedFiles:webFiles,pickFile:webPickFile,isLoading:base.loading,processingState:null,clearFile:base.clear};}const{data,loading,progress,error,isWeb,isNative,setWebFallback,clear:baseClear,clearError,updateProgress,resetProgress,setDataAndComplete,handleNativeError,executeOperation,setLoading}=base;(0,_react.useEffect)(()=>{const handleFilePicked=payload=>{try{fileObjectCache.current.clear();const normalizedData=normalizeFilePickResult(payload);console.log("📁 File picked:",normalizedData);if(!normalizedData){throw new Error("No file data received from native file picker");}setDataAndComplete(normalizedData);updateProgressFromResult(updateProgress,normalizedData);}catch(error){console.error("📁 Error processing file data:",error);handleNativeError("Error processing selected file");}};const handleFilePickError=nativeError=>{console.error("📁 File pick error:",nativeError);handleNativeError(nativeError);};const handleFilePickCancelled=data=>{console.log("📁 File pick cancelled:",data);setLoading(false);resetProgress();};const handleFilePickStateUpdate=stateData=>{try{const parsedState=(0,_utils.parseNativePayload)(stateData);console.log("📁 File picker state:",parsedState?.state);const progressUpdate=mapStateToProgress(parsedState?.state);updateProgress(progressUpdate);if(parsedState?.state){setLoading(true);}}catch(parseError){console.error("📁 Error parsing state data:",parseError);}};return(0,_utils.registerNativeHandlers)([[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICKED,handleFilePicked],[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICK_ERROR,handleFilePickError],[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICK_CANCELLED,handleFilePickCancelled],[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICK_STATE_UPDATE,handleFilePickStateUpdate]]);},[handleNativeError,resetProgress,setDataAndComplete,setLoading,updateProgress]);const pickFile=(0,_react.useCallback)((input=null)=>{let payload;try{payload=resolvePickPayload(input);}catch(error){const message=error instanceof Error?error.message:"Invalid file picker options";handleNativeError(message);return;}if(typeof payload==="string"){console.log("📁 Picking file with MIME type:",payload);}else{console.log("📁 Picking file with options:",payload);}executeOperation(()=>{_NativeBridge.default.file.pick(payload);},"file pick");},[executeOperation,handleNativeError]);const files=(0,_react.useMemo)(()=>extractFiles(data),[data]);const getFileObject=(0,_react.useCallback)(async(index=0)=>{if(!files.length){throw new Error("No file data available. Please pick a file first.");}const targetIndex=Number(index);const fileEntry=files[targetIndex];if(!fileEntry){throw new Error(`No file data available at index ${targetIndex}.`);}if(fileObjectCache.current.has(targetIndex)){console.log("📁 Returning cached File object",{index:targetIndex});return fileObjectCache.current.get(targetIndex);}const{fileSrc,fileName,mimeType,transport}=fileEntry;if(!(0,_FileObjectConverter.canCreateFileObject)(transport)){const errorMessage=(0,_FileObjectConverter.getUnsupportedTransportMessage)(transport);console.error("❌",errorMessage);throw new Error(errorMessage);}console.log("📁 Converting to File object",{index:targetIndex,transport,fileName,mimeType});try{let fileObject;if(transport==="BRIDGE_BASE64"){fileObject=(0,_FileObjectConverter.base64ToFile)(fileSrc,fileName,mimeType);}else if(transport==="FRAMEWORK_SERVER"){fileObject=await(0,_FileObjectConverter.urlToFile)(fileSrc,fileName,mimeType);}fileObjectCache.current.set(targetIndex,fileObject);console.log("✅ File object created successfully",{index:targetIndex,name:fileObject.name,size:fileObject.size,type:fileObject.type});return fileObject;}catch(error){console.error("❌ Failed to create File object:",error);throw new Error(`Failed to create File object: ${error.message}`);}},[files]);const getAllFileObjects=(0,_react.useCallback)(async()=>{if(!files.length){throw new Error("No file data available. Please pick a file first.");}return Promise.all(files.map((_,index)=>getFileObject(index)));},[files,getFileObject]);const canCreateFileObjectForCurrentFile=(0,_react.useMemo)(()=>files.length>0?(0,_FileObjectConverter.canCreateFileObject)(files[0].transport):false,[files]);const canCreateFileObjectsList=(0,_react.useMemo)(()=>files.map(file=>(0,_FileObjectConverter.canCreateFileObject)(file.transport)),[files]);const clear=(0,_react.useCallback)(()=>{fileObjectCache.current.clear();baseClear();},[baseClear]);return{data,loading,progress,error,isWeb,isNative,webFallbackActive:false,webFallbackDisabled:false,setWebFallback,execute:pickFile,clear,clearError,getFileObject,getAllFileObjects,canCreateFileObject:canCreateFileObjectForCurrentFile,canCreateFileObjects:canCreateFileObjectsList,selectedFile:files[0]||null,selectedFiles:files,pickFile,isLoading:loading,processingState:progress?.phase||null,clearFile:clear};};exports.useFilePicker=useFilePicker;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useGoogleSignIn=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");var _errors=require("../errors.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useGoogleSignIn=(defaultOptions={})=>{const base=(0,_useBaseHook.useBaseHook)("useGoogleSignIn");if(typeof window==="undefined"){return{data:null,loading:false,error:null,progress:null,isWeb:true,isNative:false,signIn:()=>{},execute:()=>{},clear:()=>{},clearError:()=>{}};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{const handleSuccess=payload=>{try{const parsed=typeof payload==="string"?JSON.parse(payload):payload;base.setDataAndComplete(parsed);}catch(err){base.handleNativeError(err);}};const handleError=nativeError=>{base.handleNativeError(nativeError);};const handleCancelled=()=>{const error=(0,_errors.createStandardError)(_errors.ERROR_CODES.OPERATION_CANCELLED,"Google sign-in cancelled",null,"User dismissed Google sign-in");base.handleNativeError(error);};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_SUCCESS,handleSuccess);window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_ERROR,handleError);window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_CANCELLED,handleCancelled);return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_SUCCESS);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_ERROR);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_CANCELLED);};},[base]);const signIn=(0,_react.useCallback)((options={})=>{base.executeOperation(()=>{const payload={...defaultOptions,...options};_NativeBridge.default.auth.googleSignIn(payload);},"google sign-in");},[base,defaultOptions]);return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,signIn,execute:signIn,clear:base.clear,clearError:base.clearError};};exports.useGoogleSignIn=useGoogleSignIn;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useHapticFeedback=exports.requestHapticFeedback=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");var _errors=require("../errors.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const requestHapticFeedback=(feedbackType="light")=>{if(typeof window==="undefined"){return Promise.resolve(null);}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}return new Promise((resolve,reject)=>{try{if(!_NativeBridge.default.isAvailable()){reject(new Error("Native bridge not available"));return;}const handleHapticResponse=data=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.HAPTIC_FEEDBACK);if(data===_NativeInterfaces.RESPONSE_STATUS.SUCCESS){resolve(data);}else{reject(new Error(`Haptic feedback failed: ${data}`));}};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.HAPTIC_FEEDBACK,handleHapticResponse);_NativeBridge.default.haptic.feedback(feedbackType);console.log("📳 Haptic feedback requested:",feedbackType);}catch(error){reject(error);}});};exports.requestHapticFeedback=requestHapticFeedback;const detectHapticCapabilities=isNative=>{const userAgent=typeof navigator!=="undefined"?navigator.userAgent.toLowerCase():"";if(isNative){const platform=userAgent.includes("android")?"android":userAgent.includes("iphone")||userAgent.includes("ipad")?"ios":"native";const availableTypes=platform==="ios"?["light","medium","heavy","success","warning","error","selection","impact"]:["light","medium","heavy"];return{isSupported:true,availableTypes,platform};}const isSupported=typeof navigator!=="undefined"&&"vibrate"in navigator;return{isSupported,availableTypes:isSupported?["light","medium","heavy"]:[],platform:"web"};};const useHapticFeedback=({webFallback}={})=>{const base=(0,_useBaseHook.useBaseHook)("useHapticFeedback",{hasWebFallback:true,webFallback});const[capabilities,setCapabilities]=(0,_react.useState)(()=>detectHapticCapabilities(base.isNative));if(base.webFallbackDisabled){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,webFallbackActive:false,webFallbackDisabled:true,setWebFallback:base.setWebFallback,execute:()=>{},clear:()=>{},clearError:()=>{},triggerHaptic:()=>{},trigger:()=>{},light:()=>{},medium:()=>{},heavy:()=>{},success:()=>{},warning:()=>{},errorHaptic:()=>{},selection:()=>{},impact:()=>{},capabilities:{isSupported:false,availableTypes:[],platform:"web"},isSupported:false,isAvailable:false,availableTypes:[],HAPTIC_TYPES:{}};}const HAPTIC_TYPES={LIGHT:"light",MEDIUM:"medium",HEAVY:"heavy",SUCCESS:"success",WARNING:"warning",ERROR:"error",SELECTION:"selection",IMPACT:"impact"};(0,_react.useEffect)(()=>{setCapabilities(detectHapticCapabilities(base.isNative));},[base.isNative]);const handleWebHaptic=type=>{if(!navigator.vibrate)return false;const vibrationPatterns={[HAPTIC_TYPES.LIGHT]:[50],[HAPTIC_TYPES.MEDIUM]:[100],[HAPTIC_TYPES.HEAVY]:[200],[HAPTIC_TYPES.SUCCESS]:[100,50,100],[HAPTIC_TYPES.WARNING]:[200,100,200],[HAPTIC_TYPES.ERROR]:[300,100,300,100,300],[HAPTIC_TYPES.SELECTION]:[25],[HAPTIC_TYPES.IMPACT]:[150]};navigator.vibrate(vibrationPatterns[type]||[100]);return true;};const handleHapticTrigger=async(type,options={})=>{try{base.setLoading(true);base.updateProgress({state:"active",phase:"triggering",message:`Triggering ${type} haptic feedback...`});const success=base.isNative?await requestHapticFeedback(type):handleWebHaptic(type,options);base.setDataAndComplete({lastType:type,lastOptions:options,timestamp:new Date().toISOString(),success,capabilities,lastOperation:"trigger",operationSuccess:success});return success;}catch(error){console.error("📳 Haptic feedback failed:",error);base.handleNativeError(error);return false;}};const executeHaptic=(type="light",options={})=>{if(!capabilities.isSupported){base.handleNativeError((0,_errors.createStandardError)(_errors.ERROR_CODES.FEATURE_UNSUPPORTED,"Haptic feedback not supported",null,"Device does not support haptic feedback"));return;}return handleHapticTrigger(type,options);};return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,webFallbackActive:base.webFallbackActive,webFallbackDisabled:false,setWebFallback:base.setWebFallback,clear:base.clear,clearError:base.clearError,execute:executeHaptic,triggerHaptic:executeHaptic,trigger:executeHaptic,light:()=>executeHaptic(HAPTIC_TYPES.LIGHT),medium:()=>executeHaptic(HAPTIC_TYPES.MEDIUM),heavy:()=>executeHaptic(HAPTIC_TYPES.HEAVY),success:()=>executeHaptic(HAPTIC_TYPES.SUCCESS),warning:()=>executeHaptic(HAPTIC_TYPES.WARNING),errorHaptic:()=>executeHaptic(HAPTIC_TYPES.ERROR),selection:()=>executeHaptic(HAPTIC_TYPES.SELECTION),impact:()=>executeHaptic(HAPTIC_TYPES.IMPACT),capabilities,isSupported:capabilities.isSupported,isAvailable:capabilities.isSupported,availableTypes:capabilities.availableTypes,HAPTIC_TYPES};};exports.useHapticFeedback=useHapticFeedback;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useIntent=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useIntent=()=>{const base=(0,_useBaseHook.useBaseHook)("useIntent");if(typeof window==="undefined"){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,execute:()=>{},clear:()=>{},clearError:()=>{},isLoading:false,processingState:null,openFile:()=>{},success:null,reset:()=>{}};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_SUCCESS,data=>{console.log("📄 Intent completed successfully:",data);base.setDataAndComplete({result:data,success:true});});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_ERROR,data=>{console.error("📄 Intent error:",data);base.handleNativeError(data);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_CANCELLED,data=>{console.log("📄 Intent cancelled:",data);base.setLoading(false);base.resetProgress();});return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_SUCCESS);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_ERROR);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_CANCELLED);};},[base.setDataAndComplete,base.handleNativeError,base.setLoading,base.resetProgress]);const openFile=(fileUrl,mimeType=null)=>{if(!fileUrl){base.handleNativeError("File URL is required");return;}console.log("📄 File open with intent requested:",{fileUrl,mimeType});base.executeOperation(()=>{base.updateProgress({state:"opening_file",phase:"processing",message:"Opening file with external app..."});_NativeBridge.default.file.openWithIntent(fileUrl,mimeType);},"intent file open");};return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,execute:openFile,clear:base.clear,clearError:base.clearError,isLoading:base.loading,processingState:base.progress?.phase||null,openFile,success:base.data?.success||null,reset:base.clear};};exports.useIntent=useIntent;
@@ -0,0 +1,43 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useNativeTransition=void 0;var _react=require("react");var _reactRouterDom=require("react-router-dom");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const DEFAULT_DURATION=300;const DEFAULT_TIMEOUT_MULTIPLIER=3;const MIN_TIMEOUT=800;/**
2
+ * Wraps useNavigate with native slide/fade transitions using a snapshot overlay pattern.
3
+ *
4
+ * Native path:
5
+ * navigate(to, opts) → startTransition → native snapshots screen → router.navigate(to) →
6
+ * commitTransition → native animates overlay out revealing new page.
7
+ *
8
+ * Safety net: native-side timer (configurable via opts.timeout, default max(duration*3, 800ms))
9
+ * force-fades the overlay if commitTransition is never called.
10
+ *
11
+ * Web fallback: CSS overlay on document.body, driven by the same state machine.
12
+ *
13
+ * @param {Object} defaults - Default transition options applied to every navigate call
14
+ * type: 'slide' | 'fade' (default: 'slide')
15
+ * direction: 'left' | 'right' | 'up' | 'down' (default: 'left')
16
+ * duration: ms (default: 300)
17
+ * timeout: ms safety timer (default: max(duration*3, 800))
18
+ */const useNativeTransition=(defaults={})=>{const router=(0,_reactRouterDom.useNavigate)();const isNative=typeof window!=="undefined"&&_NativeBridge.default.isAvailable();const[transitioning,setTransitioning]=(0,_react.useState)(false);const overlayRef=(0,_react.useRef)(null);const webTimeoutRef=(0,_react.useRef)(null);const pendingCommitRef=(0,_react.useRef)(null);// Register native callbacks once
19
+ (0,_react.useEffect)(()=>{if(typeof window==="undefined"||!window.WebBridge)return;window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_TRANSITION_COMMITTED,()=>{setTransitioning(false);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_TRANSITION_CANCELLED,()=>{setTransitioning(false);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_TRANSITION_TIMEOUT,()=>{console.warn("🔀 useNativeTransition: native safety timeout fired — overlay force-faded");setTransitioning(false);});return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_TRANSITION_COMMITTED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_TRANSITION_CANCELLED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_TRANSITION_TIMEOUT);};},[]);// Web fallback: create/remove a CSS overlay on document.body
20
+ const _showWebOverlay=(0,_react.useCallback)(duration=>{if(typeof document==="undefined")return;const overlay=document.createElement("div");overlay.style.cssText=["position:fixed","inset:0","z-index:9999","background:var(--transition-overlay-color,#fff)",`transition:opacity ${duration}ms ease`,"opacity:0","pointer-events:none"].join(";");document.body.appendChild(overlay);overlayRef.current=overlay;// Trigger enter animation (fade in)
21
+ requestAnimationFrame(()=>{requestAnimationFrame(()=>{overlay.style.opacity="1";});});},[]);const _hideWebOverlay=(0,_react.useCallback)(duration=>{const overlay=overlayRef.current;if(!overlay)return;overlay.style.opacity="0";const cleanup=()=>{overlay.remove();overlayRef.current=null;setTransitioning(false);};// Use transitionend when possible, fallback to setTimeout
22
+ overlay.addEventListener("transitionend",cleanup,{once:true});webTimeoutRef.current=setTimeout(cleanup,duration+50);},[]);// Cancel any in-flight web transition (e.g. safety timeout path)
23
+ const _cancelWebOverlay=(0,_react.useCallback)(()=>{clearTimeout(webTimeoutRef.current);if(overlayRef.current){overlayRef.current.remove();overlayRef.current=null;}setTransitioning(false);},[]);/**
24
+ * navigate(to, options)
25
+ *
26
+ * Options (in addition to standard react-router NavigateOptions):
27
+ * type: 'slide' | 'fade'
28
+ * direction: 'left' | 'right' | 'up' | 'down'
29
+ * duration: ms
30
+ * timeout: ms (native safety timer; web safety timer uses duration*3)
31
+ * replace: boolean (passed to router)
32
+ * state: any (passed to router)
33
+ */const navigate=(0,_react.useCallback)((to,options={})=>{const{type=defaults.type??"slide",direction=defaults.direction??"left",duration=defaults.duration??DEFAULT_DURATION,timeout=defaults.timeout??Math.max(duration*DEFAULT_TIMEOUT_MULTIPLIER,MIN_TIMEOUT),replace=false,state,...rest}=options;const routerOpts={replace,state,...rest};setTransitioning(true);if(isNative){try{_NativeBridge.default.transition.start({type,direction,duration,timeout});// Route swap happens immediately — native overlay hides the skeleton
34
+ router(to,routerOpts);// Give the new page one frame to mount before committing
35
+ requestAnimationFrame(()=>{requestAnimationFrame(()=>{try{_NativeBridge.default.transition.commit();}catch(err){console.error("🔀 useNativeTransition: commitTransition failed:",err);_NativeBridge.default.transition.cancel();setTransitioning(false);}});});}catch(err){console.error("🔀 useNativeTransition: startTransition failed, falling back to plain navigate:",err);setTransitioning(false);router(to,routerOpts);}}else{// Web fallback — CSS overlay
36
+ _showWebOverlay(duration);const webSafetyTimeout=Math.max(duration*DEFAULT_TIMEOUT_MULTIPLIER,MIN_TIMEOUT);pendingCommitRef.current={duration,webSafetyTimeout};// Route swap after overlay is visible
37
+ requestAnimationFrame(()=>{requestAnimationFrame(()=>{router(to,routerOpts);// Commit: fade overlay back out
38
+ requestAnimationFrame(()=>{requestAnimationFrame(()=>{_hideWebOverlay(duration);});});});});// Web safety timeout
39
+ webTimeoutRef.current=setTimeout(()=>{console.warn("🔀 useNativeTransition: web safety timeout — removing overlay");_cancelWebOverlay();},webSafetyTimeout);}},[isNative,defaults,router,_showWebOverlay,_hideWebOverlay,_cancelWebOverlay]);/**
40
+ * Imperatively cancel an in-flight transition (e.g. error boundary).
41
+ * On native: fires cancelTransition bridge command.
42
+ * On web: removes overlay immediately.
43
+ */const cancelTransition=(0,_react.useCallback)(()=>{if(isNative){try{_NativeBridge.default.transition.cancel();}catch(_){/* swallow — cancel is best-effort */}}else{_cancelWebOverlay();}setTransitioning(false);},[isNative,_cancelWebOverlay]);return{navigate,cancelTransition,transitioning,isNative,isWeb:!isNative};};exports.useNativeTransition=useNativeTransition;
@@ -0,0 +1,3 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useNetworkStatus=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _utils=require("./utils.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useNetworkStatus=({webFallback}={})=>{// navigator.onLine is unreliable in some dev/Electron environments — default true if undefined
2
+ const initialOnline=typeof navigator!=="undefined"&&typeof navigator.onLine==="boolean"?navigator.onLine:true;const[status,setStatus]=(0,_react.useState)({online:initialOnline,type:null});const[error,setError]=(0,_react.useState)(null);const isNative=_NativeBridge.default.isAvailable();const[webFallbackState,setWebFallback]=(0,_react.useState)(true);const webFallbackResolved=webFallback!==undefined?webFallback!==false:webFallbackState;const webFallbackActive=!isNative&&webFallbackResolved;const webFallbackDisabled=!isNative&&!webFallbackResolved;(0,_react.useEffect)(()=>{if(typeof window==="undefined")return;if(!isNative){if(webFallbackDisabled)return;// Web fallback: browser online/offline events
3
+ const handleOnline=()=>setStatus({online:true,type:null});const handleOffline=()=>setStatus({online:false,type:null});window.addEventListener("online",handleOnline);window.addEventListener("offline",handleOffline);return()=>{window.removeEventListener("online",handleOnline);window.removeEventListener("offline",handleOffline);};}if(!window.WebBridge)return;const handleStatus=payload=>{try{const parsed=(0,_utils.parseNativePayload)(payload)||{};setStatus({online:Boolean(parsed.online),type:parsed.type||null});setError(null);}catch(e){console.error("🌐 Error parsing network status:",e);setError(e.message);}};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NETWORK_STATUS_CHANGED,handleStatus);try{_NativeBridge.default.network.getStatus();}catch(e){setError(e.message||"Network status unavailable");}return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NETWORK_STATUS_CHANGED);};},[isNative,webFallbackDisabled]);return{...status,error,isNative,isWeb:!isNative,webFallbackActive,webFallbackDisabled,setWebFallback};};exports.useNetworkStatus=useNetworkStatus;
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useNotificationPermission=exports.useNotification=exports.requestNotificationPermission=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */// Shared callback system — allows hook + requestNotificationPermission to share one WebBridge listener
2
+ const permissionStatusListeners=new Set();let isPermissionCallbackRegistered=false;const registerPermissionStatusListener=callback=>{permissionStatusListeners.add(callback);if(!isPermissionCallbackRegistered&&typeof window!=="undefined"&&window.WebBridge){isPermissionCallbackRegistered=true;window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS,data=>{permissionStatusListeners.forEach(listener=>{try{listener(data);}catch(error){console.error("Error in permission status listener:",error);}});});}return()=>{permissionStatusListeners.delete(callback);};};const unregisterPermissionStatusListener=callback=>{permissionStatusListeners.delete(callback);};const requestNotificationPermission=()=>{if(typeof window==="undefined"){return Promise.resolve(null);}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}return new Promise((resolve,reject)=>{try{if(!_NativeBridge.default.isAvailable()){reject(new Error("Native bridge not available"));return;}const handlePermissionStatus=data=>{unregisterPermissionStatusListener(handlePermissionStatus);if(data===_NativeInterfaces.PERMISSION_STATUS.GRANTED){resolve(data);}else{reject(new Error(`Notification permission ${data.toLowerCase()}`));}};registerPermissionStatusListener(handlePermissionStatus);_NativeBridge.default.notification.requestPermission();}catch(error){reject(error);}});};exports.requestNotificationPermission=requestNotificationPermission;const useNotificationPermission=()=>{if(typeof window==="undefined"){return{permission:null,isLoading:false};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}const[permission,setPermission]=(0,_react.useState)(null);const[isLoading,setIsLoading]=(0,_react.useState)(true);(0,_react.useEffect)(()=>{const requestPermission=async()=>{try{if(!_NativeBridge.default.isAvailable()){setPermission(_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);return;}window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS,data=>{setPermission(data);setIsLoading(false);console.log("🔔 Notification permission status updated:",data);});_NativeBridge.default.notification.requestPermission();}catch(error){console.error("🔔 Error requesting notification permission:",error);setPermission(_NativeInterfaces.PERMISSION_STATUS.DENIED);setIsLoading(false);}};requestPermission();return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS);};},[]);return{permission,isLoading};};exports.useNotificationPermission=useNotificationPermission;const useNotification=()=>{const base=(0,_useBaseHook.useBaseHook)("useNotification");const[permissionStatus,setPermissionStatus]=(0,_react.useState)(null);const[pushToken,setPushToken]=(0,_react.useState)(null);const[badges,setBadges]=(0,_react.useState)(0);const[lastNotification,setLastNotification]=(0,_react.useState)(null);const[subscribedTopics,setSubscribedTopics]=(0,_react.useState)([]);if(typeof window==="undefined"){return{data:null,loading:false,error:null,execute:()=>{},scheduleLocal:()=>{},cancelLocal:()=>{},registerForPush:()=>{},updateBadge:()=>{},subscribeToTopic:()=>{},unsubscribeFromTopic:()=>{},getSubscribedTopics:()=>{},permissionStatus:null,pushToken:null,badges:0,subscribedTopics:[]};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{const unregister=registerPermissionStatusListener(data=>{setPermissionStatus(data);});if(_NativeBridge.default.isAvailable()){try{if(_NativeBridge.default.isAndroid&&window.NativeBridge?.checkNotificationPermissionStatus){window.NativeBridge.checkNotificationPermissionStatus(null);}else if(_NativeBridge.default.isIOS&&window.webkit?.messageHandlers?.NativeBridge){window.webkit.messageHandlers.NativeBridge.postMessage({command:"checkNotificationPermissionStatus",data:null});}}catch(error){console.error("🔔 Error checking notification permission status:",error);}}window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_SCHEDULED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.success===false||result?.error){base.handleNativeError(result.error||result);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_CANCELLED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.success===false||result?.error){base.handleNativeError(result.error||result);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.PUSH_NOTIFICATION_TOKEN,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}setPushToken(result.token);base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_RECEIVED,data=>{const notification=typeof data==="string"?JSON.parse(data):data;setLastNotification(notification);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_TAPPED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_ACTION_PERFORMED,data=>{const action=typeof data==="string"?JSON.parse(data):data;base.setDataAndComplete(action);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.TOPIC_SUBSCRIPTION_RESULT,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}if(result?.success===false){base.handleNativeError(result);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.SUBSCRIBED_TOPICS_RESULT,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}if(result?.success===false){base.handleNativeError(result);return;}setSubscribedTopics(result.topics||[]);base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});return()=>{unregister();window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_SCHEDULED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_CANCELLED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.PUSH_NOTIFICATION_TOKEN);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_RECEIVED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_TAPPED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_ACTION_PERFORMED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.TOPIC_SUBSCRIPTION_RESULT);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.SUBSCRIBED_TOPICS_RESULT);};},[]);const requestPermission=()=>{requestNotificationPermission().catch(err=>base.handleNativeError(err));};const scheduleLocal=config=>{base.executeOperation(()=>{_NativeBridge.default.notification.scheduleLocal(config);},"schedule local notification");};const cancelLocal=notificationId=>{base.executeOperation(()=>{_NativeBridge.default.notification.cancelLocal(notificationId);},"cancel notification");};const registerForPush=()=>{base.executeOperation(()=>{_NativeBridge.default.notification.registerForPush();},"register for push");};const updateBadge=count=>{base.callNative(()=>_NativeBridge.default.notification.updateBadge(count));setBadges(count);};const subscribeToTopic=topic=>{base.executeOperation(()=>{_NativeBridge.default.notification.subscribeToTopic(topic);},"subscribe to topic");};const unsubscribeFromTopic=topic=>{base.executeOperation(()=>{_NativeBridge.default.notification.unsubscribeFromTopic(topic);},"unsubscribe from topic");};const getSubscribedTopics=()=>{base.executeOperation(()=>{_NativeBridge.default.notification.getSubscribedTopics();},"get subscribed topics");};return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,execute:scheduleLocal,clear:base.clear,clearError:base.clearError,isNative:base.isNative,isWeb:base.isWeb,permissionStatus,pushToken,badges,lastNotification,subscribedTopics,scheduleLocal,cancelLocal,registerForPush,updateBadge,subscribeToTopic,unsubscribeFromTopic,getSubscribedTopics,schedule:scheduleLocal,requestPermission};};exports.useNotification=useNotification;
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useSafeArea=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _safeArea=require("../safeArea.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const useSafeArea=({webFallback}={})=>{const fromGlobal=(0,_safeArea.getSafeAreaFromGlobal)();const initialValue=fromGlobal||{..._safeArea.DEFAULT_INSETS};const[insets,setInsets]=(0,_react.useState)(()=>initialValue);const isNative=_NativeBridge.default.isAvailable();const[webFallbackState,setWebFallback]=(0,_react.useState)(true);const webFallbackResolved=webFallback!==undefined?webFallback!==false:webFallbackState;const webFallbackActive=!isNative&&webFallbackResolved;const webFallbackDisabled=!isNative&&!webFallbackResolved;(0,_react.useEffect)(()=>{if(typeof window==="undefined")return;if(!_NativeBridge.default.isAvailable()){if(webFallbackDisabled)return;// Web fallback: read CSS env() safe area insets (Safari notch support)
2
+ const readCSSInsets=()=>{const style=getComputedStyle(document.documentElement);const read=prop=>{const val=style.getPropertyValue(prop).trim();return val?parseFloat(val)||0:0;};const webInsets={top:read("--sat")||read("env(safe-area-inset-top)"),right:read("--sar")||read("env(safe-area-inset-right)"),bottom:read("--sab")||read("env(safe-area-inset-bottom)"),left:read("--sal")||read("env(safe-area-inset-left)")};setInsets(webInsets);(0,_safeArea.setSafeAreaGlobal)(webInsets);};const id=setTimeout(readCSSInsets,0);return()=>clearTimeout(id);}if(!window.WebBridge)return;const handleInsetsUpdate=data=>{try{const parsed=typeof data==="string"?JSON.parse(data):data;const normalized={top:Number(parsed.top)||0,right:Number(parsed.right)||0,bottom:Number(parsed.bottom)||0,left:Number(parsed.left)||0};setInsets(normalized);(0,_safeArea.setSafeAreaGlobal)(normalized);}catch(error){console.error("Error parsing safe area insets:",error);setInsets({..._safeArea.DEFAULT_INSETS});}};window.WebBridge.register("ON_SAFE_AREA_INSETS_UPDATED",handleInsetsUpdate);_NativeBridge.default.safeArea.get();return()=>{window.WebBridge.unregister("ON_SAFE_AREA_INSETS_UPDATED");};},[webFallbackDisabled]);return{...insets,isNative,isWeb:!isNative,webFallbackActive,webFallbackDisabled,setWebFallback};};exports.useSafeArea=useSafeArea;
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useVideoStream=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("../utils/NativeBridge.js"));var _NativeInterfaces=require("../constants/NativeInterfaces.js");var _useBaseHook=require("../useBaseHook.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const STREAM_STATE_DEFAULT={zoom:null,minZoom:null,maxZoom:null,torchOn:false,fpsMin:null,fpsMax:null};const useVideoStream=({onQRDetected,webFallback}={})=>{const base=(0,_useBaseHook.useBaseHook)("useVideoStream",{hasWebFallback:true,webFallback});// Native stream state
2
+ const[isStreaming,setIsStreaming]=(0,_react.useState)(false);const[streamState,setStreamState]=(0,_react.useState)(STREAM_STATE_DEFAULT);const onQRDetectedRef=(0,_react.useRef)(onQRDetected);onQRDetectedRef.current=onQRDetected;const viewfinderRef=(0,_react.useRef)(null);// Web fallback stream state — always declared (Rules of Hooks)
3
+ const[isStreamingWeb,setIsStreamingWeb]=(0,_react.useState)(false);const[streamStateWeb,setStreamStateWeb]=(0,_react.useState)(STREAM_STATE_DEFAULT);const mediaStreamRef=(0,_react.useRef)(null);const facingModeRef=(0,_react.useRef)("environment");// Web fallback: stop active stream when webFallbackActive toggles off
4
+ (0,_react.useEffect)(()=>{if(!base.webFallbackActive&&mediaStreamRef.current){mediaStreamRef.current.getTracks().forEach(t=>t.stop());mediaStreamRef.current=null;setIsStreamingWeb(false);setStreamStateWeb(STREAM_STATE_DEFAULT);}},[base.webFallbackActive]);// Web fallback: cleanup on unmount
5
+ (0,_react.useEffect)(()=>{return()=>{if(mediaStreamRef.current){mediaStreamRef.current.getTracks().forEach(t=>t.stop());mediaStreamRef.current=null;}};},[]);const applyTrackConstraints=(0,_react.useCallback)(async constraints=>{const track=mediaStreamRef.current?.getVideoTracks()[0];if(!track)return;try{await track.applyConstraints(constraints);}catch(e){base.setError({message:`applyConstraints failed: ${e.message}`});}},[base]);const webStart=(0,_react.useCallback)(async(options={})=>{if(!window.isSecureContext){base.setError({message:"getUserMedia requires a secure context (HTTPS or localhost)"});return;}if(!navigator.mediaDevices?.getUserMedia){base.setError({message:"getUserMedia is not available in this browser"});return;}try{if(mediaStreamRef.current)return;base.setLoading(true);const constraints={video:{facingMode:{ideal:facingModeRef.current},...(options.fps?{frameRate:{ideal:options.fps}}:{})},audio:false};const stream=await navigator.mediaDevices.getUserMedia(constraints);mediaStreamRef.current=stream;setIsStreamingWeb(true);base.setLoading(false);const track=stream.getVideoTracks()[0];const caps=track?.getCapabilities?.()||{};setStreamStateWeb(prev=>({...prev,minZoom:caps.zoom?.min??null,maxZoom:caps.zoom?.max??null,zoom:caps.zoom?.min??null}));}catch(e){base.setLoading(false);base.setError({message:e.message||"getUserMedia failed"});}},[base]);const webStop=(0,_react.useCallback)(()=>{if(!mediaStreamRef.current)return;mediaStreamRef.current.getTracks().forEach(t=>t.stop());mediaStreamRef.current=null;setIsStreamingWeb(false);setStreamStateWeb(STREAM_STATE_DEFAULT);},[]);const webFlip=(0,_react.useCallback)(async()=>{facingModeRef.current=facingModeRef.current==="environment"?"user":"environment";if(mediaStreamRef.current){webStop();await webStart();}},[webStart,webStop]);const webSendCommand=(0,_react.useCallback)(async(type,value)=>{if(!isStreamingWeb){base.setError({message:`sendCommand('${type}') called but stream is not active`});return;}switch(type){case"zoom":{if(typeof value!=="number"||value<1.0){base.setError({message:`sendCommand zoom: value must be a multiplier >= 1.0, got ${value}`});return;}await applyTrackConstraints({advanced:[{zoom:value}]});setStreamStateWeb(prev=>({...prev,zoom:value}));break;}case"torch":{if(typeof value!=="boolean"){base.setError({message:`sendCommand torch: value must be boolean, got ${value}`});return;}await applyTrackConstraints({advanced:[{torch:value}]});setStreamStateWeb(prev=>({...prev,torchOn:value}));break;}case"fps":{if(typeof value!=="object"||value===null){base.setError({message:`sendCommand fps: value must be { min, max }, got ${value}`});return;}const{min=null,max=null}=value;const frameRate={};if(min!==null)frameRate.min=min;if(max!==null)frameRate.max=max;await applyTrackConstraints({frameRate});setStreamStateWeb(prev=>({...prev,fpsMin:min,fpsMax:max}));break;}default:base.setError({message:`sendCommand: unknown type '${type}'`});}},[isStreamingWeb,applyTrackConstraints,base]);// Native event registration — skipped on web (WebBridge absent or native bridge unavailable)
6
+ (0,_react.useEffect)(()=>{if(typeof window==="undefined"||!window.WebBridge||!_NativeBridge.default.isAvailable())return;window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_READY,()=>{console.log("📹 Video stream ready");setIsStreaming(true);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_STOPPED,()=>{console.log("📹 Video stream stopped");setIsStreaming(false);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_QR_DETECTED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;console.log("📹 QR detected:",result);onQRDetectedRef.current?.(result);}catch(e){base.handleNativeError("Failed to parse QR data");}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_TORCH_CHANGED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;const enabled=result?.enabled??false;console.log("📹 Torch changed:",enabled);setStreamState(prev=>({...prev,torchOn:enabled}));}catch(e){console.warn("[useVideoStream] Failed to parse ON_TORCH_CHANGED data:",e);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_ZOOM_CHANGED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;const zoom=result?.zoomLevel??null;const minZoom=result?.minZoom??null;const maxZoom=result?.maxZoom??null;console.log("📹 Zoom changed:",zoom,`(min=${minZoom} max=${maxZoom})`);setStreamState(prev=>({...prev,zoom,minZoom,maxZoom}));}catch(e){console.warn("[useVideoStream] Failed to parse ON_ZOOM_CHANGED data:",e);}});const handleBeforeUnload=()=>{_NativeBridge.default.videoStream.stop();};window.addEventListener("beforeunload",handleBeforeUnload);return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_READY);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_STOPPED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_QR_DETECTED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_TORCH_CHANGED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_ZOOM_CHANGED);window.removeEventListener("beforeunload",handleBeforeUnload);_NativeBridge.default.videoStream.stop();};},[base.handleNativeError]);const nativeStart=(0,_react.useCallback)((options={})=>{base.executeOperation(()=>{console.log("[useVideoStream] start() options:",JSON.stringify(options));_NativeBridge.default.videoStream.start(options);},"start video stream");},[base.executeOperation]);const nativeStop=(0,_react.useCallback)(()=>{console.log("[useVideoStream] stop()");_NativeBridge.default.videoStream.stop();setIsStreaming(false);},[]);const nativeFlip=(0,_react.useCallback)(()=>{console.log("[useVideoStream] flip()");_NativeBridge.default.videoStream.flip();},[]);const nativeSendCommand=(0,_react.useCallback)((type,value)=>{if(!isStreaming){base.setError({message:`sendCommand('${type}') called but stream is not active`});return;}console.log(`[useVideoStream] sendCommand(${type}, ${value})`);switch(type){case"zoom":{if(typeof value!=="number"||value<1.0){base.setError({message:`sendCommand zoom: value must be a multiplier >= 1.0 (e.g. 1.0=1x, 2.0=2x), got ${value}`});return;}_NativeBridge.default.videoStream.setZoom(value);break;}case"torch":{if(typeof value!=="boolean"){base.setError({message:`sendCommand torch: value must be boolean, got ${value}`});return;}_NativeBridge.default.videoStream.setTorch(value);break;}case"fps":{if(typeof value!=="object"||value===null){base.setError({message:`sendCommand fps: value must be { min, max }, got ${value}`});return;}const{min=null,max=null}=value;if(min!==null&&(typeof min!=="number"||min<1)){base.setError({message:`sendCommand fps: min must be a positive number, got ${min}`});return;}if(max!==null&&(typeof max!=="number"||max<1)){base.setError({message:`sendCommand fps: max must be a positive number, got ${max}`});return;}if(min!==null&&max!==null&&min>max){base.setError({message:`sendCommand fps: min (${min}) must be <= max (${max})`});return;}_NativeBridge.default.videoStream.setFps(min,max);setStreamState(prev=>({...prev,fpsMin:min,fpsMax:max}));break;}default:base.setError({message:`sendCommand: unknown type '${type}'`});}},[isStreaming,base.setError]);if(typeof window==="undefined"){return{isStreaming:false,streamState:STREAM_STATE_DEFAULT,error:null,isNative:false,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:()=>{},start:()=>{},stop:()=>{},sendCommand:()=>{},flip:()=>{},clearError:()=>{}};}if(base.webFallbackDisabled){return{isStreaming:false,streamState:STREAM_STATE_DEFAULT,error:null,isNative:false,webFallbackActive:false,webFallbackDisabled:true,setWebFallback:base.setWebFallback,start:()=>{},stop:()=>{},sendCommand:()=>{},flip:()=>{},clearError:()=>{}};}if(base.webFallbackActive){return{isStreaming:isStreamingWeb,streamState:streamStateWeb,error:base.error,isNative:false,webFallbackActive:true,webFallbackDisabled:false,setWebFallback:base.setWebFallback,mediaStream:mediaStreamRef.current,viewfinderRef,start:webStart,stop:webStop,sendCommand:webSendCommand,flip:webFlip,clearError:base.clearError};}return{isStreaming,streamState,error:base.error,isNative:base.isNative,webFallbackActive:false,webFallbackDisabled:false,setWebFallback:base.setWebFallback,viewfinderRef,start:nativeStart,stop:nativeStop,sendCommand:nativeSendCommand,flip:nativeFlip,clearError:base.clearError};};exports.useVideoStream=useVideoStream;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.registerNativeHandlers=exports.parseNativePayload=exports.noop=exports.createSSRUnavailable=void 0;/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */const noop=()=>{};exports.noop=noop;const createSSRUnavailable=methodName=>async()=>{throw new Error(`${methodName} is not available in SSR environment`);};exports.createSSRUnavailable=createSSRUnavailable;const parseNativePayload=payload=>{if(payload==null)return null;if(typeof payload!=="string")return payload;return JSON.parse(payload);};exports.parseNativePayload=parseNativePayload;const registerNativeHandlers=handlers=>{handlers.forEach(([event,handler])=>window.WebBridge.register(event,handler));return()=>{handlers.forEach(([event])=>window.WebBridge.unregister(event));};};exports.registerNativeHandlers=registerNativeHandlers;
@@ -1,137 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useSafeArea=exports.useNotificationPermission=exports.useNotification=exports.useNetworkStatus=exports.useIntent=exports.useHapticFeedback=exports.useGoogleSignIn=exports.useFilePicker=exports.useDataProtection=exports.useCameraPermission=exports.useCamera=exports.requestNotificationPermission=exports.requestHapticFeedback=exports.requestCameraPermission=void 0;var _react=require("react");var _NativeBridge=_interopRequireDefault(require("./utils/NativeBridge.js"));var _NativeInterfaces=require("./constants/NativeInterfaces.js");var _useBaseHook=require("./useBaseHook.js");var _errors=require("./errors.js");var _FileObjectConverter=require("./utils/FileObjectConverter.js");var _safeArea=require("./safeArea.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e};}/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */// Shared callback system for notification permission status
2
- // This allows multiple listeners (hook + requestNotificationPermission) to receive updates
3
- const permissionStatusListeners=new Set();let isPermissionCallbackRegistered=false;const registerPermissionStatusListener=callback=>{permissionStatusListeners.add(callback);// Register the shared handler with WebBridge if this is the first listener
4
- if(!isPermissionCallbackRegistered&&typeof window!=="undefined"&&window.WebBridge){isPermissionCallbackRegistered=true;window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS,data=>{// Notify all listeners
5
- permissionStatusListeners.forEach(listener=>{try{listener(data);}catch(error){console.error("Error in permission status listener:",error);}});});}return()=>{permissionStatusListeners.delete(callback);};};const unregisterPermissionStatusListener=callback=>{permissionStatusListeners.delete(callback);};const noop=()=>{};const createSSRUnavailable=methodName=>async()=>{throw new Error(`${methodName} is not available in SSR environment`);};const SSR_FILE_PICKER_STUB={data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,execute:noop,clear:noop,clearError:noop,getFileObject:createSSRUnavailable("getFileObject"),getAllFileObjects:createSSRUnavailable("getAllFileObjects"),canCreateFileObject:false,canCreateFileObjects:[],selectedFile:null,selectedFiles:[],pickFile:noop,isLoading:false,processingState:null,clearFile:noop};const parseNativePayload=payload=>{if(payload==null)return null;if(typeof payload!=="string")return payload;return JSON.parse(payload);};const extractFiles=value=>{if(!value)return[];if(Array.isArray(value))return value.filter(Boolean);if(Array.isArray(value.files))return value.files.filter(Boolean);if(value.files)return[value.files];return[value].filter(Boolean);};const normalizeFilePickResult=payload=>{const parsed=parseNativePayload(payload);if(!parsed)return null;const files=extractFiles(parsed);if(!files.length)return null;const first=files[0];const rawOptions=!Array.isArray(parsed)&&parsed&&typeof parsed.options==="object"?parsed.options:null;let normalizedOptions=rawOptions||null;if(rawOptions){try{normalizedOptions=sanitizeFilePickerOptions(rawOptions);}catch(_error){normalizedOptions=rawOptions;}}const totalSize=parsed.totalSize??files.reduce((sum,file)=>{const size=typeof file?.size==="number"?file.size:0;return sum+size;},0);const base=Array.isArray(parsed)?{}:parsed;return{...base,files,multiple:parsed.multiple??files.length>1,count:parsed.count??files.length,totalSize,fileName:parsed.fileName??first?.fileName??first?.name??null,fileSrc:parsed.fileSrc??first?.fileSrc??first?.src??null,filePath:parsed.filePath??first?.filePath??null,size:parsed.size??first?.size??null,mimeType:parsed.mimeType??first?.mimeType??first?.type??null,transport:parsed.transport??first?.transport??null,options:normalizedOptions};};/**
6
- * Google Sign-In hook (Android-first, Credential Manager)
7
- * Provides a promise-like sign-in call and standardized callbacks
8
- */const useGoogleSignIn=(defaultOptions={})=>{const base=(0,_useBaseHook.useBaseHook)("useGoogleSignIn");// Server-side rendering safety
9
- if(typeof window==="undefined"){return{data:null,loading:false,error:null,progress:null,isWeb:true,isNative:false,signIn:()=>{},execute:()=>{},clear:()=>{},clearError:()=>{}};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{const handleSuccess=payload=>{try{const parsed=typeof payload==="string"?JSON.parse(payload):payload;base.setDataAndComplete(parsed);}catch(err){base.handleNativeError(err);}};const handleError=nativeError=>{base.handleNativeError(nativeError);};const handleCancelled=()=>{const error=(0,_errors.createStandardError)(_errors.ERROR_CODES.OPERATION_CANCELLED,"Google sign-in cancelled",null,"User dismissed Google sign-in");base.handleNativeError(error);};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_SUCCESS,handleSuccess);window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_ERROR,handleError);window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_CANCELLED,handleCancelled);return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_SUCCESS);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_ERROR);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_GOOGLE_SIGN_IN_CANCELLED);};},[base]);const signIn=(0,_react.useCallback)((options={})=>{base.executeOperation(()=>{const payload={...defaultOptions,...options};_NativeBridge.default.auth.googleSignIn(payload);},"google sign-in");},[base,defaultOptions]);return{data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,signIn,execute:signIn,clear:base.clear,clearError:base.clearError};};exports.useGoogleSignIn=useGoogleSignIn;const updateProgressFromResult=(updateProgress,result)=>{if(!result)return;const first=result.files?.[0];const transport=result.transport??first?.transport??null;const bytesTotal=result.totalSize??result.size??(typeof first?.size==="number"?first.size:null);if(transport||bytesTotal!=null){updateProgress({transport:transport??null,bytesTotal});}};const mapStateToProgress=state=>{if(state==null){return{state:"starting",phase:null,message:"File picker: starting..."};}const rawState=String(state);const normalized=rawState.toLowerCase();const allowedStates=new Set(["opening","processing","routing"]);const progressState=allowedStates.has(normalized)?normalized:"starting";return{state:progressState,phase:rawState,message:`File picker: ${rawState}...`};};const sanitizeFilePickerOptions=input=>{const options={...input};const mime=typeof options.mimeType==="string"?options.mimeType.trim():"";options.mimeType=mime.length>0?mime:"*/*";const coerceInteger=(value,min)=>{if(value==null)return undefined;const numeric=typeof value==="string"?Number(value.trim()):Number(value);if(!Number.isFinite(numeric)){throw new Error("File picker numeric options must be valid numbers");}if(!Number.isInteger(numeric)){throw new Error("File picker numeric options must be integers");}if(numeric<min){throw new Error(`File picker numeric options must be ≥ ${min}`);}return numeric;};const minFiles=coerceInteger(options.minFiles,1);const maxFiles=coerceInteger(options.maxFiles,1);const minFileSize=coerceInteger(options.minFileSize,0);const maxFileSize=coerceInteger(options.maxFileSize,0);if(minFiles!==undefined)options.minFiles=minFiles;if(maxFiles!==undefined)options.maxFiles=maxFiles;if(minFileSize!==undefined)options.minFileSize=minFileSize;if(maxFileSize!==undefined)options.maxFileSize=maxFileSize;if(minFiles!==undefined&&maxFiles!==undefined&&minFiles>maxFiles){throw new Error("minFiles cannot be greater than maxFiles");}if(minFileSize!==undefined&&maxFileSize!==undefined&&minFileSize>maxFileSize){throw new Error("minFileSize cannot be greater than maxFileSize");}const multiple=typeof options.multiple==="boolean"?options.multiple:Boolean(options.multiple);options.multiple=multiple||minFiles&&minFiles>1||maxFiles&&maxFiles>1;return options;};const resolvePickPayload=input=>{if(input==null)return"*/*";if(typeof input==="string")return input.trim()||"*/*";return sanitizeFilePickerOptions(input);};const registerNativeHandlers=handlers=>{handlers.forEach(([event,handler])=>window.WebBridge.register(event,handler));return()=>{handlers.forEach(([event])=>window.WebBridge.unregister(event));};};/**
10
- * React hook for camera functionality using standardized interface
11
- * Handles camera permissions, photo capture, and error states
12
- */const useCamera=()=>{// Use standardized base hook
13
- const base=(0,_useBaseHook.useBaseHook)("useCamera");// Camera-specific state
14
- const[permission,setPermission]=(0,_react.useState)(null);// Server-side rendering safety
15
- if(typeof window==="undefined"){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,execute:()=>{},clear:()=>{},clearError:()=>{},permission:null,// Legacy aliases
16
- photo:null,takePhoto:()=>{},isLoading:false,clearPhoto:()=>{}};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{// Register callback handlers
17
- window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_CAPTURE,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;console.log("📷 Camera capture result:",result);// Handle new tri-transport format or legacy format
18
- const photoData=result.fileSrc?{// New tri-transport format
19
- fileSrc:result.fileSrc,fileName:result.fileName,size:result.size,mimeType:result.mimeType,transport:result.transport,source:result.source}:{// Legacy format (fallback)
20
- fileSrc:result.imageUrl,fileName:"camera_photo.jpg",size:0,mimeType:"image/jpeg",transport:"LEGACY",source:"camera"};base.setDataAndComplete(photoData);// Update progress with transport info if available
21
- if(photoData.transport){base.updateProgress({transport:photoData.transport,bytesTotal:photoData.size||null});}console.log("📷 Photo captured successfully via transport:",photoData.transport);}catch(parseError){console.error("📷 Error parsing camera capture data:",parseError);base.handleNativeError("Failed to process captured photo");}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,data=>{setPermission(data);console.log("📷 Camera permission status:",data);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_ERROR,data=>{console.error("📷 Camera error:",data);base.handleNativeError(data);});return()=>{// Cleanup: unregister all handlers
22
- window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_CAPTURE);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_CAMERA_ERROR);};},[base.setDataAndComplete,base.handleNativeError,base.updateProgress]);const takePhoto=()=>{console.log("📷 Camera open requested");base.executeOperation(()=>{// Update progress to show capturing state
23
- base.updateProgress({state:"capturing",phase:"requesting",message:"Opening camera..."});_NativeBridge.default.camera.open();},"camera capture");};// Standardized execute function (new interface)
24
- const execute=takePhoto;return{// Standardized interface
25
- data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,execute,clear:base.clear,clearError:base.clearError,// Camera-specific extras
26
- permission,// Legacy aliases for backward compatibility
27
- photo:base.data,takePhoto,isLoading:base.loading,clearPhoto:base.clear};};/**
28
- * React hook for intent handling using standardized interface
29
- * Manages file opening operations with external apps
30
- */exports.useCamera=useCamera;const useIntent=()=>{// Use standardized base hook
31
- const base=(0,_useBaseHook.useBaseHook)("useIntent");// Server-side rendering safety
32
- if(typeof window==="undefined"){return{data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,execute:()=>{},clear:()=>{},clearError:()=>{},// Legacy aliases
33
- isLoading:false,processingState:null,openFile:()=>{},success:null,reset:()=>{}};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{// Register callback handlers
34
- window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_SUCCESS,data=>{console.log("📄 Intent completed successfully:",data);base.setDataAndComplete({result:data,success:true});});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_ERROR,data=>{console.error("📄 Intent error:",data);base.handleNativeError(data);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_CANCELLED,data=>{console.log("📄 Intent cancelled:",data);base.setLoading(false);base.resetProgress();// Keep data as is when cancelled
35
- });return()=>{// Cleanup: unregister all handlers
36
- window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_SUCCESS);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_ERROR);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_INTENT_CANCELLED);};},[base.setDataAndComplete,base.handleNativeError,base.setLoading,base.resetProgress]);const openFile=(fileUrl,mimeType=null)=>{if(!fileUrl){base.handleNativeError("File URL is required");return;}console.log("📄 File open with intent requested:",{fileUrl,mimeType});base.executeOperation(()=>{// Update progress to show opening state
37
- base.updateProgress({state:"opening_file",phase:"processing",message:"Opening file with external app..."});_NativeBridge.default.file.openWithIntent(fileUrl,mimeType);},"intent file open");};// Standardized execute function (new interface)
38
- const execute=openFile;return{// Standardized interface
39
- data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,execute,clear:base.clear,clearError:base.clearError,// Legacy aliases for backward compatibility
40
- isLoading:base.loading,processingState:base.progress?.phase||null,openFile,success:base.data?.success||null,reset:base.clear};};/**
41
- * React hook for file picker functionality
42
- * Manages file selection operations using standardized interface
43
- */exports.useIntent=useIntent;const useFilePicker=()=>{// Use standardized base hook
44
- const base=(0,_useBaseHook.useBaseHook)("useFilePicker");// Cache for converted File objects to prevent redundant conversions
45
- const fileObjectCache=(0,_react.useRef)(new Map());// Server-side rendering safety
46
- if(typeof window==="undefined"){return SSR_FILE_PICKER_STUB;}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}const{data,loading,progress,error,isWeb,isNative,clear:baseClear,clearError,updateProgress,resetProgress,setDataAndComplete,handleNativeError,executeOperation,setLoading}=base;(0,_react.useEffect)(()=>{const handleFilePicked=payload=>{try{fileObjectCache.current.clear();const normalizedData=normalizeFilePickResult(payload);console.log("📁 File picked:",normalizedData);if(!normalizedData){throw new Error("No file data received from native file picker");}setDataAndComplete(normalizedData);updateProgressFromResult(updateProgress,normalizedData);}catch(error){console.error("📁 Error processing file data:",error);handleNativeError("Error processing selected file");}};const handleFilePickError=nativeError=>{console.error("📁 File pick error:",nativeError);handleNativeError(nativeError);};const handleFilePickCancelled=data=>{console.log("📁 File pick cancelled:",data);setLoading(false);resetProgress();};const handleFilePickStateUpdate=stateData=>{try{const parsedState=parseNativePayload(stateData);console.log("📁 File picker state:",parsedState?.state);const progressUpdate=mapStateToProgress(parsedState?.state);updateProgress(progressUpdate);if(parsedState?.state){setLoading(true);}}catch(parseError){console.error("📁 Error parsing state data:",parseError);}};return registerNativeHandlers([[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICKED,handleFilePicked],[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICK_ERROR,handleFilePickError],[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICK_CANCELLED,handleFilePickCancelled],[_NativeInterfaces.NATIVE_CALLBACKS.ON_FILE_PICK_STATE_UPDATE,handleFilePickStateUpdate]]);},[handleNativeError,resetProgress,setDataAndComplete,setLoading,updateProgress]);const pickFile=(0,_react.useCallback)((input=null)=>{let payload;try{payload=resolvePickPayload(input);}catch(error){const message=error instanceof Error?error.message:"Invalid file picker options";handleNativeError(message);return;}if(typeof payload==="string"){console.log("📁 Picking file with MIME type:",payload);}else{console.log("📁 Picking file with options:",payload);}executeOperation(()=>{_NativeBridge.default.file.pick(payload);},"file pick");},[executeOperation,handleNativeError]);// Standardized execute function (new interface)
47
- const execute=pickFile;const files=(0,_react.useMemo)(()=>extractFiles(data),[data]);/**
48
- * Get File object from current file data
49
- * Supports accessing specific file by index when multiple files are selected
50
- * @param {number} index - Index of the file (default: 0)
51
- * @returns {Promise<File>} JavaScript File object for FormData/POST API
52
- * @throws {Error} If file data is unavailable or transport is unsupported
53
- */const getFileObject=(0,_react.useCallback)(async(index=0)=>{if(!files.length){throw new Error("No file data available. Please pick a file first.");}const targetIndex=Number(index);const fileEntry=files[targetIndex];if(!fileEntry){throw new Error(`No file data available at index ${targetIndex}.`);}if(fileObjectCache.current.has(targetIndex)){console.log("📁 Returning cached File object",{index:targetIndex});return fileObjectCache.current.get(targetIndex);}const{fileSrc,fileName,mimeType,transport}=fileEntry;// Check if transport supports File object creation
54
- if(!(0,_FileObjectConverter.canCreateFileObject)(transport)){const errorMessage=(0,_FileObjectConverter.getUnsupportedTransportMessage)(transport);console.error("❌",errorMessage);throw new Error(errorMessage);}console.log("📁 Converting to File object",{index:targetIndex,transport,fileName,mimeType});try{let fileObject;if(transport==="BRIDGE_BASE64"){// Synchronous conversion for base64
55
- fileObject=(0,_FileObjectConverter.base64ToFile)(fileSrc,fileName,mimeType);}else if(transport==="FRAMEWORK_SERVER"){// Asynchronous fetch and conversion for URL
56
- fileObject=await(0,_FileObjectConverter.urlToFile)(fileSrc,fileName,mimeType);}// Cache the result per index
57
- fileObjectCache.current.set(targetIndex,fileObject);console.log("✅ File object created successfully",{index:targetIndex,name:fileObject.name,size:fileObject.size,type:fileObject.type});return fileObject;}catch(error){console.error("❌ Failed to create File object:",error);throw new Error(`Failed to create File object: ${error.message}`);}},[files]);const getAllFileObjects=(0,_react.useCallback)(async()=>{if(!files.length){throw new Error("No file data available. Please pick a file first.");}const indices=files.map((_,index)=>index);return Promise.all(indices.map(index=>getFileObject(index)));},[files,getFileObject]);const canCreateFileObjectForCurrentFile=(0,_react.useMemo)(()=>files.length>0?(0,_FileObjectConverter.canCreateFileObject)(files[0].transport):false,[files]);const canCreateFileObjectsList=(0,_react.useMemo)(()=>files.map(file=>(0,_FileObjectConverter.canCreateFileObject)(file.transport)),[files]);const clear=(0,_react.useCallback)(()=>{fileObjectCache.current.clear();baseClear();},[baseClear]);return{// Standardized interface
58
- data,loading,progress,error,isWeb,isNative,execute,clear,clearError,// File object conversion helpers
59
- getFileObject,getAllFileObjects,canCreateFileObject:canCreateFileObjectForCurrentFile,canCreateFileObjects:canCreateFileObjectsList,// Legacy aliases for backward compatibility
60
- selectedFile:files[0]||null,selectedFiles:files,pickFile,isLoading:loading,processingState:progress?.phase||null,clearFile:clear};};/**
61
- * Promise-based camera permission request
62
- * @returns {Promise<string>} Promise that resolves with permission status
63
- */exports.useFilePicker=useFilePicker;const requestCameraPermission=()=>{if(typeof window==="undefined"){return Promise.resolve(null);}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}return new Promise((resolve,reject)=>{try{if(!_NativeBridge.default.isAvailable()){reject(new Error("Native bridge not available"));return;}// Set up one-time listener
64
- const handlePermissionStatus=data=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS);if(data===_NativeInterfaces.PERMISSION_STATUS.GRANTED){resolve(data);}else{reject(new Error(`Camera permission ${data.toLowerCase()}`));}};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,handlePermissionStatus);_NativeBridge.default.camera.requestPermission();console.log("📷 Camera permission requested");}catch(error){reject(error);}});};/**
65
- * React hook for camera permission status
66
- * Automatically requests permission on mount
67
- */exports.requestCameraPermission=requestCameraPermission;const useCameraPermission=()=>{if(typeof window==="undefined"){return{permission:null,isLoading:false};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}const[permission,setPermission]=(0,_react.useState)(null);const[isLoading,setIsLoading]=(0,_react.useState)(true);(0,_react.useEffect)(()=>{const requestPermission=async()=>{try{if(!_NativeBridge.default.isAvailable()){setPermission(_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);return;}window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS,data=>{setPermission(data);setIsLoading(false);console.log("📷 Camera permission status updated:",data);});_NativeBridge.default.camera.requestPermission();}catch(error){console.error("📷 Error requesting camera permission:",error);setPermission(_NativeInterfaces.PERMISSION_STATUS.DENIED);setIsLoading(false);}};requestPermission();return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.CAMERA_PERMISSION_STATUS);};},[]);return{permission,isLoading};};/**
68
- * Promise-based notification permission request
69
- * @returns {Promise<string>} Promise that resolves with permission status
70
- */exports.useCameraPermission=useCameraPermission;const requestNotificationPermission=()=>{if(typeof window==="undefined"){return Promise.resolve(null);}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}return new Promise((resolve,reject)=>{try{if(!_NativeBridge.default.isAvailable()){reject(new Error("Native bridge not available"));return;}const handlePermissionStatus=data=>{// Unregister this one-time listener
71
- unregisterPermissionStatusListener(handlePermissionStatus);if(data===_NativeInterfaces.PERMISSION_STATUS.GRANTED){resolve(data);}else{reject(new Error(`Notification permission ${data.toLowerCase()}`));}};registerPermissionStatusListener(handlePermissionStatus);_NativeBridge.default.notification.requestPermission();}catch(error){reject(error);}});};/**
72
- * React hook for notification permission status
73
- * Automatically requests permission on mount
74
- */exports.requestNotificationPermission=requestNotificationPermission;const useNotificationPermission=()=>{if(typeof window==="undefined"){return{permission:null,isLoading:false};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}const[permission,setPermission]=(0,_react.useState)(null);const[isLoading,setIsLoading]=(0,_react.useState)(true);(0,_react.useEffect)(()=>{const requestPermission=async()=>{try{if(!_NativeBridge.default.isAvailable()){setPermission(_NativeInterfaces.PERMISSION_STATUS.NOT_DETERMINED);setIsLoading(false);return;}window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS,data=>{setPermission(data);setIsLoading(false);console.log("🔔 Notification permission status updated:",data);});_NativeBridge.default.notification.requestPermission();}catch(error){console.error("🔔 Error requesting notification permission:",error);setPermission(_NativeInterfaces.PERMISSION_STATUS.DENIED);setIsLoading(false);}};requestPermission();return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_PERMISSION_STATUS);};},[]);return{permission,isLoading};};/**
75
- * Promise-based haptic feedback request
76
- * @param {string} feedbackType - Type of haptic feedback (from HAPTIC_FEEDBACK_TYPES)
77
- * @returns {Promise<string>} Promise that resolves with success status
78
- */exports.useNotificationPermission=useNotificationPermission;const requestHapticFeedback=(feedbackType="light")=>{if(typeof window==="undefined"){return Promise.resolve(null);}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}return new Promise((resolve,reject)=>{try{if(!_NativeBridge.default.isAvailable()){reject(new Error("Native bridge not available"));return;}// Set up one-time listener
79
- const handleHapticResponse=data=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.HAPTIC_FEEDBACK);if(data===_NativeInterfaces.RESPONSE_STATUS.SUCCESS){resolve(data);}else{reject(new Error(`Haptic feedback failed: ${data}`));}};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.HAPTIC_FEEDBACK,handleHapticResponse);_NativeBridge.default.haptic.feedback(feedbackType);console.log("📳 Haptic feedback requested:",feedbackType);}catch(error){reject(error);}});};/**
80
- * React hook for haptic feedback
81
- * Provides a function to trigger haptic feedback
82
- */exports.requestHapticFeedback=requestHapticFeedback;const useHapticFeedback=()=>{const base=(0,_useBaseHook.useBaseHook)("useHapticFeedback");const[capabilities,setCapabilities]=(0,_react.useState)({isSupported:false,availableTypes:["light","medium","heavy"],platform:"unknown"});// Haptic types
83
- const HAPTIC_TYPES={LIGHT:"light",MEDIUM:"medium",HEAVY:"heavy",SUCCESS:"success",WARNING:"warning",ERROR:"error",SELECTION:"selection",IMPACT:"impact"};(0,_react.useEffect)(()=>{// Initialize capabilities
84
- const userAgent=typeof navigator!=="undefined"?navigator.userAgent.toLowerCase():"";let platform="unknown";let isSupported=false;let availableTypes=[];if(base.isNative){isSupported=true;if(userAgent.includes("android")){platform="android";availableTypes=[HAPTIC_TYPES.LIGHT,HAPTIC_TYPES.MEDIUM,HAPTIC_TYPES.HEAVY];}else if(userAgent.includes("iphone")||userAgent.includes("ipad")){platform="ios";availableTypes=Object.values(HAPTIC_TYPES);}}else{platform="web";isSupported=typeof navigator!=="undefined"&&"vibrate"in navigator;if(isSupported){availableTypes=[HAPTIC_TYPES.LIGHT,HAPTIC_TYPES.MEDIUM,HAPTIC_TYPES.HEAVY];}}setCapabilities({isSupported,availableTypes,platform});},[base.isNative]);// Main execute function for haptic superhook
85
- const executeHaptic=(type="light",options={})=>{if(!capabilities.isSupported){const error=(0,_errors.createStandardError)(_errors.ERROR_CODES.FEATURE_UNSUPPORTED,"Haptic feedback not supported",null,"Device does not support haptic feedback");base.handleNativeError(error);return;}return handleHapticTrigger(type,options);};// Haptic trigger handler
86
- const handleHapticTrigger=async(type,options={})=>{try{base.setLoading(true);base.updateProgress({state:"active",phase:"triggering",message:`Triggering ${type} haptic feedback...`});let success=false;if(base.isNative){// Use existing native implementation
87
- success=await requestHapticFeedback(type);}else{// Web fallback
88
- success=handleWebHaptic(type,options);}const hapticData={lastType:type,lastOptions:options,timestamp:new Date().toISOString(),success:success,capabilities:capabilities,lastOperation:"trigger",operationSuccess:success};base.setDataAndComplete(hapticData);return success;}catch(error){console.error("📳 Haptic feedback failed:",error);base.handleNativeError(error);return false;}};// Web haptic fallback
89
- const handleWebHaptic=type=>{if(!navigator.vibrate){return false;}const vibrationPatterns={[HAPTIC_TYPES.LIGHT]:[50],[HAPTIC_TYPES.MEDIUM]:[100],[HAPTIC_TYPES.HEAVY]:[200],[HAPTIC_TYPES.SUCCESS]:[100,50,100],[HAPTIC_TYPES.WARNING]:[200,100,200],[HAPTIC_TYPES.ERROR]:[300,100,300,100,300],[HAPTIC_TYPES.SELECTION]:[25],[HAPTIC_TYPES.IMPACT]:[150]};const pattern=vibrationPatterns[type]||[100];navigator.vibrate(pattern);return true;};// Return standardized superhook interface
90
- return{// Standard interface (from useBaseHook)
91
- data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,clear:base.clear,clearError:base.clearError,// Main execute function
92
- execute:executeHaptic,// Semantic aliases for execute
93
- triggerHaptic:executeHaptic,// Legacy compatibility
94
- trigger:executeHaptic,light:()=>executeHaptic(HAPTIC_TYPES.LIGHT),medium:()=>executeHaptic(HAPTIC_TYPES.MEDIUM),heavy:()=>executeHaptic(HAPTIC_TYPES.HEAVY),success:()=>executeHaptic(HAPTIC_TYPES.SUCCESS),warning:()=>executeHaptic(HAPTIC_TYPES.WARNING),errorHaptic:()=>executeHaptic(HAPTIC_TYPES.ERROR),selection:()=>executeHaptic(HAPTIC_TYPES.SELECTION),impact:()=>executeHaptic(HAPTIC_TYPES.IMPACT),// Capability info
95
- capabilities:capabilities,isSupported:capabilities.isSupported,isAvailable:capabilities.isSupported,// Legacy compatibility
96
- availableTypes:capabilities.availableTypes,// Haptic types constant
97
- HAPTIC_TYPES};};/**
98
- * React hook for notification functionality
99
- * Handles local notifications, push notifications, and badge management
100
- */exports.useHapticFeedback=useHapticFeedback;const useNotification=()=>{const base=(0,_useBaseHook.useBaseHook)("useNotification");const[permissionStatus,setPermissionStatus]=(0,_react.useState)(null);const[pushToken,setPushToken]=(0,_react.useState)(null);const[badges,setBadges]=(0,_react.useState)(0);const[lastNotification,setLastNotification]=(0,_react.useState)(null);const[subscribedTopics,setSubscribedTopics]=(0,_react.useState)([]);// Server-side rendering safety
101
- if(typeof window==="undefined"){return{data:null,loading:false,error:null,execute:()=>{},scheduleLocal:()=>{},cancelLocal:()=>{},registerForPush:()=>{},updateBadge:()=>{},subscribeToTopic:()=>{},unsubscribeFromTopic:()=>{},getSubscribedTopics:()=>{},permissionStatus:null,pushToken:null,badges:0,subscribedTopics:[]};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{const unregister=registerPermissionStatusListener(data=>{setPermissionStatus(data);});// Check initial permission status without requesting (internal call)
102
- if(_NativeBridge.default.isAvailable()){try{// Call native bridge directly without going through public API
103
- if(_NativeBridge.default.isAndroid&&window.NativeBridge?.checkNotificationPermissionStatus){window.NativeBridge.checkNotificationPermissionStatus(null);}else if(_NativeBridge.default.isIOS&&window.webkit?.messageHandlers?.NativeBridge){window.webkit.messageHandlers.NativeBridge.postMessage({command:"checkNotificationPermissionStatus",data:null});}}catch(error){console.error("🔔 Error checking notification permission status:",error);}}window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_SCHEDULED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.success===false||result?.error){base.handleNativeError(result.error||result);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_CANCELLED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.success===false||result?.error){base.handleNativeError(result.error||result);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.PUSH_NOTIFICATION_TOKEN,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}setPushToken(result.token);base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_RECEIVED,data=>{const notification=typeof data==="string"?JSON.parse(data):data;setLastNotification(notification);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_TAPPED,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_ACTION_PERFORMED,data=>{const action=typeof data==="string"?JSON.parse(data):data;base.setDataAndComplete(action);});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.TOPIC_SUBSCRIPTION_RESULT,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}const success=result?.success;if(success===false){base.handleNativeError(result);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.SUBSCRIBED_TOPICS_RESULT,data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}if(result?.success===false){base.handleNativeError(result);return;}setSubscribedTopics(result.topics||[]);base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}});return()=>{// Cleanup - unregister from shared callback system
104
- unregister();// Cleanup other callbacks
105
- window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_SCHEDULED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.LOCAL_NOTIFICATION_CANCELLED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.PUSH_NOTIFICATION_TOKEN);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_RECEIVED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_TAPPED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NOTIFICATION_ACTION_PERFORMED);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.TOPIC_SUBSCRIPTION_RESULT);window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.SUBSCRIBED_TOPICS_RESULT);};},[]);// Local notification scheduling with all supported styles
106
- const scheduleLocal=config=>{base.executeOperation(()=>{_NativeBridge.default.notification.scheduleLocal(config);},"schedule local notification");};const cancelLocal=notificationId=>{base.executeOperation(()=>{_NativeBridge.default.notification.cancelLocal(notificationId);},"cancel notification");};const registerForPush=()=>{base.executeOperation(()=>{_NativeBridge.default.notification.registerForPush();},"register for push");};const updateBadge=count=>{base.callNative(()=>_NativeBridge.default.notification.updateBadge(count));setBadges(count);};const subscribeToTopic=topic=>{base.executeOperation(()=>{_NativeBridge.default.notification.subscribeToTopic(topic);},"subscribe to topic");};const unsubscribeFromTopic=topic=>{base.executeOperation(()=>{_NativeBridge.default.notification.unsubscribeFromTopic(topic);},"unsubscribe from topic");};const getSubscribedTopics=()=>{base.executeOperation(()=>{_NativeBridge.default.notification.getSubscribedTopics();},"get subscribed topics");};return{// Standardized interface
107
- data:base.data,loading:base.loading,progress:base.progress,error:base.error,execute:scheduleLocal,clear:base.clear,clearError:base.clearError,// Notification-specific
108
- permissionStatus,pushToken,badges,lastNotification,subscribedTopics,scheduleLocal,cancelLocal,registerForPush,updateBadge,subscribeToTopic,unsubscribeFromTopic,getSubscribedTopics};};/**
109
- * Network status hook
110
- * Listens to native network changes and exposes online/offline state
111
- */exports.useNotification=useNotification;const useNetworkStatus=()=>{const initialOnline=typeof navigator!=="undefined"?navigator.onLine:true;const[status,setStatus]=(0,_react.useState)({online:initialOnline,type:null});const[error,setError]=(0,_react.useState)(null);const isNative=_NativeBridge.default.isAvailable();(0,_react.useEffect)(()=>{if(typeof window==="undefined")return;if(!window.WebBridge)return;if(!isNative)return;const handleStatus=payload=>{try{const parsed=parseNativePayload(payload)||{};setStatus({online:Boolean(parsed.online),type:parsed.type||null});setError(null);}catch(e){console.error("🌐 Error parsing network status:",e);setError(e.message);}};window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.NETWORK_STATUS_CHANGED,handleStatus);try{_NativeBridge.default.network.getStatus();}catch(e){setError(e.message||"Network status unavailable");}return()=>{window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.NETWORK_STATUS_CHANGED);};},[isNative]);return{...status,error};};/**
112
- * React hook for data protection primitives.
113
- *
114
- * Exposes screen-capture prevention and web data clearing as
115
- * composable building blocks — the web layer decides when to call them
116
- * (e.g. on sensitive screen mount/unmount, on logout).
117
- *
118
- * Extensible: add future security bridge commands here.
119
- *
120
- * @returns {{
121
- * screenSecure: boolean,
122
- * setScreenSecure: (enable: boolean) => void,
123
- * clearWebData: () => void,
124
- * data: Object|null,
125
- * loading: boolean,
126
- * error: Object|null,
127
- * isWeb: boolean,
128
- * isNative: boolean,
129
- * clear: () => void,
130
- * clearError: () => void,
131
- * }}
132
- */exports.useNetworkStatus=useNetworkStatus;const useDataProtection=()=>{const base=(0,_useBaseHook.useBaseHook)("useDataProtection");const[screenSecure,setScreenSecureState]=(0,_react.useState)(false);// Server-side rendering safety
133
- if(typeof window==="undefined"){return{screenSecure:false,setScreenSecure:()=>{},clearWebData:()=>{},data:null,loading:false,progress:null,error:null,isWeb:true,isNative:false,clear:()=>{},clearError:()=>{}};}if(!window.WebBridge){throw new Error("WebBridge is not initialized. Call WebBridge.init() first.");}(0,_react.useEffect)(()=>{const handleScreenSecureSet=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}setScreenSecureState(Boolean(result?.secure));base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}};const handleScreenSecureError=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;base.handleNativeError(result?.error||"setScreenSecure failed");}catch(error){base.handleNativeError(error);}};const handleWebDataCleared=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}base.setDataAndComplete(result);}catch(error){base.handleNativeError(error);}};const handleWebDataClearError=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;base.handleNativeError(result?.error||"clearWebData failed");}catch(error){base.handleNativeError(error);}};const handleScreenSecureStatus=data=>{try{const result=typeof data==="string"?JSON.parse(data):data;if(result?.error){base.handleNativeError(result.error);return;}setScreenSecureState(Boolean(result?.secure));}catch(error){base.handleNativeError(error);}};const cleanup=registerNativeHandlers([[_NativeInterfaces.NATIVE_CALLBACKS.ON_SCREEN_SECURE_SET,handleScreenSecureSet],[_NativeInterfaces.NATIVE_CALLBACKS.ON_SCREEN_SECURE_STATUS,handleScreenSecureStatus],[_NativeInterfaces.NATIVE_CALLBACKS.ON_SCREEN_SECURE_ERROR,handleScreenSecureError],[_NativeInterfaces.NATIVE_CALLBACKS.ON_WEB_DATA_CLEARED,handleWebDataCleared],[_NativeInterfaces.NATIVE_CALLBACKS.ON_WEB_DATA_CLEAR_ERROR,handleWebDataClearError]]);// Initialize screenSecure state from native on mount (native env only)
134
- base.callNative(()=>_NativeBridge.default.security.getScreenSecure());return cleanup;},[base.setDataAndComplete,base.handleNativeError]);const setScreenSecure=(0,_react.useCallback)(enable=>{base.callNative(()=>_NativeBridge.default.security.setScreenSecure(enable));},[base.callNative]);const clearWebData=(0,_react.useCallback)(()=>{base.callNative(()=>_NativeBridge.default.security.clearWebData());},[base.callNative]);return{// Standardized base interface
135
- data:base.data,loading:base.loading,progress:base.progress,error:base.error,isWeb:base.isWeb,isNative:base.isNative,clear:base.clear,clearError:base.clearError,// Security state
136
- screenSecure,// Security actions
137
- setScreenSecure,clearWebData};};exports.useDataProtection=useDataProtection;const useSafeArea=()=>{const fromGlobal=(0,_safeArea.getSafeAreaFromGlobal)();const initialValue=fromGlobal||{..._safeArea.DEFAULT_INSETS};const[insets,setInsets]=(0,_react.useState)(()=>initialValue);(0,_react.useEffect)(()=>{if(typeof window==="undefined")return;if(!window.WebBridge)return;if(!_NativeBridge.default.isAvailable())return;const handleInsetsUpdate=data=>{try{const parsed=typeof data==="string"?JSON.parse(data):data;const normalized={top:Number(parsed.top)||0,right:Number(parsed.right)||0,bottom:Number(parsed.bottom)||0,left:Number(parsed.left)||0};setInsets(normalized);(0,_safeArea.setSafeAreaGlobal)(normalized);}catch(error){console.error("Error parsing safe area insets:",error);setInsets({..._safeArea.DEFAULT_INSETS});}};window.WebBridge.register("ON_SAFE_AREA_INSETS_UPDATED",handleInsetsUpdate);_NativeBridge.default.safeArea.get();return()=>{window.WebBridge.unregister("ON_SAFE_AREA_INSETS_UPDATED");};},[]);return insets;};exports.useSafeArea=useSafeArea;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});var _index=require("./hooks/index.js");Object.keys(_index).forEach(function(key){if(key==="default"||key==="__esModule")return;if(key in exports&&exports[key]===_index[key])return;Object.defineProperty(exports,key,{enumerable:true,get:function(){return _index[key];}});});