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.
Files changed (316) hide show
  1. package/changelog.md +80 -0
  2. package/dist/errors/generateDocs.js +100 -0
  3. package/dist/errors/index.js +243 -0
  4. package/dist/errors/registry.js +483 -0
  5. package/dist/errors-index.json +506 -0
  6. package/dist/globals.d.ts +62 -0
  7. package/dist/index.d.ts +5 -0
  8. package/dist/index.jsx +5 -8
  9. package/dist/logger.js +1 -1
  10. package/dist/native/androidProject/app/build.gradle.kts +142 -7
  11. package/dist/native/androidProject/app/src/main/AndroidManifest.xml +4 -0
  12. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +2 -2
  13. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/BarcodeDetector.kt +3 -0
  14. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/CameraSessionManager.kt +3 -0
  15. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +43 -8
  16. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/BridgeUtilsTest.kt +181 -1
  17. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/CameraUtilsTest.kt +156 -236
  18. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileSizeRouterUtilsTest.kt +471 -0
  19. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FileUtilsTest.kt +222 -226
  20. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/FrameworkServerUtilsTest.kt +300 -0
  21. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/IntentUtilsTest.kt +244 -0
  22. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/MetricsMonitorTest.kt +359 -0
  23. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NativeBridgeTest.kt +108 -63
  24. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/NotificationUtilsTest.kt +329 -385
  25. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/OfflineCacheServiceTest.kt +302 -0
  26. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/PerfEventBufferTest.kt +133 -0
  27. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/UtilsKtTest.kt +152 -0
  28. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/WebCacheManagerTest.kt +145 -324
  29. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/BarcodeDetectorTest.kt +132 -0
  30. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/HoldControllerTest.kt +155 -0
  31. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/TorchControllerTest.kt +150 -0
  32. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/VideoStreamStateMachineTest.kt +120 -0
  33. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/VideoStreamStateTest.kt +62 -0
  34. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/ViewfinderMapperTest.kt +143 -0
  35. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/camera/ZoomControllerTest.kt +421 -0
  36. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/design/DesignTokensTest.kt +207 -0
  37. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/plugins/PluginBridgeTest.kt +368 -0
  38. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/FridaDetectorTest.kt +193 -0
  39. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/SecurityCheckManagerTest.kt +260 -0
  40. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/security/SecurityCheckSchedulerTest.kt +166 -0
  41. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/DeviceInfoUtilsTest.kt +167 -0
  42. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/DownloadUtilsTest.kt +197 -0
  43. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/NetworkMonitorTest.kt +271 -0
  44. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/PushNotificationUtilsTest.kt +119 -0
  45. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/utils/SafeAreaUtilsTest.kt +108 -0
  46. package/dist/native/androidProject/build.gradle.kts +1 -0
  47. package/dist/native/androidProject/gradle/libs.versions.toml +26 -0
  48. package/dist/native/androidProject/settings.gradle.kts +11 -8
  49. package/dist/native/androidSetup.js +2 -2
  50. package/dist/native/bridge/WebBridge.d.ts +98 -0
  51. package/dist/native/bridge/WebBridge.js +40 -6
  52. package/dist/native/bridge/constants/NativeInterfaces.d.ts +391 -0
  53. package/dist/native/bridge/errors.d.ts +67 -0
  54. package/dist/native/bridge/errors.js +66 -151
  55. package/dist/native/bridge/hooks/index.d.ts +13 -0
  56. package/dist/native/bridge/hooks/index.js +0 -6
  57. package/dist/native/bridge/hooks/useAI.d.ts +1 -0
  58. package/dist/native/bridge/hooks/useAI.js +3 -1
  59. package/dist/native/bridge/hooks/useCamera.d.ts +86 -0
  60. package/dist/native/bridge/hooks/useCamera.js +35 -6
  61. package/dist/native/bridge/hooks/useDataProtection.d.ts +17 -0
  62. package/dist/native/bridge/hooks/useDeviceInfo.d.ts +34 -0
  63. package/dist/native/bridge/hooks/useDeviceInfo.js +5 -0
  64. package/dist/native/bridge/hooks/useFilePicker.d.ts +53 -0
  65. package/dist/native/bridge/hooks/useFilePicker.js +13 -0
  66. package/dist/native/bridge/hooks/useGoogleSignIn.d.ts +12 -0
  67. package/dist/native/bridge/hooks/useHapticFeedback.d.ts +76 -0
  68. package/dist/native/bridge/hooks/useHapticFeedback.js +6 -1
  69. package/dist/native/bridge/hooks/useIntent.d.ts +33 -0
  70. package/dist/native/bridge/hooks/useIntent.js +2 -0
  71. package/dist/native/bridge/hooks/useNativeTransition.d.ts +53 -0
  72. package/dist/native/bridge/hooks/useNativeTransition.js +14 -7
  73. package/dist/native/bridge/hooks/useNetworkStatus.d.ts +22 -0
  74. package/dist/native/bridge/hooks/useNetworkStatus.js +7 -0
  75. package/dist/native/bridge/hooks/useNotification.d.ts +83 -0
  76. package/dist/native/bridge/hooks/useNotification.js +81 -34
  77. package/dist/native/bridge/hooks/useSafeArea.d.ts +12 -0
  78. package/dist/native/bridge/hooks/useSafeArea.js +8 -0
  79. package/dist/native/bridge/hooks/useVideoStream.d.ts +67 -0
  80. package/dist/native/bridge/hooks/useVideoStream.js +38 -52
  81. package/dist/native/bridge/hooks/utils.d.ts +4 -0
  82. package/dist/native/bridge/hooks.d.ts +1 -0
  83. package/dist/native/bridge/perf/collectors/ApiCollector.d.ts +30 -0
  84. package/dist/native/bridge/perf/collectors/ApiCollector.js +4 -0
  85. package/dist/native/bridge/perf/collectors/CacheCollector.d.ts +43 -0
  86. package/dist/native/bridge/perf/collectors/CacheCollector.js +4 -0
  87. package/dist/native/bridge/perf/collectors/HookCollector.d.ts +37 -0
  88. package/dist/native/bridge/perf/collectors/HookCollector.js +4 -0
  89. package/dist/native/bridge/perf/collectors/InsightsCollector.d.ts +103 -0
  90. package/dist/native/bridge/perf/collectors/InsightsCollector.js +4 -0
  91. package/dist/native/bridge/perf/collectors/InteractionCollector.d.ts +53 -0
  92. package/dist/native/bridge/perf/collectors/InteractionCollector.js +4 -0
  93. package/dist/native/bridge/perf/collectors/KeyboardCollector.d.ts +30 -0
  94. package/dist/native/bridge/perf/collectors/KeyboardCollector.js +4 -0
  95. package/dist/native/bridge/perf/collectors/NavigationCollector.d.ts +37 -0
  96. package/dist/native/bridge/perf/collectors/NavigationCollector.js +4 -0
  97. package/dist/native/bridge/perf/collectors/NetworkTimingCollector.d.ts +30 -0
  98. package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +4 -0
  99. package/dist/native/bridge/perf/collectors/RenderCollector.d.ts +47 -0
  100. package/dist/native/bridge/perf/collectors/RenderCollector.js +8 -0
  101. package/dist/native/bridge/perf/collectors/ScrollCollector.d.ts +29 -0
  102. package/dist/native/bridge/perf/collectors/ScrollCollector.js +4 -0
  103. package/dist/native/bridge/perf/collectors/ThreadCollector.d.ts +31 -0
  104. package/dist/native/bridge/perf/collectors/ThreadCollector.js +4 -0
  105. package/dist/native/bridge/perf/core/constants.d.ts +76 -0
  106. package/dist/native/bridge/perf/core/measure.d.ts +39 -0
  107. package/dist/native/bridge/perf/core/measure.js +4 -0
  108. package/dist/native/bridge/perf/core/session.d.ts +49 -0
  109. package/dist/native/bridge/perf/core/session.js +4 -0
  110. package/dist/native/bridge/perf/core/store.d.ts +37 -0
  111. package/dist/native/bridge/perf/core/store.js +4 -0
  112. package/dist/native/bridge/perf/core/summary.d.ts +60 -0
  113. package/dist/native/bridge/perf/core/traceExport.d.ts +10 -0
  114. package/dist/native/bridge/perf/core/waterfalls.d.ts +2 -0
  115. package/dist/native/bridge/perf/index.d.ts +63 -0
  116. package/dist/native/bridge/perf/index.js +4 -0
  117. package/dist/native/bridge/safeArea.d.ts +11 -0
  118. package/dist/native/bridge/safeArea.js +2 -0
  119. package/dist/native/bridge/useBaseHook.d.ts +137 -0
  120. package/dist/native/bridge/useBaseHook.js +34 -4
  121. package/dist/native/bridge/utils/CameraUtils.d.ts +94 -0
  122. package/dist/native/bridge/utils/CameraUtils.js +4 -0
  123. package/dist/native/bridge/utils/FileObjectConverter.d.ts +36 -0
  124. package/dist/native/bridge/utils/NativeBridge.d.ts +270 -0
  125. package/dist/native/bridge/utils/NativeBridge.js +10 -0
  126. package/dist/native/buildAndroid/index.js +1 -1
  127. package/dist/native/buildAppAndroid.js +9 -0
  128. package/dist/native/buildAppIos.js +16 -1
  129. package/dist/native/buildErrorFormat.js +57 -0
  130. package/dist/native/buildIos/config.js +15 -1
  131. package/dist/native/buildIos/index.js +1 -1
  132. package/dist/native/buildIos/plugins.js +10 -1
  133. package/dist/native/iosnativeWebView/CoreLogic/Package.swift +36 -0
  134. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Camera/VideoStreamState.swift +1 -1
  135. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Camera/VideoStreamStateMachine.swift +6 -4
  136. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/BootTimingUtility.swift +3 -3
  137. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/FrameworkServerUtils.swift +14 -9
  138. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NetworkMonitor.swift +11 -9
  139. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NotificationHandlerProvider.swift +1 -1
  140. package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/URLWhitelistManager.swift +7 -7
  141. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/AnyCodableTests.swift +154 -0
  142. package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/BootTimingUtilityTests.swift +23 -5
  143. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/CatalystConstantsTests.swift +192 -0
  144. package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/ConfigMappingTests.swift +1 -1
  145. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/FrameworkServerUtilsErrorPathTests.swift +106 -0
  146. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/FrameworkServerUtilsLoopbackTests.swift +243 -0
  147. package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/FrameworkServerUtilsTests.swift +1 -1
  148. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/NetworkMonitorTests.swift +119 -0
  149. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/NotificationHandlerProviderTests.swift +59 -0
  150. package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/NotificationHandlerTests.swift +1 -1
  151. package/dist/native/iosnativeWebView/{iosnativeWebViewTests → CoreLogic/Tests/CatalystCoreLogicTests}/URLWhitelistManagerTests.swift +1 -1
  152. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/VideoStreamStateMachineTests.swift +171 -0
  153. package/dist/native/iosnativeWebView/CoreLogic/Tests/CatalystCoreLogicTests/VideoStreamStateTests.swift +91 -0
  154. package/dist/native/iosnativeWebView/Package.swift +10 -9
  155. package/dist/native/iosnativeWebView/Sources/CatalystNotifications/LocalNotificationHandler.swift +7 -2
  156. package/dist/native/iosnativeWebView/Sources/CatalystNotifications/NotificationManager.swift +1 -2
  157. package/dist/native/iosnativeWebView/Sources/CatalystNotifications/PushNotificationHandler.swift +5 -4
  158. package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraSessionManager.swift +1 -0
  159. package/dist/native/iosnativeWebView/Sources/Core/Camera/HoldController.swift +1 -0
  160. package/dist/native/iosnativeWebView/Sources/Core/Camera/NativeCameraManager.swift +6 -5
  161. package/dist/native/iosnativeWebView/Sources/Core/Camera/ZoomController.swift +1 -0
  162. package/dist/native/iosnativeWebView/Sources/Core/Plugins/PluginBridge.swift +1 -0
  163. package/dist/native/iosnativeWebView/Sources/Core/Utils/CacheManager.swift +31 -30
  164. package/dist/native/iosnativeWebView/Sources/Core/Utils/CameraTransportUtils.swift +2 -1
  165. package/dist/native/iosnativeWebView/Sources/Core/Utils/DeviceInfoUtils.swift +1 -1
  166. package/dist/native/iosnativeWebView/Sources/Core/Utils/FilePickerHandler.swift +22 -19
  167. package/dist/native/iosnativeWebView/Sources/Core/Utils/ImageHandler.swift +40 -39
  168. package/dist/native/iosnativeWebView/Sources/Core/Utils/PerfEventBuffer.swift +1 -0
  169. package/dist/native/iosnativeWebView/Sources/Core/Utils/ResourceURLProtocol.swift +15 -15
  170. package/dist/native/iosnativeWebView/Sources/Core/Utils/WebKitConfig.swift +4 -3
  171. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeCommandHandler.swift +6 -1
  172. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeDelegateHandler.swift +1 -0
  173. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeFileHandler.swift +2 -1
  174. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeJavaScriptInterface.swift +2 -1
  175. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +3 -5
  176. package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +20 -13
  177. package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashView.swift +6 -5
  178. package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashViewModel.swift +14 -13
  179. package/dist/native/iosnativeWebView/Sources/Core/WebView/TransitionManager.swift +3 -3
  180. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +9 -8
  181. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewModel.swift +7 -6
  182. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +24 -25
  183. package/dist/native/iosnativeWebView/iosnativeWebView/AppDelegate.swift +6 -1
  184. package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +1 -0
  185. package/dist/native/iosnativeWebView/iosnativeWebView/iosnativeWebViewApp.swift +4 -0
  186. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +2 -22
  187. package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeMessageValidatorTests.swift +1 -0
  188. package/dist/native/iosnativeWebView/iosnativeWebViewTests/CacheManagerTests.swift +1 -0
  189. package/dist/native/iosnativeWebView/iosnativeWebViewTests/FilePickerHandlerTests.swift +2 -1
  190. package/dist/native/iosnativeWebView/iosnativeWebViewTests/NativeBridgeTests.swift +15 -9
  191. package/dist/native/iosnativeWebView/iosnativeWebViewTests/WebViewTests.swift +1 -0
  192. package/dist/native/setupEmulatorIos.js +2 -2
  193. package/dist/native/terminalProgress.js +17 -17
  194. package/dist/router/ClientRouter.d.ts +8 -0
  195. package/dist/router/ClientRouter.js +13 -11
  196. package/dist/router/ServerRouter.d.ts +13 -0
  197. package/dist/router/ServerRouter.js +19 -7
  198. package/dist/scripts/build.js +14 -2
  199. package/dist/scripts/loadEnvironmentVariables.js +3 -2
  200. package/dist/scripts/plugins.js +1 -1
  201. package/dist/scripts/preServerInit.js +49 -3
  202. package/dist/scripts/preflight.js +111 -0
  203. package/dist/scripts/scriptUtils.js +46 -1
  204. package/dist/scripts/serve.js +7 -1
  205. package/dist/scripts/start.js +8 -1
  206. package/dist/server/expressServer.d.ts +1 -0
  207. package/dist/server/expressServer.js +247 -271
  208. package/dist/server/manifestCache.d.ts +2 -0
  209. package/dist/server/manifestCache.js +25 -33
  210. package/dist/server/renderer/ChunkExtractor.d.ts +44 -0
  211. package/dist/server/renderer/ChunkExtractor.js +113 -125
  212. package/dist/server/renderer/document/Body.d.ts +21 -0
  213. package/dist/server/renderer/document/Body.jsx +45 -45
  214. package/dist/server/renderer/document/FastRefresh.d.ts +3 -0
  215. package/dist/server/renderer/document/FastRefresh.jsx +7 -13
  216. package/dist/server/renderer/document/Head.d.ts +20 -0
  217. package/dist/server/renderer/document/Head.jsx +32 -32
  218. package/dist/server/renderer/document/index.d.ts +2 -0
  219. package/dist/server/renderer/document/index.jsx +2 -2
  220. package/dist/server/renderer/extract.d.ts +67 -0
  221. package/dist/server/renderer/extract.js +92 -89
  222. package/dist/server/renderer/handler.d.ts +2 -0
  223. package/dist/server/renderer/handler.jsx +401 -404
  224. package/dist/server/renderer/index.d.ts +2 -0
  225. package/dist/server/renderer/index.js +5 -8
  226. package/dist/server/renderer/render.d.ts +35 -0
  227. package/dist/server/renderer/render.js +33 -32
  228. package/dist/server/utils/botDetectionMiddleware.d.ts +1 -0
  229. package/dist/server/utils/botDetectionMiddleware.js +33 -23
  230. package/dist/server/utils/cjsRequire.d.ts +8 -0
  231. package/dist/server/utils/cjsRequire.js +2 -2
  232. package/dist/server/utils/userAgentUtil.d.ts +7 -0
  233. package/dist/server/utils/userAgentUtil.js +68 -71
  234. package/dist/server/utils/validator.d.ts +31 -0
  235. package/dist/server/utils/validator.js +133 -158
  236. package/dist/vite/inject-cache-key-plugin.js +3 -27
  237. package/dist/vite/moduleAliases.js +36 -0
  238. package/dist/vite/node-loader.mjs +2 -29
  239. package/dist/vite/resolveDevServerConfig.js +4 -1
  240. package/dist/vite/vite.config.js +13 -31
  241. package/dist/web-router/components/MetaTag.d.ts +4 -0
  242. package/dist/web-router/components/MetaTag.jsx +26 -28
  243. package/dist/web-router/components/MetaTag.test.jsx +100 -0
  244. package/dist/web-router/components/RouterDataProvider.d.ts +96 -0
  245. package/dist/web-router/components/RouterDataProvider.jsx +260 -259
  246. package/dist/web-router/components/RouterDataProvider.server.test.jsx +98 -0
  247. package/dist/web-router/components/RouterDataProvider.test.jsx +310 -0
  248. package/dist/web-router/components/Split.d.ts +74 -0
  249. package/dist/web-router/components/Split.jsx +147 -156
  250. package/dist/web-router/components/Split.server.test.jsx +52 -0
  251. package/dist/web-router/components/Split.test.jsx +167 -0
  252. package/dist/web-router/components/SplitInview.d.ts +22 -0
  253. package/dist/web-router/components/SplitInview.jsx +78 -89
  254. package/dist/web-router/components/SplitInview.test.jsx +112 -0
  255. package/dist/web-router/components/SsrRequestContext.d.ts +20 -0
  256. package/dist/web-router/components/SsrRequestContext.jsx +17 -7
  257. package/dist/web-router/components/SsrRequestContext.test.jsx +53 -0
  258. package/dist/web-router/context.d.ts +15 -0
  259. package/dist/web-router/context.jsx +5 -5
  260. package/dist/web-router/context.test.jsx +10 -0
  261. package/dist/web-router/utils/metaDataUtils.d.ts +24 -0
  262. package/dist/web-router/utils/metaDataUtils.jsx +86 -86
  263. package/dist/web-router/utils/metaDataUtils.test.jsx +188 -0
  264. package/dist/web-router/vitest.setup.js +12 -0
  265. package/mcp_v2/knowledge-base.json +52 -8
  266. package/mcp_v2/mcp.js +140 -3
  267. package/mcp_v2/package-lock.json +2031 -0
  268. package/mcp_v2/package.json +13 -2
  269. package/mcp_v2/scripts/copyErrorsIndex.cjs +34 -0
  270. package/mcp_v2/test/errors.test.ts +123 -0
  271. package/mcp_v2/test/github.test.ts +177 -0
  272. package/mcp_v2/tools/errors.d.ts +20 -0
  273. package/mcp_v2/tools/errors.js +63 -0
  274. package/mcp_v2/tools/github.d.ts +41 -0
  275. package/mcp_v2/tools/github.js +231 -0
  276. package/mcp_v2/vitest.config.mjs +22 -0
  277. package/package.json +60 -11
  278. package/test/errors/docsDrift.test.ts +113 -0
  279. package/test/errors/index.test.ts +200 -0
  280. package/test/errors/registry.test.ts +108 -0
  281. package/test/scripts/preflight.test.ts +121 -0
  282. package/test/server/ChunkExtractor.test.ts +97 -0
  283. package/test/server/extract.test.ts +128 -0
  284. package/test/server/fixtures/template/server/document.jsx +19 -0
  285. package/test/server/fixtures/template/server/index.js +10 -0
  286. package/test/server/fixtures/template/src/js/containers/App/index.jsx +33 -0
  287. package/test/server/fixtures/template/src/js/routes/index.jsx +72 -0
  288. package/test/server/fixtures/template/src/js/routes/utils.jsx +39 -0
  289. package/test/server/fixtures/template/src/js/store/index.js +19 -0
  290. package/test/server/handler.assets.test.ts +331 -0
  291. package/test/server/handler.test.ts +210 -0
  292. package/test/server/manifestCache.test.ts +71 -0
  293. package/test/server/render.test.ts +90 -0
  294. package/test/server/scriptUtils.test.ts +103 -0
  295. package/test/server/userAgentUtil.test.ts +48 -0
  296. package/test/server/validator.test.ts +228 -0
  297. package/test/vite/resolveDevServerConfig.test.js +4 -1
  298. package/tsconfig.test.json +23 -0
  299. package/vitest.config.ts +93 -0
  300. package/dist/caching.js +0 -1
  301. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/DeviceInfoUtilsTest.kt +0 -187
  302. package/dist/native/bridge/standardizedHooks.js +0 -611
  303. package/dist/router.js +0 -1
  304. package/dist/scripts/validator.js +0 -149
  305. package/dist/web-router/hooks.jsx +0 -72
  306. package/dist/web-router/types/components/MetaTag.d.ts +0 -2
  307. package/dist/web-router/types/components/RouterDataProvider.d.ts +0 -95
  308. package/dist/web-router/types/context.d.ts +0 -14
  309. package/dist/web-router/types/hooks.d.ts +0 -1
  310. package/dist/web-router/types/index.d.ts +0 -3
  311. package/dist/web-router/types/utils/metaDataUtils.d.ts +0 -24
  312. /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Constants/CatalystConstants.swift +0 -0
  313. /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Constants/ConfigConstants.swift +0 -0
  314. /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Notifications/NotificationModels.swift +0 -0
  315. /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Protocols/NotificationHandlerProtocol.swift +0 -0
  316. /package/dist/native/iosnativeWebView/{Sources/Core → CoreLogic/Sources/CatalystCoreLogic}/Utils/NullNotificationHandler.swift +0 -0
@@ -1,17 +1,32 @@
1
- import React, { Suspense, lazy, useContext, useEffect, useReducer } from "react"
2
- import { SsrRequestContext } from "./SsrRequestContext.jsx"
3
- import SplitInview from "./SplitInview.jsx"
1
+ import React, { Suspense, lazy, useContext, useEffect, useReducer } from "react";
2
+ import { SsrRequestContext } from "./SsrRequestContext.jsx";
3
+ import SplitInview from "./SplitInview.jsx";
4
+
5
+ /**
6
+ * A dynamic import of a module whose default export is the component to split.
7
+ * Matches the argument React's `lazy` accepts.
8
+ */
9
+
10
+ /**
11
+ * Options accepted by {@link split}.
12
+ */
13
+
14
+ /**
15
+ * The component returned by {@link split}. It renders the lazily imported
16
+ * component and additionally carries the route statics copied off the loaded
17
+ * module, plus `load()` for the fetcher contract RouterDataProvider relies on.
18
+ */
4
19
 
5
20
  // Synchronous module cache: importFn → resolved module.
6
21
  // Populated by the eager importFn().then() calls at split() invocation time.
7
22
  // By the time window.load fires (when hydrateRoot runs), all chunk <script>
8
23
  // tags in the HTML have already executed, so every .then() has already
9
24
  // resolved and the module is available here synchronously.
10
- const moduleCache = new Map()
25
+ const moduleCache = new Map();
11
26
 
12
27
  // Collects one promise per SSR-rendered split() call on the client.
13
28
  // loadableReady() waits for all of them before hydration begins.
14
- const prefetchPromises = []
29
+ const prefetchPromises = [];
15
30
 
16
31
  /**
17
32
  * Returns a promise that resolves once every SSR-rendered split component
@@ -24,58 +39,55 @@ const prefetchPromises = []
24
39
  * hydrateRoot(document.getElementById("root"), <App />)
25
40
  * })
26
41
  */
27
- export const hydrationReady = () => Promise.all(prefetchPromises)
42
+ export const hydrationReady = () => Promise.all(prefetchPromises);
43
+
44
+ /**
45
+ * Props for the internal Split wrapper. `split()` is the public entry point;
46
+ * this component is an implementation detail of it.
47
+ */
28
48
 
29
49
  /**
30
50
  * Split component that wraps React's lazy and Suspense for SSR compatibility
31
- * @param {Object} props
32
- * @param {boolean} props.ssr - Whether to render the component on the server
33
- * @param {React.ComponentType|React.ReactElement} props.fallback - Fallback component for loading state
34
- * @param {Function} props.children - Function that returns the lazy component import
35
- * @param {string} props.cacheKey - Resolved path for better asset tracking
36
51
  */
37
52
  const Split = ({
38
- ssr = true,
39
- fallback = null,
40
- cacheKey,
41
- rootOptions,
42
- onVisible,
43
- skipVisibility,
44
- children,
53
+ ssr = true,
54
+ fallback = null,
55
+ cacheKey,
56
+ rootOptions,
57
+ onVisible,
58
+ skipVisibility,
59
+ children
45
60
  }) => {
46
- // Check if we're on the server
47
- const isServer = typeof window === "undefined"
48
- if (isServer) {
49
- if (ssr) {
50
- // On server with SSR enabled: actually load and render the component
51
- try {
52
- // Track this component for asset extraction
53
- if (global.__CHUNK_EXTRACTOR__) {
54
- global.__CHUNK_EXTRACTOR__.addComponent(cacheKey)
55
- }
56
-
57
- return <Suspense fallback={fallback}>{children}</Suspense>
58
- } catch (error) {
59
- console.warn("Error loading component for SSR:", error)
60
- return fallback
61
- }
62
- } else {
63
- // Match SplitInview's client-side wrapper so hydration doesn't mismatch.
64
- // SplitInview renders <div ref>{fallback}</div> until visible; without this
65
- // wrap, server outputs `fallback` and client outputs `<div>{fallback}</div>`.
66
- return <div>{fallback}</div>
61
+ // Check if we're on the server
62
+ const isServer = typeof window === "undefined";
63
+ if (isServer) {
64
+ if (ssr) {
65
+ // On server with SSR enabled: actually load and render the component
66
+ try {
67
+ // Track this component for asset extraction
68
+ if (global.__CHUNK_EXTRACTOR__) {
69
+ global.__CHUNK_EXTRACTOR__.addComponent(cacheKey);
67
70
  }
71
+ return <Suspense fallback={fallback}>{children}</Suspense>;
72
+ } catch (error) {
73
+ console.warn("Error loading component for SSR:", error);
74
+ return fallback;
75
+ }
68
76
  } else {
69
- if (skipVisibility) {
70
- return <Suspense fallback={fallback}>{children}</Suspense>
71
- }
72
- return (
73
- <SplitInview fallback={fallback} rootOptions={rootOptions} onVisible={onVisible}>
74
- <Suspense fallback={fallback}>{children}</Suspense>
75
- </SplitInview>
76
- )
77
+ // Match SplitInview's client-side wrapper so hydration doesn't mismatch.
78
+ // SplitInview renders <div ref>{fallback}</div> until visible; without this
79
+ // wrap, server outputs `fallback` and client outputs `<div>{fallback}</div>`.
80
+ return <div>{fallback}</div>;
77
81
  }
78
- }
82
+ } else {
83
+ if (skipVisibility) {
84
+ return <Suspense fallback={fallback}>{children}</Suspense>;
85
+ }
86
+ return <SplitInview fallback={fallback} rootOptions={rootOptions} onVisible={onVisible}>
87
+ <Suspense fallback={fallback}>{children}</Suspense>
88
+ </SplitInview>;
89
+ }
90
+ };
79
91
 
80
92
  /**
81
93
  * Like {@link split}, but forces SSR when the request is a known Google crawler (same UA rules as Head).
@@ -85,116 +97,95 @@ const Split = ({
85
97
  * still hydrates without a Suspense flash.
86
98
  */
87
99
  export const split = (importFn, options = {}, thirdArg, fourthArg) => {
88
- const { ssr = true, fallback = null } = options || {}
89
- const hasThirdArg = typeof thirdArg !== "undefined"
90
- const hasFourthArg = typeof fourthArg !== "undefined"
91
- const cacheKey =
92
- typeof fourthArg === "string" ? fourthArg : typeof thirdArg === "string" ? thirdArg : undefined
93
- const rootOptions = hasFourthArg
94
- ? thirdArg
95
- : hasThirdArg && typeof thirdArg !== "string"
96
- ? thirdArg
97
- : undefined
98
-
99
- const LazyComponent = lazy(importFn)
100
- let loadInFlight = null
101
-
102
- // Per-split instance subscribers. Pending wrapper instances register their
103
- // forceUpdate here; notifyAll() wakes them when load() resolves or any
104
- // sibling becomes visible, so they can re-render against the now-hot cache
105
- // or skip their own observer setup.
106
- const subscribers = new Set()
107
- let anyVisible = false
108
- const notifyAll = () => {
109
- anyVisible = true
110
- subscribers.forEach((fn) => fn())
111
- }
112
- const copyRouteStatics = (mod) => {
113
- const Component = mod?.default || mod
114
- for (const key of ["clientFetcher", "serverFetcher", "setMetaData"]) {
115
- if (Component?.[key]) wrapper[key] = Component[key]
116
- }
117
- return mod
118
- }
119
-
120
- if (typeof window !== "undefined" && window.__SSR_RENDERED_COMPONENTS__?.has(cacheKey)) {
121
- const prefetch = importFn().then((mod) => {
122
- moduleCache.set(importFn, mod)
123
- copyRouteStatics(mod)
124
- })
125
- prefetchPromises.push(prefetch)
100
+ const {
101
+ ssr = true,
102
+ fallback = null
103
+ } = options || {};
104
+ const hasThirdArg = typeof thirdArg !== "undefined";
105
+ const hasFourthArg = typeof fourthArg !== "undefined";
106
+ const cacheKey = typeof fourthArg === "string" ? fourthArg : typeof thirdArg === "string" ? thirdArg : undefined;
107
+ const rootOptions = hasFourthArg ? thirdArg : hasThirdArg && typeof thirdArg !== "string" ? thirdArg : undefined;
108
+ const LazyComponent = lazy(importFn);
109
+ let loadInFlight = null;
110
+
111
+ // Per-split instance subscribers. Pending wrapper instances register their
112
+ // forceUpdate here; notifyAll() wakes them when load() resolves or any
113
+ // sibling becomes visible, so they can re-render against the now-hot cache
114
+ // or skip their own observer setup.
115
+ const subscribers = new Set();
116
+ let anyVisible = false;
117
+ const notifyAll = () => {
118
+ anyVisible = true;
119
+ subscribers.forEach(fn => fn());
120
+ };
121
+ const copyRouteStatics = mod => {
122
+ const Component = mod?.default || mod;
123
+ for (const key of ["clientFetcher", "serverFetcher", "setMetaData"]) {
124
+ if (Component?.[key]) wrapper[key] = Component[key];
126
125
  }
127
-
128
- const wrapper = ({ fallback: fallbackProp, ...props }) => {
129
- const { isBot: isBotFromContext } = useContext(SsrRequestContext)
130
- const isBotFromWindow = typeof window !== "undefined" && window.__CATALYST_IS_BOT__ === true
131
- const isBot = Boolean(isBotFromContext || isBotFromWindow)
132
- const effectiveSsr = ssr || isBot
133
- const effectiveFallback = fallbackProp !== undefined ? fallbackProp : fallback
134
-
135
- const [, forceUpdate] = useReducer((x) => x + 1, 0)
136
- useEffect(() => {
137
- subscribers.add(forceUpdate)
138
- return () => {
139
- subscribers.delete(forceUpdate)
140
- }
141
- }, [])
142
-
143
- const mod = moduleCache.get(importFn)
144
- if (mod) {
145
- const Component = mod.default || mod
146
- return (
147
- <Suspense fallback={effectiveFallback}>
126
+ return mod;
127
+ };
128
+ if (typeof window !== "undefined" && window.__SSR_RENDERED_COMPONENTS__?.has(cacheKey)) {
129
+ const prefetch = importFn().then(mod => {
130
+ moduleCache.set(importFn, mod);
131
+ copyRouteStatics(mod);
132
+ });
133
+ prefetchPromises.push(prefetch);
134
+ }
135
+ const wrapper = ({
136
+ fallback: fallbackProp,
137
+ ...props
138
+ }) => {
139
+ const {
140
+ isBot: isBotFromContext
141
+ } = useContext(SsrRequestContext);
142
+ const isBotFromWindow = typeof window !== "undefined" && window.__CATALYST_IS_BOT__ === true;
143
+ const isBot = Boolean(isBotFromContext || isBotFromWindow);
144
+ const effectiveSsr = ssr || isBot;
145
+ const effectiveFallback = fallbackProp !== undefined ? fallbackProp : fallback;
146
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
147
+ useEffect(() => {
148
+ subscribers.add(forceUpdate);
149
+ return () => {
150
+ subscribers.delete(forceUpdate);
151
+ };
152
+ }, []);
153
+ const mod = moduleCache.get(importFn);
154
+ if (mod) {
155
+ const Component = mod.default || mod;
156
+ return <Suspense fallback={effectiveFallback}>
148
157
  <Component {...props} />
149
- </Suspense>
150
- )
151
- }
152
-
153
- return (
154
- <Split
155
- ssr={effectiveSsr}
156
- fallback={effectiveFallback}
157
- cacheKey={cacheKey}
158
- rootOptions={rootOptions}
159
- onVisible={() => {
160
- notifyAll()
161
- props.onVisible?.()
162
- }}
163
- skipVisibility={effectiveSsr || anyVisible}
164
- {...props}
165
- isBot={isBot}
166
- >
167
- <LazyComponent {...props} />
168
- </Split>
169
- )
158
+ </Suspense>;
170
159
  }
171
-
172
- wrapper.__cacheKey = cacheKey
173
-
174
- /** Same contract as loadable components: RouterDataProvider awaits this before reading serverFetcher/clientFetcher. */
175
- wrapper.load = () => {
176
- const cached = moduleCache.get(importFn)
177
- if (cached) return Promise.resolve(cached)
178
- if (!loadInFlight) {
179
- loadInFlight = importFn()
180
- .then((mod) => {
181
- copyRouteStatics(mod)
182
- if (typeof window !== "undefined") {
183
- moduleCache.set(importFn, mod)
184
- }
185
- loadInFlight = null
186
- notifyAll()
187
- return mod
188
- })
189
- .catch((err) => {
190
- loadInFlight = null
191
- throw err
192
- })
160
+ return <Split ssr={effectiveSsr} fallback={effectiveFallback} cacheKey={cacheKey} rootOptions={rootOptions} onVisible={() => {
161
+ notifyAll();
162
+ props.onVisible?.();
163
+ }} skipVisibility={effectiveSsr || anyVisible} {...props} isBot={isBot}>
164
+ <LazyComponent {...props} />
165
+ </Split>;
166
+ };
167
+ wrapper.__cacheKey = cacheKey;
168
+
169
+ /** Same contract as loadable components: RouterDataProvider awaits this before reading serverFetcher/clientFetcher. */
170
+ wrapper.load = () => {
171
+ const cached = moduleCache.get(importFn);
172
+ if (cached) return Promise.resolve(cached);
173
+ if (!loadInFlight) {
174
+ loadInFlight = importFn().then(mod => {
175
+ copyRouteStatics(mod);
176
+ if (typeof window !== "undefined") {
177
+ moduleCache.set(importFn, mod);
193
178
  }
194
- return loadInFlight
179
+ loadInFlight = null;
180
+ notifyAll();
181
+ return mod;
182
+ }).catch(err => {
183
+ loadInFlight = null;
184
+ throw err;
185
+ });
195
186
  }
196
-
197
- return wrapper
198
- }
199
-
200
- export default Split
187
+ return loadInFlight;
188
+ };
189
+ return wrapper;
190
+ };
191
+ export default Split;
@@ -0,0 +1,52 @@
1
+ // @vitest-environment node
2
+ //
3
+ // Server-side Split coverage (#347/#348-style split). The jsdom
4
+ // Split.test.jsx cannot reach these branches -- Split checks
5
+ // `typeof window === "undefined"` and jsdom always defines window. Routed
6
+ // to the "node" project by the *.server.test.* include/exclude split in
7
+ // vitest.config.ts.
8
+
9
+ import React from "react"
10
+ import { renderToStaticMarkup } from "react-dom/server"
11
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
12
+ import Split from "./Split.jsx"
13
+
14
+ afterEach(() => {
15
+ delete global.__CHUNK_EXTRACTOR__
16
+ vi.restoreAllMocks()
17
+ })
18
+
19
+ describe("Split (server)", () => {
20
+ it("with ssr enabled: registers the component with the chunk extractor and renders children in Suspense", () => {
21
+ const addComponent = vi.fn()
22
+ global.__CHUNK_EXTRACTOR__ = { addComponent }
23
+
24
+ const html = renderToStaticMarkup(
25
+ <Split ssr cacheKey="pages/Widget" fallback={<span>fallback</span>}>
26
+ <p>real child</p>
27
+ </Split>,
28
+ )
29
+
30
+ expect(addComponent).toHaveBeenCalledWith("pages/Widget")
31
+ expect(html).toContain("real child")
32
+ })
33
+
34
+ it("with ssr enabled and no chunk extractor present: still renders children (no throw)", () => {
35
+ const html = renderToStaticMarkup(
36
+ <Split ssr cacheKey="pages/NoExtractor">
37
+ <p>child ok</p>
38
+ </Split>,
39
+ )
40
+ expect(html).toContain("child ok")
41
+ })
42
+
43
+ it("with ssr disabled: renders the fallback wrapped in a <div> to match the client hydration shape", () => {
44
+ const html = renderToStaticMarkup(
45
+ <Split ssr={false} cacheKey="pages/Deferred" fallback={<span>loading…</span>}>
46
+ <p>should not appear</p>
47
+ </Split>,
48
+ )
49
+ expect(html).toBe("<div><span>loading…</span></div>")
50
+ expect(html).not.toContain("should not appear")
51
+ })
52
+ })
@@ -0,0 +1,167 @@
1
+ import React, { Suspense } from "react"
2
+ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
3
+ import { render, screen, waitFor, act } from "@testing-library/react"
4
+ import Split, { split } from "./Split.jsx"
5
+ import { SsrRequestProvider } from "./SsrRequestContext.jsx"
6
+
7
+ // jsdom does not implement IntersectionObserver; SplitInview (used by the
8
+ // client, non-skipVisibility path) needs one. Stub it to fire visible
9
+ // immediately so tests default to "already visible" unless a test wants
10
+ // to hold back visibility deliberately.
11
+ class ImmediateIntersectionObserver {
12
+ constructor(callback) {
13
+ this.callback = callback
14
+ }
15
+ observe(node) {
16
+ // Fire on next tick so React has committed the ref first.
17
+ Promise.resolve().then(() => this.callback([{ target: node, isIntersecting: true }]))
18
+ }
19
+ unobserve() {}
20
+ disconnect() {}
21
+ }
22
+
23
+ beforeEach(() => {
24
+ vi.stubGlobal("IntersectionObserver", ImmediateIntersectionObserver)
25
+ })
26
+
27
+ afterEach(() => {
28
+ vi.unstubAllGlobals()
29
+ vi.restoreAllMocks()
30
+ })
31
+
32
+ describe("Split (client-side, window defined)", () => {
33
+ it("renders children directly when skipVisibility is true", () => {
34
+ render(
35
+ <Split skipVisibility fallback={<span>loading</span>}>
36
+ <span>content</span>
37
+ </Split>
38
+ )
39
+ expect(screen.getByText("content")).toBeInTheDocument()
40
+ })
41
+
42
+ it("defers to SplitInview (shows fallback first) when skipVisibility is false", () => {
43
+ render(
44
+ <Split fallback={<span>loading</span>}>
45
+ <span>content</span>
46
+ </Split>
47
+ )
48
+ // Before the stubbed IntersectionObserver's microtask fires,
49
+ // SplitInview should still be showing the fallback.
50
+ expect(screen.getByText("loading")).toBeInTheDocument()
51
+ })
52
+
53
+ it("eventually renders children once SplitInview reports visibility", async () => {
54
+ render(
55
+ <Split fallback={<span>loading</span>}>
56
+ <span>content</span>
57
+ </Split>
58
+ )
59
+ await waitFor(() => expect(screen.getByText("content")).toBeInTheDocument())
60
+ })
61
+ })
62
+
63
+ describe("split()", () => {
64
+ it("returns a component (wrapper) rather than throwing, given a lazy-style import function", () => {
65
+ const importFn = () => Promise.resolve({ default: () => <span>lazy content</span> })
66
+ const LazyThing = split(importFn, { ssr: false })
67
+ expect(typeof LazyThing).toBe("function")
68
+ expect(typeof LazyThing.load).toBe("function")
69
+ })
70
+
71
+ it("eventually renders the resolved component's output", async () => {
72
+ const importFn = () => Promise.resolve({ default: () => <span>lazy content</span> })
73
+ const LazyThing = split(importFn, { ssr: false, fallback: <span>loading</span> })
74
+ render(<LazyThing skipVisibility />)
75
+ await waitFor(() => expect(screen.getByText("lazy content")).toBeInTheDocument())
76
+ })
77
+
78
+ it("copies clientFetcher/serverFetcher/setMetaData from the resolved module onto the wrapper via load()", async () => {
79
+ const clientFetcher = vi.fn()
80
+ const serverFetcher = vi.fn()
81
+ const setMetaData = vi.fn()
82
+ const importFn = () =>
83
+ Promise.resolve({
84
+ default: Object.assign(() => <span>x</span>, { clientFetcher, serverFetcher, setMetaData }),
85
+ })
86
+ const LazyThing = split(importFn, {})
87
+ await LazyThing.load()
88
+ expect(LazyThing.clientFetcher).toBe(clientFetcher)
89
+ expect(LazyThing.serverFetcher).toBe(serverFetcher)
90
+ expect(LazyThing.setMetaData).toBe(setMetaData)
91
+ })
92
+
93
+ it("load() only calls the import function once even when called multiple times concurrently", async () => {
94
+ const importFn = vi.fn().mockResolvedValue({ default: () => <span>x</span> })
95
+ const LazyThing = split(importFn, {})
96
+ const [a, b] = await Promise.all([LazyThing.load(), LazyThing.load()])
97
+ expect(importFn).toHaveBeenCalledTimes(1)
98
+ expect(a).toBe(b)
99
+ })
100
+
101
+ it("load() caches its result -- a second call after resolution reuses the cached module without re-importing", async () => {
102
+ const importFn = vi.fn().mockResolvedValue({ default: () => <span>x</span> })
103
+ const LazyThing = split(importFn, {})
104
+ await LazyThing.load()
105
+ await LazyThing.load()
106
+ expect(importFn).toHaveBeenCalledTimes(1)
107
+ })
108
+
109
+ it("load() clears the in-flight promise and rethrows when the import rejects", async () => {
110
+ const importFn = vi.fn().mockRejectedValue(new Error("chunk 404"))
111
+ const LazyThing = split(importFn, {})
112
+ await expect(LazyThing.load()).rejects.toThrow("chunk 404")
113
+ // in-flight was cleared -> a retry re-imports rather than
114
+ // returning the settled rejection.
115
+ importFn.mockResolvedValueOnce({ default: () => <span>recovered</span> })
116
+ await expect(LazyThing.load()).resolves.toBeTruthy()
117
+ expect(importFn).toHaveBeenCalledTimes(2)
118
+ })
119
+
120
+ it("copies clientFetcher / serverFetcher / setMetaData statics onto the wrapper after load()", async () => {
121
+ const clientFetcher = () => {}
122
+ const setMetaData = () => {}
123
+ const importFn = vi
124
+ .fn()
125
+ .mockResolvedValue({ default: Object.assign(() => <span>c</span>, { clientFetcher, setMetaData }) })
126
+ const LazyThing = split(importFn, {})
127
+ await LazyThing.load()
128
+ expect(LazyThing.clientFetcher).toBe(clientFetcher)
129
+ expect(LazyThing.setMetaData).toBe(setMetaData)
130
+ })
131
+
132
+ it("renders straight from the module cache (no Split/observer) once load() has resolved", async () => {
133
+ const importFn = vi.fn().mockResolvedValue({ default: () => <span>from cache</span> })
134
+ const LazyThing = split(importFn, { ssr: false })
135
+ await LazyThing.load()
136
+ render(<LazyThing />)
137
+ await waitFor(() => expect(screen.getByText("from cache")).toBeInTheDocument())
138
+ })
139
+
140
+ it("prefetches when window.__SSR_RENDERED_COMPONENTS__ already contains the cacheKey", async () => {
141
+ const prev = window.__SSR_RENDERED_COMPONENTS__
142
+ window.__SSR_RENDERED_COMPONENTS__ = new Set(["pages/Prefetched"])
143
+ try {
144
+ const importFn = vi.fn().mockResolvedValue({ default: () => <span>pf</span> })
145
+ split(importFn, {}, undefined, "pages/Prefetched")
146
+ // the constructor-time prefetch fired
147
+ await waitFor(() => expect(importFn).toHaveBeenCalled())
148
+ } finally {
149
+ window.__SSR_RENDERED_COMPONENTS__ = prev
150
+ }
151
+ })
152
+
153
+ it("treats a bot request (via SsrRequestContext) as forcing effectiveSsr, skipping visibility gating", async () => {
154
+ const importFn = () => Promise.resolve({ default: () => <span>bot content</span> })
155
+ const LazyThing = split(importFn, { ssr: false })
156
+ render(
157
+ <SsrRequestProvider value={{ isBot: true }}>
158
+ <LazyThing />
159
+ </SsrRequestProvider>
160
+ )
161
+ // effectiveSsr = ssr || isBot = false || true = true, so Split's
162
+ // `!isServer` branch takes skipVisibility={effectiveSsr || anyVisible}
163
+ // = true -- content should render without waiting on an
164
+ // IntersectionObserver callback at all.
165
+ await waitFor(() => expect(screen.getByText("bot content")).toBeInTheDocument())
166
+ })
167
+ })
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Props for the internal visibility-deferring wrapper. Not part of the public
3
+ * surface: `split()` supplies these from its own options.
4
+ */
5
+ interface SplitInviewProps {
6
+ /** Shown while the component is outside the viewport */
7
+ fallback?: any;
8
+ /** Rendered once the placeholder scrolls into view */
9
+ children?: any;
10
+ /** Optional IntersectionObserver options for parity with react-loadable-visibility */
11
+ rootOptions?: any;
12
+ /** Called once when the placeholder enters the viewport */
13
+ onVisible?: () => void;
14
+ }
15
+ /**
16
+ * Defers rendering of children until the placeholder enters the viewport.
17
+ * Once visible, it stays visible.
18
+ *
19
+ * On the server or when IntersectionObserver is unavailable, children render immediately.
20
+ */
21
+ declare const SplitInview: ({ fallback, children, rootOptions, onVisible }: SplitInviewProps) => any;
22
+ export default SplitInview;