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
@@ -0,0 +1,291 @@
1
+ "use client";
2
+ import { type ErrorResponsePayload, type FetchBridge, type FetchBridgeCall, restoreRemoteError } from "akanjs/fetch";
3
+
4
+ interface JsonRpcMessage {
5
+ jsonrpc: "2.0";
6
+ id?: string | number | null;
7
+ method?: string;
8
+ params?: Record<string, unknown>;
9
+ result?: unknown;
10
+ error?: { code: number; message: string; data?: unknown };
11
+ }
12
+
13
+ export interface McpToolResultLike {
14
+ content?: { type: string; text?: string }[];
15
+ structuredContent?: unknown;
16
+ isError?: boolean;
17
+ _meta?: Record<string, unknown>;
18
+ }
19
+
20
+ export interface McpAppTool {
21
+ name: string;
22
+ description?: string;
23
+ inputSchema: Record<string, unknown>;
24
+ annotations?: { readOnlyHint?: boolean; destructiveHint?: boolean; openWorldHint?: boolean };
25
+ }
26
+
27
+ export interface McpAppToolServer {
28
+ list: () => McpAppTool[];
29
+ call: (name: string, args: Record<string, unknown>, signal: AbortSignal) => Promise<McpToolResultLike>;
30
+ }
31
+
32
+ export interface McpHostCapabilities {
33
+ openLinks?: object;
34
+ downloadFile?: object;
35
+ updateModelContext?: { text?: object };
36
+ serverTools?: { listChanged?: boolean };
37
+ }
38
+
39
+ export type McpDownloadContent =
40
+ | { type: "resource"; resource: { uri: string; mimeType?: string; text?: string; blob?: string } }
41
+ | { type: "resource_link"; uri: string; name: string; mimeType?: string };
42
+
43
+ export interface McpHostContext {
44
+ theme?: "light" | "dark";
45
+ displayMode?: "inline" | "fullscreen" | "pip";
46
+ locale?: string;
47
+ timeZone?: string;
48
+ containerDimensions?: { width?: number; height?: number; maxWidth?: number; maxHeight?: number };
49
+ styles?: { variables?: Record<string, string | undefined> };
50
+ }
51
+
52
+ interface McpAppSnapshotRecord {
53
+ key: string;
54
+ args: Record<string, unknown>;
55
+ value: unknown;
56
+ }
57
+
58
+ export type McpAppStart =
59
+ | { ok: true; href: string; snapshot: McpAppSnapshotRecord[]; account: Record<string, unknown> | null }
60
+ | { ok: false; message: string };
61
+
62
+ export class McpAppBridge {
63
+ static readonly protocolVersion = "2026-01-26";
64
+ static readonly initializeTimeoutMs = 15_000;
65
+ static readonly #hostRequests = new Set(["ping", "ui/resource-teardown"]);
66
+
67
+ readonly #pending = new Map<number, { resolve: (value: unknown) => void; reject: (error: Error) => void }>();
68
+ readonly #contextListeners = new Set<(context: McpHostContext) => void>();
69
+ readonly #toolResult: Promise<McpToolResultLike>;
70
+ #resolveToolResult: (result: McpToolResultLike) => void = () => undefined;
71
+ #context: McpHostContext = {};
72
+ #capabilities: McpHostCapabilities = {};
73
+ #tools: McpAppToolServer | null = null;
74
+ #heldToolRequests: JsonRpcMessage[] = [];
75
+ #toolsListed = false;
76
+ readonly #toolCalls = new Map<string | number, AbortController>();
77
+ #seq = 0;
78
+
79
+ constructor() {
80
+ this.#toolResult = new Promise((resolve) => {
81
+ this.#resolveToolResult = resolve;
82
+ });
83
+ window.addEventListener("message", (event) => {
84
+ if (event.source !== window.parent) return;
85
+ const message = event.data as JsonRpcMessage | null;
86
+ if (message?.jsonrpc === "2.0") this.#receive(message);
87
+ });
88
+ }
89
+
90
+ get hostContext(): McpHostContext {
91
+ return this.#context;
92
+ }
93
+
94
+ get hostCapabilities(): McpHostCapabilities {
95
+ return this.#capabilities;
96
+ }
97
+
98
+ /** Whether the host asked for the view's own tools, which is the only sign it offers them to its model. */
99
+ get toolsListed(): boolean {
100
+ return this.#toolsListed;
101
+ }
102
+
103
+ async connect(): Promise<McpAppStart> {
104
+ const initialize = this.request("ui/initialize", {
105
+ protocolVersion: McpAppBridge.protocolVersion,
106
+ appCapabilities: { availableDisplayModes: ["inline", "fullscreen"], tools: { listChanged: true } },
107
+ appInfo: { name: process.env.AKAN_PUBLIC_APP_NAME ?? "akan", version: "0" },
108
+ });
109
+ const timeout = new Promise<null>((resolve) => setTimeout(() => resolve(null), McpAppBridge.initializeTimeoutMs));
110
+ const initialized = (await Promise.race([initialize, timeout]).catch(() => null)) as {
111
+ hostContext?: McpHostContext;
112
+ hostCapabilities?: McpHostCapabilities;
113
+ } | null;
114
+ if (!initialized) return { ok: false, message: "The host did not answer this view." };
115
+ this.#context = { ...initialized.hostContext, ...this.#context };
116
+ this.#capabilities = initialized.hostCapabilities ?? {};
117
+ this.notify("ui/notifications/initialized", {});
118
+ const result = await this.#toolResult;
119
+ const page = (result.structuredContent ?? {}) as { href?: unknown };
120
+ const text = result.content?.find((block) => block.type === "text")?.text;
121
+ if (result.isError || typeof page.href !== "string")
122
+ return { ok: false, message: text ?? "This screen is not available here." };
123
+ const snapshot = result._meta?.["akanjs/snapshot"];
124
+ const account = result._meta?.["akanjs/account"];
125
+ return {
126
+ ok: true,
127
+ href: page.href,
128
+ snapshot: Array.isArray(snapshot) ? (snapshot as McpAppSnapshotRecord[]) : [],
129
+ account: account && typeof account === "object" ? (account as Record<string, unknown>) : null,
130
+ };
131
+ }
132
+
133
+ onHostContext(listener: (context: McpHostContext) => void) {
134
+ this.#contextListeners.add(listener);
135
+ return () => this.#contextListeners.delete(listener);
136
+ }
137
+
138
+ request(
139
+ method: string,
140
+ params: Record<string, unknown>,
141
+ { timeoutMs }: { timeoutMs?: number } = {},
142
+ ): Promise<unknown> {
143
+ const id = ++this.#seq;
144
+ return new Promise((resolve, reject) => {
145
+ this.#pending.set(id, { resolve, reject });
146
+ window.parent.postMessage({ jsonrpc: "2.0", id, method, params }, "*");
147
+ if (timeoutMs)
148
+ setTimeout(() => {
149
+ if (!this.#pending.delete(id)) return;
150
+ reject(new Error(`The host did not answer ${method}`));
151
+ }, timeoutMs);
152
+ });
153
+ }
154
+
155
+ notify(method: string, params: Record<string, unknown>) {
156
+ window.parent.postMessage({ jsonrpc: "2.0", method, params }, "*");
157
+ }
158
+
159
+ async callTool(name: string, args: Record<string, unknown>) {
160
+ return (await this.request("tools/call", {
161
+ name,
162
+ arguments: args,
163
+ _meta: { "akanjs/view": true },
164
+ })) as McpToolResultLike;
165
+ }
166
+
167
+ async openLink(url: string) {
168
+ const result = (await this.request("ui/open-link", { url })) as { isError?: boolean } | null;
169
+ if (result?.isError) throw new Error(`The host declined to open ${url}`);
170
+ }
171
+
172
+ async downloadFile(contents: McpDownloadContent[]) {
173
+ await this.request("ui/download-file", { contents });
174
+ }
175
+
176
+ async updateModelContext(text: string) {
177
+ await this.request("ui/update-model-context", { content: [{ type: "text", text }] }, { timeoutMs: 10_000 });
178
+ }
179
+
180
+ serveTools(server: McpAppToolServer) {
181
+ this.#tools = server;
182
+ const held = this.#heldToolRequests;
183
+ this.#heldToolRequests = [];
184
+ for (const message of held) this.#handle(message);
185
+ }
186
+
187
+ toolsChanged() {
188
+ this.notify("notifications/tools/list_changed", {});
189
+ }
190
+
191
+ fetchBridge(snapshot: McpAppSnapshotRecord[]): FetchBridge {
192
+ const seeded = new Map(snapshot.map((record) => [McpAppBridge.#callKey(record.key, record.args), record.value]));
193
+ return {
194
+ call: async (request: FetchBridgeCall) => {
195
+ const callKey = McpAppBridge.#callKey(request.key, request.args);
196
+ if (request.type === "query" && seeded.has(callKey)) {
197
+ const value = seeded.get(callKey);
198
+ seeded.delete(callKey);
199
+ return value;
200
+ }
201
+ return McpAppBridge.#valueOf(request, await this.callTool(request.key, McpAppBridge.#defined(request.args)));
202
+ },
203
+ };
204
+ }
205
+
206
+ #receive(message: JsonRpcMessage) {
207
+ if (message.method) {
208
+ this.#handle(message);
209
+ return;
210
+ }
211
+ if (typeof message.id !== "number") return;
212
+ const pending = this.#pending.get(message.id);
213
+ if (!pending) return;
214
+ this.#pending.delete(message.id);
215
+ if (message.error) pending.reject(new Error(message.error.message));
216
+ else pending.resolve(message.result);
217
+ }
218
+
219
+ #handle({ id, method = "", params = {} }: JsonRpcMessage) {
220
+ if (method === "ui/notifications/tool-result") this.#resolveToolResult(params as McpToolResultLike);
221
+ if (method === "notifications/cancelled") this.#toolCalls.get(params.requestId as string | number)?.abort();
222
+ if (method === "ui/notifications/tool-cancelled")
223
+ this.#resolveToolResult({ isError: true, content: [{ type: "text", text: "The tool call was cancelled." }] });
224
+
225
+ if (method === "ui/notifications/host-context-changed") {
226
+ const changed = params as McpHostContext;
227
+ const { styles, ...kept } = this.#context;
228
+ this.#context = { ...(changed.theme && !changed.styles ? kept : { ...kept, styles }), ...changed };
229
+ for (const listener of this.#contextListeners) listener(this.#context);
230
+ }
231
+ if (id === undefined || id === null) return;
232
+ if (method === "tools/list" || method === "tools/call") {
233
+
234
+ if (this.#tools) void this.#answerTool(id, method, params, this.#tools);
235
+ else this.#heldToolRequests.push({ jsonrpc: "2.0", id, method, params });
236
+ return;
237
+ }
238
+
239
+ const reply = McpAppBridge.#hostRequests.has(method)
240
+ ? { result: {} }
241
+ : { error: { code: -32601, message: `Method not found: ${method}` } };
242
+ window.parent.postMessage({ jsonrpc: "2.0", id, ...reply }, "*");
243
+ }
244
+
245
+ async #answerTool(id: string | number, method: string, params: Record<string, unknown>, tools: McpAppToolServer) {
246
+ const controller = new AbortController();
247
+ let reply: Pick<JsonRpcMessage, "result" | "error">;
248
+ try {
249
+ if (method === "tools/list") {
250
+ this.#toolsListed = true;
251
+ reply = { result: { tools: tools.list() } };
252
+ } else {
253
+ const { name, arguments: args } = params as { name?: unknown; arguments?: unknown };
254
+ if (typeof name !== "string") throw new Error("tools/call names no tool");
255
+ const callArgs = args && typeof args === "object" ? (args as Record<string, unknown>) : {};
256
+ this.#toolCalls.set(id, controller);
257
+ reply = { result: await tools.call(name, callArgs, controller.signal) };
258
+ }
259
+ } catch (error) {
260
+ reply = { error: { code: -32603, message: error instanceof Error ? error.message : String(error) } };
261
+ } finally {
262
+ this.#toolCalls.delete(id);
263
+ }
264
+ if (!controller.signal.aborted) window.parent.postMessage({ jsonrpc: "2.0", id, ...reply }, "*");
265
+ }
266
+
267
+ static #valueOf({ key, returns }: FetchBridgeCall, result: McpToolResultLike) {
268
+ const text = result.content?.find((block) => block.type === "text")?.text ?? "";
269
+ const failure = result._meta?.["akanjs/error"] as ErrorResponsePayload | undefined;
270
+ if (result.isError && failure?.error) throw restoreRemoteError(failure, failure.statusCode ?? 400);
271
+ if (result.isError) throw new Error(text || `${key} failed`);
272
+ if (result._meta && "akanjs/value" in result._meta) return result._meta["akanjs/value"];
273
+ const structured = result.structuredContent as Record<string, unknown> | undefined;
274
+ if (structured !== undefined) return returns.arrDepth ? structured.items : structured;
275
+ if (returns.nullable && text === "null") return null;
276
+ const parsed = returns.modelType || returns.arrDepth || ["Int", "Float", "Boolean"].includes(returns.refName);
277
+ return parsed ? (JSON.parse(text) as unknown) : text;
278
+ }
279
+
280
+ static #defined(args: Record<string, unknown>) {
281
+ return Object.fromEntries(Object.entries(args).filter(([, value]) => value !== undefined));
282
+ }
283
+
284
+ static #callKey(key: string, args: Record<string, unknown>) {
285
+ const sorted = Object.keys(args)
286
+ .filter((name) => args[name] !== undefined && args[name] !== null)
287
+ .sort()
288
+ .map((name) => [name, args[name]]);
289
+ return `${key}:${JSON.stringify(sorted)}`;
290
+ }
291
+ }
@@ -0,0 +1,258 @@
1
+ "use client";
2
+ import { router, setCookie } from "akanjs/client";
3
+ import { Logger, parseAkanI18nEnv } from "akanjs/common";
4
+ import { st } from "akanjs/store";
5
+ import type { McpAppBridge, McpDownloadContent, McpHostContext } from "./McpAppBridge";
6
+
7
+ export class McpAppView {
8
+ static readonly contentGap = 24;
9
+
10
+ static readonly hostTokens = {
11
+ "--color-background-primary": ["--background", "--card", "--popover"],
12
+ "--color-background-secondary": ["--muted"],
13
+ "--color-text-primary": ["--foreground", "--card-foreground", "--popover-foreground"],
14
+ "--color-text-secondary": ["--muted-foreground"],
15
+ "--color-border-primary": ["--border", "--input"],
16
+ "--color-ring-primary": ["--ring"],
17
+ "--font-sans": ["--font-sans"],
18
+ "--font-mono": ["--font-mono"],
19
+ } as const;
20
+
21
+ readonly #bridge: McpAppBridge;
22
+ readonly #blobs = new Map<string, Blob>();
23
+ #lastHeight = 0;
24
+ #theme: string | undefined;
25
+
26
+ constructor(bridge: McpAppBridge) {
27
+ this.#bridge = bridge;
28
+ }
29
+
30
+ /** `href` in the host's language when the app speaks it: the page run used the server's MCP language. */
31
+ static localize(href: string, locale: string | undefined, locales: readonly string[]) {
32
+ const lang = locale?.split("-")[0]?.toLowerCase();
33
+ const current = /^\/([^/?#]+)/.exec(href)?.[1];
34
+ if (!lang || !current || !locales.includes(lang) || !locales.includes(current)) return href;
35
+ return `/${lang}${href.slice(current.length + 1)}`;
36
+ }
37
+
38
+ mount() {
39
+ this.#apply(this.#bridge.hostContext);
40
+ this.#bridge.onHostContext((context) => this.#apply(context));
41
+ this.#watchSize();
42
+ this.#keepBlobs();
43
+ this.#routeLinks();
44
+ }
45
+
46
+ /** In place of the app, for a result that names no screen: the host still sizes the view to what it shows. */
47
+ showUnavailable(message: string) {
48
+ this.#apply(this.#bridge.hostContext);
49
+ const notice = document.createElement("p");
50
+ notice.textContent = message;
51
+ notice.style.cssText = "margin:0;padding:16px;font:14px/1.5 system-ui,sans-serif;color:var(--foreground)";
52
+ document.getElementById("root")?.replaceChildren();
53
+ document.body.style.overflow = "visible";
54
+ document.body.replaceChildren(notice);
55
+ this.#bridge.notify("ui/notifications/size-changed", { height: Math.ceil(notice.getBoundingClientRect().height) });
56
+ }
57
+
58
+ #apply({ theme, displayMode, styles }: McpHostContext) {
59
+ const root = document.documentElement;
60
+ root.dataset.akanEmbed = displayMode ?? "inline";
61
+
62
+ if (theme && theme !== this.#theme) {
63
+ this.#theme = theme;
64
+ setCookie("theme", theme);
65
+ root.dataset.theme = theme;
66
+ st.do.setTheme(theme);
67
+
68
+ root.style.colorScheme = theme;
69
+ }
70
+ const variables = styles?.variables ?? {};
71
+ for (const [hostKey, tokens] of Object.entries(McpAppView.hostTokens)) {
72
+ const value = variables[hostKey];
73
+ for (const token of tokens)
74
+ if (value) root.style.setProperty(token, value);
75
+ else root.style.removeProperty(token);
76
+ }
77
+ }
78
+
79
+ #watchSize() {
80
+ let scheduled = false;
81
+ const report = () => {
82
+ if (scheduled) return;
83
+ scheduled = true;
84
+ requestAnimationFrame(() => {
85
+ scheduled = false;
86
+ const height = McpAppView.#contentHeight();
87
+ if (height === this.#lastHeight) return;
88
+ this.#lastHeight = height;
89
+ this.#bridge.notify("ui/notifications/size-changed", { height });
90
+ });
91
+ };
92
+ const resized = new ResizeObserver(report);
93
+ resized.observe(document.documentElement);
94
+ const observeContent = () => {
95
+ for (const content of document.querySelectorAll(".akan-page-content"))
96
+ for (const child of content.children) resized.observe(child);
97
+ };
98
+ new MutationObserver(() => {
99
+ observeContent();
100
+ report();
101
+ }).observe(document.body, { childList: true, subtree: true, attributes: true });
102
+
103
+ document.addEventListener("load", report, true);
104
+ void document.fonts.ready.then(report);
105
+ observeContent();
106
+ report();
107
+ }
108
+
109
+ static #contentHeight() {
110
+ const content = document.querySelector<HTMLElement>('[id^="pageContainer-"]:not([inert]) .akan-page-content');
111
+ if (!content) return Math.ceil(document.documentElement.scrollHeight);
112
+ const viewport = window.innerHeight;
113
+ const style = getComputedStyle(content);
114
+ const top = content.getBoundingClientRect().top - content.scrollTop;
115
+ let bottom = top + Number.parseFloat(style.paddingTop || "0");
116
+ const pending: Element[] = [content];
117
+ for (let box = pending.pop(); box; box = pending.pop())
118
+ for (const child of box.children) {
119
+ const rect = child.getBoundingClientRect();
120
+ if (getComputedStyle(child).position === "fixed") continue;
121
+ if (rect.height === 0 || rect.height >= viewport - 1 || Math.abs(rect.bottom - viewport) <= 1)
122
+ pending.push(child);
123
+ else bottom = Math.max(bottom, rect.bottom);
124
+ }
125
+ const height = bottom - top + Number.parseFloat(style.paddingBottom || "0") + McpAppView.contentGap;
126
+ return Math.ceil(Math.max(height + McpAppView.#overlayHeight(), McpAppView.#dialogHeight()));
127
+ }
128
+
129
+ static #overlayHeight() {
130
+ let height = 0;
131
+ for (const overlay of document.querySelectorAll<HTMLElement>("[data-akan-embed-overlay]"))
132
+ height += overlay.getBoundingClientRect().height;
133
+ return height;
134
+ }
135
+
136
+ static #dialogHeight() {
137
+ let height = 0;
138
+ for (const dialog of document.querySelectorAll<HTMLElement>('[aria-modal="true"]')) {
139
+ if (!dialog.getClientRects().length) continue;
140
+ let natural = 0;
141
+ for (const child of dialog.children)
142
+ if (!["absolute", "fixed"].includes(getComputedStyle(child).position)) natural += child.scrollHeight;
143
+ height = Math.max(height, natural + McpAppView.contentGap * 2);
144
+ }
145
+ return height;
146
+ }
147
+
148
+ #routeLinks() {
149
+ const { locales } = parseAkanI18nEnv();
150
+ const base = McpAppView.#parse(document.baseURI);
151
+ const open = (raw: string) => {
152
+ if (!raw) return;
153
+
154
+ if (raw.startsWith("#")) {
155
+ document.getElementById(decodeURIComponent(raw.slice(1)))?.scrollIntoView();
156
+ return;
157
+ }
158
+ const url = McpAppView.#parse(raw, document.baseURI);
159
+ if (!url) return;
160
+ const [, lang] = url.pathname.split("/");
161
+ if (url.origin === base?.origin && lang && locales.includes(lang))
162
+ router.push(`${url.pathname}${url.search}${url.hash}`);
163
+ else if (["http:", "https:", "mailto:", "tel:"].includes(url.protocol))
164
+ this.#bridge.openLink(url.href).catch((error: unknown) => {
165
+ Logger.warn(`The host did not open ${url.href}: ${error instanceof Error ? error.message : error}`);
166
+ });
167
+ };
168
+ const download = (href: string, name: string | null) =>
169
+ this.#download(href, name).catch((error: unknown) => {
170
+ Logger.warn(`The host did not save ${href}: ${error instanceof Error ? error.message : error}`);
171
+ });
172
+ document.addEventListener("click", (event) => {
173
+ if (event.defaultPrevented || event.button !== 0) return;
174
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
175
+ const anchor = (event.target as Element | null)?.closest?.("a[href]");
176
+ if (!(anchor instanceof HTMLAnchorElement)) return;
177
+ event.preventDefault();
178
+ const href = anchor.getAttribute("href") ?? "";
179
+ if (!anchor.hasAttribute("download")) open(href);
180
+ else void download(href, anchor.getAttribute("download"));
181
+ });
182
+ window.open = (url?: string | URL) => {
183
+ if (url !== undefined) open(String(url));
184
+ return null;
185
+ };
186
+
187
+ const click = HTMLAnchorElement.prototype.click;
188
+ HTMLAnchorElement.prototype.click = function (this: HTMLAnchorElement) {
189
+ if (this.isConnected || !this.hasAttribute("download")) click.call(this);
190
+ else void download(this.getAttribute("href") ?? "", this.getAttribute("download"));
191
+ };
192
+ }
193
+
194
+ async #download(href: string, suggested: string | null) {
195
+ const content = await this.#downloadOf(href, suggested || null);
196
+ if (!content) throw new Error("it is neither a web address nor a file this view made");
197
+ if (this.#bridge.hostCapabilities.downloadFile) await this.#bridge.downloadFile([content]);
198
+ else if (content.type === "resource_link") await this.#bridge.openLink(content.uri);
199
+ else throw new Error("this host does not save files");
200
+ }
201
+
202
+ async #downloadOf(href: string, suggested: string | null): Promise<McpDownloadContent | null> {
203
+ const blob = this.#blobs.get(href) ?? (href.startsWith("data:") ? McpAppView.#dataBlob(href) : null);
204
+ if (blob) {
205
+ const name = suggested ?? "download";
206
+ const bytes = new Uint8Array(await blob.arrayBuffer());
207
+ return {
208
+ type: "resource",
209
+ resource: {
210
+ uri: `file:///${encodeURIComponent(name)}`,
211
+ mimeType: blob.type || "application/octet-stream",
212
+ blob: McpAppView.#base64(bytes),
213
+ },
214
+ };
215
+ }
216
+ const url = McpAppView.#parse(href, document.baseURI);
217
+ if (!url || !["http:", "https:"].includes(url.protocol)) return null;
218
+ return { type: "resource_link", uri: url.href, name: suggested ?? url.pathname.split("/").at(-1) ?? "download" };
219
+ }
220
+
221
+ #keepBlobs() {
222
+ const create = URL.createObjectURL.bind(URL);
223
+ const revoke = URL.revokeObjectURL.bind(URL);
224
+ URL.createObjectURL = (object: Blob | MediaSource) => {
225
+ const url = create(object);
226
+ if (object instanceof Blob) this.#blobs.set(url, object);
227
+ return url;
228
+ };
229
+ URL.revokeObjectURL = (url: string) => {
230
+ this.#blobs.delete(url);
231
+ revoke(url);
232
+ };
233
+ }
234
+
235
+ static #dataBlob(href: string) {
236
+ const match = /^data:([^,]*?)(;base64)?,(.*)$/s.exec(href);
237
+ if (!match) return null;
238
+ const [, type = "", base64, body = ""] = match;
239
+ const bytes = base64
240
+ ? Uint8Array.from(atob(body), (char) => char.charCodeAt(0))
241
+ : new TextEncoder().encode(decodeURIComponent(body));
242
+ return new Blob([bytes], { type: type.split(";")[0] });
243
+ }
244
+
245
+ static #base64(bytes: Uint8Array) {
246
+ let binary = "";
247
+ for (let at = 0; at < bytes.length; at += 0x8000) binary += String.fromCharCode(...bytes.subarray(at, at + 0x8000));
248
+ return btoa(binary);
249
+ }
250
+
251
+ static #parse(raw: string, base?: string) {
252
+ try {
253
+ return new URL(raw, base);
254
+ } catch {
255
+ return null;
256
+ }
257
+ }
258
+ }
@@ -1,9 +1,14 @@
1
1
  "use client";
2
- import { csrContext, Device, getStoredAuthToken, initAuth } from "akanjs/client";
2
+ import { csrContext, csrLocation, Device, getStoredAuthToken, initAuth } from "akanjs/client";
3
3
  import { Logger, parseAkanI18nEnv, parseBasePaths } from "akanjs/common";
4
+ import { FetchClient } from "akanjs/fetch";
5
+ import { st } from "akanjs/store";
4
6
  import { useSyncExternalStore } from "react";
5
7
  import * as ReactDOM from "react-dom/client";
6
8
  import { type CsrRouteContext, CsrRouteTable } from "./CsrRouteTable";
9
+ import { McpAppAgent } from "./McpAppAgent";
10
+ import { McpAppBridge } from "./McpAppBridge";
11
+ import { McpAppView } from "./McpAppView";
7
12
  import { RenderLayer } from "./RenderLayer";
8
13
  import { useCsrValues } from "./useCsrValues";
9
14
 
@@ -18,8 +23,15 @@ export const bootCsr = async (context: CsrRouteContext) => {
18
23
  window.document.body.style.overflow = "hidden";
19
24
  initializeMobileTargetFromSearch();
20
25
  if (window.location.pathname === "/404") return;
26
+
27
+ let remount: () => void = () => undefined;
28
+ const embedded = globalThis.__AKAN_EMBED__ ? await bootMcpApp(i18n.locales, () => remount()) : false;
29
+ if (embedded === null) return;
21
30
 
22
- const [device, jwt] = await Promise.all([Device.load({ supportLanguages: i18n.locales }), getStoredAuthToken()]);
31
+ const [device, jwt] = await Promise.all([
32
+ Device.load({ supportLanguages: i18n.locales }),
33
+ embedded ? undefined : getStoredAuthToken(),
34
+ ]);
23
35
  const mobileTarget = window.__AKAN_MOBILE_TARGET__;
24
36
 
25
37
  if (mobileTarget && window.location.pathname === "/")
@@ -28,8 +40,8 @@ export const bootCsr = async (context: CsrRouteContext) => {
28
40
  "",
29
41
  `${mobileHomePath(device.lang, mobileTarget)}${window.location.search}${window.location.hash}`,
30
42
  );
31
- const pathname = window.location.pathname;
32
- if (!mobileTarget && !pathname.startsWith(`/${device.lang}`))
43
+ const pathname = csrLocation.pathname;
44
+ if (!mobileTarget && !embedded && !pathname.startsWith(`/${device.lang}`))
33
45
  window.location.replace(`/${device.lang}${pathname}${window.location.search}${window.location.hash}`);
34
46
 
35
47
  if (jwt) initAuth({ jwt });
@@ -62,10 +74,19 @@ export const bootCsr = async (context: CsrRouteContext) => {
62
74
  );
63
75
  };
64
76
 
77
+ st.set({ searchParams: searchParamsOf(csrLocation.search) });
65
78
  const el = document.getElementById("root");
66
79
  if (!el) throw new Error("No root element");
67
- const root = ReactDOM.createRoot(el);
80
+ let root = ReactDOM.createRoot(el);
68
81
  root.render(<RouterProvider />);
82
+
83
+ remount = () => {
84
+ setTimeout(() => {
85
+ root.unmount();
86
+ root = ReactDOM.createRoot(el);
87
+ root.render(<RouterProvider />);
88
+ }, 0);
89
+ };
69
90
  };
70
91
 
71
92
  /**
@@ -74,6 +95,34 @@ export const bootCsr = async (context: CsrRouteContext) => {
74
95
  */
75
96
  export const replacePages = async (context: CsrRouteContext) => (await CsrRouteTable.active?.replace(context)) ?? false;
76
97
 
98
+ function searchParamsOf(search: string): { [key: string]: string | string[] } {
99
+ const params: { [key: string]: string | string[] } = {};
100
+ for (const [key, value] of new URLSearchParams(search)) {
101
+ const current = params[key];
102
+ params[key] = current === undefined ? value : Array.isArray(current) ? [...current, value] : [current, value];
103
+ }
104
+ return params;
105
+ }
106
+
107
+ async function bootMcpApp(locales: readonly string[], reload: () => void) {
108
+ const bridge = new McpAppBridge();
109
+ const view = new McpAppView(bridge);
110
+ const start = await bridge.connect();
111
+ if (!start.ok) {
112
+ view.showUnavailable(start.message);
113
+ return null;
114
+ }
115
+ if (globalThis.__AKAN_EMBED__) globalThis.__AKAN_EMBED__.account = start.account;
116
+ csrLocation.useMemory(McpAppView.localize(start.href, bridge.hostContext.locale, locales), {
117
+ leave: () => view.showUnavailable("This screen is not available here."),
118
+ reload,
119
+ });
120
+ FetchClient.setBridge(bridge.fetchBridge(start.snapshot));
121
+ view.mount();
122
+ new McpAppAgent(bridge).start();
123
+ return true;
124
+ }
125
+
77
126
  function initializeMobileTargetFromSearch() {
78
127
  if (window.__AKAN_MOBILE_TARGET__) return;
79
128
 
package/webkit/index.ts CHANGED
@@ -19,3 +19,4 @@ export { usePageTool } from "./usePageTool";
19
19
  export type { ScreenScopeItem } from "./useScreenScope";
20
20
  export { useScreenScope } from "./useScreenScope";
21
21
  export { useThrottle } from "./useThrottle";
22
+ export { useVisualViewportFrame, type VisualViewportFrame } from "./useVisualViewportFrame";