catalyst-core 0.0.3-canary.9 → 0.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/bin/catalyst.js +28 -15
- package/changelog.md +139 -30
- package/dist/native/androidProject/app/build.gradle.kts +125 -15
- package/dist/native/androidProject/app/proguard-rules.pro +85 -14
- package/dist/native/androidProject/app/src/debug/res/xml/network_security_config.xml +8 -0
- package/dist/native/androidProject/app/src/main/AndroidManifest.xml +10 -3
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/BridgeMessageValidator.kt +552 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CatalystConstants.kt +109 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +605 -124
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +405 -47
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MetricsMonitor.kt +341 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +954 -71
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/SplashActivity.kt +111 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/URLWhitelistManager.kt +231 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/Utils.kt +49 -55
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/WebCacheManager.kt +81 -8
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/design/DesignTokens.kt +307 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/EmulatorDetector.kt +203 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/FridaDetector.kt +187 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/SecurityAlertHandler.kt +170 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/SecurityAlertUI.kt +366 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/SecurityBottomSheet.kt +138 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/SecurityCheckManager.kt +511 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/SecurityCheckScheduler.kt +68 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +47 -11
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/DeviceInfoUtils.kt +38 -13
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/DownloadUtils.kt +36 -14
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FileUtils.kt +3 -2
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +57 -8
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/IntentUtils.kt +31 -6
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/KeyboardUtil.kt +82 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/NetworkUtils.kt +105 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/NotificationConstants.kt +28 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/NotificationUtils.kt +639 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/SafeAreaUtils.kt +62 -0
- package/dist/native/androidProject/app/src/main/res/drawable/splashscreen_fallback.png +0 -0
- package/dist/native/androidProject/app/src/main/res/layout/activity_main.xml +1 -0
- package/dist/native/androidProject/app/src/main/res/layout/activity_splash.xml +20 -0
- package/dist/native/androidProject/app/src/main/res/values/themes.xml +23 -0
- package/dist/native/androidProject/app/src/main/res/values-night/themes.xml +11 -0
- package/dist/native/androidProject/app/src/main/res/xml/network_security_config.xml +12 -0
- package/dist/native/androidProject/app/src/noFcm/java/io/yourname/androidproject/utils/NotificationManager.kt +166 -0
- package/dist/native/androidProject/app/src/noFcm/java/io/yourname/androidproject/utils/PushNotificationUtils.kt +94 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/BridgeMessageValidatorTest.kt +267 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/BridgeUtilsTest.kt +286 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/CameraUtilsTest.kt +296 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/ConfigMappingTest.kt +594 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/CustomWebviewTest.kt +466 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/DeviceInfoUtilsTest.kt +187 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileUtilsTest.kt +304 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NativeBridgeTest.kt +424 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NotificationUtilsTest.kt +469 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/SecurityBridgeTest.kt +199 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/URLWhitelistManagerTest.kt +462 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/WebCacheManagerTest.kt +391 -0
- package/dist/native/androidProject/app/src/withFcm/java/io/yourname/androidproject/utils/NotificationManager.kt +224 -0
- package/dist/native/androidProject/app/src/withFcm/java/io/yourname/androidproject/utils/PushNotificationUtils.kt +399 -0
- package/dist/native/androidProject/build.gradle.kts +6 -0
- package/dist/native/androidProject/gradle/libs.versions.toml +8 -2
- package/dist/native/androidSetup.js +4 -3
- package/dist/native/assets/catalyst.png +0 -0
- package/dist/native/bridge/WebBridge.js +16 -3
- package/dist/native/bridge/constants/NativeInterfaces.js +28 -10
- package/dist/native/bridge/errors.js +1 -1
- package/dist/native/bridge/hooks.js +76 -16
- package/dist/native/bridge/safeArea.js +5 -0
- package/dist/native/bridge/standardizedHooks.js +23 -5
- package/dist/native/bridge/useBaseHook.js +7 -9
- package/dist/native/bridge/utils/CameraUtils.js +58 -0
- package/dist/native/bridge/utils/FileObjectConverter.js +40 -0
- package/dist/native/bridge/utils/NativeBridge.js +57 -8
- package/dist/native/buildAppAndroid.js +115 -43
- package/dist/native/buildAppIos.js +291 -26
- package/dist/native/iosnativeWebView/Configurations/Debug.xcconfig +21 -0
- package/dist/native/iosnativeWebView/Configurations/Release.xcconfig +24 -0
- package/dist/native/iosnativeWebView/Configurations/Shared.xcconfig +50 -0
- package/dist/native/iosnativeWebView/Package.resolved +32 -0
- package/dist/native/iosnativeWebView/Package.swift +37 -0
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/LocalNotificationHandler.swift +293 -0
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/NotificationManager.swift +299 -0
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/PushNotificationHandler.swift +199 -0
- package/dist/native/iosnativeWebView/Sources/Core/Constants/CatalystConstants.swift +125 -0
- package/dist/native/iosnativeWebView/Sources/Core/Constants/ConfigConstants.swift +70 -0
- package/dist/native/iosnativeWebView/Sources/Core/Notifications/NotificationModels.swift +156 -0
- package/dist/native/iosnativeWebView/Sources/Core/Protocols/NotificationHandlerProtocol.swift +35 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/BootTimingUtility.swift +26 -0
- package/dist/native/iosnativeWebView/{iosnativeWebView → Sources/Core/Utils}/CacheManager.swift +69 -36
- package/dist/native/iosnativeWebView/Sources/Core/Utils/CameraTransportUtils.swift +363 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/DeviceInfoUtils.swift +67 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/FilePickerHandler.swift +1053 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/FrameworkServerUtils.swift +901 -0
- package/dist/native/iosnativeWebView/{iosnativeWebView → Sources/Core/Utils}/ImageHandler.swift +206 -20
- package/dist/native/iosnativeWebView/Sources/Core/Utils/NetworkMonitor.swift +112 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/NotificationHandlerProvider.swift +20 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/NullNotificationHandler.swift +85 -0
- package/dist/native/iosnativeWebView/{iosnativeWebView → Sources/Core/Utils}/ResourceURLProtocol.swift +60 -25
- package/dist/native/iosnativeWebView/Sources/Core/Utils/SafeAreaUtils.swift +132 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/ScreenSecureManager.swift +131 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/URLWhitelistManager.swift +224 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/WebKitConfig.swift +43 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeCommandHandler.swift +991 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeDelegateHandler.swift +166 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeFileHandler.swift +340 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeJavaScriptInterface.swift +149 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +611 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +334 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashView.swift +95 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashViewModel.swift +86 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +181 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewModel.swift +182 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +395 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/AppDelegate.swift +84 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/Assets.xcassets/AccentColor.colorset/Contents.json +8 -8
- package/dist/native/iosnativeWebView/iosnativeWebView/Assets.xcassets/AppIcon.appiconset/Contents.json +10 -10
- package/dist/native/iosnativeWebView/iosnativeWebView/Assets.xcassets/Contents.json +4 -4
- package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +65 -10
- package/dist/native/iosnativeWebView/iosnativeWebView/Info-Release.plist +21 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/Info.plist +13 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/Preview Content/Preview Assets.xcassets/Contents.json +4 -4
- package/dist/native/iosnativeWebView/iosnativeWebView/iosnativeWebView.entitlements +12 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/iosnativeWebViewApp.swift +80 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/localhost.p12 +0 -0
- package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +118 -100
- package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +69 -0
- package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/xcshareddata/xcschemes/iosnativeWebView.xcscheme +9 -4
- package/dist/native/iosnativeWebView/iosnativeWebView.xctestplan +47 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/BootTimingUtilityTests.swift +236 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeCommandHandlerSecurityTests.swift +212 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeMessageValidatorTests.swift +418 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/CacheManagerTests.swift +390 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/ConfigMappingTests.swift +299 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/FilePickerHandlerTests.swift +383 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/FrameworkServerUtilsTests.swift +391 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/NativeBridgeTests.swift +581 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/NotificationHandlerTests.swift +430 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/ScreenSecureManagerTests.swift +121 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/URLWhitelistManagerTests.swift +367 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/WebViewTests.swift +440 -0
- package/dist/native/renameAndroidProject.js +80 -70
- package/dist/native/setupEmulatorIos.js +22 -5
- package/dist/native/setupServer.js +11 -10
- package/dist/native/terminalProgress.js +10 -10
- package/dist/native/utils.js +4 -5
- package/dist/otel.js +4 -0
- package/dist/scripts/build.js +2 -2
- package/dist/scripts/devBuild.js +2 -2
- package/dist/scripts/loadEnvironmentVariables.js +3 -1
- package/dist/scripts/scriptUtils.js +2 -2
- package/dist/sentry.js +4 -1
- package/dist/server/renderer/document/Body.js +4 -4
- package/dist/server/renderer/handler.js +7 -5
- package/dist/webpack/development.client.babel.js +1 -1
- package/mcp_v2/conversion-tasks.json +326 -0
- package/mcp_v2/knowledge-base.json +1068 -0
- package/mcp_v2/lib/helpers.js +165 -0
- package/mcp_v2/mcp.js +563 -0
- package/mcp_v2/package.json +13 -0
- package/mcp_v2/schema.sql +88 -0
- package/mcp_v2/setup.js +278 -0
- package/mcp_v2/tools/build.js +686 -0
- package/mcp_v2/tools/config.js +453 -0
- package/mcp_v2/tools/conversion.js +799 -0
- package/mcp_v2/tools/debug.js +113 -0
- package/mcp_v2/tools/knowledge.js +219 -0
- package/mcp_v2/tools/sync.js +23 -0
- package/mcp_v2/tools/tasks.js +945 -0
- package/package.json +11 -15
- package/dist/native/androidProject/.idea/.name +0 -1
- package/dist/native/androidProject/.idea/AndroidProjectSystem.xml +0 -6
- package/dist/native/androidProject/.idea/compiler.xml +0 -6
- package/dist/native/androidProject/.idea/deploymentTargetSelector.xml +0 -10
- package/dist/native/androidProject/.idea/gradle.xml +0 -18
- package/dist/native/androidProject/.idea/migrations.xml +0 -10
- package/dist/native/androidProject/.idea/misc.xml +0 -10
- package/dist/native/androidProject/.idea/runConfigurations.xml +0 -17
- package/dist/native/androidProject/.idea/vcs.xml +0 -6
- package/dist/native/iosnativeWebView/iosnativeWebView/NativeBridge.swift +0 -217
- package/dist/native/iosnativeWebView/iosnativeWebView/WebView.swift +0 -96
- package/dist/native/iosnativeWebView/iosnativeWebView/WebViewModel.swift +0 -47
- package/dist/native/iosnativeWebView/iosnativeWebView/WebViewNavigationDelegate.swift +0 -140
- package/license +0 -10
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
</intent>
|
|
13
13
|
</queries>
|
|
14
14
|
<application
|
|
15
|
-
android:allowBackup="
|
|
15
|
+
android:allowBackup="${allowBackup}"
|
|
16
16
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
|
17
17
|
android:fullBackupContent="@xml/backup_rules"
|
|
18
18
|
android:hardwareAccelerated="true"
|
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
android:roundIcon="@mipmap/ic_launcher_round"
|
|
22
22
|
android:supportsRtl="true"
|
|
23
23
|
android:theme="@style/Theme.AndroidProject"
|
|
24
|
-
android:usesCleartextTraffic="
|
|
24
|
+
android:usesCleartextTraffic="true"
|
|
25
|
+
android:networkSecurityConfig="@xml/network_security_config"
|
|
25
26
|
tools:targetApi="31">
|
|
26
27
|
<activity
|
|
27
|
-
android:name="io.yourname.androidproject.
|
|
28
|
+
android:name="io.yourname.androidproject.SplashActivity"
|
|
28
29
|
android:exported="true"
|
|
30
|
+
android:theme="@style/Theme.AndroidProject.Splash"
|
|
29
31
|
android:screenOrientation="portrait">
|
|
30
32
|
<intent-filter>
|
|
31
33
|
<action android:name="android.intent.action.MAIN" />
|
|
@@ -33,6 +35,11 @@
|
|
|
33
35
|
<category android:name="android.intent.category.LAUNCHER" />
|
|
34
36
|
</intent-filter>
|
|
35
37
|
</activity>
|
|
38
|
+
<activity
|
|
39
|
+
android:name="io.yourname.androidproject.MainActivity"
|
|
40
|
+
android:exported="false"
|
|
41
|
+
android:screenOrientation="portrait">
|
|
42
|
+
</activity>
|
|
36
43
|
<provider
|
|
37
44
|
android:name="androidx.core.content.FileProvider"
|
|
38
45
|
android:authorities="io.yourname.androidproject.fileprovider"
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
package io.yourname.androidproject
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import io.yourname.androidproject.utils.BridgeUtils
|
|
5
|
+
import org.json.JSONObject
|
|
6
|
+
import org.json.JSONException
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Bridge message validation using custom schema validation
|
|
10
|
+
* Mirrors iOS BridgeMessageValidator.swift for cross-platform consistency
|
|
11
|
+
* Zero external dependencies for minimal APK impact
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// MARK: - Validation Result Data Classes
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Result of bridge message validation
|
|
18
|
+
*/
|
|
19
|
+
data class BridgeValidationResult(
|
|
20
|
+
val isValid: Boolean,
|
|
21
|
+
val command: String?,
|
|
22
|
+
val params: Any?,
|
|
23
|
+
val body: JSONObject?,
|
|
24
|
+
val error: BridgeValidationError?
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Validation error details
|
|
29
|
+
*/
|
|
30
|
+
data class BridgeValidationError(
|
|
31
|
+
val message: String,
|
|
32
|
+
val code: String,
|
|
33
|
+
val eventName: String
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
// MARK: - Schema Definition Classes
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Property schema definition
|
|
40
|
+
*/
|
|
41
|
+
data class PropertySchema(
|
|
42
|
+
val type: String,
|
|
43
|
+
val enum: List<String>? = null,
|
|
44
|
+
val minimum: Number? = null,
|
|
45
|
+
val maximum: Number? = null
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Object schema definition
|
|
50
|
+
*/
|
|
51
|
+
data class SchemaDefinition(
|
|
52
|
+
val type: String = "object",
|
|
53
|
+
val properties: Map<String, PropertySchema>,
|
|
54
|
+
val required: List<String> = emptyList(),
|
|
55
|
+
val additionalProperties: Boolean = true
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// MARK: - Bridge Message Validator
|
|
59
|
+
|
|
60
|
+
object BridgeMessageValidator {
|
|
61
|
+
|
|
62
|
+
private const val TAG = "BridgeMessageValidator"
|
|
63
|
+
private const val MAX_MESSAGE_SIZE = 10 * 1024 * 1024 // 10MB (match iOS)
|
|
64
|
+
|
|
65
|
+
// Valid commands — single source of truth from CatalystConstants
|
|
66
|
+
private val validCommands = CatalystConstants.Bridge.VALID_COMMANDS
|
|
67
|
+
|
|
68
|
+
// MARK: - Schema Definitions (mirror iOS schemas)
|
|
69
|
+
|
|
70
|
+
private val schemas = mapOf(
|
|
71
|
+
"openCamera" to SchemaDefinition(
|
|
72
|
+
properties = mapOf(
|
|
73
|
+
"quality" to PropertySchema(
|
|
74
|
+
type = "string",
|
|
75
|
+
enum = listOf("high", "medium", "low")
|
|
76
|
+
),
|
|
77
|
+
"allowsEditing" to PropertySchema(type = "boolean"),
|
|
78
|
+
"preferredCameraType" to PropertySchema(
|
|
79
|
+
type = "string",
|
|
80
|
+
enum = listOf("front", "back")
|
|
81
|
+
),
|
|
82
|
+
"flashMode" to PropertySchema(
|
|
83
|
+
type = "string",
|
|
84
|
+
enum = listOf("auto", "on", "off")
|
|
85
|
+
),
|
|
86
|
+
"videoMaximumDuration" to PropertySchema(
|
|
87
|
+
type = "number",
|
|
88
|
+
minimum = 0,
|
|
89
|
+
maximum = 3600
|
|
90
|
+
)
|
|
91
|
+
),
|
|
92
|
+
additionalProperties = false
|
|
93
|
+
),
|
|
94
|
+
|
|
95
|
+
"requestCameraPermission" to SchemaDefinition(
|
|
96
|
+
properties = mapOf(
|
|
97
|
+
"showRationale" to PropertySchema(type = "boolean"),
|
|
98
|
+
"fallbackToSettings" to PropertySchema(type = "boolean"),
|
|
99
|
+
"includeDetails" to PropertySchema(type = "boolean")
|
|
100
|
+
),
|
|
101
|
+
additionalProperties = false
|
|
102
|
+
),
|
|
103
|
+
|
|
104
|
+
"pickFile" to SchemaDefinition(
|
|
105
|
+
properties = mapOf(
|
|
106
|
+
"mimeType" to PropertySchema(type = "string"),
|
|
107
|
+
"multiple" to PropertySchema(type = "boolean"),
|
|
108
|
+
"minFileSize" to PropertySchema(
|
|
109
|
+
type = "number",
|
|
110
|
+
minimum = 0
|
|
111
|
+
),
|
|
112
|
+
"maxFileSize" to PropertySchema(
|
|
113
|
+
type = "number",
|
|
114
|
+
minimum = 0
|
|
115
|
+
),
|
|
116
|
+
"minFiles" to PropertySchema(
|
|
117
|
+
type = "number",
|
|
118
|
+
minimum = 1
|
|
119
|
+
),
|
|
120
|
+
"maxFiles" to PropertySchema(
|
|
121
|
+
type = "number",
|
|
122
|
+
minimum = 1
|
|
123
|
+
)
|
|
124
|
+
),
|
|
125
|
+
additionalProperties = false
|
|
126
|
+
),
|
|
127
|
+
|
|
128
|
+
"requestHapticFeedback" to SchemaDefinition(
|
|
129
|
+
properties = mapOf(
|
|
130
|
+
"type" to PropertySchema(
|
|
131
|
+
type = "string",
|
|
132
|
+
enum = listOf(
|
|
133
|
+
"light", "medium", "heavy", "selection",
|
|
134
|
+
"impact", "notification", "VIRTUAL_KEY",
|
|
135
|
+
"LONG_PRESS", "DEFAULT"
|
|
136
|
+
)
|
|
137
|
+
),
|
|
138
|
+
"intensity" to PropertySchema(
|
|
139
|
+
type = "number",
|
|
140
|
+
minimum = 0,
|
|
141
|
+
maximum = 1
|
|
142
|
+
)
|
|
143
|
+
),
|
|
144
|
+
required = listOf("type"),
|
|
145
|
+
additionalProperties = false
|
|
146
|
+
),
|
|
147
|
+
|
|
148
|
+
"openFileWithIntent" to SchemaDefinition(
|
|
149
|
+
properties = mapOf(
|
|
150
|
+
"url" to PropertySchema(type = "string"),
|
|
151
|
+
"filename" to PropertySchema(type = "string"),
|
|
152
|
+
"mimeType" to PropertySchema(type = "string"),
|
|
153
|
+
"data" to PropertySchema(type = "string")
|
|
154
|
+
),
|
|
155
|
+
additionalProperties = false
|
|
156
|
+
),
|
|
157
|
+
|
|
158
|
+
"getDeviceInfo" to SchemaDefinition(
|
|
159
|
+
properties = emptyMap(),
|
|
160
|
+
additionalProperties = false
|
|
161
|
+
),
|
|
162
|
+
|
|
163
|
+
"logger" to SchemaDefinition(
|
|
164
|
+
properties = emptyMap(),
|
|
165
|
+
additionalProperties = false
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
// Commands that support flexible parameter formats (string or object)
|
|
170
|
+
// Mirror iOS flexible commands for backward compatibility
|
|
171
|
+
private val flexibleCommands = setOf(
|
|
172
|
+
"openCamera",
|
|
173
|
+
"requestCameraPermission",
|
|
174
|
+
"pickFile",
|
|
175
|
+
"requestHapticFeedback",
|
|
176
|
+
"openFileWithIntent"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
// MARK: - Public Validation Interface
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Validate a bridge message
|
|
183
|
+
* @param body The message body as JSONObject
|
|
184
|
+
* @return BridgeValidationResult with validation status and error details
|
|
185
|
+
*/
|
|
186
|
+
fun validate(body: JSONObject): BridgeValidationResult {
|
|
187
|
+
BridgeUtils.logDebug(TAG, "Starting validation for bridge message")
|
|
188
|
+
|
|
189
|
+
// Step 1: Validate message size
|
|
190
|
+
try {
|
|
191
|
+
val messageSize = body.toString().toByteArray(Charsets.UTF_8).size
|
|
192
|
+
if (messageSize > MAX_MESSAGE_SIZE) {
|
|
193
|
+
BridgeUtils.logError(TAG, "Message size exceeds limit: $messageSize > $MAX_MESSAGE_SIZE")
|
|
194
|
+
return BridgeValidationResult(
|
|
195
|
+
isValid = false,
|
|
196
|
+
command = null,
|
|
197
|
+
params = null,
|
|
198
|
+
body = body,
|
|
199
|
+
error = BridgeValidationError(
|
|
200
|
+
message = "Message too large",
|
|
201
|
+
code = "MESSAGE_TOO_LARGE",
|
|
202
|
+
eventName = "BRIDGE_ERROR"
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
} catch (e: Exception) {
|
|
207
|
+
BridgeUtils.logError(TAG, "Error checking message size", e)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Step 2: Validate root message structure
|
|
211
|
+
val rootValidationResult = validateRootMessageStructure(body)
|
|
212
|
+
if (rootValidationResult == null) {
|
|
213
|
+
return BridgeValidationResult(
|
|
214
|
+
isValid = false,
|
|
215
|
+
command = null,
|
|
216
|
+
params = null,
|
|
217
|
+
body = body,
|
|
218
|
+
error = BridgeValidationError(
|
|
219
|
+
message = "Invalid root message structure",
|
|
220
|
+
code = "INVALID_ROOT_STRUCTURE",
|
|
221
|
+
eventName = "BRIDGE_ERROR"
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
val command = rootValidationResult.first
|
|
227
|
+
val params = rootValidationResult.second
|
|
228
|
+
|
|
229
|
+
// Step 3: Validate command is supported
|
|
230
|
+
if (!validCommands.contains(command)) {
|
|
231
|
+
BridgeUtils.logError(TAG, "Unsupported command: $command")
|
|
232
|
+
return BridgeValidationResult(
|
|
233
|
+
isValid = false,
|
|
234
|
+
command = command,
|
|
235
|
+
params = params,
|
|
236
|
+
body = body,
|
|
237
|
+
error = BridgeValidationError(
|
|
238
|
+
message = "Unsupported command: $command",
|
|
239
|
+
code = "UNSUPPORTED_COMMAND",
|
|
240
|
+
eventName = "BRIDGE_ERROR"
|
|
241
|
+
)
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Step 4: Validate command-specific parameters
|
|
246
|
+
if (params != null) {
|
|
247
|
+
val validationError = validateCommandParameters(command, params)
|
|
248
|
+
if (validationError != null) {
|
|
249
|
+
return BridgeValidationResult(
|
|
250
|
+
isValid = false,
|
|
251
|
+
command = command,
|
|
252
|
+
params = params,
|
|
253
|
+
body = body,
|
|
254
|
+
error = validationError
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
BridgeUtils.logDebug(TAG, "Message validation successful for command: $command")
|
|
260
|
+
return BridgeValidationResult(
|
|
261
|
+
isValid = true,
|
|
262
|
+
command = command,
|
|
263
|
+
params = params,
|
|
264
|
+
body = body,
|
|
265
|
+
error = null
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// MARK: - Private Validation Helpers
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Validate root message structure (command + data fields)
|
|
273
|
+
* @return Pair of (command, params) or null if invalid
|
|
274
|
+
*/
|
|
275
|
+
private fun validateRootMessageStructure(body: JSONObject): Pair<String, Any?>? {
|
|
276
|
+
// Validate required command field
|
|
277
|
+
val command = body.optString("command", "")
|
|
278
|
+
if (command.isEmpty()) {
|
|
279
|
+
BridgeUtils.logError(TAG, "Root message missing 'command' field")
|
|
280
|
+
return null
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Optional: Validate timestamp if present
|
|
284
|
+
if (body.has("timestamp")) {
|
|
285
|
+
val timestamp = body.optString("timestamp")
|
|
286
|
+
if (timestamp.isNotEmpty()) {
|
|
287
|
+
// Basic ISO8601 format check (simplified)
|
|
288
|
+
if (!timestamp.matches(Regex("\\d{4}-\\d{2}-\\d{2}T.*"))) {
|
|
289
|
+
BridgeUtils.logWarning(TAG, "Invalid timestamp format in message: $timestamp")
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Optional: Validate requestId if present
|
|
295
|
+
if (body.has("requestId")) {
|
|
296
|
+
val requestId = body.optString("requestId")
|
|
297
|
+
if (requestId.isEmpty()) {
|
|
298
|
+
BridgeUtils.logWarning(TAG, "Empty requestId in message")
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Extract params from 'data' field
|
|
303
|
+
val params = if (body.has("data")) {
|
|
304
|
+
val data = body.get("data")
|
|
305
|
+
when (data) {
|
|
306
|
+
JSONObject.NULL -> null
|
|
307
|
+
is JSONObject -> data
|
|
308
|
+
is String -> data
|
|
309
|
+
else -> data
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
null
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return Pair(command, params)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Validate command-specific parameters against schema
|
|
320
|
+
*/
|
|
321
|
+
private fun validateCommandParameters(command: String, params: Any): BridgeValidationError? {
|
|
322
|
+
// Handle flexible commands (allow string, object, or null for legacy compatibility)
|
|
323
|
+
if (flexibleCommands.contains(command)) {
|
|
324
|
+
// Allow string or null parameters
|
|
325
|
+
if (params is String || params == null) {
|
|
326
|
+
BridgeUtils.logDebug(TAG, "Command '$command' received string/nil parameters - allowing for legacy compatibility")
|
|
327
|
+
return null
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// If it's an object, validate against schema if available
|
|
331
|
+
if (params is JSONObject) {
|
|
332
|
+
val schema = schemas[command]
|
|
333
|
+
if (schema == null) {
|
|
334
|
+
BridgeUtils.logDebug(TAG, "No schema defined for command: $command, allowing object parameters")
|
|
335
|
+
return null
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return validateObjectAgainstSchema(params, schema, command)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
BridgeUtils.logWarning(TAG, "Command '$command' received unexpected parameter type: ${params.javaClass.simpleName}")
|
|
342
|
+
return null // Allow for backward compatibility
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// For strict commands, require object parameters and validate against schema
|
|
346
|
+
val schema = schemas[command]
|
|
347
|
+
if (schema == null) {
|
|
348
|
+
BridgeUtils.logDebug(TAG, "No schema defined for command: $command, allowing all parameters")
|
|
349
|
+
return null
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (params !is JSONObject) {
|
|
353
|
+
BridgeUtils.logError(TAG, "Parameters for command '$command' must be an object")
|
|
354
|
+
return BridgeValidationError(
|
|
355
|
+
message = "Invalid parameters format for $command",
|
|
356
|
+
code = "INVALID_PARAMS",
|
|
357
|
+
eventName = "BRIDGE_ERROR"
|
|
358
|
+
)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return validateObjectAgainstSchema(params, schema, command)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Validate a JSON object against a schema definition
|
|
366
|
+
*/
|
|
367
|
+
private fun validateObjectAgainstSchema(
|
|
368
|
+
obj: JSONObject,
|
|
369
|
+
schema: SchemaDefinition,
|
|
370
|
+
commandName: String
|
|
371
|
+
): BridgeValidationError? {
|
|
372
|
+
// Validate schema type
|
|
373
|
+
if (schema.type != "object") {
|
|
374
|
+
BridgeUtils.logWarning(TAG, "Schema for $commandName is not of type 'object'")
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Validate required fields
|
|
378
|
+
for (requiredField in schema.required) {
|
|
379
|
+
if (!obj.has(requiredField) || obj.isNull(requiredField)) {
|
|
380
|
+
BridgeUtils.logError(TAG, "Required field '$requiredField' missing for command $commandName")
|
|
381
|
+
return BridgeValidationError(
|
|
382
|
+
message = "Missing required field: $requiredField",
|
|
383
|
+
code = "MISSING_REQUIRED_FIELD",
|
|
384
|
+
eventName = "BRIDGE_ERROR"
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Validate each property
|
|
390
|
+
val keys = obj.keys()
|
|
391
|
+
while (keys.hasNext()) {
|
|
392
|
+
val key = keys.next()
|
|
393
|
+
val value = obj.get(key)
|
|
394
|
+
|
|
395
|
+
if (value == JSONObject.NULL) {
|
|
396
|
+
continue // Skip null values
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
val propertySchema = schema.properties[key]
|
|
400
|
+
if (propertySchema != null) {
|
|
401
|
+
val error = validatePropertyAgainstSchema(value, propertySchema, key, commandName)
|
|
402
|
+
if (error != null) {
|
|
403
|
+
return error
|
|
404
|
+
}
|
|
405
|
+
} else if (!schema.additionalProperties) {
|
|
406
|
+
BridgeUtils.logError(TAG, "Additional property '$key' not allowed for command $commandName")
|
|
407
|
+
return BridgeValidationError(
|
|
408
|
+
message = "Additional property '$key' not allowed",
|
|
409
|
+
code = "ADDITIONAL_PROPERTY_NOT_ALLOWED",
|
|
410
|
+
eventName = "BRIDGE_ERROR"
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (commandName == "pickFile") {
|
|
416
|
+
val minFiles = if (obj.has("minFiles") && !obj.isNull("minFiles")) obj.optInt("minFiles") else null
|
|
417
|
+
val maxFiles = if (obj.has("maxFiles") && !obj.isNull("maxFiles")) obj.optInt("maxFiles") else null
|
|
418
|
+
if (minFiles != null && maxFiles != null && minFiles > maxFiles) {
|
|
419
|
+
BridgeUtils.logError(TAG, "minFiles cannot be greater than maxFiles for pickFile command")
|
|
420
|
+
return BridgeValidationError(
|
|
421
|
+
message = "minFiles cannot be greater than maxFiles",
|
|
422
|
+
code = "INVALID_FILE_PICKER_OPTIONS",
|
|
423
|
+
eventName = "ON_FILE_PICK_ERROR"
|
|
424
|
+
)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
val minFileSize = if (obj.has("minFileSize") && !obj.isNull("minFileSize")) obj.optLong("minFileSize") else null
|
|
428
|
+
val maxFileSize = if (obj.has("maxFileSize") && !obj.isNull("maxFileSize")) obj.optLong("maxFileSize") else null
|
|
429
|
+
if (minFileSize != null && maxFileSize != null && minFileSize > maxFileSize) {
|
|
430
|
+
BridgeUtils.logError(TAG, "minFileSize cannot be greater than maxFileSize for pickFile command")
|
|
431
|
+
return BridgeValidationError(
|
|
432
|
+
message = "minFileSize cannot be greater than maxFileSize",
|
|
433
|
+
code = "INVALID_FILE_PICKER_OPTIONS",
|
|
434
|
+
eventName = "ON_FILE_PICK_ERROR"
|
|
435
|
+
)
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return null
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Validate a single property against its schema
|
|
444
|
+
*/
|
|
445
|
+
private fun validatePropertyAgainstSchema(
|
|
446
|
+
value: Any,
|
|
447
|
+
schema: PropertySchema,
|
|
448
|
+
propertyName: String,
|
|
449
|
+
commandName: String
|
|
450
|
+
): BridgeValidationError? {
|
|
451
|
+
when (schema.type) {
|
|
452
|
+
"string" -> {
|
|
453
|
+
if (value !is String) {
|
|
454
|
+
BridgeUtils.logError(TAG, "Property '$propertyName' must be a string for command $commandName")
|
|
455
|
+
return BridgeValidationError(
|
|
456
|
+
message = "Property '$propertyName' must be a string",
|
|
457
|
+
code = "INVALID_TYPE",
|
|
458
|
+
eventName = "BRIDGE_ERROR"
|
|
459
|
+
)
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Validate enum values
|
|
463
|
+
if (schema.enum != null && !schema.enum.contains(value)) {
|
|
464
|
+
BridgeUtils.logError(TAG, "Property '$propertyName' value '$value' not in allowed enum values")
|
|
465
|
+
return BridgeValidationError(
|
|
466
|
+
message = "Invalid value for $propertyName: $value",
|
|
467
|
+
code = "INVALID_ENUM_VALUE",
|
|
468
|
+
eventName = "BRIDGE_ERROR"
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
"number" -> {
|
|
474
|
+
val numberValue = when (value) {
|
|
475
|
+
is Number -> value.toDouble()
|
|
476
|
+
is String -> value.toDoubleOrNull()
|
|
477
|
+
else -> null
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (numberValue == null) {
|
|
481
|
+
BridgeUtils.logError(TAG, "Property '$propertyName' must be a number for command $commandName")
|
|
482
|
+
return BridgeValidationError(
|
|
483
|
+
message = "Property '$propertyName' must be a number",
|
|
484
|
+
code = "INVALID_TYPE",
|
|
485
|
+
eventName = "BRIDGE_ERROR"
|
|
486
|
+
)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Validate minimum
|
|
490
|
+
if (schema.minimum != null && numberValue < schema.minimum.toDouble()) {
|
|
491
|
+
BridgeUtils.logError(TAG, "Property '$propertyName' value $numberValue is below minimum ${schema.minimum}")
|
|
492
|
+
return BridgeValidationError(
|
|
493
|
+
message = "Value for $propertyName below minimum",
|
|
494
|
+
code = "VALUE_BELOW_MINIMUM",
|
|
495
|
+
eventName = "BRIDGE_ERROR"
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Validate maximum
|
|
500
|
+
if (schema.maximum != null && numberValue > schema.maximum.toDouble()) {
|
|
501
|
+
BridgeUtils.logError(TAG, "Property '$propertyName' value $numberValue is above maximum ${schema.maximum}")
|
|
502
|
+
return BridgeValidationError(
|
|
503
|
+
message = "Value for $propertyName above maximum",
|
|
504
|
+
code = "VALUE_ABOVE_MAXIMUM",
|
|
505
|
+
eventName = "BRIDGE_ERROR"
|
|
506
|
+
)
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
"boolean" -> {
|
|
511
|
+
if (value !is Boolean) {
|
|
512
|
+
BridgeUtils.logError(TAG, "Property '$propertyName' must be a boolean for command $commandName")
|
|
513
|
+
return BridgeValidationError(
|
|
514
|
+
message = "Property '$propertyName' must be a boolean",
|
|
515
|
+
code = "INVALID_TYPE",
|
|
516
|
+
eventName = "BRIDGE_ERROR"
|
|
517
|
+
)
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
else -> {
|
|
522
|
+
BridgeUtils.logWarning(TAG, "Unknown schema type '${schema.type}' for property $propertyName")
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return null
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// MARK: - Schema Management
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Add a custom schema for a command
|
|
533
|
+
*/
|
|
534
|
+
fun addCustomSchema(command: String, schema: SchemaDefinition) {
|
|
535
|
+
// Note: Since schemas is immutable, we'd need to make it mutable if dynamic schemas are needed
|
|
536
|
+
BridgeUtils.logInfo(TAG, "Custom schema support not yet implemented for runtime additions")
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Get all available commands that have schemas
|
|
541
|
+
*/
|
|
542
|
+
fun getAvailableCommands(): Set<String> {
|
|
543
|
+
return schemas.keys
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Check if a command has a schema defined
|
|
548
|
+
*/
|
|
549
|
+
fun hasSchema(command: String): Boolean {
|
|
550
|
+
return schemas.containsKey(command)
|
|
551
|
+
}
|
|
552
|
+
}
|
package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CatalystConstants.kt
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
package io.yourname.androidproject
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CatalystConstants.kt
|
|
5
|
+
* Unified configuration constants for the Android native web bridge
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the iOS-side constants to keep behavior consistent across platforms
|
|
8
|
+
*/
|
|
9
|
+
object CatalystConstants {
|
|
10
|
+
|
|
11
|
+
// MARK: - File Transport
|
|
12
|
+
object FileTransport {
|
|
13
|
+
// Max size to inline over the JS bridge as Base64 (2 MB)
|
|
14
|
+
const val BASE64_SIZE_LIMIT: Long = 2 * 1024 * 1024L
|
|
15
|
+
const val BASE64_SIZE_LIMIT_MB: Int = 2
|
|
16
|
+
|
|
17
|
+
// Max size supported overall via the framework server (100 MB)
|
|
18
|
+
const val FRAMEWORK_SERVER_SIZE_LIMIT: Long = 100 * 1024 * 1024L
|
|
19
|
+
const val FRAMEWORK_SERVER_SIZE_LIMIT_MB: Int = 100
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// MARK: - Image Processing
|
|
23
|
+
object ImageProcessing {
|
|
24
|
+
object Quality {
|
|
25
|
+
const val HIGH: Int = 90
|
|
26
|
+
const val MEDIUM: Int = 70
|
|
27
|
+
const val LOW: Int = 50
|
|
28
|
+
}
|
|
29
|
+
// Default JPEG compression quality
|
|
30
|
+
const val DEFAULT_QUALITY: Int = Quality.MEDIUM
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// MARK: - Network Server (Framework Server)
|
|
34
|
+
object NetworkServer {
|
|
35
|
+
// Port range to probe for starting the local HTTP server
|
|
36
|
+
const val PORT_RANGE_START: Int = 18080
|
|
37
|
+
const val PORT_RANGE_END: Int = 18110
|
|
38
|
+
|
|
39
|
+
// Session/file timeout and cleanup cadence
|
|
40
|
+
const val SESSION_TIMEOUT_MINUTES: Long = 10L // 10 minutes
|
|
41
|
+
const val SESSION_TIMEOUT_MS: Long = SESSION_TIMEOUT_MINUTES * 60 * 1000L
|
|
42
|
+
const val CLEANUP_INTERVAL_SECONDS: Long = 60L // 1 minute
|
|
43
|
+
const val CLEANUP_INTERVAL_MS: Long = CLEANUP_INTERVAL_SECONDS * 1000L
|
|
44
|
+
|
|
45
|
+
// Connection policies
|
|
46
|
+
const val MAX_CONNECTIONS: Int = 16
|
|
47
|
+
const val CONNECTION_TIMEOUT_SECONDS: Int = 30
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// MARK: - Error Codes
|
|
51
|
+
object ErrorCodes {
|
|
52
|
+
const val BAD_REQUEST: Int = 400
|
|
53
|
+
const val FILE_NOT_FOUND: Int = 404
|
|
54
|
+
const val INTERNAL_SERVER_ERROR: Int = 500
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// MARK: - Bridge Limits / Validation
|
|
58
|
+
object Bridge {
|
|
59
|
+
// Safety limit for inbound JS message size (128 KB)
|
|
60
|
+
const val MAX_MESSAGE_SIZE: Int = 128 * 1024
|
|
61
|
+
|
|
62
|
+
// Command execution timeout window
|
|
63
|
+
const val COMMAND_TIMEOUT_SECONDS: Int = 30
|
|
64
|
+
|
|
65
|
+
// Whitelisted commands the bridge will accept
|
|
66
|
+
val VALID_COMMANDS: Set<String> = setOf(
|
|
67
|
+
"openCamera",
|
|
68
|
+
"requestCameraPermission",
|
|
69
|
+
"getDeviceInfo",
|
|
70
|
+
"logger",
|
|
71
|
+
"pickFile",
|
|
72
|
+
"openFileWithIntent",
|
|
73
|
+
"requestHapticFeedback",
|
|
74
|
+
"setScreenSecure",
|
|
75
|
+
"getScreenSecure",
|
|
76
|
+
"clearWebData"
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MARK: - Caching
|
|
81
|
+
object Cache {
|
|
82
|
+
// Fresh/stale windows for SWR behavior
|
|
83
|
+
const val FRESH_WINDOW_SECONDS: Long = 60L // seconds
|
|
84
|
+
const val STALE_WINDOW_SECONDS: Long = 5 * 60L // seconds
|
|
85
|
+
|
|
86
|
+
// URLCache capacities (bytes)
|
|
87
|
+
const val MEMORY_CAPACITY: Long = 10 * 1024 * 1024L // 10 MB
|
|
88
|
+
const val DISK_CAPACITY: Long = 50 * 1024 * 1024L // 50 MB
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// MARK: - File Provider
|
|
92
|
+
object FileProvider {
|
|
93
|
+
const val AUTHORITY: String = "io.yourname.androidproject.fileprovider"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// MARK: - Logging Configuration
|
|
97
|
+
object Logging {
|
|
98
|
+
object Categories {
|
|
99
|
+
const val NATIVE_BRIDGE = "NativeBridge"
|
|
100
|
+
const val BRIDGE_UTILS = "BridgeUtils"
|
|
101
|
+
const val MESSAGE_VALIDATOR = "BridgeMessageValidator"
|
|
102
|
+
const val FILE_UTILS = "FileUtils"
|
|
103
|
+
const val INTENT_UTILS = "IntentUtils"
|
|
104
|
+
const val CAMERA_UTILS = "CameraUtils"
|
|
105
|
+
const val DOWNLOAD_UTILS = "DownloadUtils"
|
|
106
|
+
const val FRAMEWORK_SERVER_UTILS = "FrameworkServerUtils"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|