akanjs 3.0.2 → 3.1.0-rc.0

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 (378) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/base/baseEnv.ts +0 -4
  3. package/base/primitiveRegistry.ts +2 -2
  4. package/client/cookie.ts +5 -1
  5. package/client/csrLocation.ts +122 -0
  6. package/client/csrTypes.ts +32 -4
  7. package/client/device.ts +2 -1
  8. package/client/frameConfig.ts +78 -7
  9. package/client/index.ts +3 -0
  10. package/client/makePageProto.tsx +3 -2
  11. package/client/native/external-view.ts +1 -0
  12. package/client/route/RootLayoutDefinition.ts +7 -1
  13. package/client/route/RouteHead.ts +108 -0
  14. package/client/route/index.ts +1 -0
  15. package/client/router.ts +36 -23
  16. package/client/rscNavigation.ts +8 -2
  17. package/client/viewportMeta.ts +60 -0
  18. package/client/webManifest.ts +18 -0
  19. package/common/Logger.ts +7 -2
  20. package/common/PipelineNames.ts +31 -0
  21. package/common/PipelinePattern.ts +70 -0
  22. package/common/PipelinePlanSchema.ts +490 -0
  23. package/common/backoff.ts +14 -0
  24. package/common/index.ts +39 -0
  25. package/common/pipelinePlan.ts +259 -0
  26. package/common/routeConvention.ts +1 -0
  27. package/common/types.ts +17 -0
  28. package/constant/constantRegistry.ts +26 -6
  29. package/dictionary/base.dictionary.ts +8 -0
  30. package/dictionary/trans.ts +9 -1
  31. package/document/into.ts +5 -0
  32. package/fetch/client/fetchClient.ts +135 -31
  33. package/fetch/client/httpClient.ts +45 -0
  34. package/fetch/client/wsClient.ts +125 -16
  35. package/fetch/fetchType/buildFetch.type.ts +1 -0
  36. package/index.ts +243 -10
  37. package/package.json +1 -5
  38. package/server/akanApp.ts +5 -2
  39. package/server/akanServer.ts +44 -8
  40. package/server/artifact/builderRpc.ts +8 -3
  41. package/server/artifact/ipcTypes.ts +5 -2
  42. package/server/di/diLifecycle.ts +39 -3
  43. package/server/di/utils.ts +28 -1
  44. package/server/ed25519Key.ts +48 -0
  45. package/server/index.ts +1 -0
  46. package/server/machine/index.ts +2 -0
  47. package/server/machine/machineAccount.ts +27 -0
  48. package/server/machine/machineToken.ts +151 -0
  49. package/server/mcp/McpApps.ts +256 -0
  50. package/server/mcp/McpDispatcher.ts +31 -7
  51. package/server/mcp/McpRouter.ts +209 -46
  52. package/server/ops/opsToken.ts +3 -10
  53. package/server/resolver/database.resolver.ts +3 -0
  54. package/server/resolver/signal.resolver.ts +40 -3
  55. package/server/routeElementComposer.tsx +78 -2
  56. package/server/routeState.ts +6 -0
  57. package/server/routeTreeBuilder.ts +26 -9
  58. package/server/routing/apiRouter.ts +6 -3
  59. package/server/routing/roomReplay.ts +88 -0
  60. package/server/rscClient.tsx +53 -8
  61. package/server/rscWorker.tsx +141 -27
  62. package/server/rscWorkerHost.ts +18 -5
  63. package/server/sitemap.ts +14 -0
  64. package/server/ssrFromRscRenderer.tsx +12 -6
  65. package/server/ssrTypes.ts +3 -1
  66. package/server/systemPageDocument.tsx +38 -30
  67. package/server/types.tsx +2 -0
  68. package/server/webRouter.ts +74 -5
  69. package/service/injectInfo.ts +9 -1
  70. package/service/ipcTypes.ts +2 -1
  71. package/service/predefinedAdaptor/database.adaptor.ts +1 -146
  72. package/service/predefinedAdaptor/queue.adaptor.ts +44 -6
  73. package/service/predefinedAdaptor/queueBackoff.ts +12 -0
  74. package/service/predefinedAdaptor/solidQueue.adaptor.ts +17 -13
  75. package/service/predefinedAdaptor/sql/SqlDocumentStore.ts +44 -2
  76. package/service/predefinedAdaptor/sql/dialect/postgres.ts +3 -0
  77. package/service/predefinedAdaptor/sql/dialect/sqlite.ts +5 -2
  78. package/service/predefinedAdaptor/sql/search/fts5.ts +1 -1
  79. package/service/predefinedAdaptor/sql/types.ts +8 -6
  80. package/service/predefinedAdaptor/sql/values.ts +0 -23
  81. package/service/serve.ts +5 -1
  82. package/signal/agent.signal.ts +1 -1
  83. package/signal/base.signal.ts +2 -2
  84. package/signal/endpointIdempotency.ts +53 -0
  85. package/signal/internalArg.ts +14 -0
  86. package/signal/mcp/McpDocument.ts +38 -1
  87. package/signal/mcp/mcpProtocol.ts +18 -0
  88. package/signal/signalContext.ts +58 -30
  89. package/signal/signalRegistry.ts +14 -4
  90. package/signal/types.ts +18 -3
  91. package/store/agent/StoreSurfaceSource.ts +1 -1
  92. package/store/agentic/StToolBuilder.ts +3 -0
  93. package/test/conformance.ts +9 -33
  94. package/types/base/baseEnv.d.ts +0 -4
  95. package/types/base/primitiveRegistry.d.ts +1 -1
  96. package/types/client/csrLocation.d.ts +32 -0
  97. package/types/client/csrTypes.d.ts +40 -4
  98. package/types/client/frameConfig.d.ts +14 -2
  99. package/types/client/index.d.ts +3 -0
  100. package/types/client/native/external-view.d.ts +1 -0
  101. package/types/client/route/RootLayoutDefinition.d.ts +2 -1
  102. package/types/client/route/RouteHead.d.ts +13 -0
  103. package/types/client/route/index.d.ts +1 -0
  104. package/types/client/router.d.ts +6 -0
  105. package/types/client/rscNavigation.d.ts +4 -0
  106. package/types/client/viewportMeta.d.ts +18 -0
  107. package/types/client/webManifest.d.ts +4 -0
  108. package/types/common/PipelineNames.d.ts +6 -0
  109. package/types/common/PipelinePattern.d.ts +14 -0
  110. package/types/common/PipelinePlanSchema.d.ts +9 -0
  111. package/types/common/backoff.d.ts +10 -0
  112. package/types/common/index.d.ts +5 -0
  113. package/types/common/pipelinePlan.d.ts +224 -0
  114. package/types/common/types.d.ts +16 -0
  115. package/types/constant/constantRegistry.d.ts +5 -2
  116. package/types/dictionary/base.dictionary.d.ts +1 -1
  117. package/types/dictionary/dictionary.d.ts +8 -8
  118. package/types/document/into.d.ts +9 -0
  119. package/types/fetch/client/fetchClient.d.ts +31 -4
  120. package/types/fetch/client/httpClient.d.ts +8 -0
  121. package/types/fetch/client/wsClient.d.ts +26 -2
  122. package/types/fetch/fetchType/buildFetch.type.d.ts +1 -0
  123. package/types/index.d.ts +230 -9
  124. package/types/server/akanServer.d.ts +16 -1
  125. package/types/server/artifact/builderRpc.d.ts +7 -2
  126. package/types/server/artifact/ipcTypes.d.ts +5 -1
  127. package/types/server/di/utils.d.ts +1 -0
  128. package/types/server/ed25519Key.d.ts +13 -0
  129. package/types/server/index.d.ts +1 -0
  130. package/types/server/machine/index.d.ts +2 -0
  131. package/types/server/machine/machineAccount.d.ts +5 -0
  132. package/types/server/machine/machineToken.d.ts +29 -0
  133. package/types/server/machine.d.ts +1 -0
  134. package/types/server/mcp/McpApps.d.ts +50 -0
  135. package/types/server/mcp/McpDispatcher.d.ts +4 -1
  136. package/types/server/mcp/McpRouter.d.ts +4 -0
  137. package/types/server/resolver/signal.resolver.d.ts +2 -1
  138. package/types/server/routeElementComposer.d.ts +24 -4
  139. package/types/server/routeState.d.ts +4 -1
  140. package/types/server/routing/roomReplay.d.ts +24 -0
  141. package/types/server/rscWorkerHost.d.ts +5 -2
  142. package/types/server/sitemap.d.ts +2 -0
  143. package/types/server/ssrFromRscRenderer.d.ts +3 -3
  144. package/types/server/ssrTypes.d.ts +4 -1
  145. package/types/server/systemPageDocument.d.ts +2 -0
  146. package/types/server/types.d.ts +4 -1
  147. package/types/server/webRouter.d.ts +3 -1
  148. package/types/service/ipcTypes.d.ts +2 -0
  149. package/types/service/predefinedAdaptor/database.adaptor.d.ts +1 -24
  150. package/types/service/predefinedAdaptor/queue.adaptor.d.ts +10 -3
  151. package/types/service/predefinedAdaptor/queueBackoff.d.ts +4 -0
  152. package/types/service/predefinedAdaptor/solidQueue.adaptor.d.ts +3 -3
  153. package/types/service/predefinedAdaptor/sql/SqlDocumentStore.d.ts +6 -1
  154. package/types/service/predefinedAdaptor/sql/dialect/postgres.d.ts +1 -0
  155. package/types/service/predefinedAdaptor/sql/dialect/sqlite.d.ts +1 -0
  156. package/types/service/predefinedAdaptor/sql/search/fts5.d.ts +1 -1
  157. package/types/service/predefinedAdaptor/sql/types.d.ts +9 -5
  158. package/types/service/predefinedAdaptor/sql/values.d.ts +0 -3
  159. package/types/service/serve.d.ts +3 -0
  160. package/types/signal/endpointIdempotency.d.ts +7 -0
  161. package/types/signal/internalArg.d.ts +10 -0
  162. package/types/signal/mcp/McpDocument.d.ts +8 -0
  163. package/types/signal/mcp/mcpProtocol.d.ts +17 -0
  164. package/types/signal/signalContext.d.ts +5 -3
  165. package/types/signal/signalRegistry.d.ts +4 -4
  166. package/types/signal/types.d.ts +21 -1
  167. package/types/store/agentic/StToolBuilder.d.ts +2 -0
  168. package/types/test/conformance.d.ts +7 -10
  169. package/types/ui/Agent/Chat.d.ts +5 -1
  170. package/types/ui/Agent/EmbedApproval.d.ts +1 -0
  171. package/types/ui/Agent/index.d.ts +3 -0
  172. package/types/ui/Agent/useKeyboardFrame.d.ts +2 -0
  173. package/types/ui/Agent/useScreenActions.d.ts +18 -0
  174. package/types/ui/BottomSheet.d.ts +1 -0
  175. package/types/ui/Constant/Doc.d.ts +11 -17
  176. package/types/ui/Constant/index.d.ts +7 -2
  177. package/types/ui/Constant/schemaDoc.d.ts +11 -0
  178. package/types/ui/Dialog/Modal.d.ts +6 -1
  179. package/types/ui/Dialog/index.d.ts +1 -1
  180. package/types/ui/Dialog/modalSurface.d.ts +12 -0
  181. package/types/ui/Layout/BottomTab.d.ts +11 -2
  182. package/types/ui/Layout/FrameSlotFallback.d.ts +9 -0
  183. package/types/ui/Layout/Navbar.d.ts +4 -1
  184. package/types/ui/Layout/TopInset.d.ts +1 -1
  185. package/types/ui/Layout/index.d.ts +3 -3
  186. package/types/ui/Link/Action.d.ts +5 -1
  187. package/types/ui/Link/Anchor.d.ts +5 -3
  188. package/types/ui/Link/activePath.d.ts +13 -0
  189. package/types/ui/Link/index.d.ts +1 -1
  190. package/types/ui/Modal.d.ts +6 -1
  191. package/types/ui/Model/EditModal.d.ts +6 -1
  192. package/types/ui/Model/New.d.ts +6 -1
  193. package/types/ui/Model/ViewEditModal.d.ts +6 -1
  194. package/types/ui/Model/ViewModal.d.ts +6 -1
  195. package/types/ui/Model/newFormOrigin.d.ts +7 -0
  196. package/types/ui/Portal.d.ts +3 -1
  197. package/types/ui/Reference/origin.d.ts +12 -0
  198. package/types/ui/Signal/Doc.d.ts +23 -18
  199. package/types/ui/Signal/Listener.d.ts +2 -6
  200. package/types/ui/Signal/Object.d.ts +6 -10
  201. package/types/ui/Signal/Response.d.ts +3 -6
  202. package/types/ui/Signal/RestApi.d.ts +11 -15
  203. package/types/ui/Signal/WebSocket.d.ts +11 -21
  204. package/types/ui/Signal/endpointEntries.d.ts +8 -0
  205. package/types/ui/Signal/index.d.ts +35 -12
  206. package/types/ui/Signal/signalText.d.ts +178 -0
  207. package/types/ui/System/CSR.d.ts +2 -2
  208. package/types/ui/System/Client.d.ts +4 -3
  209. package/types/ui/System/Common.d.ts +27 -6
  210. package/types/ui/System/SSR.d.ts +6 -6
  211. package/types/ui/Tooltip.d.ts +4 -2
  212. package/types/ui/index.d.ts +2 -1
  213. package/types/ui/overlayLayer.d.ts +6 -0
  214. package/types/ui/overlayPosition.d.ts +17 -0
  215. package/types/vendor/@akanjs/native/packages/cli/src/api.d.ts +14 -3
  216. package/types/vendor/@akanjs/native/packages/cli/src/commands/update.d.ts +1 -1
  217. package/types/vendor/@akanjs/native/packages/cli/src/config.d.ts +30 -5
  218. package/types/vendor/@akanjs/native/packages/cli/src/lib/compat.d.ts +8 -0
  219. package/types/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.d.ts +5 -0
  220. package/types/vendor/@akanjs/native/packages/cli/src/lib/distribution.d.ts +22 -0
  221. package/types/vendor/@akanjs/native/packages/cli/src/lib/project.d.ts +4 -0
  222. package/types/vendor/@akanjs/native/packages/cli/src/lib/publish.d.ts +16 -10
  223. package/types/vendor/@akanjs/native/packages/cli/src/lib/updates.d.ts +51 -7
  224. package/types/vendor/@akanjs/native/packages/cli/src/lib/vectors.d.ts +1 -1
  225. package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.d.ts +7 -0
  226. package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows.d.ts +5 -0
  227. package/types/vendor/@akanjs/native/packages/core/src/kernel.d.ts +36 -0
  228. package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +2 -0
  229. package/types/vendor/@akanjs/native/packages/desktop/src/server.d.ts +11 -0
  230. package/types/vendor/@akanjs/native/plugins/external-view/src/desktop.d.ts +17 -0
  231. package/types/vendor/@akanjs/native/plugins/external-view/src/index.d.ts +132 -0
  232. package/types/vendor/@akanjs/native/plugins/external-view/src.d.ts +1 -0
  233. package/types/vendor/@akanjs/native/plugins/updates/src/index.d.ts +8 -0
  234. package/types/vendor/@akanjs/native/plugins/window/src/desktop.d.ts +4 -1
  235. package/types/vendor/@akanjs/native/plugins/window/src/index.d.ts +49 -0
  236. package/types/vendor/use-agentic/types.d.ts +2 -0
  237. package/types/webkit/CsrStack.d.ts +1 -1
  238. package/types/webkit/McpAppAgent.d.ts +14 -0
  239. package/types/webkit/McpAppApprovals.d.ts +8 -0
  240. package/types/webkit/McpAppBridge.d.ts +101 -0
  241. package/types/webkit/McpAppView.d.ts +21 -0
  242. package/types/webkit/index.d.ts +1 -0
  243. package/types/webkit/useLocation.d.ts +1 -1
  244. package/types/webkit/useVisualViewportFrame.d.ts +13 -0
  245. package/ui/Agent/Chat.tsx +29 -10
  246. package/ui/Agent/Composer.tsx +2 -1
  247. package/ui/Agent/EmbedApproval.tsx +17 -0
  248. package/ui/Agent/RichInput.tsx +1 -1
  249. package/ui/Agent/index.ts +2 -0
  250. package/ui/Agent/useKeyboardFrame.ts +10 -0
  251. package/ui/Agent/useScreenActions.ts +45 -0
  252. package/ui/BottomSheet.tsx +82 -53
  253. package/ui/Constant/Doc.tsx +113 -60
  254. package/ui/Constant/index.ts +2 -2
  255. package/ui/Constant/schemaDoc.ts +86 -26
  256. package/ui/Dialog/LegacyModal.tsx +53 -52
  257. package/ui/Dialog/Modal.tsx +93 -49
  258. package/ui/Dialog/modalSurface.ts +61 -0
  259. package/ui/DragAction.tsx +1 -1
  260. package/ui/DraggableList.tsx +1 -1
  261. package/ui/Dropdown.tsx +4 -6
  262. package/ui/KeyboardAvoiding.tsx +1 -1
  263. package/ui/Layout/BottomInset.tsx +20 -14
  264. package/ui/Layout/BottomTab.tsx +42 -16
  265. package/ui/Layout/FrameSlotFallback.tsx +59 -0
  266. package/ui/Layout/Navbar.tsx +37 -11
  267. package/ui/Layout/Sider.tsx +1 -1
  268. package/ui/Layout/TopInset.tsx +15 -14
  269. package/ui/Link/Action.tsx +15 -5
  270. package/ui/Link/Anchor.tsx +25 -13
  271. package/ui/Link/activePath.ts +25 -0
  272. package/ui/Link/index.tsx +1 -1
  273. package/ui/Load/Pagination.tsx +1 -1
  274. package/ui/Load/Units.tsx +1 -1
  275. package/ui/Loading/ProgressBar.tsx +1 -1
  276. package/ui/Modal.tsx +9 -0
  277. package/ui/Model/EditModal.tsx +16 -1
  278. package/ui/Model/New.tsx +25 -2
  279. package/ui/Model/NewWrapper_Client.tsx +2 -0
  280. package/ui/Model/ViewEditModal.tsx +9 -0
  281. package/ui/Model/ViewModal.tsx +16 -1
  282. package/ui/Model/newFormOrigin.ts +45 -0
  283. package/ui/Popconfirm.tsx +5 -7
  284. package/ui/Portal.tsx +4 -7
  285. package/ui/Reference/origin.ts +31 -0
  286. package/ui/ScreenNavigator.tsx +1 -1
  287. package/ui/Select.tsx +2 -7
  288. package/ui/Signal/Arg.tsx +2 -2
  289. package/ui/Signal/Doc.tsx +125 -63
  290. package/ui/Signal/Endpoint.tsx +11 -10
  291. package/ui/Signal/Listener.tsx +7 -10
  292. package/ui/Signal/Object.tsx +7 -14
  293. package/ui/Signal/Response.tsx +24 -24
  294. package/ui/Signal/RestApi.tsx +63 -52
  295. package/ui/Signal/WebSocket.tsx +65 -72
  296. package/ui/Signal/endpointEntries.ts +25 -0
  297. package/ui/Signal/index.ts +23 -6
  298. package/ui/Signal/signalText.ts +59 -0
  299. package/ui/System/CSR.tsx +34 -8
  300. package/ui/System/Client.tsx +36 -5
  301. package/ui/System/Common.tsx +76 -32
  302. package/ui/System/SSR.tsx +73 -31
  303. package/ui/Toast.tsx +1 -1
  304. package/ui/Tooltip.tsx +84 -30
  305. package/ui/index.ts +11 -1
  306. package/ui/overlayLayer.ts +25 -2
  307. package/ui/overlayPosition.ts +90 -0
  308. package/ui/recipe/inputRecipe.ts +8 -1
  309. package/ui/styles.css +152 -0
  310. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeActivity.kt +22 -2
  311. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeKernel.kt +37 -0
  312. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeUpdateReports.kt +169 -0
  313. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeUpdates.kt +110 -38
  314. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeVectors.kt +20 -0
  315. package/vendor/@akanjs/native/native/desktop/Cargo.lock +16 -16
  316. package/vendor/@akanjs/native/native/desktop/src/external.rs +651 -0
  317. package/vendor/@akanjs/native/native/desktop/src/json.rs +23 -0
  318. package/vendor/@akanjs/native/native/desktop/src/lib.rs +228 -5
  319. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeApp.swift +2 -1
  320. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeKernel.swift +47 -1
  321. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeUpdateReports.swift +145 -0
  322. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeUpdates.swift +112 -43
  323. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeVectors.swift +18 -0
  324. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeViewController.swift +24 -2
  325. package/vendor/@akanjs/native/packages/cli/src/api.ts +22 -6
  326. package/vendor/@akanjs/native/packages/cli/src/commands/build.ts +24 -8
  327. package/vendor/@akanjs/native/packages/cli/src/commands/update.ts +11 -9
  328. package/vendor/@akanjs/native/packages/cli/src/config.ts +35 -7
  329. package/vendor/@akanjs/native/packages/cli/src/lib/compat.ts +2 -0
  330. package/vendor/@akanjs/native/packages/cli/src/lib/configkeys.ts +6 -4
  331. package/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.ts +11 -1
  332. package/vendor/@akanjs/native/packages/cli/src/lib/distribution.ts +73 -0
  333. package/vendor/@akanjs/native/packages/cli/src/lib/project.ts +15 -3
  334. package/vendor/@akanjs/native/packages/cli/src/lib/publish.ts +70 -23
  335. package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +159 -23
  336. package/vendor/@akanjs/native/packages/cli/src/lib/vectors.ts +2 -0
  337. package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +9 -4
  338. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.ts +1 -1
  339. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop.ts +4 -2
  340. package/vendor/@akanjs/native/packages/cli/src/platforms/ios.ts +9 -4
  341. package/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.ts +25 -11
  342. package/vendor/@akanjs/native/packages/cli/src/platforms/windows.ts +14 -3
  343. package/vendor/@akanjs/native/packages/core/src/kernel.ts +49 -0
  344. package/vendor/@akanjs/native/packages/core/vectors/updates.json +31 -0
  345. package/vendor/@akanjs/native/packages/desktop/src/main.ts +3 -0
  346. package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +2 -0
  347. package/vendor/@akanjs/native/packages/desktop/src/server.ts +70 -6
  348. package/vendor/@akanjs/native/plugins/external-view/native-plugin.json +23 -0
  349. package/vendor/@akanjs/native/plugins/external-view/src/desktop.ts +321 -0
  350. package/vendor/@akanjs/native/plugins/external-view/src/index.ts +106 -0
  351. package/vendor/@akanjs/native/plugins/updates/android/UpdatesPlugin.kt +133 -41
  352. package/vendor/@akanjs/native/plugins/updates/ios/UpdatesPlugin.swift +101 -36
  353. package/vendor/@akanjs/native/plugins/updates/native-plugin.json +4 -2
  354. package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +15 -1
  355. package/vendor/@akanjs/native/plugins/updates/src/index.ts +7 -1
  356. package/vendor/@akanjs/native/plugins/window/native-plugin.json +4 -0
  357. package/vendor/@akanjs/native/plugins/window/src/desktop.ts +68 -1
  358. package/vendor/@akanjs/native/plugins/window/src/index.ts +47 -0
  359. package/vendor/use-agentic/ToolRunner.ts +8 -1
  360. package/vendor/use-agentic/types.ts +2 -0
  361. package/webkit/CsrRouteTable.ts +1 -0
  362. package/webkit/CsrStack.ts +9 -2
  363. package/webkit/McpAppAgent.ts +138 -0
  364. package/webkit/McpAppApprovals.ts +56 -0
  365. package/webkit/McpAppBridge.ts +291 -0
  366. package/webkit/McpAppView.ts +258 -0
  367. package/webkit/bootCsr.tsx +54 -5
  368. package/webkit/index.ts +1 -0
  369. package/webkit/useCsrValues.ts +16 -10
  370. package/webkit/useFrameRuntime.ts +10 -1
  371. package/webkit/useLocation.ts +4 -3
  372. package/webkit/useVisualViewportFrame.tsx +52 -0
  373. package/service/predefinedAdaptor/sql/driver/libsql.ts +0 -45
  374. package/types/service/predefinedAdaptor/sql/driver/libsql.d.ts +0 -20
  375. package/types/ui/Agent/useKeyboardInset.d.ts +0 -1
  376. package/types/ui/ServerPortal.d.ts +0 -15
  377. package/ui/Agent/useKeyboardInset.ts +0 -19
  378. package/ui/ServerPortal.tsx +0 -49
@@ -6,6 +6,8 @@ import type {
6
6
  PathRoute,
7
7
  RedirectStatus,
8
8
  ResolvedHead,
9
+ RouteRender,
10
+ RouteViewport,
9
11
  } from "akanjs/client";
10
12
  import { type AkanI18nConfig, DEFAULT_AKAN_I18N, getBasePathFromPathname, Logger } from "akanjs/common";
11
13
  import {
@@ -24,6 +26,8 @@ import {
24
26
  } from "akanjs/fetch";
25
27
  import type { ReactNode } from "react";
26
28
  import { renderToReadableStream } from "react-server-dom-webpack/server.node";
29
+ import { ViewportMeta } from "../client/viewportMeta";
30
+ import { toManifestJson, webManifestHref } from "../client/webManifest";
27
31
  import type { PagePromptRunInput } from "../signal/mcp/pagePrompt";
28
32
  import { getCurrentTrace, runTraced, SignalTrace } from "../signal/trace";
29
33
  import type { ClientManifest } from "./artifact";
@@ -40,7 +44,7 @@ import {
40
44
  import { createAkanLocaleAlternateHeadSnapshot, mergeAkanHeadSnapshots, renderAkanHeadSnapshot } from "./head";
41
45
  import { LogForwarder } from "./logging/logForwarder";
42
46
  import { ProcessMetricsCollector } from "./processMetricsCollector";
43
- import { RouteElementComposer } from "./routeElementComposer";
47
+ import { RouteElementComposer, type RouteNotFoundInPlace } from "./routeElementComposer";
44
48
  import {
45
49
  type AkanRscPatchDecision,
46
50
  createAkanRouterState,
@@ -69,7 +73,12 @@ import {
69
73
  shouldUseRscWorkerFullResultCache,
70
74
  } from "./rscWorkerCache";
71
75
  import type { RscTraceMetadata } from "./ssrTypes";
72
- import { createSystemPageDocument, getPathnameLocale, getSystemPageHomeHref } from "./systemPageDocument";
76
+ import {
77
+ createSystemPageDocument,
78
+ getPathnameLocale,
79
+ getSystemPageHomeHref,
80
+ SystemPageMain,
81
+ } from "./systemPageDocument";
73
82
 
74
83
  interface InitMsg {
75
84
  type: "init";
@@ -123,6 +132,11 @@ interface PagePromptRunMsg {
123
132
  requestId: string;
124
133
  input: PagePromptRunInput;
125
134
  }
135
+ interface WebManifestMsg {
136
+ type: "web-manifest";
137
+ requestId: string;
138
+ basePath: string | null;
139
+ }
126
140
  type InMsg =
127
141
  | InitMsg
128
142
  | RenderMsg
@@ -132,7 +146,8 @@ type InMsg =
132
146
  | InvalidateCacheMsg
133
147
  | LogLevelMsg
134
148
  | PagePromptsMsg
135
- | PagePromptRunMsg;
149
+ | PagePromptRunMsg
150
+ | WebManifestMsg;
136
151
  type RenderControl =
137
152
  | { type: "redirect"; location: string; method: "replace" | "push"; status: RedirectStatus }
138
153
  | { type: "not-found" }
@@ -306,9 +321,20 @@ export class RscRenderer {
306
321
  case "page-prompt.run":
307
322
  void this.#answer(msg.requestId, "page-prompt.result", () => this.#pagePrompts.run(msg.input));
308
323
  return;
324
+ case "web-manifest":
325
+ void this.#answer(msg.requestId, "web-manifest.result", () => this.#webManifest(msg.basePath));
326
+ return;
309
327
  }
310
328
  }
311
329
 
330
+ async #webManifest(basePath: string | null): Promise<unknown> {
331
+ const pathname = `/${this.#i18n.defaultLocale}${basePath ? `/${basePath}` : ""}`;
332
+ const rootLayouts = RouteTreeBuilder.matchFallback(pathname, this.#fallbackRoutes)?.fallbackRoute.renderRootLayouts;
333
+ const manifests = await Promise.all((rootLayouts ?? []).map((render) => render.getLayoutManifest?.()));
334
+ const manifest = manifests.find((entry) => entry !== undefined);
335
+ return manifest ? toManifestJson(manifest) : null;
336
+ }
337
+
312
338
  async #answer(requestId: string, type: string, fn: () => Promise<unknown>): Promise<void> {
313
339
  try {
314
340
  this.#send({ type, requestId, result: await fn() });
@@ -458,11 +484,18 @@ export class RscRenderer {
458
484
  const beforeLoadedKeys = RouteTreeBuilder.getCacheStats().loadedModuleKeys;
459
485
  const cacheDecision = match ? this.#getResultCacheEntry(request, urlObj) : { entry: null };
460
486
  const cacheEntry = cacheDecision.entry;
487
+ const targetFrame = match
488
+ ? await RouteElementComposer.resolveSsrFramePathRoute({
489
+ pathRoute: match.pathRoute,
490
+ basePath: this.#getBasePath(urlObj),
491
+ })
492
+ : null;
461
493
  const targetRouterState = match
462
494
  ? createAkanRouterState({
463
495
  pathRoute: match.pathRoute,
464
496
  href: urlObj.href,
465
497
  buildId: this.#pagesBundleBuildId,
498
+ transition: targetFrame?.pageState.transition,
466
499
  })
467
500
  : null;
468
501
  const searchParams = RouteTreeBuilder.parseSearchParams(urlObj.search);
@@ -569,12 +602,15 @@ export class RscRenderer {
569
602
  }
570
603
  let element: ReactNode;
571
604
  let effectivePatchDecision = safePatchDecision;
605
+ const notFoundProbe = { hit: false };
606
+ const notFound = this.#notFoundInPlace(urlObj, notFoundProbe);
572
607
  if (match && safePatchDecision.status === "patch" && safePatchDecision.patch) {
573
608
  const suffixElement = await this.#renderMatchedSuffix(
574
609
  urlObj,
575
610
  match,
576
611
  safePatchDecision.patch.patchStartIndex,
577
612
  searchParams,
613
+ notFound,
578
614
  );
579
615
  if (suffixElement === null) {
580
616
  effectivePatchDecision = {
@@ -582,9 +618,9 @@ export class RscRenderer {
582
618
  reason: "suffix-compose-fallback",
583
619
  commonPrefixLength: safePatchDecision.commonPrefixLength,
584
620
  };
585
- element = await this.#renderMatched(urlObj, match, searchParams);
621
+ element = await this.#renderMatched(urlObj, match, searchParams, notFound);
586
622
  } else element = suffixElement;
587
- } else if (match) element = await this.#renderMatched(urlObj, match, searchParams);
623
+ } else if (match) element = await this.#renderMatched(urlObj, match, searchParams, notFound);
588
624
  else element = await this.#renderNotFound(urlObj);
589
625
  const traceCacheKey =
590
626
  effectivePatchDecision.status === "patch" ? (patchCacheEntry?.key ?? cacheEntry?.key) : cacheEntry?.key;
@@ -604,6 +640,7 @@ export class RscRenderer {
604
640
  }),
605
641
  status: match ? undefined : 404,
606
642
  trace,
643
+ notFoundProbe,
607
644
  onComplete: ({ chunks, bytes, chunksCount, control, lateControlSent }) => {
608
645
  const cacheState = shouldStoreRouteCache({
609
646
  policy: getRequestPolicy(),
@@ -827,6 +864,8 @@ export class RscRenderer {
827
864
  collectChunks?: boolean;
828
865
  status?: number;
829
866
  trace?: RscTraceMetadata;
867
+ /** Raised by a render that answered `router.notFound()` in place, which React never reports as an error. */
868
+ notFoundProbe?: { hit: boolean };
830
869
  onComplete?: (
831
870
  result: Omit<FlightRenderResult, "cancelled">,
832
871
  ) => Promise<RouteCacheRenderState> | RouteCacheRenderState;
@@ -881,17 +920,29 @@ export class RscRenderer {
881
920
  reportedTheme = theme;
882
921
  this.#send({ type: "theme", requestId: options.requestId, theme });
883
922
  };
884
- const sendLateRedirect = () => {
885
- if (!options.requestId || lateControlSent || controlRef.current?.type !== "redirect") return;
886
-
923
+ const readProbe = () => {
924
+ if (!controlRef.current && options.notFoundProbe?.hit) controlRef.current = { type: "not-found" };
925
+ };
926
+
927
+ const sendLateControl = () => {
928
+ const control = controlRef.current;
929
+ if (!options.requestId || lateControlSent || !control || control.type === "error") return;
887
930
  lateControlSent = true;
888
- this.#send({
889
- type: "late-redirect",
890
- requestId: options.requestId,
891
- location: controlRef.current.location,
892
- method: controlRef.current.method,
893
- status: controlRef.current.status,
894
- });
931
+ if (control.type === "redirect") {
932
+ this.#send({
933
+ type: "late-redirect",
934
+ requestId: options.requestId,
935
+ location: control.location,
936
+ method: control.method,
937
+ status: control.status,
938
+ });
939
+ return;
940
+ }
941
+ if (!options.notFoundProbe?.hit)
942
+ this.#logger.warn(
943
+ `render[${options.requestId}] not-found raised below a route render after the stream started; that subtree renders nothing — call router.notFound() from the page or layout body`,
944
+ );
945
+ this.#send({ type: "late-not-found", requestId: options.requestId });
895
946
  };
896
947
  try {
897
948
  for (;;) {
@@ -900,12 +951,22 @@ export class RscRenderer {
900
951
  return { chunks, bytes, chunksCount, control: null, lateControlSent, cancelled: true };
901
952
  }
902
953
  const { value, done } = await reader.read();
954
+ readProbe();
903
955
  if (controlRef.current && !sentChunk) {
904
956
  await reader.cancel();
905
957
  return { chunks, bytes, chunksCount, control: controlRef.current, lateControlSent, cancelled: false };
906
958
  }
907
- if (controlRef.current && sentChunk) sendLateRedirect();
959
+ if (controlRef.current && sentChunk) sendLateControl();
908
960
  if (done) break;
961
+
962
+ if (!sentChunk && options.requestId) {
963
+ await new Promise((resolve) => setTimeout(resolve, 0));
964
+ readProbe();
965
+ if (controlRef.current) {
966
+ await reader.cancel();
967
+ return { chunks, bytes, chunksCount, control: controlRef.current, lateControlSent, cancelled: false };
968
+ }
969
+ }
909
970
  const chunk = value instanceof Uint8Array ? value : new Uint8Array(value as ArrayBufferLike);
910
971
  bytes += chunk.byteLength;
911
972
  chunksCount += 1;
@@ -926,7 +987,8 @@ export class RscRenderer {
926
987
  if (options.requestId) this.#activeRenderReaders.delete(options.requestId);
927
988
  reader.releaseLock();
928
989
  }
929
- if (controlRef.current && sentChunk) sendLateRedirect();
990
+ readProbe();
991
+ if (controlRef.current && sentChunk) sendLateControl();
930
992
  if (controlRef.current && !sentChunk)
931
993
  return { chunks, bytes, chunksCount, control: controlRef.current, lateControlSent, cancelled: false };
932
994
  if (options.requestId) {
@@ -1211,6 +1273,8 @@ export class RscRenderer {
1211
1273
  digest,
1212
1274
  });
1213
1275
  if (!body) return null;
1276
+ const viewport = await RscRenderer.#rootViewport(route.renderRootLayouts);
1277
+ const manifestLink = await this.#renderManifestLink(url, route.renderRootLayouts);
1214
1278
  const routeHead =
1215
1279
  "resolveHead" in route
1216
1280
  ? await RouteElementComposer.resolveHeadWithSnapshot({
@@ -1224,7 +1288,8 @@ export class RscRenderer {
1224
1288
  <html lang={params.lang ?? getPathnameLocale(pathname, this.#i18n)} suppressHydrationWarning>
1225
1289
  <head key="head">
1226
1290
  <meta key="charset" charSet="utf-8" />
1227
- <meta key="viewport" name="viewport" content="width=device-width, initial-scale=1" />
1291
+ {this.#renderViewport(viewport)}
1292
+ {manifestLink}
1228
1293
  <meta key="robots" name="robots" content="noindex" />
1229
1294
  {routeHeadSnapshot
1230
1295
  ? renderAkanHeadSnapshot(routeHeadSnapshot)
@@ -1240,7 +1305,8 @@ export class RscRenderer {
1240
1305
  async #renderMatched(
1241
1306
  url: URL,
1242
1307
  match: { pathRoute: PathRoute; params: Record<string, string> },
1243
- searchParams = RouteTreeBuilder.parseSearchParams(url.search),
1308
+ searchParams: Record<string, string | string[]>,
1309
+ notFound: RouteNotFoundInPlace,
1244
1310
  ): Promise<ReactNode> {
1245
1311
  this.#logger.verbose(
1246
1312
  `composing route element pathname=${url.pathname} search=${url.search || "(none)"} params=${JSON.stringify(match.params)}`,
@@ -1250,10 +1316,13 @@ export class RscRenderer {
1250
1316
  basePath: this.#getBasePath(url),
1251
1317
  });
1252
1318
  setRequestFrameState(pathRoute.pageState);
1319
+ await RouteElementComposer.checkArgs({ pathRoute, params: match.params, searchParams });
1253
1320
 
1254
1321
  const rootThemes = await Promise.all(pathRoute.renderRootLayouts.map((render) => render.getLayoutTheme?.()));
1255
1322
  const rootTheme = rootThemes.find((theme) => theme !== undefined);
1256
1323
  if (rootTheme) setRequestTheme(rootTheme);
1324
+ const viewport = await RscRenderer.#rootViewport(pathRoute.renderRootLayouts);
1325
+ const manifestLink = await this.#renderManifestLink(url, pathRoute.renderRootLayouts);
1257
1326
  const routeHead = await RouteElementComposer.resolveHeadWithSnapshot({
1258
1327
  pathRoute,
1259
1328
  params: match.params,
@@ -1265,13 +1334,15 @@ export class RscRenderer {
1265
1334
  params: match.params,
1266
1335
  searchParams,
1267
1336
  navKey: url.pathname + url.search,
1337
+ notFound,
1268
1338
  });
1269
1339
 
1270
1340
  return (
1271
1341
  <html lang={match.params.lang ?? this.#i18n.defaultLocale} suppressHydrationWarning>
1272
1342
  <head key="head">
1273
1343
  <meta key="charset" charSet="utf-8" />
1274
- <meta key="viewport" name="viewport" content="width=device-width, initial-scale=1" />
1344
+ {this.#renderViewport(viewport, rootTheme)}
1345
+ {manifestLink}
1275
1346
  {routeHeadSnapshot
1276
1347
  ? renderAkanHeadSnapshot(routeHeadSnapshot)
1277
1348
  : (routeHead.node ?? this.#renderDefaultHead())}
@@ -1287,7 +1358,8 @@ export class RscRenderer {
1287
1358
  url: URL,
1288
1359
  match: { pathRoute: PathRoute; params: Record<string, string> },
1289
1360
  patchStartIndex: number,
1290
- searchParams = RouteTreeBuilder.parseSearchParams(url.search),
1361
+ searchParams: Record<string, string | string[]>,
1362
+ notFound: RouteNotFoundInPlace,
1291
1363
  ): Promise<ReactNode | null> {
1292
1364
  this.#logger.verbose(
1293
1365
  `composing route suffix pathname=${url.pathname} start=${patchStartIndex} params=${JSON.stringify(match.params)}`,
@@ -1297,6 +1369,7 @@ export class RscRenderer {
1297
1369
  basePath: this.#getBasePath(url),
1298
1370
  });
1299
1371
  setRequestFrameState(pathRoute.pageState);
1372
+ await RouteElementComposer.checkArgs({ pathRoute, params: match.params, searchParams });
1300
1373
  await RouteElementComposer.resolveSuffixLoadings(pathRoute, patchStartIndex);
1301
1374
  return RouteElementComposer.composeSuffix({
1302
1375
  pathRoute,
@@ -1304,6 +1377,7 @@ export class RscRenderer {
1304
1377
  searchParams,
1305
1378
  patchStartIndex,
1306
1379
  navKey: url.pathname + url.search,
1380
+ notFound,
1307
1381
  });
1308
1382
  }
1309
1383
 
@@ -1329,21 +1403,61 @@ export class RscRenderer {
1329
1403
  return this.#renderSystemNotFound(url);
1330
1404
  }
1331
1405
 
1406
+ #notFoundInPlace(url: URL, probe: { hit: boolean }): RouteNotFoundInPlace {
1407
+ return {
1408
+ pathname: url.pathname,
1409
+ onNotFound: () => {
1410
+ probe.hit = true;
1411
+ },
1412
+ systemFallback: () => (
1413
+ <SystemPageMain kind="not-found" pathname={url.pathname} homeHref={this.#systemHomeHref(url)} />
1414
+ ),
1415
+ };
1416
+ }
1417
+
1418
+ #systemHomeHref(url: URL): string {
1419
+ return getSystemPageHomeHref({
1420
+ pathname: url.pathname,
1421
+ i18n: this.#i18n,
1422
+ basePaths: this.#basePaths,
1423
+ headerBasePath: untrackedRequest()?.headers.get("x-base-path"),
1424
+ });
1425
+ }
1426
+
1332
1427
  #renderSystemNotFound(url: URL): ReactNode {
1333
1428
  return createSystemPageDocument({
1334
1429
  kind: "not-found",
1335
1430
  pathname: url.pathname,
1336
1431
  lang: getPathnameLocale(url.pathname, this.#i18n),
1337
- homeHref: getSystemPageHomeHref({
1338
- pathname: url.pathname,
1339
- i18n: this.#i18n,
1340
- basePaths: this.#basePaths,
1341
- headerBasePath: untrackedRequest()?.headers.get("x-base-path"),
1342
- }),
1432
+ homeHref: this.#systemHomeHref(url),
1343
1433
  stylesheetHref: this.#getStylesheetHref(url.pathname),
1344
1434
  });
1345
1435
  }
1346
1436
 
1437
+ static async #rootViewport(renderRootLayouts: RouteRender[]): Promise<RouteViewport | undefined> {
1438
+ const viewports = await Promise.all(renderRootLayouts.map((render) => render.getLayoutViewport?.()));
1439
+ return viewports.find((viewport) => viewport !== undefined);
1440
+ }
1441
+
1442
+ #renderViewport(viewport: RouteViewport | undefined, theme?: string): ReactNode {
1443
+ return (
1444
+ <>
1445
+ <meta key="viewport" name="viewport" content={ViewportMeta.content(viewport)} />
1446
+ {ViewportMeta.themeColors(viewport, theme).map(({ content, media }) => (
1447
+ <meta key={`theme-color:${media ?? ""}`} name="theme-color" content={content} media={media} />
1448
+ ))}
1449
+ </>
1450
+ );
1451
+ }
1452
+
1453
+ async #renderManifestLink(url: URL, renderRootLayouts: RouteRender[]): Promise<ReactNode> {
1454
+ const manifests = await Promise.all(renderRootLayouts.map((render) => render.getLayoutManifest?.()));
1455
+ if (!manifests.some((manifest) => manifest !== undefined)) return null;
1456
+
1457
+ const basePath = getBasePathFromPathname(url.pathname, { basePaths: this.#basePaths, i18n: this.#i18n });
1458
+ return <link key="manifest" rel="manifest" href={webManifestHref(basePath)} />;
1459
+ }
1460
+
1347
1461
  #renderDefaultHead(): ReactNode {
1348
1462
  return <title key="title">{process.env.AKAN_PUBLIC_APP_NAME ?? "Akan App"}</title>;
1349
1463
  }
@@ -9,7 +9,7 @@ import type { ClientManifest } from "./artifact";
9
9
  import type { RouteCacheInvalidation, RouteCacheRenderState } from "./cachePolicy";
10
10
  import { ChildOutputReader } from "./logging/childOutputReader";
11
11
  import { MemoryLimit } from "./memoryLimit";
12
- import type { RscTraceMetadata, SsrLateRedirect } from "./ssrTypes";
12
+ import type { RscTraceMetadata, SsrLateControl } from "./ssrTypes";
13
13
  import type { BaseBuildArtifact, CssAsset } from "./types";
14
14
 
15
15
  const DEFAULT_RSC_HOST_MAX_PENDING_CHUNKS = 256;
@@ -23,6 +23,7 @@ export interface RscPending {
23
23
  onCacheState?: (state: RouteCacheRenderState) => void;
24
24
  onRedirect?: (location: string, method: RscRedirectMethod, status: RscRedirectStatus) => void;
25
25
  onLateRedirect?: (location: string, method: RscRedirectMethod, status: RscRedirectStatus) => void;
26
+ onLateNotFound?: () => void;
26
27
  onNotFound?: () => void;
27
28
  }
28
29
 
@@ -48,7 +49,7 @@ export type RscRenderResult =
48
49
  theme?: AkanTheme;
49
50
  status?: number;
50
51
  trace?: RscTraceMetadata;
51
- lateControl: Promise<SsrLateRedirect | null>;
52
+ lateControl: Promise<SsrLateControl | null>;
52
53
  cacheState: Promise<RouteCacheRenderState>;
53
54
  cancel: (reason?: unknown) => void;
54
55
  }
@@ -159,9 +160,9 @@ export function createRscHostRenderStream(input: {
159
160
  let theme: AkanTheme | undefined;
160
161
  let status: number | undefined;
161
162
  let trace: RscTraceMetadata | undefined;
162
- let resolveLateControl!: (control: SsrLateRedirect | null) => void;
163
+ let resolveLateControl!: (control: SsrLateControl | null) => void;
163
164
  let resolveCacheState!: (state: RouteCacheRenderState) => void;
164
- const lateControl = new Promise<SsrLateRedirect | null>((resolve) => {
165
+ const lateControl = new Promise<SsrLateControl | null>((resolve) => {
165
166
  resolveLateControl = resolve;
166
167
  });
167
168
  const cacheState = new Promise<RouteCacheRenderState>((resolve) => {
@@ -169,7 +170,7 @@ export function createRscHostRenderStream(input: {
169
170
  });
170
171
  let lateControlSettled = false;
171
172
  let cacheStateSettled = false;
172
- const settleLateControl = (control: SsrLateRedirect | null) => {
173
+ const settleLateControl = (control: SsrLateControl | null) => {
173
174
  if (lateControlSettled) return;
174
175
  lateControlSettled = true;
175
176
  resolveLateControl(control);
@@ -277,6 +278,7 @@ export function createRscHostRenderStream(input: {
277
278
  },
278
279
  onLateRedirect: (location, method, status) =>
279
280
  settleLateControl({ type: "redirect", location, method, status }),
281
+ onLateNotFound: () => settleLateControl({ type: "not-found" }),
280
282
  onCacheState: settleCacheState,
281
283
  onNotFound: () => {
282
284
  settleLateControl(null);
@@ -326,11 +328,13 @@ type RscInMsg =
326
328
  method?: RscRedirectMethod;
327
329
  status?: RscRedirectStatus;
328
330
  }
331
+ | { type: "late-not-found"; requestId: string }
329
332
  | { type: "not-found"; requestId: string }
330
333
  | { type: "metrics"; metrics: AkanMetricsReport }
331
334
  | { type: "log.records"; records: LogRecord[]; dropped?: number }
332
335
  | { type: "page-prompts.result"; requestId: string; result: PagePromptEntry[] }
333
336
  | { type: "page-prompt.result"; requestId: string; result: PagePromptRun }
337
+ | { type: "web-manifest.result"; requestId: string; result: unknown }
334
338
  | {
335
339
  type: "error";
336
340
  requestId: string;
@@ -475,6 +479,11 @@ export class RscWorker {
475
479
  return this.#call<PagePromptRun>((requestId) => ({ type: "page-prompt.run", requestId, input }));
476
480
  }
477
481
 
482
+ /** The root layout's `.manifest()` for `basePath`, in the browser's keys; `null` when it declares none. */
483
+ webManifest(basePath: string | null): Promise<unknown> {
484
+ return this.#call<unknown>((requestId) => ({ type: "web-manifest", requestId, basePath }));
485
+ }
486
+
478
487
  #call<T>(message: (requestId: string) => object): Promise<T> {
479
488
  const requestId = crypto.randomUUID();
480
489
  return new Promise<T>((resolve, reject) => {
@@ -805,6 +814,9 @@ export class RscWorker {
805
814
  .get(message.requestId)
806
815
  ?.onLateRedirect?.(message.location, message.method ?? "replace", message.status ?? 307);
807
816
  return;
817
+ case "late-not-found":
818
+ this.#pending.get(message.requestId)?.onLateNotFound?.();
819
+ return;
808
820
  case "not-found":
809
821
  this.#resolvePending(message.requestId, (p) => p.onNotFound?.());
810
822
  return;
@@ -817,6 +829,7 @@ export class RscWorker {
817
829
  return;
818
830
  case "page-prompts.result":
819
831
  case "page-prompt.result":
832
+ case "web-manifest.result":
820
833
  this.#settleCall(message.requestId, (call) => call.resolve(message.result));
821
834
  return;
822
835
  case "error":
package/server/sitemap.ts CHANGED
@@ -34,6 +34,20 @@ export function isSitemapPath(pathname: string, basePaths: readonly string[]): b
34
34
  return normalizePathname(pathname) === "/sitemap.xml";
35
35
  }
36
36
 
37
+ /** The basePath a `/manifest.webmanifest` request asks for: by a visible prefix, else by the request's basePath. */
38
+ export function getWebManifestBasePath(
39
+ pathname: string,
40
+ basePaths: readonly string[],
41
+ headerBasePath?: string | null,
42
+ ): string | null | undefined {
43
+ const segments = normalizePathname(pathname).split("/").filter(Boolean);
44
+ if (segments.at(-1) !== "manifest.webmanifest" || segments.length > 2) return undefined;
45
+ const known = basePaths.map(normalizeSegment);
46
+ if (segments.length === 2) return known.includes(segments[0] ?? "") ? (segments[0] ?? null) : undefined;
47
+ const fromHeader = normalizeSegment(headerBasePath ?? "");
48
+ return known.includes(fromHeader) ? fromHeader : null;
49
+ }
50
+
37
51
  export function getSitemapBasePath(
38
52
  pathname: string,
39
53
  basePaths: readonly string[],
@@ -9,7 +9,13 @@ import { renderToReadableStream } from "react-dom/server.browser";
9
9
  import { createFromNodeStream } from "react-server-dom-webpack/client.node";
10
10
  import { parsePositiveInt } from "./cachePolicy";
11
11
  import { concatBytes } from "./rscHttp";
12
- import type { SsrChunkRegistryStats, SsrDocumentOptions, SsrFromRscInput, SsrLateRedirect } from "./ssrTypes";
12
+ import type {
13
+ SsrChunkRegistryStats,
14
+ SsrDocumentOptions,
15
+ SsrFromRscInput,
16
+ SsrLateControl,
17
+ SsrLateRedirect,
18
+ } from "./ssrTypes";
13
19
 
14
20
  const DEFAULT_SSR_CHUNK_REGISTRY_MAX_ENTRIES = 1024;
15
21
  const DEFAULT_MAX_PENDING_INLINE_RSC_SCRIPTS = 32;
@@ -196,7 +202,7 @@ export class ExpectedLateRedirectStderrSuppressor {
196
202
  #lateRedirect = false;
197
203
  #lateControlSettled = false;
198
204
 
199
- private constructor(lateControl: Promise<SsrLateRedirect | null>) {
205
+ private constructor(lateControl: Promise<SsrLateControl | null>) {
200
206
  lateControl
201
207
  .then((control) => {
202
208
  this.#lateRedirect = control?.type === "redirect";
@@ -210,7 +216,7 @@ export class ExpectedLateRedirectStderrSuppressor {
210
216
  });
211
217
  }
212
218
 
213
- static start(lateControl?: Promise<SsrLateRedirect | null>): ExpectedLateRedirectStderrSuppressor | null {
219
+ static start(lateControl?: Promise<SsrLateControl | null>): ExpectedLateRedirectStderrSuppressor | null {
214
220
  if (!lateControl) return null;
215
221
 
216
222
  if (process.env.NODE_ENV === "production" && process.env.AKAN_SUPPRESS_LATE_REDIRECT_STDERR !== "1") return null;
@@ -337,7 +343,7 @@ export function interleaveRscScriptsWithHtml(
337
343
  rscClientStream: ReadableStream<Uint8Array>,
338
344
  options: {
339
345
  bootstrapModuleScripts?: string;
340
- lateControl?: Promise<SsrLateRedirect | null>;
346
+ lateControl?: Promise<SsrLateControl | null>;
341
347
  maxPendingRscScripts?: number;
342
348
  onPendingRscScriptsSize?: (size: number) => void;
343
349
  onComplete?: () => void;
@@ -433,7 +439,7 @@ export function interleaveRscScriptsWithHtml(
433
439
  const rscPump = pumpRscScripts();
434
440
  const lateControlPump = options.lateControl?.then((control) => {
435
441
  try {
436
- if (!control || errored) return;
442
+ if (control?.type !== "redirect" || errored) return;
437
443
  pendingControlScripts.push(encoder.encode(createSoftRedirectScript(control)));
438
444
  notifyScriptAvailable();
439
445
  } finally {
@@ -691,7 +697,7 @@ export class SsrFromRscRenderer {
691
697
 
692
698
  static #suppressExpectedLateRedirectError(
693
699
  thenable: PromiseLike<ReactNode>,
694
- lateControl?: Promise<SsrLateRedirect | null>,
700
+ lateControl?: Promise<SsrLateControl | null>,
695
701
  ): Promise<ReactNode> {
696
702
  const promise = Promise.resolve(thenable);
697
703
  if (!lateControl) return promise;
@@ -26,6 +26,8 @@ export interface SsrLateRedirect {
26
26
  status: 303 | 307 | 308;
27
27
  }
28
28
 
29
+ export type SsrLateControl = SsrLateRedirect | { type: "not-found" };
30
+
29
31
  export interface RscTraceMetadata {
30
32
  navId?: string;
31
33
  pathname: string;
@@ -57,7 +59,7 @@ export interface SsrFromRscInput {
57
59
  importmap?: Record<string, string>;
58
60
  theme?: AkanTheme;
59
61
  injectThemeInitScript?: boolean;
60
- lateControl?: Promise<SsrLateRedirect | null>;
62
+ lateControl?: Promise<SsrLateControl | null>;
61
63
  onCancel?: (reason?: unknown) => void;
62
64
  /** Buffers until `stream.allReady` (`pageConfig.ssr: "block"`); `AKAN_SSR_WAIT_FOR_ALL_READY=1` forces it globally. */
63
65
  waitForAllReady?: boolean;
@@ -57,9 +57,45 @@ a { color: inherit; }
57
57
  .akan-system-details { margin-top: 28px; max-height: 260px; overflow: auto; border-radius: 18px; background: rgba(26, 26, 26, 0.82); border: 1px solid rgba(240, 32, 32, 0.22); padding: 16px; color: rgba(255, 255, 255, 0.78); font-size: 0.82rem; line-height: 1.55; white-space: pre-wrap; }
58
58
  `;
59
59
 
60
- export function createSystemPageDocument(options: SystemPageOptions): ReactNode {
60
+ /** The card alone, styled by the app's own tokens: what a not-found raised after the layouts streamed renders in place. */
61
+ export const SystemPageMain = (options: Omit<SystemPageOptions, "lang" | "stylesheetHref" | "script">) => {
61
62
  const copy = SYSTEM_PAGE_STATUS_COPY[options.kind];
62
63
  const details = options.showDetails ? getSystemPageErrorDetails(options.error) : null;
64
+ return (
65
+ <main className="akan-system-page min-h-screen bg-background text-foreground">
66
+ <section
67
+ className="akan-system-card rounded-3xl border border-foreground/10 bg-foreground/4 p-8 shadow-2xl backdrop-blur-xl"
68
+ aria-labelledby="akan-system-title"
69
+ >
70
+ <p className="akan-system-status text-primary">{copy.status}</p>
71
+ <p className="akan-system-eyebrow text-primary">{copy.eyebrow}</p>
72
+ <h1 id="akan-system-title" className="akan-system-title font-black">
73
+ {copy.title}
74
+ </h1>
75
+ <p className="akan-system-description text-foreground/70">{copy.description}</p>
76
+ <p className="akan-system-path border border-foreground/10 bg-muted/50" aria-label="Requested path">
77
+ {options.pathname}
78
+ </p>
79
+ <div className="akan-system-actions">
80
+ <a className="akan-system-action" href={options.homeHref}>
81
+ {copy.actionLabel}
82
+ </a>
83
+ <a className="akan-system-action akan-system-secondary" href={options.pathname}>
84
+ Try again
85
+ </a>
86
+ </div>
87
+ {details ? (
88
+ <pre className="akan-system-details" aria-label="Development error details">
89
+ {details}
90
+ </pre>
91
+ ) : null}
92
+ </section>
93
+ </main>
94
+ );
95
+ };
96
+
97
+ export function createSystemPageDocument(options: SystemPageOptions): ReactNode {
98
+ const copy = SYSTEM_PAGE_STATUS_COPY[options.kind];
63
99
  const title = `${copy.status} - ${copy.eyebrow}`;
64
100
 
65
101
  return (
@@ -75,35 +111,7 @@ export function createSystemPageDocument(options: SystemPageOptions): ReactNode
75
111
  <style data-akan-system-page>{SYSTEM_PAGE_STYLE}</style>
76
112
  </head>
77
113
  <body>
78
- <main className="akan-system-page min-h-screen bg-background text-foreground">
79
- <section
80
- className="akan-system-card rounded-3xl border border-foreground/10 bg-foreground/4 p-8 shadow-2xl backdrop-blur-xl"
81
- aria-labelledby="akan-system-title"
82
- >
83
- <p className="akan-system-status text-primary">{copy.status}</p>
84
- <p className="akan-system-eyebrow text-primary">{copy.eyebrow}</p>
85
- <h1 id="akan-system-title" className="akan-system-title font-black">
86
- {copy.title}
87
- </h1>
88
- <p className="akan-system-description text-foreground/70">{copy.description}</p>
89
- <p className="akan-system-path border border-foreground/10 bg-muted/50" aria-label="Requested path">
90
- {options.pathname}
91
- </p>
92
- <div className="akan-system-actions">
93
- <a className="akan-system-action" href={options.homeHref}>
94
- {copy.actionLabel}
95
- </a>
96
- <a className="akan-system-action akan-system-secondary" href={options.pathname}>
97
- Try again
98
- </a>
99
- </div>
100
- {details ? (
101
- <pre className="akan-system-details" aria-label="Development error details">
102
- {details}
103
- </pre>
104
- ) : null}
105
- </section>
106
- </main>
114
+ <SystemPageMain {...options} />
107
115
  {options.script ? (
108
116
 
109
117
  <script dangerouslySetInnerHTML={{ __html: options.script }} />
package/server/types.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { AkanWebConfig } from "akanjs";
2
2
  import type { PromiseOrObject } from "akanjs/base";
3
3
  import type { AkanI18nConfig } from "akanjs/common";
4
+ import type { WebsocketRoomCursor } from "akanjs/signal";
4
5
  import type { ClientManifest } from "./artifact";
5
6
  import type { SsrManifest } from "./ssrTypes";
6
7
 
@@ -8,6 +9,7 @@ export type WebsocketRoute = (
8
9
  ws: Bun.ServerWebSocket<unknown>,
9
10
  data: unknown[],
10
11
  event?: "message" | "subscribe" | "unsubscribe",
12
+ request?: { since?: WebsocketRoomCursor },
11
13
  ) => PromiseOrObject<unknown>;
12
14
 
13
15
  export type WebsocketRoutes = Record<string, WebsocketRoute>;