catalyst-core 0.3.0-beta.5 → 0.3.0-canary.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/changelog.md +185 -71
- package/dist/errors/generateDocs.js +100 -0
- package/dist/errors/index.js +243 -0
- package/dist/errors/registry.js +483 -0
- package/dist/errors-index.json +506 -0
- package/dist/globals.d.ts +62 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.jsx +5 -8
- package/dist/logger.js +1 -1
- package/dist/native/androidProject/app/build.gradle.kts +142 -7
- package/dist/native/androidProject/app/src/main/AndroidManifest.xml +4 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +2 -2
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/BarcodeDetector.kt +3 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/CameraSessionManager.kt +3 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +43 -8
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/BridgeUtilsTest.kt +181 -1
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/CameraUtilsTest.kt +156 -236
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileSizeRouterUtilsTest.kt +471 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileUtilsTest.kt +222 -226
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FrameworkServerUtilsTest.kt +300 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/IntentUtilsTest.kt +244 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/MetricsMonitorTest.kt +359 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NativeBridgeTest.kt +108 -63
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NotificationUtilsTest.kt +329 -385
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/OfflineCacheServiceTest.kt +302 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/PerfEventBufferTest.kt +133 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/UtilsKtTest.kt +152 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/WebCacheManagerTest.kt +145 -324
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/BarcodeDetectorTest.kt +132 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/HoldControllerTest.kt +155 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/TorchControllerTest.kt +150 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/VideoStreamStateMachineTest.kt +120 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/VideoStreamStateTest.kt +62 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/ViewfinderMapperTest.kt +143 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/ZoomControllerTest.kt +421 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/design/DesignTokensTest.kt +207 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/plugins/PluginBridgeTest.kt +368 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/FridaDetectorTest.kt +193 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/SecurityCheckManagerTest.kt +260 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/SecurityCheckSchedulerTest.kt +166 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/DeviceInfoUtilsTest.kt +167 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/DownloadUtilsTest.kt +197 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/NetworkMonitorTest.kt +271 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/PushNotificationUtilsTest.kt +119 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/SafeAreaUtilsTest.kt +108 -0
- package/dist/native/androidProject/build.gradle.kts +1 -0
- package/dist/native/androidProject/gradle/libs.versions.toml +26 -0
- package/dist/native/androidProject/settings.gradle.kts +11 -8
- package/dist/native/androidSetup.js +2 -2
- package/dist/native/bridge/WebBridge.d.ts +98 -0
- package/dist/native/bridge/WebBridge.js +40 -6
- package/dist/native/bridge/constants/NativeInterfaces.d.ts +391 -0
- package/dist/native/bridge/errors.d.ts +67 -0
- package/dist/native/bridge/errors.js +66 -151
- package/dist/native/bridge/hooks/index.d.ts +13 -0
- package/dist/native/bridge/hooks/index.js +0 -6
- package/dist/native/bridge/hooks/useAI.d.ts +1 -0
- package/dist/native/bridge/hooks/useAI.js +3 -1
- package/dist/native/bridge/hooks/useCamera.d.ts +86 -0
- package/dist/native/bridge/hooks/useCamera.js +35 -6
- package/dist/native/bridge/hooks/useDataProtection.d.ts +17 -0
- package/dist/native/bridge/hooks/useDeviceInfo.d.ts +34 -0
- package/dist/native/bridge/hooks/useDeviceInfo.js +5 -0
- package/dist/native/bridge/hooks/useFilePicker.d.ts +53 -0
- package/dist/native/bridge/hooks/useFilePicker.js +13 -0
- package/dist/native/bridge/hooks/useGoogleSignIn.d.ts +12 -0
- package/dist/native/bridge/hooks/useHapticFeedback.d.ts +76 -0
- package/dist/native/bridge/hooks/useHapticFeedback.js +6 -1
- package/dist/native/bridge/hooks/useIntent.d.ts +33 -0
- package/dist/native/bridge/hooks/useIntent.js +2 -0
- package/dist/native/bridge/hooks/useNativeTransition.d.ts +53 -0
- package/dist/native/bridge/hooks/useNativeTransition.js +12 -5
- package/dist/native/bridge/hooks/useNetworkStatus.d.ts +22 -0
- package/dist/native/bridge/hooks/useNetworkStatus.js +7 -0
- package/dist/native/bridge/hooks/useNotification.d.ts +83 -0
- package/dist/native/bridge/hooks/useNotification.js +81 -34
- package/dist/native/bridge/hooks/useSafeArea.d.ts +12 -0
- package/dist/native/bridge/hooks/useSafeArea.js +8 -0
- package/dist/native/bridge/hooks/useVideoStream.d.ts +67 -0
- package/dist/native/bridge/hooks/useVideoStream.js +38 -52
- package/dist/native/bridge/hooks/utils.d.ts +4 -0
- package/dist/native/bridge/hooks.d.ts +1 -0
- package/dist/native/bridge/perf/collectors/ApiCollector.d.ts +30 -0
- package/dist/native/bridge/perf/collectors/ApiCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/CacheCollector.d.ts +43 -0
- package/dist/native/bridge/perf/collectors/CacheCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/HookCollector.d.ts +37 -0
- package/dist/native/bridge/perf/collectors/HookCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/InsightsCollector.d.ts +103 -0
- package/dist/native/bridge/perf/collectors/InsightsCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/InteractionCollector.d.ts +53 -0
- package/dist/native/bridge/perf/collectors/InteractionCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/KeyboardCollector.d.ts +30 -0
- package/dist/native/bridge/perf/collectors/KeyboardCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/NavigationCollector.d.ts +37 -0
- package/dist/native/bridge/perf/collectors/NavigationCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.d.ts +30 -0
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/RenderCollector.d.ts +47 -0
- package/dist/native/bridge/perf/collectors/RenderCollector.js +8 -0
- package/dist/native/bridge/perf/collectors/ScrollCollector.d.ts +29 -0
- package/dist/native/bridge/perf/collectors/ScrollCollector.js +4 -0
- package/dist/native/bridge/perf/collectors/ThreadCollector.d.ts +31 -0
- package/dist/native/bridge/perf/collectors/ThreadCollector.js +4 -0
- package/dist/native/bridge/perf/core/constants.d.ts +76 -0
- package/dist/native/bridge/perf/core/measure.d.ts +39 -0
- package/dist/native/bridge/perf/core/measure.js +4 -0
- package/dist/native/bridge/perf/core/session.d.ts +49 -0
- package/dist/native/bridge/perf/core/session.js +4 -0
- package/dist/native/bridge/perf/core/store.d.ts +37 -0
- package/dist/native/bridge/perf/core/store.js +4 -0
- package/dist/native/bridge/perf/core/summary.d.ts +60 -0
- package/dist/native/bridge/perf/core/traceExport.d.ts +10 -0
- package/dist/native/bridge/perf/core/waterfalls.d.ts +2 -0
- package/dist/native/bridge/perf/index.d.ts +63 -0
- package/dist/native/bridge/perf/index.js +4 -0
- package/dist/native/bridge/safeArea.d.ts +11 -0
- package/dist/native/bridge/safeArea.js +2 -0
- package/dist/native/bridge/useBaseHook.d.ts +137 -0
- package/dist/native/bridge/useBaseHook.js +34 -4
- package/dist/native/bridge/utils/CameraUtils.d.ts +94 -0
- package/dist/native/bridge/utils/CameraUtils.js +4 -0
- package/dist/native/bridge/utils/FileObjectConverter.d.ts +36 -0
- package/dist/native/bridge/utils/NativeBridge.d.ts +270 -0
- package/dist/native/bridge/utils/NativeBridge.js +10 -0
- package/dist/native/buildAndroid/index.js +1 -1
- package/dist/native/buildAppAndroid.js +9 -0
- package/dist/native/buildAppIos.js +16 -1
- package/dist/native/buildErrorFormat.js +57 -0
- package/dist/native/buildIos/config.js +15 -1
- package/dist/native/buildIos/index.js +1 -1
- package/dist/native/buildIos/plugins.js +10 -1
- package/dist/native/iosnativeWebView/CoreLogic/Package.swift +36 -0
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Camera/VideoStreamState.swift +1 -1
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Camera/VideoStreamStateMachine.swift +6 -4
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/BootTimingUtility.swift +3 -3
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/FrameworkServerUtils.swift +14 -9
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NetworkMonitor.swift +11 -9
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NotificationHandlerProvider.swift +1 -1
- package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/URLWhitelistManager.swift +7 -7
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/AnyCodableTests.swift +154 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/BootTimingUtilityTests.swift +23 -5
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/CatalystConstantsTests.swift +192 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/ConfigMappingTests.swift +1 -1
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/FrameworkServerUtilsErrorPathTests.swift +106 -0
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/FrameworkServerUtilsLoopbackTests.swift +243 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/FrameworkServerUtilsTests.swift +1 -1
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/NetworkMonitorTests.swift +119 -0
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/NotificationHandlerProviderTests.swift +59 -0
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/NotificationHandlerTests.swift +1 -1
- package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/URLWhitelistManagerTests.swift +1 -1
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/VideoStreamStateMachineTests.swift +171 -0
- package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/VideoStreamStateTests.swift +91 -0
- package/dist/native/iosnativeWebView/Package.swift +10 -9
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/LocalNotificationHandler.swift +7 -2
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/NotificationManager.swift +1 -2
- package/dist/native/iosnativeWebView/Sources/CatalystNotifications/PushNotificationHandler.swift +5 -4
- package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraSessionManager.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Camera/HoldController.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Camera/NativeCameraManager.swift +6 -5
- package/dist/native/iosnativeWebView/Sources/Core/Camera/ZoomController.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Plugins/PluginBridge.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/CacheManager.swift +31 -30
- package/dist/native/iosnativeWebView/Sources/Core/Utils/CameraTransportUtils.swift +2 -1
- package/dist/native/iosnativeWebView/Sources/Core/Utils/DeviceInfoUtils.swift +1 -1
- package/dist/native/iosnativeWebView/Sources/Core/Utils/FilePickerHandler.swift +22 -19
- package/dist/native/iosnativeWebView/Sources/Core/Utils/ImageHandler.swift +40 -39
- package/dist/native/iosnativeWebView/Sources/Core/Utils/PerfEventBuffer.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/ResourceURLProtocol.swift +15 -15
- package/dist/native/iosnativeWebView/Sources/Core/Utils/WebKitConfig.swift +4 -3
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeCommandHandler.swift +6 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeDelegateHandler.swift +1 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeFileHandler.swift +2 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeJavaScriptInterface.swift +2 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +3 -5
- package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +20 -13
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashView.swift +6 -5
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashViewModel.swift +14 -13
- package/dist/native/iosnativeWebView/Sources/Core/WebView/TransitionManager.swift +3 -3
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +9 -8
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewModel.swift +7 -6
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +24 -25
- package/dist/native/iosnativeWebView/iosnativeWebView/AppDelegate.swift +6 -1
- package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +1 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/iosnativeWebViewApp.swift +4 -0
- package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +2 -22
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeMessageValidatorTests.swift +1 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/CacheManagerTests.swift +1 -0
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/FilePickerHandlerTests.swift +2 -1
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/NativeBridgeTests.swift +15 -9
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/WebViewTests.swift +1 -0
- package/dist/native/setupEmulatorIos.js +2 -2
- package/dist/native/terminalProgress.js +17 -17
- package/dist/router/ClientRouter.d.ts +8 -0
- package/dist/router/ClientRouter.js +13 -11
- package/dist/router/ServerRouter.d.ts +13 -0
- package/dist/router/ServerRouter.js +19 -7
- package/dist/scripts/build.js +14 -2
- package/dist/scripts/loadEnvironmentVariables.js +3 -2
- package/dist/scripts/plugins.js +1 -1
- package/dist/scripts/preServerInit.js +49 -3
- package/dist/scripts/preflight.js +111 -0
- package/dist/scripts/scriptUtils.js +46 -1
- package/dist/scripts/serve.js +7 -3
- package/dist/scripts/start.js +8 -3
- package/dist/server/expressServer.d.ts +1 -0
- package/dist/server/expressServer.js +247 -271
- package/dist/server/manifestCache.d.ts +2 -0
- package/dist/server/manifestCache.js +25 -33
- package/dist/server/renderer/ChunkExtractor.d.ts +44 -0
- package/dist/server/renderer/ChunkExtractor.js +113 -125
- package/dist/server/renderer/document/Body.d.ts +21 -0
- package/dist/server/renderer/document/Body.jsx +45 -45
- package/dist/server/renderer/document/FastRefresh.d.ts +3 -0
- package/dist/server/renderer/document/FastRefresh.jsx +7 -13
- package/dist/server/renderer/document/Head.d.ts +20 -0
- package/dist/server/renderer/document/Head.jsx +32 -32
- package/dist/server/renderer/document/index.d.ts +2 -0
- package/dist/server/renderer/document/index.jsx +2 -2
- package/dist/server/renderer/extract.d.ts +67 -0
- package/dist/server/renderer/extract.js +92 -89
- package/dist/server/renderer/handler.d.ts +2 -0
- package/dist/server/renderer/handler.jsx +401 -404
- package/dist/server/renderer/index.d.ts +2 -0
- package/dist/server/renderer/index.js +5 -8
- package/dist/server/renderer/render.d.ts +35 -0
- package/dist/server/renderer/render.js +25 -32
- package/dist/server/utils/botDetectionMiddleware.d.ts +1 -0
- package/dist/server/utils/botDetectionMiddleware.js +33 -23
- package/dist/server/utils/cjsRequire.d.ts +8 -0
- package/dist/server/utils/cjsRequire.js +2 -2
- package/dist/server/utils/userAgentUtil.d.ts +7 -0
- package/dist/server/utils/userAgentUtil.js +68 -71
- package/dist/server/utils/validator.d.ts +31 -0
- package/dist/server/utils/validator.js +133 -158
- package/dist/vite/inject-cache-key-plugin.js +3 -27
- package/dist/vite/moduleAliases.js +36 -0
- package/dist/vite/node-loader.mjs +2 -29
- package/dist/vite/resolveDevServerConfig.js +4 -1
- package/dist/vite/vite.config.js +2 -29
- package/dist/web-router/components/MetaTag.d.ts +4 -0
- package/dist/web-router/components/MetaTag.jsx +26 -28
- package/dist/web-router/components/MetaTag.test.jsx +100 -0
- package/dist/web-router/components/RouterDataProvider.d.ts +96 -0
- package/dist/web-router/components/RouterDataProvider.jsx +260 -259
- package/dist/web-router/components/RouterDataProvider.server.test.jsx +98 -0
- package/dist/web-router/components/RouterDataProvider.test.jsx +310 -0
- package/dist/web-router/components/Split.d.ts +74 -0
- package/dist/web-router/components/Split.jsx +147 -156
- package/dist/web-router/components/Split.server.test.jsx +52 -0
- package/dist/web-router/components/Split.test.jsx +167 -0
- package/dist/web-router/components/SplitInview.d.ts +22 -0
- package/dist/web-router/components/SplitInview.jsx +78 -89
- package/dist/web-router/components/SplitInview.test.jsx +112 -0
- package/dist/web-router/components/SsrRequestContext.d.ts +20 -0
- package/dist/web-router/components/SsrRequestContext.jsx +17 -7
- package/dist/web-router/components/SsrRequestContext.test.jsx +53 -0
- package/dist/web-router/context.d.ts +15 -0
- package/dist/web-router/context.jsx +5 -5
- package/dist/web-router/context.test.jsx +10 -0
- package/dist/web-router/utils/metaDataUtils.d.ts +24 -0
- package/dist/web-router/utils/metaDataUtils.jsx +86 -86
- package/dist/web-router/utils/metaDataUtils.test.jsx +188 -0
- package/dist/web-router/vitest.setup.js +12 -0
- package/mcp_v2/knowledge-base.json +115 -17
- package/mcp_v2/mcp.js +141 -3
- package/mcp_v2/package-lock.json +2031 -0
- package/mcp_v2/package.json +13 -2
- package/mcp_v2/scripts/copyErrorsIndex.cjs +34 -0
- package/mcp_v2/test/errors.test.ts +123 -0
- package/mcp_v2/test/github.test.ts +177 -0
- package/mcp_v2/tools/errors.d.ts +20 -0
- package/mcp_v2/tools/errors.js +63 -0
- package/mcp_v2/tools/github.d.ts +41 -0
- package/mcp_v2/tools/github.js +231 -0
- package/mcp_v2/vitest.config.mjs +22 -0
- package/package.json +60 -11
- package/test/errors/docsDrift.test.ts +113 -0
- package/test/errors/index.test.ts +200 -0
- package/test/errors/registry.test.ts +108 -0
- package/test/scripts/preflight.test.ts +118 -0
- package/test/server/ChunkExtractor.test.ts +97 -0
- package/test/server/extract.test.ts +128 -0
- package/test/server/fixtures/template/server/document.jsx +19 -0
- package/test/server/fixtures/template/server/index.js +10 -0
- package/test/server/fixtures/template/src/js/containers/App/index.jsx +33 -0
- package/test/server/fixtures/template/src/js/routes/index.jsx +72 -0
- package/test/server/fixtures/template/src/js/routes/utils.jsx +39 -0
- package/test/server/fixtures/template/src/js/store/index.js +19 -0
- package/test/server/handler.assets.test.ts +330 -0
- package/test/server/handler.test.ts +208 -0
- package/test/server/manifestCache.test.ts +71 -0
- package/test/server/render.test.ts +71 -0
- package/test/server/scriptUtils.test.ts +103 -0
- package/test/server/userAgentUtil.test.ts +48 -0
- package/test/server/validator.test.ts +225 -0
- package/test/vite/resolveDevServerConfig.test.js +4 -1
- package/tsconfig.test.json +23 -0
- package/vitest.config.ts +93 -0
- package/dist/caching.js +0 -1
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/DeviceInfoUtilsTest.kt +0 -187
- package/dist/native/bridge/standardizedHooks.js +0 -611
- package/dist/router.js +0 -1
- package/dist/scripts/validator.js +0 -149
- package/dist/web-router/hooks.jsx +0 -72
- package/dist/web-router/types/components/MetaTag.d.ts +0 -2
- package/dist/web-router/types/components/RouterDataProvider.d.ts +0 -95
- package/dist/web-router/types/context.d.ts +0 -14
- package/dist/web-router/types/hooks.d.ts +0 -1
- package/dist/web-router/types/index.d.ts +0 -3
- package/dist/web-router/types/utils/metaDataUtils.d.ts +0 -40
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Constants/CatalystConstants.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Constants/ConfigConstants.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Notifications/NotificationModels.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Protocols/NotificationHandlerProtocol.swift +0 -0
- /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NullNotificationHandler.swift +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const pc = require("ansis");
|
|
4
|
+
|
|
5
|
+
// src/native is a CJS-only subtree (see src/native/package.json) and cannot
|
|
6
|
+
// synchronously require() the ESM errors/index.js module under Node 20, so
|
|
7
|
+
// output-mode formatting for buildAppAndroid.js/buildAppIos.js is
|
|
8
|
+
// hand-rolled here rather than shared with errors/index.js's box/formatVerbose/
|
|
9
|
+
// formatDebug — those two files are the only callers, and both native build
|
|
10
|
+
// failure sites need the same minimal shape.
|
|
11
|
+
|
|
12
|
+
function resolveOutputMode() {
|
|
13
|
+
if (process.argv.includes("--debug")) return "debug";
|
|
14
|
+
if (process.argv.includes("--verbose")) return "verbose";
|
|
15
|
+
return "default";
|
|
16
|
+
}
|
|
17
|
+
function box(bodyLines) {
|
|
18
|
+
const width = 70;
|
|
19
|
+
const top = pc.red(`┌${"─".repeat(width)}`);
|
|
20
|
+
const bottom = pc.red(`└${"─".repeat(width)}`);
|
|
21
|
+
const body = bodyLines.map(line => line === "" ? pc.red("│") : `${pc.red("│")} ${line}`);
|
|
22
|
+
return [top, ...body, bottom].join("\n");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Format a native build failure for terminal output. `code`/`category`
|
|
27
|
+
* identify the generic upstream-toolchain wrapper (ANDROID-000/IOS-000 —
|
|
28
|
+
* see errors/ANDROID/ANDROID-000.md and errors/IOS/IOS-000.md); the
|
|
29
|
+
* upstream message is always shown verbatim, never reinterpreted.
|
|
30
|
+
*/
|
|
31
|
+
function formatBuildError({
|
|
32
|
+
code,
|
|
33
|
+
category,
|
|
34
|
+
upstreamName,
|
|
35
|
+
error
|
|
36
|
+
}) {
|
|
37
|
+
// Xcode/Gradle tooling (via execSync and friends) can reject with a plain
|
|
38
|
+
// string, null, or undefined instead of an Error instance — normalize
|
|
39
|
+
// before touching .message/.stack so a non-Error failure still prints
|
|
40
|
+
// something useful instead of throwing or rendering "undefined".
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
const stack = error instanceof Error ? error.stack || "(no stack available)" : "(no stack available)";
|
|
43
|
+
const mode = resolveOutputMode();
|
|
44
|
+
if (mode === "default") {
|
|
45
|
+
return `[${code}] Build failed (upstream: ${upstreamName})\n→ ${message}`;
|
|
46
|
+
}
|
|
47
|
+
const lines = [`❌ Build failed (upstream: ${upstreamName})`, `Code: ${code}`, `Category: ${category}`, `Time: ${new Date().toISOString()}`, "", `Problem: ${message}`];
|
|
48
|
+
if (mode === "debug") {
|
|
49
|
+
lines.push("", "Environment:", ` node: ${process.version}`, ` platform: ${process.platform}`);
|
|
50
|
+
lines.push("", "Stack trace:", ...stack.split("\n").map(l => ` ${l}`));
|
|
51
|
+
}
|
|
52
|
+
return box(lines);
|
|
53
|
+
}
|
|
54
|
+
module.exports = {
|
|
55
|
+
resolveOutputMode,
|
|
56
|
+
formatBuildError
|
|
57
|
+
};
|
|
@@ -121,15 +121,29 @@ module.exports = function createConfigPhase(ctx) {
|
|
|
121
121
|
async function generateConfigConstants() {
|
|
122
122
|
progress.start("config");
|
|
123
123
|
try {
|
|
124
|
+
// CatalystCoreLogic (#432): ConfigConstants moved into the nested
|
|
125
|
+
// CoreLogic/ package so it can be consumed by swift-test-only code
|
|
126
|
+
// without pulling in UIKit. This generator must write to the new
|
|
127
|
+
// location, not the old Sources/Core/Constants/ path.
|
|
124
128
|
const appConfigPath = path.join(PROJECT_DIR,
|
|
125
129
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - PROJECT_DIR is the fixed generated iOS project directory.
|
|
126
|
-
"Sources", "
|
|
130
|
+
"CoreLogic", "Sources", "CatalystCoreLogic", "Constants", "ConfigConstants.swift");
|
|
127
131
|
const appConfigDir = path.dirname(appConfigPath);
|
|
128
132
|
if (!fs.existsSync(appConfigDir)) fs.mkdirSync(appConfigDir, {
|
|
129
133
|
recursive: true
|
|
130
134
|
});
|
|
135
|
+
|
|
136
|
+
// CatalystCoreLogic's Package.swift declares platforms: [.iOS(.v17),
|
|
137
|
+
// .macOS(.v13)] so `swift test` can run this file on plain macOS (no
|
|
138
|
+
// simulator). UIKit doesn't exist there, so CGFloat needs the same
|
|
139
|
+
// canImport guard already used in the checked-in CatalystConstants.swift.
|
|
131
140
|
let configContent = `// This file is auto-generated. Do not edit.
|
|
132
141
|
import Foundation
|
|
142
|
+
#if canImport(UIKit)
|
|
143
|
+
import UIKit
|
|
144
|
+
#elseif canImport(CoreGraphics)
|
|
145
|
+
import CoreGraphics
|
|
146
|
+
#endif
|
|
133
147
|
|
|
134
148
|
public enum ConfigConstants {
|
|
135
149
|
public static let url = "${url}"`;
|
|
@@ -6,7 +6,7 @@ const {
|
|
|
6
6
|
} = require("child_process");
|
|
7
7
|
const fs = require("fs");
|
|
8
8
|
const path = require("path");
|
|
9
|
-
const TerminalProgress = require("../
|
|
9
|
+
const TerminalProgress = require("../terminalProgress.js").default;
|
|
10
10
|
const createConfigPhase = require("./config.js");
|
|
11
11
|
const createPluginsPhase = require("./plugins.js");
|
|
12
12
|
const createAssetsPhase = require("./assets.js");
|
|
@@ -158,15 +158,23 @@ import PackageDescription
|
|
|
158
158
|
|
|
159
159
|
let package = Package(
|
|
160
160
|
name: "iosnativeWebView",
|
|
161
|
-
platforms: [.iOS(.v17)],
|
|
161
|
+
platforms: [.iOS(.v17), .macOS(.v13)],
|
|
162
162
|
products: [
|
|
163
163
|
.library(name: "CatalystCore", targets: ["CatalystCore"])`;
|
|
164
164
|
if (isNotificationsEnabled) {
|
|
165
165
|
packageContent += `,\n .library(name: "CatalystNotifications", targets: ["CatalystNotifications"])`;
|
|
166
166
|
}
|
|
167
|
+
|
|
168
|
+
// CatalystCoreLogic (#432) is a local nested package (CoreLogic/), not a
|
|
169
|
+
// remote dependency, so it has no `url` and cannot flow through
|
|
170
|
+
// mergePackageDependency/formatSwiftPackageEntries (both keyed on url).
|
|
171
|
+
// Emitted as a literal .package(path:) entry instead. Its own
|
|
172
|
+
// Package.swift is static/checked-in (no config-dependent content), so
|
|
173
|
+
// it is never itself regenerated here.
|
|
167
174
|
packageContent += `
|
|
168
175
|
],
|
|
169
176
|
dependencies: [
|
|
177
|
+
.package(path: "CoreLogic"),
|
|
170
178
|
${formatSwiftPackageEntries(packageDependencies).join(",\n")}
|
|
171
179
|
],
|
|
172
180
|
targets: [
|
|
@@ -175,6 +183,7 @@ ${formatSwiftPackageEntries(packageDependencies).join(",\n")}
|
|
|
175
183
|
.target(
|
|
176
184
|
name: "CatalystCore",
|
|
177
185
|
dependencies: [
|
|
186
|
+
.product(name: "CatalystCoreLogic", package: "CoreLogic"),
|
|
178
187
|
${formatSwiftProductEntries(coreDependencies).join(",\n")}
|
|
179
188
|
],
|
|
180
189
|
path: "Sources/Core"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
// Nested package for UIKit-free logic (#432).
|
|
3
|
+
// Static/checked-in — never generated. Unlike the parent Package.swift,
|
|
4
|
+
// this file has no config-dependent content (no plugin manifests, no
|
|
5
|
+
// notifications gate), so buildIos/plugins.js does not regenerate it.
|
|
6
|
+
//
|
|
7
|
+
// Kept as a genuinely separate SPM package (not a target inside the parent
|
|
8
|
+
// package) because `swift test`/`swift build` at the parent package root
|
|
9
|
+
// always resolves and builds every target in the graph regardless of
|
|
10
|
+
// --target/--filter scoping — verified directly: with CatalystCoreLogic as
|
|
11
|
+
// a target of the parent package, `swift test --filter
|
|
12
|
+
// BootTimingUtilityTests` still compiled CatalystCore and failed on
|
|
13
|
+
// `import UIKit`. A separate package with its own root sidesteps this:
|
|
14
|
+
// `swift test --package-path CoreLogic` only resolves this package's own
|
|
15
|
+
// graph (zero dependencies), never touches the parent package or its
|
|
16
|
+
// UIKit/GoogleSignIn-importing files.
|
|
17
|
+
import PackageDescription
|
|
18
|
+
|
|
19
|
+
let package = Package(
|
|
20
|
+
name: "CatalystCoreLogic",
|
|
21
|
+
platforms: [.iOS(.v17), .macOS(.v13)],
|
|
22
|
+
products: [
|
|
23
|
+
.library(name: "CatalystCoreLogic", targets: ["CatalystCoreLogic"])
|
|
24
|
+
],
|
|
25
|
+
targets: [
|
|
26
|
+
.target(
|
|
27
|
+
name: "CatalystCoreLogic",
|
|
28
|
+
path: "Sources/CatalystCoreLogic"
|
|
29
|
+
),
|
|
30
|
+
.testTarget(
|
|
31
|
+
name: "CatalystCoreLogicTests",
|
|
32
|
+
dependencies: ["CatalystCoreLogic"],
|
|
33
|
+
path: "Tests/CatalystCoreLogicTests"
|
|
34
|
+
)
|
|
35
|
+
]
|
|
36
|
+
)
|
|
@@ -8,19 +8,21 @@ private final class WeakListenerBox {
|
|
|
8
8
|
init(_ value: VideoStreamStateListener) { self.value = value }
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
class VideoStreamStateMachine {
|
|
11
|
+
public class VideoStreamStateMachine {
|
|
12
12
|
|
|
13
13
|
private var _state: VideoStreamState = .idle
|
|
14
14
|
private var listeners: [WeakListenerBox] = []
|
|
15
15
|
private let lock = NSLock()
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
public init() {}
|
|
18
|
+
|
|
19
|
+
public var state: VideoStreamState {
|
|
18
20
|
lock.lock()
|
|
19
21
|
defer { lock.unlock() }
|
|
20
22
|
return _state
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
var isActive: Bool {
|
|
25
|
+
public var isActive: Bool {
|
|
24
26
|
lock.lock()
|
|
25
27
|
defer { lock.unlock() }
|
|
26
28
|
return _state.isActive
|
|
@@ -39,7 +41,7 @@ class VideoStreamStateMachine {
|
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
@discardableResult
|
|
42
|
-
func transition(to next: VideoStreamState) -> Bool {
|
|
44
|
+
public func transition(to next: VideoStreamState) -> Bool {
|
|
43
45
|
lock.lock()
|
|
44
46
|
let prev = _state
|
|
45
47
|
guard prev.canTransitionTo(next) else {
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
import Foundation
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
|
-
enum AppBoot {
|
|
13
|
-
static let nativeStartMs = Int64(ProcessInfo.processInfo.systemUptime * 1000)
|
|
12
|
+
public enum AppBoot {
|
|
13
|
+
public static let nativeStartMs = Int64(ProcessInfo.processInfo.systemUptime * 1000)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
#if DEBUG
|
|
17
17
|
// Global app launch timestamp for all timing measurements
|
|
18
|
-
let APP_LAUNCH_TIME = CFAbsoluteTimeGetCurrent()
|
|
18
|
+
public let APP_LAUNCH_TIME = CFAbsoluteTimeGetCurrent()
|
|
19
19
|
|
|
20
20
|
private let timingLogger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "com.app", category: "Timing")
|
|
21
21
|
|
|
@@ -90,7 +90,7 @@ private class ConnectionWrapper: Hashable {
|
|
|
90
90
|
|
|
91
91
|
// MARK: - Framework Server Utils
|
|
92
92
|
|
|
93
|
-
class FrameworkServerUtils {
|
|
93
|
+
public class FrameworkServerUtils {
|
|
94
94
|
|
|
95
95
|
// Constants from unified configuration
|
|
96
96
|
static let FRAMEWORK_PORT_RANGE_START: UInt16 = CatalystConstants.NetworkServer.portRangeStart
|
|
@@ -98,7 +98,7 @@ class FrameworkServerUtils {
|
|
|
98
98
|
static let SESSION_TIMEOUT_SECONDS: TimeInterval = CatalystConstants.NetworkServer.sessionTimeout
|
|
99
99
|
|
|
100
100
|
// Singleton instance
|
|
101
|
-
static let shared = FrameworkServerUtils()
|
|
101
|
+
public static let shared = FrameworkServerUtils()
|
|
102
102
|
|
|
103
103
|
// Server state
|
|
104
104
|
private var listener: NWListener?
|
|
@@ -134,7 +134,7 @@ class FrameworkServerUtils {
|
|
|
134
134
|
* Initialize and start the framework server
|
|
135
135
|
* @return Boolean indicating success/failure of server startup
|
|
136
136
|
*/
|
|
137
|
-
func startServer() -> Bool {
|
|
137
|
+
public func startServer() -> Bool {
|
|
138
138
|
logger.debug("Starting framework server...")
|
|
139
139
|
|
|
140
140
|
if self.isServerRunning {
|
|
@@ -283,7 +283,7 @@ class FrameworkServerUtils {
|
|
|
283
283
|
* @param mimeType MIME type
|
|
284
284
|
* @return URL where the file can be accessed, or nil if failed
|
|
285
285
|
*/
|
|
286
|
-
func copyAndServeFile(originalFile: URL, fileName: String, mimeType: String) -> String? {
|
|
286
|
+
public func copyAndServeFile(originalFile: URL, fileName: String, mimeType: String) -> String? {
|
|
287
287
|
guard isServerRunning, let cacheDirectory = cacheDirectory else {
|
|
288
288
|
logger.error("Cannot copy and serve file - server not running or cache not initialized")
|
|
289
289
|
return nil
|
|
@@ -328,7 +328,7 @@ class FrameworkServerUtils {
|
|
|
328
328
|
/**
|
|
329
329
|
* Check if server is running
|
|
330
330
|
*/
|
|
331
|
-
func isRunning() -> Bool {
|
|
331
|
+
public func isRunning() -> Bool {
|
|
332
332
|
return isServerRunning
|
|
333
333
|
}
|
|
334
334
|
|
|
@@ -484,10 +484,15 @@ class FrameworkServerUtils {
|
|
|
484
484
|
return nil
|
|
485
485
|
}
|
|
486
486
|
|
|
487
|
-
guard let
|
|
487
|
+
guard let identityAny = firstItem[kSecImportItemIdentity as String],
|
|
488
|
+
CFGetTypeID(identityAny as CFTypeRef) == SecIdentityGetTypeID() else {
|
|
488
489
|
logger.error("No identity found in PKCS#12 import")
|
|
489
490
|
return nil
|
|
490
491
|
}
|
|
492
|
+
let identity = identityAny as! SecIdentity // swiftlint:disable:this force_cast
|
|
493
|
+
// ^ SecIdentity is a CoreFoundation type with no Swift-native
|
|
494
|
+
// bridge; `as?` can't express it. The CFTypeID check above is the
|
|
495
|
+
// real guard.
|
|
491
496
|
|
|
492
497
|
logger.info("✅ Successfully loaded identity from PKCS#12 file")
|
|
493
498
|
return identity
|
|
@@ -502,13 +507,13 @@ class FrameworkServerUtils {
|
|
|
502
507
|
if let identity = loadIdentityFromP12(),
|
|
503
508
|
let secIdentity = sec_identity_create(identity) {
|
|
504
509
|
let tlsOptions = NWProtocolTLS.Options()
|
|
505
|
-
|
|
510
|
+
|
|
506
511
|
// Set the identity
|
|
507
512
|
sec_protocol_options_set_local_identity(tlsOptions.securityProtocolOptions, secIdentity)
|
|
508
|
-
|
|
513
|
+
|
|
509
514
|
// Set minimum TLS version
|
|
510
515
|
sec_protocol_options_set_min_tls_protocol_version(tlsOptions.securityProtocolOptions, .TLSv12)
|
|
511
|
-
|
|
516
|
+
|
|
512
517
|
// Add TLS to the protocol stack
|
|
513
518
|
parameters.defaultProtocolStack.applicationProtocols.insert(tlsOptions, at: 0)
|
|
514
519
|
|
|
@@ -2,13 +2,13 @@ import Foundation
|
|
|
2
2
|
import Network
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
-
struct NetworkStatus {
|
|
6
|
-
let isOnline: Bool
|
|
7
|
-
let type: String?
|
|
5
|
+
public struct NetworkStatus {
|
|
6
|
+
public let isOnline: Bool
|
|
7
|
+
public let type: String?
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
final class NetworkMonitor {
|
|
11
|
-
static let shared = NetworkMonitor()
|
|
10
|
+
public final class NetworkMonitor {
|
|
11
|
+
public static let shared = NetworkMonitor()
|
|
12
12
|
|
|
13
13
|
private let monitor: NWPathMonitor
|
|
14
14
|
private let monitorQueue = DispatchQueue(label: "com.catalyst.network.monitor")
|
|
@@ -32,12 +32,12 @@ final class NetworkMonitor {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
var currentStatus: NetworkStatus {
|
|
35
|
+
public var currentStatus: NetworkStatus {
|
|
36
36
|
stateQueue.sync { latestStatus }
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
@discardableResult
|
|
40
|
-
func addListener(_ listener: @escaping (NetworkStatus) -> Void) -> UUID {
|
|
40
|
+
public func addListener(_ listener: @escaping (NetworkStatus) -> Void) -> UUID {
|
|
41
41
|
let id = UUID()
|
|
42
42
|
|
|
43
43
|
stateQueue.async { [weak self] in
|
|
@@ -55,7 +55,7 @@ final class NetworkMonitor {
|
|
|
55
55
|
return id
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
func removeListener(_ id: UUID) {
|
|
58
|
+
public func removeListener(_ id: UUID) {
|
|
59
59
|
stateQueue.async { [weak self] in
|
|
60
60
|
self?.listeners.removeValue(forKey: id)
|
|
61
61
|
}
|
|
@@ -87,7 +87,9 @@ final class NetworkMonitor {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
private
|
|
90
|
+
// Internal (not private) so @testable import can exercise this pure
|
|
91
|
+
// mapping logic directly without needing a live NWPathMonitor callback.
|
|
92
|
+
static func mapPathToStatus(_ path: NWPath) -> NetworkStatus {
|
|
91
93
|
let isOnline = path.status == .satisfied
|
|
92
94
|
|
|
93
95
|
let type: String?
|
|
@@ -11,7 +11,7 @@ import Foundation
|
|
|
11
11
|
/// Allows the App target to inject the real NotificationManager when notifications are enabled
|
|
12
12
|
public class NotificationHandlerProvider {
|
|
13
13
|
public static var shared: NotificationHandlerProtocol = NullNotificationHandler.shared
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
/// Inject the notification handler at app startup
|
|
16
16
|
/// Call this from the App target when notifications are enabled
|
|
17
17
|
public static func inject(_ handler: NotificationHandlerProtocol) {
|
|
@@ -22,8 +22,8 @@ private struct CategorizedPatterns {
|
|
|
22
22
|
/// - Query parameters and hash fragments are stripped before matching
|
|
23
23
|
/// - Matching is case-insensitive
|
|
24
24
|
/// - Ports are kept as-is (user must include port in pattern if URL has explicit port)
|
|
25
|
-
class URLWhitelistManager {
|
|
26
|
-
static let shared = URLWhitelistManager()
|
|
25
|
+
public class URLWhitelistManager {
|
|
26
|
+
public static let shared = URLWhitelistManager()
|
|
27
27
|
|
|
28
28
|
private var accessControlEnabled: Bool = false
|
|
29
29
|
private var patterns: CategorizedPatterns?
|
|
@@ -66,7 +66,7 @@ class URLWhitelistManager {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/// Check if URL whitelisting is enabled
|
|
69
|
-
var isAccessControlEnabled: Bool {
|
|
69
|
+
public var isAccessControlEnabled: Bool {
|
|
70
70
|
return syncQueue.sync { self.accessControlEnabled }
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -74,7 +74,7 @@ class URLWhitelistManager {
|
|
|
74
74
|
/// If access control is disabled, all URLs are allowed
|
|
75
75
|
/// - Parameter url: The URL to check
|
|
76
76
|
/// - Returns: true if URL is allowed, false otherwise
|
|
77
|
-
func isUrlAllowed(_ url: URL) -> Bool {
|
|
77
|
+
public func isUrlAllowed(_ url: URL) -> Bool {
|
|
78
78
|
return isUrlAllowed(url.absoluteString)
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -82,7 +82,7 @@ class URLWhitelistManager {
|
|
|
82
82
|
/// If access control is disabled, all URLs are allowed
|
|
83
83
|
/// - Parameter urlString: The URL string to check
|
|
84
84
|
/// - Returns: true if URL is allowed, false otherwise
|
|
85
|
-
func isUrlAllowed(_ urlString: String) -> Bool {
|
|
85
|
+
public func isUrlAllowed(_ urlString: String) -> Bool {
|
|
86
86
|
return syncQueue.sync {
|
|
87
87
|
// If access control is disabled, allow everything
|
|
88
88
|
if !self.accessControlEnabled {
|
|
@@ -139,7 +139,7 @@ class URLWhitelistManager {
|
|
|
139
139
|
/// If access control is disabled, nothing is considered external
|
|
140
140
|
/// - Parameter url: The URL to check
|
|
141
141
|
/// - Returns: true if URL is external, false if it's whitelisted
|
|
142
|
-
func isExternalDomain(_ url: URL) -> Bool {
|
|
142
|
+
public func isExternalDomain(_ url: URL) -> Bool {
|
|
143
143
|
return isExternalDomain(url.absoluteString)
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -147,7 +147,7 @@ class URLWhitelistManager {
|
|
|
147
147
|
/// If access control is disabled, nothing is considered external
|
|
148
148
|
/// - Parameter urlString: The URL string to check
|
|
149
149
|
/// - Returns: true if URL is external, false if it's whitelisted
|
|
150
|
-
func isExternalDomain(_ urlString: String) -> Bool {
|
|
150
|
+
public func isExternalDomain(_ urlString: String) -> Bool {
|
|
151
151
|
// If access control is disabled, nothing is external
|
|
152
152
|
if !self.accessControlEnabled {
|
|
153
153
|
return false
|
package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/AnyCodableTests.swift
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import CatalystCoreLogic
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Unit tests for AnyCodable
|
|
6
|
+
*
|
|
7
|
+
* AnyCodable's encode/decode both try a fixed sequence of types (bool, int,
|
|
8
|
+
* double, string, array, dictionary) — these tests exercise every branch of
|
|
9
|
+
* both chains directly, plus the NotificationConfig.data field (the actual
|
|
10
|
+
* production use site) round-tripping through it.
|
|
11
|
+
*/
|
|
12
|
+
final class AnyCodableTests: XCTestCase {
|
|
13
|
+
|
|
14
|
+
// MARK: - Decode: each branch of the type-sniffing chain
|
|
15
|
+
|
|
16
|
+
func testDecode_Bool() throws {
|
|
17
|
+
let json = "true"
|
|
18
|
+
let decoded = try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
19
|
+
XCTAssertEqual(decoded.value as? Bool, true)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func testDecode_Int() throws {
|
|
23
|
+
let json = "42"
|
|
24
|
+
let decoded = try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
25
|
+
XCTAssertEqual(decoded.value as? Int, 42)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
func testDecode_Double() throws {
|
|
29
|
+
let json = "3.14"
|
|
30
|
+
let decoded = try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
31
|
+
XCTAssertEqual(decoded.value as? Double, 3.14)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func testDecode_String() throws {
|
|
35
|
+
let json = "\"hello\""
|
|
36
|
+
let decoded = try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
37
|
+
XCTAssertEqual(decoded.value as? String, "hello")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func testDecode_Array() throws {
|
|
41
|
+
let json = "[1, 2, 3]"
|
|
42
|
+
let decoded = try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
43
|
+
let array = try XCTUnwrap(decoded.value as? [Any])
|
|
44
|
+
XCTAssertEqual(array.count, 3)
|
|
45
|
+
XCTAssertEqual(array[0] as? Int, 1)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func testDecode_Dictionary() throws {
|
|
49
|
+
let json = #"{"key": "value", "count": 5}"#
|
|
50
|
+
let decoded = try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
51
|
+
let dict = try XCTUnwrap(decoded.value as? [String: Any])
|
|
52
|
+
XCTAssertEqual(dict["key"] as? String, "value")
|
|
53
|
+
XCTAssertEqual(dict["count"] as? Int, 5)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func testDecode_UnsupportedType_ThrowsDataCorrupted() {
|
|
57
|
+
// `null` isn't handled by any branch (no explicit null case), so
|
|
58
|
+
// decoding should fail rather than silently succeed with a wrong value.
|
|
59
|
+
let json = "null"
|
|
60
|
+
XCTAssertThrowsError(
|
|
61
|
+
try JSONDecoder().decode(AnyCodable.self, from: Data(json.utf8))
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// MARK: - Encode: each branch of the type-checking chain
|
|
66
|
+
|
|
67
|
+
func testEncode_Bool() throws {
|
|
68
|
+
let encodable = AnyCodable(true)
|
|
69
|
+
let data = try JSONEncoder().encode(encodable)
|
|
70
|
+
XCTAssertEqual(String(data: data, encoding: .utf8), "true")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func testEncode_Int() throws {
|
|
74
|
+
let encodable = AnyCodable(42)
|
|
75
|
+
let data = try JSONEncoder().encode(encodable)
|
|
76
|
+
XCTAssertEqual(String(data: data, encoding: .utf8), "42")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func testEncode_Double() throws {
|
|
80
|
+
let encodable = AnyCodable(3.14)
|
|
81
|
+
let data = try JSONEncoder().encode(encodable)
|
|
82
|
+
XCTAssertEqual(String(data: data, encoding: .utf8), "3.14")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func testEncode_String() throws {
|
|
86
|
+
let encodable = AnyCodable("hello")
|
|
87
|
+
let data = try JSONEncoder().encode(encodable)
|
|
88
|
+
XCTAssertEqual(String(data: data, encoding: .utf8), "\"hello\"")
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func testEncode_Array() throws {
|
|
92
|
+
let encodable = AnyCodable([1, 2, 3])
|
|
93
|
+
let data = try JSONEncoder().encode(encodable)
|
|
94
|
+
let decoded = try JSONSerialization.jsonObject(with: data) as? [Int]
|
|
95
|
+
XCTAssertEqual(decoded, [1, 2, 3])
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func testEncode_Dictionary() throws {
|
|
99
|
+
let encodable = AnyCodable(["key": "value"])
|
|
100
|
+
let data = try JSONEncoder().encode(encodable)
|
|
101
|
+
let decoded = try JSONSerialization.jsonObject(with: data) as? [String: String]
|
|
102
|
+
XCTAssertEqual(decoded, ["key": "value"])
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
func testEncode_UnsupportedType_Throws() {
|
|
106
|
+
struct NotCodableAtAll {}
|
|
107
|
+
let encodable = AnyCodable(NotCodableAtAll())
|
|
108
|
+
XCTAssertThrowsError(try JSONEncoder().encode(encodable))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// MARK: - Round trip via NotificationConfig.data (the real production use site)
|
|
112
|
+
|
|
113
|
+
func testNotificationConfig_DataFieldRoundTripsMixedTypes() throws {
|
|
114
|
+
let config = NotificationConfig(
|
|
115
|
+
title: "Test",
|
|
116
|
+
body: "Body",
|
|
117
|
+
data: [
|
|
118
|
+
"flag": true,
|
|
119
|
+
"count": 7,
|
|
120
|
+
"label": "hello",
|
|
121
|
+
"list": [1, 2, 3],
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
let json = try XCTUnwrap(config.toJSON())
|
|
126
|
+
let restored = try XCTUnwrap(NotificationConfig.fromJSON(json))
|
|
127
|
+
let data = try XCTUnwrap(restored.data)
|
|
128
|
+
|
|
129
|
+
XCTAssertEqual(data["flag"]?.value as? Bool, true)
|
|
130
|
+
XCTAssertEqual(data["count"]?.value as? Int, 7)
|
|
131
|
+
XCTAssertEqual(data["label"]?.value as? String, "hello")
|
|
132
|
+
XCTAssertEqual((data["list"]?.value as? [Any])?.count, 3)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
func testNotificationConfig_NilDataFieldRoundTrips() throws {
|
|
136
|
+
let config = NotificationConfig(title: "Test", body: "Body", data: nil)
|
|
137
|
+
|
|
138
|
+
let json = try XCTUnwrap(config.toJSON())
|
|
139
|
+
let restored = try XCTUnwrap(NotificationConfig.fromJSON(json))
|
|
140
|
+
|
|
141
|
+
XCTAssertNil(restored.data)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
func testNotificationConfig_FromJSON_InvalidJSON_ReturnsNil() {
|
|
145
|
+
XCTAssertNil(NotificationConfig.fromJSON("{not valid json"))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
func testNotificationConfig_FromJSON_NonUTF8_ReturnsNil() {
|
|
149
|
+
// fromJSON's own guard (data(using: .utf8)) is defensive — exercised
|
|
150
|
+
// indirectly since almost all Swift Strings are representable as
|
|
151
|
+
// UTF8. Documented as effectively unreachable in practice, not
|
|
152
|
+
// asserted here.
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import XCTest
|
|
2
2
|
import Foundation
|
|
3
|
-
@testable import
|
|
3
|
+
@testable import CatalystCoreLogic
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Unit tests for BootTimingUtility
|
|
@@ -94,10 +94,17 @@ final class BootTimingUtilityTests: XCTestCase {
|
|
|
94
94
|
XCTAssertGreaterThan(elapsedAfter, elapsedBefore,
|
|
95
95
|
"Elapsed time should increase over time")
|
|
96
96
|
|
|
97
|
-
// Verify the difference is
|
|
97
|
+
// Verify the difference is at least the ~10ms sleep, with a floor
|
|
98
|
+
// to catch a broken/zero calculation. No upper bound: this was
|
|
99
|
+
// previously capped at 50ms "accounting for system load", but
|
|
100
|
+
// that's asserting real OS scheduler latency for Thread.sleep,
|
|
101
|
+
// which a shared/loaded CI runner can legitimately exceed (seen:
|
|
102
|
+
// 62ms) with zero relation to whether APP_LAUNCH_TIME-based
|
|
103
|
+
// elapsed-time math is correct. The floor + the
|
|
104
|
+
// elapsedAfter > elapsedBefore check above already cover the
|
|
105
|
+
// logic this test exists to verify.
|
|
98
106
|
let difference = elapsedAfter - elapsedBefore
|
|
99
107
|
XCTAssertGreaterThan(difference, 5.0, "Time difference should be at least 5ms")
|
|
100
|
-
XCTAssertLessThan(difference, 50.0, "Time difference should be less than 50ms (accounting for system load)")
|
|
101
108
|
#else
|
|
102
109
|
XCTAssertTrue(true, "Skipping DEBUG-only test in RELEASE build")
|
|
103
110
|
#endif
|
|
@@ -193,14 +200,25 @@ final class BootTimingUtilityTests: XCTestCase {
|
|
|
193
200
|
let expectation = self.expectation(description: "Concurrent logging completes")
|
|
194
201
|
expectation.expectedFulfillmentCount = 10
|
|
195
202
|
|
|
203
|
+
// Raising the wait timeout alone did not fix this test: it failed at
|
|
204
|
+
// exactly 10s, then again at exactly 60s after that bump -- a hit-the-
|
|
205
|
+
// timeout-precisely pattern is scheduling starvation, not slowness.
|
|
206
|
+
// `.background` QoS is deliberately deprioritized by the OS and can be
|
|
207
|
+
// starved indefinitely under CPU contention on a busy CI host, so no
|
|
208
|
+
// timeout is safe against it. `.userInitiated` still exercises the
|
|
209
|
+
// thing this test actually verifies (logWithTimestamp handles
|
|
210
|
+
// concurrent calls without crashing/corrupting) without depending on
|
|
211
|
+
// background-priority scheduling ever getting CPU time.
|
|
196
212
|
for i in 0..<10 {
|
|
197
|
-
DispatchQueue.global(qos: .
|
|
213
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
198
214
|
logWithTimestamp("Concurrent log \(i)")
|
|
199
215
|
expectation.fulfill()
|
|
200
216
|
}
|
|
201
217
|
}
|
|
202
218
|
|
|
203
|
-
|
|
219
|
+
// Kept generous as headroom for host variance (~15-20% build/test time
|
|
220
|
+
// swings observed run-to-run on shared CI runners), not as the fix.
|
|
221
|
+
waitForExpectations(timeout: 60.0) { error in
|
|
204
222
|
XCTAssertNil(error, "Concurrent logging should complete without errors")
|
|
205
223
|
}
|
|
206
224
|
}
|