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
@@ -39,6 +39,7 @@ import { type Endpoint, type EndpointCls, sliceEndpoint } from "../../signal/end
39
39
  import type { EndpointInfo } from "../../signal/endpointInfo";
40
40
  import { EndpointRateLimit } from "../../signal/endpointRateLimit";
41
41
  import type { Internal, InternalCls } from "../../signal/internal";
42
+ import { Machine } from "../../signal/internalArg";
42
43
  import type { InternalInfo } from "../../signal/internalInfo";
43
44
  import type { MiddlewareCls } from "../../signal/middleware";
44
45
  import type { ServerSignal, ServerSignalCls } from "../../signal/serverSignal";
@@ -52,6 +53,8 @@ import type {
52
53
  WebsocketMessageData,
53
54
  WebsocketSubscribeAck,
54
55
  } from "../../signal/types";
56
+ import { MachineToken } from "../machine/machineToken";
57
+ import type { RoomReplay } from "../routing/roomReplay";
55
58
  import type { HttpRoutes, LocalPublish, SignalRoutes, WebsocketRoutes } from "../types";
56
59
 
57
60
  type LiveChangeListener = (doc: unknown, type: unknown, previous?: unknown) => void;
@@ -79,8 +82,15 @@ export class SignalResolver {
79
82
  const separator = roomId.indexOf("-");
80
83
  return SignalResolver.#coalescingRooms.has(separator >= 0 ? roomId.slice(0, separator) : roomId);
81
84
  }
82
- static setLocalPublish(localPublish: LocalPublish, websocket: WebsocketAdaptor, live?: LiveRegistry) {
85
+ static #roomReplay: RoomReplay | null = null;
86
+ static setLocalPublish(
87
+ localPublish: LocalPublish,
88
+ websocket: WebsocketAdaptor,
89
+ live?: LiveRegistry,
90
+ roomReplay: RoomReplay | null = null,
91
+ ) {
83
92
  SignalResolver.#localPublish = localPublish;
93
+ SignalResolver.#roomReplay = roomReplay;
84
94
  websocket.setEventHandler((roomId, data) => localPublish(roomId, data as object | object[] | Uint8Array));
85
95
 
86
96
  websocket.onRecovered?.(() => {
@@ -245,12 +255,14 @@ export class SignalResolver {
245
255
  if (!internalInfo.execFn) throw new Error(`Exec function is not set for ${key}`);
246
256
  const execFn = internalInfo.execFn.bind(internal);
247
257
 
258
+ const { onFailed } = internalInfo.signalOption;
248
259
  internal.queue.registerProcessWorker(
249
260
  key,
250
261
  SignalResolver.#traced(
251
262
  key,
252
263
  async (job) => await execFn(...SignalResolver.#getJobArgs(key, internalInfo, job), job),
253
264
  ),
265
+ onFailed ? { onFailed: (job, error) => onFailed.call(internal, job, error) } : {},
254
266
  );
255
267
  break;
256
268
  }
@@ -626,6 +638,7 @@ export class SignalResolver {
626
638
  const wsRoutes: WebsocketRoutes = {};
627
639
  const defaultPrefix = endpointCls.srv.cnst?.refName;
628
640
  SignalResolver.#warnUnguarded(endpointMeta);
641
+ SignalResolver.#warnMachineKeyless(endpointMeta);
629
642
  Object.entries(endpointMeta).forEach(([key, endpointInfo]) => {
630
643
  const path = endpointInfo.getRoutePath(key, defaultPrefix);
631
644
  if (endpointInfo.signalOption.globalPrefix !== undefined) {
@@ -686,7 +699,7 @@ export class SignalResolver {
686
699
  );
687
700
  break;
688
701
  case "pubsub":
689
- wsRoutes[key] = async (ws, message, event) =>
702
+ wsRoutes[key] = async (ws, message, event, request) =>
690
703
  await SignalContext.run(endpoint, endpointInfo, key, "websocket", async () => {
691
704
  const websocket = SignalResolver.#getWebsocket(registry);
692
705
  const context = await new SignalContext(
@@ -710,14 +723,28 @@ export class SignalResolver {
710
723
  roomId,
711
724
  query: query as never,
712
725
  fallback: liveOption.fallback,
726
+ payload: liveOption.payload,
713
727
  fields: SignalResolver.#queryFieldsOf(live, liveOption.refName),
714
728
  });
729
+ const replay = SignalResolver.#roomReplay;
730
+ replay?.watch(roomId);
715
731
  ws.subscribe(roomId);
732
+
733
+ const missed = request?.since && replay ? replay.since(roomId, request.since) : null;
734
+ for (const frame of missed ?? []) ws.send(frame);
716
735
  roomCtxMap.set(roomId, context);
717
736
  SignalResolver.#liveWsPubsubRoomCtx.set(ws, roomCtxMap);
718
737
  websocket.joinRoom(ws, roomId);
719
738
  SignalResolver.logger.verbose(`WebSocket subscribed to room ${roomId}`);
720
- const ack: WebsocketSubscribeAck = { type: "sub", roomId, requestRoomId, subscribe };
739
+ const cursor = replay?.cursor(roomId);
740
+ const ack: WebsocketSubscribeAck = {
741
+ type: "sub",
742
+ roomId,
743
+ requestRoomId,
744
+ subscribe,
745
+ ...(cursor ? { cursor } : {}),
746
+ ...(request?.since ? { replayed: !!missed } : {}),
747
+ };
721
748
  return ack;
722
749
  }
723
750
  if (liveOption) await context.resolveInternalArgs();
@@ -768,6 +795,16 @@ export class SignalResolver {
768
795
  `${open.join(", ")} declare${open.length === 1 ? "s" : ""} no guards, so anyone can call ${open.length === 1 ? "it" : "them"} over HTTP and WebSocket. Name the guards, or \`guards: [Public]\` to keep one open on purpose.`,
769
796
  );
770
797
  }
798
+ static #warnMachineKeyless(endpointMeta: { [key: string]: EndpointInfo }) {
799
+ if (MachineToken.canVerify()) return;
800
+ const machineOnly = Object.entries(endpointMeta)
801
+ .filter(([, endpointInfo]) => endpointInfo.internalArgs.some((arg) => arg.argRef === Machine))
802
+ .map(([key]) => key);
803
+ if (!machineOnly.length) return;
804
+ SignalResolver.logger.error(
805
+ `${machineOnly.join(", ")} take${machineOnly.length === 1 ? "s" : ""} .with(Machine), and this server has neither AKAN_MACHINE_PUBLIC_KEY nor AKAN_MACHINE_PRIVATE_KEY to verify a machine token: every machine call to ${machineOnly.length === 1 ? "it" : "them"} is refused.`,
806
+ );
807
+ }
771
808
  static #selectCache = new WeakMap<Cls, Record<string, true>>();
772
809
  static #selectForConstant(constant: Cls): Record<string, true> | undefined {
773
810
  const cached = SignalResolver.#selectCache.get(constant);
@@ -19,6 +19,14 @@ import {
19
19
  } from "./routeState";
20
20
  import { AkanSegmentOutletReference } from "./rscSegmentOutletReference";
21
21
 
22
+ /** How a render reached after the layouts streamed answers `router.notFound()` — in place, since its parents are out. */
23
+ export interface RouteNotFoundInPlace {
24
+ pathname: string;
25
+ /** Rendered when no layout above the thrower declares `.notFound()`. */
26
+ systemFallback: () => ReactNode;
27
+ onNotFound: () => void;
28
+ }
29
+
22
30
  export class RouteElementComposer {
23
31
  static async resolveSsrFramePathRoute({
24
32
  pathRoute,
@@ -63,11 +71,13 @@ export class RouteElementComposer {
63
71
  params,
64
72
  searchParams,
65
73
  navKey,
74
+ notFound,
66
75
  }: {
67
76
  pathRoute: PathRoute;
68
77
  params: Record<string, string>;
69
78
  searchParams: Record<string, string | string[]>;
70
79
  navKey?: string;
80
+ notFound?: RouteNotFoundInPlace;
71
81
  }): ReactNode {
72
82
  return RouteElementComposer.composeRenders({
73
83
  renders: RouteElementComposer.#getRenderStack(pathRoute),
@@ -75,29 +85,50 @@ export class RouteElementComposer {
75
85
  params,
76
86
  searchParams,
77
87
  navKey,
88
+ notFound,
78
89
  });
79
90
  }
80
91
 
92
+ static async checkArgs({
93
+ pathRoute,
94
+ params,
95
+ searchParams,
96
+ }: {
97
+ pathRoute: PathRoute;
98
+ params: Record<string, string>;
99
+ searchParams: Record<string, string | string[]>;
100
+ }): Promise<void> {
101
+ await Promise.all(
102
+ RouteElementComposer.#getRenderStack(pathRoute).map((routeRender) =>
103
+ routeRender?.checkArgs?.({ params, searchParams }),
104
+ ),
105
+ );
106
+ }
107
+
81
108
  static composeSuffix({
82
109
  pathRoute,
83
110
  params,
84
111
  searchParams,
85
112
  patchStartIndex,
86
113
  navKey,
114
+ notFound,
87
115
  }: {
88
116
  pathRoute: PathRoute;
89
117
  params: Record<string, string>;
90
118
  searchParams: Record<string, string | string[]>;
91
119
  patchStartIndex: number;
92
120
  navKey?: string;
121
+ notFound?: RouteNotFoundInPlace;
93
122
  }): ReactNode | null {
94
123
  const renders = RouteElementComposer.#getRenderStack(pathRoute);
95
124
  if (!Number.isInteger(patchStartIndex) || patchStartIndex < 0 || patchStartIndex >= renders.length) return null;
96
125
  return RouteElementComposer.composeRenders({
97
126
  renders: renders.slice(patchStartIndex),
127
+ owners: renders.slice(0, patchStartIndex),
98
128
  params,
99
129
  searchParams,
100
130
  navKey,
131
+ notFound,
101
132
  });
102
133
  }
103
134
 
@@ -174,16 +205,21 @@ export class RouteElementComposer {
174
205
 
175
206
  static composeRenders({
176
207
  renders,
208
+ owners = [],
177
209
  segments,
178
210
  params,
179
211
  searchParams,
180
212
  navKey,
213
+ notFound,
181
214
  }: {
182
215
  renders: RouteRender[];
216
+ /** Layouts above `renders` that this element leaves out (a patch) but whose `.notFound()` still applies. */
217
+ owners?: RouteRender[];
183
218
  segments?: AkanRouteSegmentState[];
184
219
  params: Record<string, string>;
185
220
  searchParams: Record<string, string | string[]>;
186
221
  navKey?: string;
222
+ notFound?: RouteNotFoundInPlace;
187
223
  }): ReactNode {
188
224
  let element: ReactNode = null;
189
225
  for (let i = renders.length - 1; i >= 0; i--) {
@@ -194,7 +230,12 @@ export class RouteElementComposer {
194
230
  navKey && loadingFallback != null && i === renders.length - 1 ? `akan-loading:${navKey}` : undefined;
195
231
  element = (
196
232
  <Suspense key={suspenseKey} fallback={loadingFallback}>
197
- <RouteElementComposer.AsyncRender routeRender={routeRender} params={params} searchParams={searchParams}>
233
+ <RouteElementComposer.AsyncRender
234
+ routeRender={routeRender}
235
+ params={params}
236
+ searchParams={searchParams}
237
+ notFound={notFound ? { ...notFound, owners: [...owners, ...renders.slice(0, i)] } : undefined}
238
+ >
198
239
  {element}
199
240
  </RouteElementComposer.AsyncRender>
200
241
  </Suspense>
@@ -217,12 +258,47 @@ export class RouteElementComposer {
217
258
  children,
218
259
  params,
219
260
  searchParams,
261
+ notFound,
220
262
  }: {
221
263
  routeRender: RouteRender;
222
264
  children: ReactNode;
223
265
  params: Record<string, string>;
224
266
  searchParams: Record<string, string | string[]>;
225
- }) => RouteElementComposer.#normalizeReactNode(await routeRender.render({ children, params, searchParams } as never));
267
+ notFound?: RouteNotFoundInPlace & { owners: RouteRender[] };
268
+ }) => {
269
+ try {
270
+ return RouteElementComposer.#normalizeReactNode(
271
+ await routeRender.render({ children, params, searchParams } as never),
272
+ );
273
+ } catch (error) {
274
+ if (!notFound || (error as { digest?: unknown } | null)?.digest !== "AKAN_NOT_FOUND") throw error;
275
+ notFound.onNotFound();
276
+ return await RouteElementComposer.#renderNotFoundInPlace(notFound, params, searchParams);
277
+ }
278
+ };
279
+
280
+ static async #renderNotFoundInPlace(
281
+ { owners, pathname, systemFallback }: RouteNotFoundInPlace & { owners: RouteRender[] },
282
+ params: Record<string, string>,
283
+ searchParams: Record<string, string | string[]>,
284
+ ): Promise<ReactNode> {
285
+ for (let index = owners.length - 1; index >= 0; index--) {
286
+ const fallback = await owners[index]?.resolveNotFound?.();
287
+ if (!fallback) continue;
288
+ return (
289
+ <>
290
+ <meta name="robots" content="noindex" />
291
+ {RouteElementComposer.#normalizeReactNode(await fallback({ params, searchParams, pathname }))}
292
+ </>
293
+ );
294
+ }
295
+ return (
296
+ <>
297
+ <meta name="robots" content="noindex" />
298
+ {systemFallback()}
299
+ </>
300
+ );
301
+ }
226
302
 
227
303
  static #makeFallbackRouteRender({
228
304
  kind,
@@ -27,6 +27,8 @@ export interface AkanRouterStateV1 {
27
27
  href: string;
28
28
  routeId: string;
29
29
  segments: AkanRouteSegmentState[];
30
+ /** The route's `.config({ transition })`, which the browser plays as a view transition on the way in and out. */
31
+ transition?: string;
30
32
  }
31
33
 
32
34
  export type AkanHeadSnapshotTag = "title" | "meta" | "link";
@@ -132,6 +134,7 @@ export function isAkanRouterStateV1(value: unknown): value is AkanRouterStateV1
132
134
  (state.buildId === undefined || typeof state.buildId === "number") &&
133
135
  typeof state.href === "string" &&
134
136
  typeof state.routeId === "string" &&
137
+ (state.transition === undefined || typeof state.transition === "string") &&
135
138
  Array.isArray(state.segments) &&
136
139
  state.segments.every(isSegmentState)
137
140
  );
@@ -207,10 +210,12 @@ export function createAkanRouterState({
207
210
  pathRoute,
208
211
  href,
209
212
  buildId,
213
+ transition,
210
214
  }: {
211
215
  pathRoute: PathRoute;
212
216
  href: string;
213
217
  buildId?: number;
218
+ transition?: string;
214
219
  }): AkanRouterStateV1 {
215
220
  return {
216
221
  version: AKAN_RSC_STATE_VERSION,
@@ -218,6 +223,7 @@ export function createAkanRouterState({
218
223
  href,
219
224
  routeId: pathRoute.path,
220
225
  segments: createAkanRouteSegments(pathRoute),
226
+ ...(transition && transition !== "none" ? { transition } : {}),
221
227
  };
222
228
  }
223
229
 
@@ -8,6 +8,8 @@ import type {
8
8
  Route,
9
9
  RouteModule,
10
10
  RouteRender,
11
+ RouteViewport,
12
+ WebAppManifest,
11
13
  } from "akanjs/client";
12
14
  import {
13
15
  assertUniqueRoutePatterns,
@@ -22,6 +24,7 @@ import {
22
24
  } from "akanjs/common";
23
25
  import { createElement } from "react";
24
26
  import { defaultPageState, validatePageConfig } from "../client/frameConfig";
27
+ import { RouteHead } from "../client/route/RouteHead";
25
28
  import {
26
29
  type ResolvedRouteModule,
27
30
  type RouteModuleSource,
@@ -291,7 +294,18 @@ export class RouteTreeBuilder {
291
294
  },
292
295
  resolveHead: async (props: PageProps) => {
293
296
  const mod = await loadSynced();
294
- return mod.generateHead ? await mod.generateHead(props) : mod.head;
297
+ try {
298
+ return mod.generateHead ? await mod.generateHead(props) : mod.head;
299
+ } catch (error) {
300
+
301
+ const digest = (error as { digest?: unknown } | null)?.digest;
302
+ if (digest === "AKAN_REDIRECT" || digest === "AKAN_NOT_FOUND") throw error;
303
+ RouteTreeBuilder.logger.warn(`${key}: .head() threw, so the route renders without it: ${String(error)}`);
304
+ return undefined;
305
+ }
306
+ },
307
+ checkArgs: async ({ params, searchParams }: PageProps) => {
308
+ (await loadModule()).definition?.resolveArgs({ params, searchParams });
295
309
  },
296
310
  };
297
311
  if (kind === "page") {
@@ -303,6 +317,14 @@ export class RouteTreeBuilder {
303
317
  const { module: mod } = await loadModule();
304
318
  return "theme" in mod ? (mod.theme as string | undefined) : undefined;
305
319
  };
320
+ routeRender.getLayoutViewport = async () => {
321
+ const { module: mod } = await loadModule();
322
+ return "viewport" in mod ? (mod.viewport as RouteViewport | undefined) : undefined;
323
+ };
324
+ routeRender.getLayoutManifest = async () => {
325
+ const { module: mod } = await loadModule();
326
+ return "manifest" in mod ? (mod.manifest as WebAppManifest | undefined) : undefined;
327
+ };
306
328
  routeRender.resolveNotFound = async () => syncFallbacks((await loadModule()).module as LayoutModule).NotFound;
307
329
  routeRender.resolveError = async () => syncFallbacks((await loadModule()).module as LayoutModule).Error;
308
330
  }
@@ -321,15 +343,10 @@ export class RouteTreeBuilder {
321
343
  };
322
344
  }
323
345
 
346
+ /** `resolvers` run leaf first; their heads merge root first, so a deeper level takes over each tag it writes. */
324
347
  static #composeHeadResolvers(...resolvers: (ResolveHead | undefined)[]): ResolveHead | undefined {
325
348
  const chain = resolvers.filter((resolver): resolver is ResolveHead => Boolean(resolver));
326
- if (chain.length === 0) return undefined;
327
- return async (props) => {
328
- for (const resolver of chain) {
329
- const head = await resolver(props);
330
- if (head !== null && head !== undefined) return head;
331
- }
332
- return undefined;
333
- };
349
+ if (chain.length <= 1) return chain[0];
350
+ return async (props) => RouteHead.merge(await Promise.all(chain.toReversed().map((resolver) => resolver(props))));
334
351
  }
335
352
  }
@@ -140,10 +140,13 @@ export class ApiRouter {
140
140
  if (typeof message === "string" && typeof hmrHub?.handleMessage === "function") hmrHub.handleMessage(message);
141
141
  return;
142
142
  }
143
+
144
+ let failedKey: string | undefined;
143
145
  try {
144
146
  if (typeof message === "string") {
145
147
  const msg = JSON.parse(message) as WebsocketReqData;
146
148
  if (!msg.key) throw new Error("Message key is required");
149
+ failedKey = msg.key;
147
150
  if (msg.key === websocketAuthContract.key) {
148
151
 
149
152
  AppWsData.applyCredential(AppWsData.of(ws), websocketAuthContract.readJwt(msg.data));
@@ -159,19 +162,19 @@ export class ApiRouter {
159
162
  if (!wsRoute) throw new Error(`WebSocket route "${msg.key}" is not registered`);
160
163
  const eventType =
161
164
  typeof msg.subscribe === "boolean" ? (msg.subscribe ? "subscribe" : "unsubscribe") : "message";
162
- const result = await wsRoute(ws, msg.data, eventType);
165
+ const result = await wsRoute(ws, msg.data, eventType, { since: msg.since });
163
166
  ws.send(JSON.stringify(result));
164
167
  } else throw new Error("Message is not a string");
165
168
  } catch (error) {
166
169
  if (isExceptionLike(error)) {
167
- ws.send(JSON.stringify({ ...error.toJSON(), timestamp: new Date().toISOString() }));
170
+ ws.send(JSON.stringify({ ...error.toJSON(), key: failedKey, timestamp: new Date().toISOString() }));
168
171
  return;
169
172
  }
170
173
  if (!SignalContext.wasReported(error)) {
171
174
  logger.error(error instanceof Error ? (error.stack ?? error.message) : String(error));
172
175
  }
173
176
 
174
- ws.send(JSON.stringify({ ...SignalFailure.body(error), at: dayjs() }));
177
+ ws.send(JSON.stringify({ ...SignalFailure.body(error), key: failedKey, at: dayjs() }));
175
178
  }
176
179
  },
177
180
  close: (ws) => {
@@ -0,0 +1,88 @@
1
+ import type { WebsocketPublishData, WebsocketRoomCursor } from "akanjs/signal";
2
+
3
+ interface RoomLog {
4
+ /** Names this numbering: a room log that expired and started over counts from 1 again under another epoch. */
5
+ epoch: string;
6
+ seq: number;
7
+ watchedAt: number;
8
+ frames: { seq: number; at: number; frame: string }[];
9
+ }
10
+
11
+ export interface RoomReplayOptions {
12
+ /** Whether this process sees every publish to a room, so a run of sequence numbers it holds has no hole. */
13
+ vouches: boolean;
14
+ /** Frames kept per room. */
15
+ depth?: number;
16
+ /** How long a room nobody subscribes to here keeps numbering and keeping its frames. */
17
+ retainMs?: number;
18
+ /** Rooms tracked at once; the least recently watched goes first. */
19
+ rooms?: number;
20
+ }
21
+
22
+ export class RoomReplay {
23
+ readonly #process = crypto.randomUUID();
24
+ #generation = 0;
25
+ readonly vouches: boolean;
26
+ readonly #depth: number;
27
+ readonly #retainMs: number;
28
+ readonly #maxRooms: number;
29
+ readonly #rooms = new Map<string, RoomLog>();
30
+
31
+ constructor({ vouches, depth = 128, retainMs = 5 * 60_000, rooms = 10_000 }: RoomReplayOptions) {
32
+ this.vouches = vouches;
33
+ this.#depth = depth;
34
+ this.#retainMs = retainMs;
35
+ this.#maxRooms = rooms;
36
+ }
37
+
38
+ /** A socket subscribed here: the room is numbered from now on, and for `retainMs` after its last subscriber left. */
39
+ watch(roomId: string, now = Date.now()) {
40
+ const room = this.#rooms.get(roomId) ?? {
41
+ epoch: `${this.#process}.${++this.#generation}`,
42
+ seq: 0,
43
+ watchedAt: now,
44
+ frames: [],
45
+ };
46
+ room.watchedAt = now;
47
+ this.#rooms.delete(roomId);
48
+ this.#rooms.set(roomId, room);
49
+ while (this.#rooms.size > this.#maxRooms) {
50
+ const oldest = this.#rooms.keys().next().value;
51
+ if (oldest === undefined) break;
52
+ this.#rooms.delete(oldest);
53
+ }
54
+ }
55
+
56
+ /** The frame to send for one publish; numbered, and kept, while the room is watched. */
57
+ frameOf(publishData: WebsocketPublishData, subscribed: boolean, now = Date.now()): string {
58
+ const room = this.#rooms.get(publishData.roomId);
59
+ if (room && subscribed) room.watchedAt = now;
60
+ if (!room || now - room.watchedAt > this.#retainMs) {
61
+ if (room) this.#rooms.delete(publishData.roomId);
62
+ return JSON.stringify(publishData);
63
+ }
64
+ room.seq += 1;
65
+ const frame = JSON.stringify({ ...publishData, seq: room.seq });
66
+ room.frames.push({ seq: room.seq, at: now, frame });
67
+ while (room.frames.length > this.#depth || (room.frames[0] && now - room.frames[0].at > this.#retainMs))
68
+ room.frames.shift();
69
+ return frame;
70
+ }
71
+
72
+ /** Where the room's numbering stands here, for a subscribe's ack; `null` for a room nobody watches. */
73
+ cursor(roomId: string): WebsocketRoomCursor | null {
74
+ const room = this.#rooms.get(roomId);
75
+ return room ? { epoch: room.epoch, seq: room.seq } : null;
76
+ }
77
+
78
+ /** The frames numbered after the cursor, or `null` when this process cannot tell whether that is all of them. */
79
+ since(roomId: string, { epoch, seq }: WebsocketRoomCursor): string[] | null {
80
+ const room = this.#rooms.get(roomId);
81
+ if (!this.vouches || !room || epoch !== room.epoch || !Number.isSafeInteger(seq) || seq < 0 || seq > room.seq)
82
+ return null;
83
+ if (seq === room.seq) return [];
84
+ const first = room.frames[0];
85
+ if (!first || first.seq > seq + 1) return null;
86
+ return room.frames.filter((entry) => entry.seq > seq).map((entry) => entry.frame);
87
+ }
88
+ }
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import { createElement, type ReactNode, startTransition, type Usable, use, useLayoutEffect, useState } from "react";
2
3
  import { hydrateRoot } from "react-dom/client";
3
4
  import { createFromReadableStream } from "react-server-dom-webpack/client.browser";
@@ -179,8 +180,7 @@ function commitRscPatchNavigation({
179
180
  rollbackPreparedAkanHeadSnapshotPatch(preparedHeadPatch);
180
181
  return;
181
182
  }
182
- if (replace) window.history.replaceState(null, "", target);
183
- else window.history.pushState(null, "", target);
183
+ commitHistory(target, replace);
184
184
  if (scrollToTop) bumpScrollToTop?.();
185
185
  } catch {
186
186
  if (headApplied) rollbackPreparedAkanHeadSnapshotPatch(preparedHeadPatch);
@@ -192,6 +192,37 @@ function commitRscPatchNavigation({
192
192
  return outletCommitted && headApplied;
193
193
  }
194
194
 
195
+ function akanHistoryState(replace: boolean, shallow = false) {
196
+ const idx = (window.history.state as { __akanRouter?: { idx?: unknown } } | null)?.__akanRouter?.idx;
197
+ const current = Number.isInteger(idx) ? (idx as number) : 0;
198
+ return { __akanRouter: { idx: replace ? current : current + 1, ...(shallow ? { shallow: true } : {}) } };
199
+ }
200
+
201
+ let renderedHref = normalizeHref(window.location.href);
202
+ const pathnameOf = (href: string) => new URL(href).pathname;
203
+
204
+ function commitHistory(target: string, replace: boolean | undefined) {
205
+ if (replace) window.history.replaceState(akanHistoryState(true), "", target);
206
+ else window.history.pushState(akanHistoryState(false), "", target);
207
+ renderedHref = target;
208
+ }
209
+
210
+ const addTransitionType = (React as { addTransitionType?: (type: string) => void }).addTransitionType;
211
+
212
+ function viewTransitionTypeOf(transition: string | undefined, push: boolean): string | null {
213
+ if (!transition || transition === "none") return null;
214
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return null;
215
+ return `akan-${transition}-${push ? "push" : "pop"}`;
216
+ }
217
+
218
+ /** Writes the entry without asking the server for the page; only a change that keeps the rendered path qualifies. */
219
+ function navigateShallow(target: string, replace: boolean | undefined): boolean {
220
+ if (pathnameOf(target) !== pathnameOf(renderedHref)) return false;
221
+ if (replace) window.history.replaceState(akanHistoryState(true, true), "", target);
222
+ else window.history.pushState(akanHistoryState(false, true), "", target);
223
+ return true;
224
+ }
225
+
195
226
  async function fetchRsc(
196
227
  href: string,
197
228
  options: {
@@ -383,6 +414,7 @@ function Root(): ReactNode {
383
414
  };
384
415
 
385
416
  globalThis.__AKAN_RSC_NAVIGATE__ = async (href, options = {}) => {
417
+ if (options.shallow && navigateShallow(normalizeHref(href), options.replace)) return;
386
418
  const navId = ++navigationSeq;
387
419
  const target = normalizeHref(href);
388
420
  const scrollToTop = options.scrollToTop ?? true;
@@ -482,6 +514,11 @@ function Root(): ReactNode {
482
514
  });
483
515
 
484
516
  await nextNode.thenable;
517
+
518
+ const viewTransitionType = viewTransitionTypeOf(
519
+ options.pop ? currentRouterState?.transition : nextNode.routerState?.transition,
520
+ !options.pop,
521
+ );
485
522
  const committed = commitLatestRscNavigation({
486
523
  cache: rscCache,
487
524
  href: target,
@@ -489,13 +526,16 @@ function Root(): ReactNode {
489
526
  maxEntries: MAX_RSC_CACHE_ENTRIES,
490
527
  startTransition,
491
528
  commitThenable: (node) => {
529
+ if (viewTransitionType && addTransitionType) {
530
+ addTransitionType("akan-nav");
531
+ addTransitionType(viewTransitionType);
532
+ }
492
533
  currentCommitFromCache = servedFromCache;
493
534
  resetAkanSegmentOutletPatches();
494
535
  setThenable(node.thenable);
495
536
  },
496
537
  updateHistory: () => {
497
- if (options.replace) window.history.replaceState(null, "", target);
498
- else window.history.pushState(null, "", target);
538
+ commitHistory(target, options.replace);
499
539
  },
500
540
  scrollToTop,
501
541
  bumpScrollToTop: () => setScrollToTopTick((tick) => tick + 1),
@@ -514,11 +554,16 @@ function Root(): ReactNode {
514
554
  return use(thenable as Usable<ReactNode>);
515
555
  }
516
556
 
517
- window.addEventListener("popstate", () => {
557
+ window.addEventListener("popstate", (event) => {
558
+ const here = normalizeHref(window.location.href);
559
+ const shallowEntry = (event.state as { __akanRouter?: { shallow?: boolean } } | null)?.__akanRouter?.shallow;
560
+
561
+ const keepsPage = pathnameOf(here) === pathnameOf(renderedHref) && (shallowEntry || here === renderedHref);
518
562
 
519
- void globalThis
520
- .__AKAN_RSC_NAVIGATE__?.(window.location.href, { replace: true, scrollToTop: false })
521
- ?.catch((error: unknown) => hardNavigateAfterRscFailure(window.location.href, true, error));
563
+ if (!keepsPage)
564
+ void globalThis
565
+ .__AKAN_RSC_NAVIGATE__?.(window.location.href, { replace: true, scrollToTop: false, pop: true })
566
+ ?.catch((error: unknown) => hardNavigateAfterRscFailure(window.location.href, true, error));
522
567
  window.setTimeout(() => {
523
568
  if (globalThis.__AKAN_DEV_SYNC_NAVIGATION_APPLYING__) return;
524
569
  const href = globalThis.__AKAN_GET_SYNC_ROUTE_HREF__?.(window.location.href) ?? window.location.href;