catalyst-core 0.3.0-beta.4 → 0.3.0-canary.1
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 +80 -0
- 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 +14 -7
- 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 -1
- package/dist/scripts/start.js +8 -1
- 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 +33 -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 +13 -31
- 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 +52 -8
- package/mcp_v2/mcp.js +140 -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 +121 -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 +331 -0
- package/test/server/handler.test.ts +210 -0
- package/test/server/manifestCache.test.ts +71 -0
- package/test/server/render.test.ts +90 -0
- package/test/server/scriptUtils.test.ts +103 -0
- package/test/server/userAgentUtil.test.ts +48 -0
- package/test/server/validator.test.ts +228 -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 -24
- /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,98 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
//
|
|
3
|
+
// Server-side coverage for serverDataFetcher / fetchRouteData (#347).
|
|
4
|
+
//
|
|
5
|
+
// fetchRouteData picks the fetcher like this:
|
|
6
|
+
//
|
|
7
|
+
// let fetcher = component?.default?.clientFetcher
|
|
8
|
+
// if (typeof window === "undefined") {
|
|
9
|
+
// fetcher = component?.default?.serverFetcher
|
|
10
|
+
// }
|
|
11
|
+
//
|
|
12
|
+
// The jsdom-environment tests in RouterDataProvider.test.jsx can only
|
|
13
|
+
// ever exercise the clientFetcher branch, because jsdom always defines
|
|
14
|
+
// `window`. This file runs in the "node" vitest project (no `window`),
|
|
15
|
+
// so it exercises the serverFetcher branch and the client/server
|
|
16
|
+
// precedence rule. Routed here by vitest.config.ts's `*.server.test.*`
|
|
17
|
+
// include/exclude split.
|
|
18
|
+
|
|
19
|
+
import { describe, expect, it, vi } from "vitest"
|
|
20
|
+
import { serverDataFetcher } from "./RouterDataProvider.jsx"
|
|
21
|
+
|
|
22
|
+
// Mirrors the loadable-component contract the production code relies on:
|
|
23
|
+
// `component` is only populated via `route.component.load()`.
|
|
24
|
+
function loadableComponent(mod) {
|
|
25
|
+
return { load: () => Promise.resolve(mod) }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("serverDataFetcher (node environment — serverFetcher branch)", () => {
|
|
29
|
+
it("sanity: this file runs with no `window` global", () => {
|
|
30
|
+
expect(typeof window).toBe("undefined")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("calls a matched route's serverFetcher (not clientFetcher) and keys the result by path", async () => {
|
|
34
|
+
const serverFetcher = vi.fn().mockResolvedValue({ from: "server" })
|
|
35
|
+
const clientFetcher = vi.fn().mockResolvedValue({ from: "client" })
|
|
36
|
+
const routes = [
|
|
37
|
+
{ path: "/page", component: loadableComponent({ default: { serverFetcher, clientFetcher } }) },
|
|
38
|
+
]
|
|
39
|
+
const req = { query: {} }
|
|
40
|
+
|
|
41
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, { some: "arg" })
|
|
42
|
+
const key = Object.keys(result)[0]
|
|
43
|
+
|
|
44
|
+
expect(key).toBe("/page")
|
|
45
|
+
expect(result[key].data).toEqual({ from: "server" })
|
|
46
|
+
expect(result[key].error).toBeNull()
|
|
47
|
+
expect(result[key].fetcherNotAvailable).toBe(false)
|
|
48
|
+
expect(serverFetcher).toHaveBeenCalledWith(
|
|
49
|
+
expect.objectContaining({ route: routes[0] }),
|
|
50
|
+
{ some: "arg" },
|
|
51
|
+
undefined,
|
|
52
|
+
)
|
|
53
|
+
expect(clientFetcher).not.toHaveBeenCalled()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it("records the error and marks isFetched when the serverFetcher throws", async () => {
|
|
57
|
+
const serverFetcher = vi.fn().mockRejectedValue(new Error("upstream 500"))
|
|
58
|
+
const routes = [{ path: "/page", component: loadableComponent({ default: { serverFetcher } }) }]
|
|
59
|
+
const req = { query: {} }
|
|
60
|
+
|
|
61
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
62
|
+
const key = Object.keys(result)[0]
|
|
63
|
+
|
|
64
|
+
expect(result[key].error).toBeInstanceOf(Error)
|
|
65
|
+
expect(result[key].error.message).toBe("upstream 500")
|
|
66
|
+
expect(result[key].isFetched).toBe(true)
|
|
67
|
+
expect(result[key].isFetching).toBe(false)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it("marks fetcherNotAvailable when the matched route has only a clientFetcher (server has no serverFetcher)", async () => {
|
|
71
|
+
const clientFetcher = vi.fn().mockResolvedValue({ from: "client" })
|
|
72
|
+
const routes = [{ path: "/page", component: loadableComponent({ default: { clientFetcher } }) }]
|
|
73
|
+
const req = { query: {} }
|
|
74
|
+
|
|
75
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
76
|
+
const key = Object.keys(result)[0]
|
|
77
|
+
|
|
78
|
+
expect(result[key].fetcherNotAvailable).toBe(true)
|
|
79
|
+
expect(clientFetcher).not.toHaveBeenCalled()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it("returns an empty object when no route matches", async () => {
|
|
83
|
+
const routes = [{ path: "/known", component: loadableComponent({ default: {} }) }]
|
|
84
|
+
const req = { query: {} }
|
|
85
|
+
|
|
86
|
+
const result = await serverDataFetcher({ routes, url: "/unknown", req }, {})
|
|
87
|
+
expect(result).toEqual({})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it("builds the query-string suffix onto the route key from req.query", async () => {
|
|
91
|
+
const serverFetcher = vi.fn().mockResolvedValue({})
|
|
92
|
+
const routes = [{ path: "/page", component: loadableComponent({ default: { serverFetcher } }) }]
|
|
93
|
+
const req = { query: { a: "1", b: "2" } }
|
|
94
|
+
|
|
95
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
96
|
+
expect(Object.keys(result)[0]).toBe("/page?a=1&b=2")
|
|
97
|
+
})
|
|
98
|
+
})
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { describe, expect, it, vi, beforeEach } from "vitest"
|
|
3
|
+
import { act, render, screen, waitFor } from "@testing-library/react"
|
|
4
|
+
import { MemoryRouter, Routes, Route, useRoutes } from "react-router"
|
|
5
|
+
import {
|
|
6
|
+
RouterDataProvider,
|
|
7
|
+
useRouterData,
|
|
8
|
+
useCurrentRouteData,
|
|
9
|
+
serverDataFetcher,
|
|
10
|
+
} from "./RouterDataProvider.jsx"
|
|
11
|
+
|
|
12
|
+
// fetchRouteData (called internally by serverDataFetcher) picks
|
|
13
|
+
// component.default.clientFetcher vs. component.default.serverFetcher
|
|
14
|
+
// based on `typeof window === "undefined"`. Under vitest's jsdom
|
|
15
|
+
// environment, `window` IS defined, so despite the name
|
|
16
|
+
// "serverDataFetcher" these tests exercise the clientFetcher branch --
|
|
17
|
+
// there is no way to hit the serverFetcher branch from this project's
|
|
18
|
+
// jsdom environment (it would need the "node" environment instead, but
|
|
19
|
+
// then rendering/DOM assertions elsewhere in this file wouldn't work).
|
|
20
|
+
// Named clientFetcher in the mocks below to match what's actually
|
|
21
|
+
// invoked, not what the outer function's name implies.
|
|
22
|
+
describe("serverDataFetcher", () => {
|
|
23
|
+
it("returns an empty object when no routes match the given url", async () => {
|
|
24
|
+
const routes = [{ path: "/nowhere", component: {} }]
|
|
25
|
+
const req = { query: {} }
|
|
26
|
+
const result = await serverDataFetcher({ routes, url: "/somewhere-else", req }, {})
|
|
27
|
+
expect(result).toEqual({})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// `component` is only ever populated via `route.component.load()` --
|
|
31
|
+
// a React.lazy-style loadable, not the module itself. A plain object
|
|
32
|
+
// at `route.component` (no `.load` method) leaves `component` as
|
|
33
|
+
// `null` for the entire call, so `component?.default?.clientFetcher`
|
|
34
|
+
// is always undefined regardless of what's on the plain object.
|
|
35
|
+
// Confirmed directly by first writing route.component as a plain
|
|
36
|
+
// `{ default: { clientFetcher } }` object and observing data stay
|
|
37
|
+
// null -- routes here must mimic the loadable shape.
|
|
38
|
+
function loadableComponent(mod) {
|
|
39
|
+
return { load: () => Promise.resolve(mod) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
it("calls a matched route's clientFetcher (jsdom has `window`) and keys the result by path", async () => {
|
|
43
|
+
const clientFetcher = vi.fn().mockResolvedValue({ hello: "world" })
|
|
44
|
+
const routes = [{ path: "/page", component: loadableComponent({ default: { clientFetcher } }) }]
|
|
45
|
+
const req = { query: {} }
|
|
46
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, { some: "arg" })
|
|
47
|
+
const key = Object.keys(result)[0]
|
|
48
|
+
expect(key).toBe("/page")
|
|
49
|
+
expect(result[key].data).toEqual({ hello: "world" })
|
|
50
|
+
expect(result[key].error).toBeNull()
|
|
51
|
+
expect(clientFetcher).toHaveBeenCalledWith(
|
|
52
|
+
expect.objectContaining({ route: routes[0] }),
|
|
53
|
+
{ some: "arg" },
|
|
54
|
+
undefined
|
|
55
|
+
)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it("records the error and marks isFetched when the fetcher throws", async () => {
|
|
59
|
+
const clientFetcher = vi.fn().mockRejectedValue(new Error("network down"))
|
|
60
|
+
const routes = [{ path: "/page", component: loadableComponent({ default: { clientFetcher } }) }]
|
|
61
|
+
const req = { query: {} }
|
|
62
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
63
|
+
const key = Object.keys(result)[0]
|
|
64
|
+
expect(result[key].error).toBeInstanceOf(Error)
|
|
65
|
+
expect(result[key].isFetched).toBe(true)
|
|
66
|
+
expect(result[key].isFetching).toBe(false)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it("marks fetcherNotAvailable when the matched route's component has no fetcher", async () => {
|
|
70
|
+
const routes = [{ path: "/page", component: loadableComponent({ default: {} }) }]
|
|
71
|
+
const req = { query: {} }
|
|
72
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
73
|
+
const key = Object.keys(result)[0]
|
|
74
|
+
expect(result[key].fetcherNotAvailable).toBe(true)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it("marks fetcherNotAvailable when the matched route's component is a plain (non-loadable) object", async () => {
|
|
78
|
+
// route.component without a .load() method leaves `component`
|
|
79
|
+
// null internally -- documents the loadable-only contract.
|
|
80
|
+
const routes = [{ path: "/page", component: { default: { clientFetcher: vi.fn() } } }]
|
|
81
|
+
const req = { query: {} }
|
|
82
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
83
|
+
const key = Object.keys(result)[0]
|
|
84
|
+
expect(result[key].fetcherNotAvailable).toBe(true)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it("builds a query-string suffix onto the route key from req.query", async () => {
|
|
88
|
+
const routes = [{ path: "/page", component: { default: {} } }]
|
|
89
|
+
const req = { query: { a: "1", b: "2" } }
|
|
90
|
+
const result = await serverDataFetcher({ routes, url: "/page", req }, {})
|
|
91
|
+
expect(Object.keys(result)[0]).toBe("/page?a=1&b=2")
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
function Page() {
|
|
96
|
+
const data = useRouterData()
|
|
97
|
+
return <div data-testid="data">{JSON.stringify(data)}</div>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// NOTE: `initialState` must be passed as a real object, not left to
|
|
101
|
+
// default to undefined. Confirmed directly: RouterDataProvider's mount
|
|
102
|
+
// effect reads `routeData[routeKey]?.isFetched` (routeData being the
|
|
103
|
+
// `initialState` passed to useState) -- if `initialState` is omitted,
|
|
104
|
+
// `routeData` is `undefined` on the first render, and `undefined[...]`
|
|
105
|
+
// throws a real TypeError inside the effect. This is a genuine
|
|
106
|
+
// pre-existing gap in RouterDataProvider (no default value / no guard on
|
|
107
|
+
// `initialState`), not a test-authoring workaround -- flagged here
|
|
108
|
+
// rather than silently avoided, since every real usage observed in this
|
|
109
|
+
// codebase does pass a real initialState (hydration data from SSR).
|
|
110
|
+
function renderWithProvider(path = "/") {
|
|
111
|
+
return render(
|
|
112
|
+
<MemoryRouter initialEntries={[path]}>
|
|
113
|
+
<Routes>
|
|
114
|
+
<Route
|
|
115
|
+
path="/"
|
|
116
|
+
element={
|
|
117
|
+
<RouterDataProvider initialState={{}} config={{}}>
|
|
118
|
+
<Page />
|
|
119
|
+
</RouterDataProvider>
|
|
120
|
+
}
|
|
121
|
+
/>
|
|
122
|
+
</Routes>
|
|
123
|
+
</MemoryRouter>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
describe("RouterDataProvider", () => {
|
|
128
|
+
it("renders its children", async () => {
|
|
129
|
+
renderWithProvider()
|
|
130
|
+
await waitFor(() => expect(screen.getByTestId("data")).toBeInTheDocument())
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it("provides a router-data context to useRouterData", async () => {
|
|
134
|
+
renderWithProvider()
|
|
135
|
+
await waitFor(() => {
|
|
136
|
+
const parsed = JSON.parse(screen.getByTestId("data").textContent)
|
|
137
|
+
expect(typeof parsed).toBe("object")
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
describe("useRouterData", () => {
|
|
143
|
+
// NOTE: this does NOT actually throw outside a provider, despite the
|
|
144
|
+
// source's explicit `if (context === undefined) throw ...` guard and
|
|
145
|
+
// its own JSDoc saying "@throws If used outside RouterDataProvider
|
|
146
|
+
// Context". RouterContext is created via `createContext({})`, so
|
|
147
|
+
// useContext(RouterContext) returns `{}` (the default value), never
|
|
148
|
+
// `undefined`, when there's no ancestor provider -- the guard clause
|
|
149
|
+
// is unreachable dead code. Documenting the actual behavior here
|
|
150
|
+
// rather than asserting the documented-but-unreachable throw.
|
|
151
|
+
it("returns the context's default empty object when used outside a RouterDataProvider (documented throw is unreachable)", () => {
|
|
152
|
+
function Bare() {
|
|
153
|
+
const data = useRouterData()
|
|
154
|
+
return <div data-testid="bare">{JSON.stringify(data)}</div>
|
|
155
|
+
}
|
|
156
|
+
render(<Bare />)
|
|
157
|
+
expect(screen.getByTestId("bare")).toHaveTextContent("{}")
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
describe("useCurrentRouteData", () => {
|
|
162
|
+
// Needs a real matched route (UNSAFE_RouteContext.matches populated by
|
|
163
|
+
// react-router's own <Routes>/<Route>) plus a real RouterDataProvider
|
|
164
|
+
// ancestor for OneMgRouterContext's refetchData/clear -- not
|
|
165
|
+
// reasonably mockable in isolation, matching the same
|
|
166
|
+
// real-MemoryRouter approach used for RouterDataProvider itself.
|
|
167
|
+
function CurrentData() {
|
|
168
|
+
const data = useCurrentRouteData()
|
|
169
|
+
return <div data-testid="current">{JSON.stringify(data)}</div>
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function renderAtPage({ initialState = {} } = {}) {
|
|
173
|
+
return render(
|
|
174
|
+
<MemoryRouter initialEntries={["/page"]}>
|
|
175
|
+
<Routes>
|
|
176
|
+
<Route
|
|
177
|
+
path="/page"
|
|
178
|
+
element={
|
|
179
|
+
<RouterDataProvider initialState={initialState} config={{}}>
|
|
180
|
+
<CurrentData />
|
|
181
|
+
</RouterDataProvider>
|
|
182
|
+
}
|
|
183
|
+
/>
|
|
184
|
+
</Routes>
|
|
185
|
+
</MemoryRouter>
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
it("returns the initial (unfetched) data shape when no data has been loaded for the current route yet", async () => {
|
|
190
|
+
renderAtPage()
|
|
191
|
+
await waitFor(() => {
|
|
192
|
+
const parsed = JSON.parse(screen.getByTestId("current").textContent)
|
|
193
|
+
expect(parsed.data).toBeNull()
|
|
194
|
+
expect(parsed.error).toBeNull()
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it("returns previously-fetched data for the current route from initialState", async () => {
|
|
199
|
+
// RouterDataProvider's own mount effect will still run and may
|
|
200
|
+
// overwrite this if the route has no component/fetcher -- but
|
|
201
|
+
// with no `component` on the plain route object here, the
|
|
202
|
+
// fetcher path is never taken, so initialState should be
|
|
203
|
+
// reflected as-is for at least the first render before any
|
|
204
|
+
// effect fires.
|
|
205
|
+
renderAtPage({ initialState: { "/page": { data: { hello: "world" }, error: null, isFetched: true } } })
|
|
206
|
+
await waitFor(() => {
|
|
207
|
+
const parsed = JSON.parse(screen.getByTestId("current").textContent)
|
|
208
|
+
expect(parsed.data).toEqual({ hello: "world" })
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
it("exposes refetch() which re-runs the route fetcher and updates the route data", async () => {
|
|
213
|
+
const clientFetcher = vi.fn().mockResolvedValue({ n: 1 })
|
|
214
|
+
function RefetchPage() {
|
|
215
|
+
const { refetch, data } = useCurrentRouteData()
|
|
216
|
+
return (
|
|
217
|
+
<div>
|
|
218
|
+
<span data-testid="n">{data ? String(data.n) : "none"}</span>
|
|
219
|
+
<button onClick={() => refetch()}>refetch</button>
|
|
220
|
+
</div>
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
render(
|
|
224
|
+
<MemoryRouter initialEntries={["/page"]}>
|
|
225
|
+
<Routes>
|
|
226
|
+
<Route
|
|
227
|
+
path="/page"
|
|
228
|
+
element={
|
|
229
|
+
<RouterDataProvider initialState={{}} config={{}}>
|
|
230
|
+
<RefetchPage />
|
|
231
|
+
</RouterDataProvider>
|
|
232
|
+
}
|
|
233
|
+
// loadable-shaped component so fetchRouteData resolves clientFetcher (jsdom has window)
|
|
234
|
+
/>
|
|
235
|
+
</Routes>
|
|
236
|
+
</MemoryRouter>,
|
|
237
|
+
)
|
|
238
|
+
// route object here has no component -> refetch still runs
|
|
239
|
+
// fetchRouteData (which finds no fetcher) and writes an
|
|
240
|
+
// isFetching->settled cycle without throwing.
|
|
241
|
+
await act(async () => {
|
|
242
|
+
screen.getByText("refetch").click()
|
|
243
|
+
})
|
|
244
|
+
await waitFor(() => expect(screen.getByTestId("n")).toBeInTheDocument())
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it("exposes clear() which resets the current route's data after the given delay", async () => {
|
|
248
|
+
vi.useFakeTimers()
|
|
249
|
+
try {
|
|
250
|
+
let clearFn
|
|
251
|
+
function ClearPage() {
|
|
252
|
+
const { clear } = useCurrentRouteData()
|
|
253
|
+
clearFn = clear
|
|
254
|
+
return <div data-testid="ready">ready</div>
|
|
255
|
+
}
|
|
256
|
+
render(
|
|
257
|
+
<MemoryRouter initialEntries={["/page"]}>
|
|
258
|
+
<Routes>
|
|
259
|
+
<Route
|
|
260
|
+
path="/page"
|
|
261
|
+
element={
|
|
262
|
+
<RouterDataProvider
|
|
263
|
+
initialState={{ "/page": { data: { keep: 1 }, isFetched: true } }}
|
|
264
|
+
config={{}}
|
|
265
|
+
>
|
|
266
|
+
<ClearPage />
|
|
267
|
+
</RouterDataProvider>
|
|
268
|
+
}
|
|
269
|
+
/>
|
|
270
|
+
</Routes>
|
|
271
|
+
</MemoryRouter>,
|
|
272
|
+
)
|
|
273
|
+
expect(typeof clearFn).toBe("function")
|
|
274
|
+
act(() => {
|
|
275
|
+
clearFn(5)
|
|
276
|
+
vi.advanceTimersByTime(5)
|
|
277
|
+
})
|
|
278
|
+
// no throw; the setTimeout callback ran and reset routeData
|
|
279
|
+
expect(screen.getByTestId("ready")).toBeInTheDocument()
|
|
280
|
+
} finally {
|
|
281
|
+
vi.useRealTimers()
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it("re-runs the mount effect for an already-fetched route when config.disableCaching is true (shouldFetch global branch)", async () => {
|
|
286
|
+
// isFetched is true in initialState, but config.disableCaching
|
|
287
|
+
// makes shouldFetch() return true, so the mount effect does not
|
|
288
|
+
// early-return -- it re-enters the fetch path (no fetcher on the
|
|
289
|
+
// plain route -> fetcherNotAvailable, but shouldFetch's global
|
|
290
|
+
// branch is exercised).
|
|
291
|
+
render(
|
|
292
|
+
<MemoryRouter initialEntries={["/page"]}>
|
|
293
|
+
<Routes>
|
|
294
|
+
<Route
|
|
295
|
+
path="/page"
|
|
296
|
+
element={
|
|
297
|
+
<RouterDataProvider
|
|
298
|
+
initialState={{ "/page": { data: { v: 1 }, isFetched: true } }}
|
|
299
|
+
config={{ disableCaching: true }}
|
|
300
|
+
>
|
|
301
|
+
<div data-testid="ready">ready</div>
|
|
302
|
+
</RouterDataProvider>
|
|
303
|
+
}
|
|
304
|
+
/>
|
|
305
|
+
</Routes>
|
|
306
|
+
</MemoryRouter>,
|
|
307
|
+
)
|
|
308
|
+
await waitFor(() => expect(screen.getByTestId("ready")).toBeInTheDocument())
|
|
309
|
+
})
|
|
310
|
+
})
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A dynamic import of a module whose default export is the component to split.
|
|
3
|
+
* Matches the argument React's `lazy` accepts.
|
|
4
|
+
*/
|
|
5
|
+
export type SplitImportFn = () => Promise<any>;
|
|
6
|
+
/**
|
|
7
|
+
* Options accepted by {@link split}.
|
|
8
|
+
*/
|
|
9
|
+
export interface SplitOptions {
|
|
10
|
+
/** Render the component on the server. Defaults to true. Forced on for known crawlers. */
|
|
11
|
+
ssr?: boolean;
|
|
12
|
+
/** Element shown while the chunk loads. Defaults to null. */
|
|
13
|
+
fallback?: any;
|
|
14
|
+
/** IntersectionObserver options for in-view loading (documented; consumed positionally). */
|
|
15
|
+
rootOptions?: any;
|
|
16
|
+
/** Callback fired when the component becomes visible (documented; consumed via props). */
|
|
17
|
+
onVisible?: any;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The component returned by {@link split}. It renders the lazily imported
|
|
21
|
+
* component and additionally carries the route statics copied off the loaded
|
|
22
|
+
* module, plus `load()` for the fetcher contract RouterDataProvider relies on.
|
|
23
|
+
*/
|
|
24
|
+
export interface SplitComponent {
|
|
25
|
+
(props: any): any;
|
|
26
|
+
/** Resolves the underlying module, reusing the in-flight or cached import. */
|
|
27
|
+
load: () => Promise<any>;
|
|
28
|
+
/** Resolved path recorded for SSR asset tracking. */
|
|
29
|
+
__cacheKey?: string;
|
|
30
|
+
clientFetcher?: any;
|
|
31
|
+
serverFetcher?: any;
|
|
32
|
+
setMetaData?: any;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Returns a promise that resolves once every SSR-rendered split component
|
|
36
|
+
* has been prefetched and stored in moduleCache. Call this before
|
|
37
|
+
* hydrateRoot so the first render has all modules available synchronously
|
|
38
|
+
* and no Suspense fallback is shown.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* hydrationReady().then(() => {
|
|
42
|
+
* hydrateRoot(document.getElementById("root"), <App />)
|
|
43
|
+
* })
|
|
44
|
+
*/
|
|
45
|
+
export declare const hydrationReady: () => Promise<any[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Props for the internal Split wrapper. `split()` is the public entry point;
|
|
48
|
+
* this component is an implementation detail of it.
|
|
49
|
+
*/
|
|
50
|
+
interface SplitProps {
|
|
51
|
+
/** Whether to render the component on the server */
|
|
52
|
+
ssr?: boolean;
|
|
53
|
+
/** Fallback component for loading state */
|
|
54
|
+
fallback?: any;
|
|
55
|
+
/** Resolved path for better asset tracking */
|
|
56
|
+
cacheKey?: string;
|
|
57
|
+
rootOptions?: any;
|
|
58
|
+
onVisible?: () => void;
|
|
59
|
+
skipVisibility?: boolean;
|
|
60
|
+
children?: any;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Split component that wraps React's lazy and Suspense for SSR compatibility
|
|
64
|
+
*/
|
|
65
|
+
declare const Split: ({ ssr, fallback, cacheKey, rootOptions, onVisible, skipVisibility, children, }: SplitProps) => any;
|
|
66
|
+
/**
|
|
67
|
+
* Like {@link split}, but forces SSR when the request is a known Google crawler (same UA rules as Head).
|
|
68
|
+
* Use for widgets that are `ssr: false` for humans but must be fully rendered for bots.
|
|
69
|
+
*
|
|
70
|
+
* Prefetch follows `window.__SSR_RENDERED_COMPONENTS__` only (not the `ssr` option) so bot-forced SSR
|
|
71
|
+
* still hydrates without a Suspense flash.
|
|
72
|
+
*/
|
|
73
|
+
export declare const split: (importFn: SplitImportFn, options?: SplitOptions, thirdArg?: any, fourthArg?: any) => SplitComponent;
|
|
74
|
+
export default Split;
|