akanjs 3.0.2 → 3.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) 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 +36 -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 +12 -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/adapt.ts +1 -1
  70. package/service/injectInfo.ts +9 -1
  71. package/service/ipcTypes.ts +2 -1
  72. package/service/predefinedAdaptor/database.adaptor.ts +1 -146
  73. package/service/predefinedAdaptor/queue.adaptor.ts +44 -6
  74. package/service/predefinedAdaptor/queueBackoff.ts +12 -0
  75. package/service/predefinedAdaptor/solidQueue.adaptor.ts +17 -13
  76. package/service/predefinedAdaptor/sql/SqlDocumentStore.ts +44 -2
  77. package/service/predefinedAdaptor/sql/dialect/postgres.ts +3 -0
  78. package/service/predefinedAdaptor/sql/dialect/sqlite.ts +5 -2
  79. package/service/predefinedAdaptor/sql/search/fts5.ts +1 -1
  80. package/service/predefinedAdaptor/sql/types.ts +8 -6
  81. package/service/predefinedAdaptor/sql/values.ts +0 -23
  82. package/service/serve.ts +5 -1
  83. package/signal/agent.signal.ts +1 -1
  84. package/signal/base.signal.ts +2 -2
  85. package/signal/endpointIdempotency.ts +53 -0
  86. package/signal/internalArg.ts +14 -0
  87. package/signal/mcp/McpDocument.ts +38 -1
  88. package/signal/mcp/mcpProtocol.ts +18 -0
  89. package/signal/signalContext.ts +58 -30
  90. package/signal/signalRegistry.ts +14 -4
  91. package/signal/types.ts +18 -3
  92. package/store/action.ts +17 -19
  93. package/store/agent/StoreSurfaceSource.ts +1 -1
  94. package/store/agentic/StToolBuilder.ts +3 -0
  95. package/test/conformance.ts +9 -33
  96. package/types/base/baseEnv.d.ts +0 -4
  97. package/types/base/primitiveRegistry.d.ts +1 -1
  98. package/types/client/csrLocation.d.ts +32 -0
  99. package/types/client/csrTypes.d.ts +43 -4
  100. package/types/client/frameConfig.d.ts +14 -2
  101. package/types/client/index.d.ts +3 -0
  102. package/types/client/native/external-view.d.ts +1 -0
  103. package/types/client/route/RootLayoutDefinition.d.ts +2 -1
  104. package/types/client/route/RouteHead.d.ts +13 -0
  105. package/types/client/route/index.d.ts +1 -0
  106. package/types/client/router.d.ts +6 -0
  107. package/types/client/rscNavigation.d.ts +4 -0
  108. package/types/client/viewportMeta.d.ts +18 -0
  109. package/types/client/webManifest.d.ts +4 -0
  110. package/types/common/PipelineNames.d.ts +6 -0
  111. package/types/common/PipelinePattern.d.ts +14 -0
  112. package/types/common/PipelinePlanSchema.d.ts +9 -0
  113. package/types/common/backoff.d.ts +10 -0
  114. package/types/common/index.d.ts +5 -0
  115. package/types/common/pipelinePlan.d.ts +224 -0
  116. package/types/common/types.d.ts +16 -0
  117. package/types/constant/constantRegistry.d.ts +5 -2
  118. package/types/dictionary/base.dictionary.d.ts +1 -1
  119. package/types/dictionary/dictionary.d.ts +8 -8
  120. package/types/document/into.d.ts +9 -0
  121. package/types/fetch/client/fetchClient.d.ts +31 -4
  122. package/types/fetch/client/httpClient.d.ts +8 -0
  123. package/types/fetch/client/wsClient.d.ts +26 -2
  124. package/types/fetch/fetchType/buildFetch.type.d.ts +1 -0
  125. package/types/index.d.ts +230 -9
  126. package/types/server/akanServer.d.ts +16 -1
  127. package/types/server/artifact/builderRpc.d.ts +7 -2
  128. package/types/server/artifact/ipcTypes.d.ts +5 -1
  129. package/types/server/di/utils.d.ts +1 -0
  130. package/types/server/ed25519Key.d.ts +13 -0
  131. package/types/server/index.d.ts +1 -0
  132. package/types/server/machine/index.d.ts +2 -0
  133. package/types/server/machine/machineAccount.d.ts +5 -0
  134. package/types/server/machine/machineToken.d.ts +29 -0
  135. package/types/server/machine.d.ts +1 -0
  136. package/types/server/mcp/McpApps.d.ts +50 -0
  137. package/types/server/mcp/McpDispatcher.d.ts +4 -1
  138. package/types/server/mcp/McpRouter.d.ts +4 -0
  139. package/types/server/resolver/signal.resolver.d.ts +2 -1
  140. package/types/server/routeElementComposer.d.ts +24 -4
  141. package/types/server/routeState.d.ts +4 -1
  142. package/types/server/routing/roomReplay.d.ts +24 -0
  143. package/types/server/rscWorkerHost.d.ts +5 -2
  144. package/types/server/sitemap.d.ts +2 -0
  145. package/types/server/ssrFromRscRenderer.d.ts +3 -3
  146. package/types/server/ssrTypes.d.ts +4 -1
  147. package/types/server/systemPageDocument.d.ts +2 -0
  148. package/types/server/types.d.ts +4 -1
  149. package/types/server/webRouter.d.ts +3 -1
  150. package/types/service/adapt.d.ts +1 -1
  151. package/types/service/ipcTypes.d.ts +2 -0
  152. package/types/service/predefinedAdaptor/database.adaptor.d.ts +1 -24
  153. package/types/service/predefinedAdaptor/queue.adaptor.d.ts +10 -3
  154. package/types/service/predefinedAdaptor/queueBackoff.d.ts +4 -0
  155. package/types/service/predefinedAdaptor/solidQueue.adaptor.d.ts +3 -3
  156. package/types/service/predefinedAdaptor/sql/SqlDocumentStore.d.ts +6 -1
  157. package/types/service/predefinedAdaptor/sql/dialect/postgres.d.ts +1 -0
  158. package/types/service/predefinedAdaptor/sql/dialect/sqlite.d.ts +1 -0
  159. package/types/service/predefinedAdaptor/sql/search/fts5.d.ts +1 -1
  160. package/types/service/predefinedAdaptor/sql/types.d.ts +9 -5
  161. package/types/service/predefinedAdaptor/sql/values.d.ts +0 -3
  162. package/types/service/serve.d.ts +3 -0
  163. package/types/signal/endpointIdempotency.d.ts +7 -0
  164. package/types/signal/internalArg.d.ts +10 -0
  165. package/types/signal/mcp/McpDocument.d.ts +8 -0
  166. package/types/signal/mcp/mcpProtocol.d.ts +17 -0
  167. package/types/signal/signalContext.d.ts +5 -3
  168. package/types/signal/signalRegistry.d.ts +4 -4
  169. package/types/signal/types.d.ts +21 -1
  170. package/types/store/agentic/StToolBuilder.d.ts +2 -0
  171. package/types/test/conformance.d.ts +7 -10
  172. package/types/ui/Agent/Chat.d.ts +5 -1
  173. package/types/ui/Agent/EmbedApproval.d.ts +1 -0
  174. package/types/ui/Agent/index.d.ts +3 -0
  175. package/types/ui/Agent/useKeyboardFrame.d.ts +2 -0
  176. package/types/ui/Agent/useScreenActions.d.ts +18 -0
  177. package/types/ui/BottomSheet.d.ts +1 -0
  178. package/types/ui/Constant/Doc.d.ts +11 -17
  179. package/types/ui/Constant/index.d.ts +7 -2
  180. package/types/ui/Constant/schemaDoc.d.ts +11 -0
  181. package/types/ui/Dialog/Modal.d.ts +6 -1
  182. package/types/ui/Dialog/index.d.ts +1 -1
  183. package/types/ui/Dialog/modalSurface.d.ts +12 -0
  184. package/types/ui/Layout/BottomInset.d.ts +1 -1
  185. package/types/ui/Layout/BottomTab.d.ts +11 -2
  186. package/types/ui/Layout/FrameSlotFallback.d.ts +9 -0
  187. package/types/ui/Layout/Navbar.d.ts +4 -1
  188. package/types/ui/Layout/TopInset.d.ts +1 -1
  189. package/types/ui/Layout/index.d.ts +4 -4
  190. package/types/ui/Link/Action.d.ts +5 -1
  191. package/types/ui/Link/Anchor.d.ts +5 -3
  192. package/types/ui/Link/activePath.d.ts +13 -0
  193. package/types/ui/Link/index.d.ts +1 -1
  194. package/types/ui/Modal.d.ts +6 -1
  195. package/types/ui/Model/EditModal.d.ts +6 -1
  196. package/types/ui/Model/New.d.ts +6 -1
  197. package/types/ui/Model/ViewEditModal.d.ts +6 -1
  198. package/types/ui/Model/ViewModal.d.ts +6 -1
  199. package/types/ui/Model/newFormOrigin.d.ts +7 -0
  200. package/types/ui/Portal.d.ts +3 -1
  201. package/types/ui/Reference/origin.d.ts +12 -0
  202. package/types/ui/Signal/Doc.d.ts +23 -18
  203. package/types/ui/Signal/Listener.d.ts +2 -6
  204. package/types/ui/Signal/Object.d.ts +6 -10
  205. package/types/ui/Signal/Response.d.ts +3 -6
  206. package/types/ui/Signal/RestApi.d.ts +11 -15
  207. package/types/ui/Signal/WebSocket.d.ts +11 -21
  208. package/types/ui/Signal/endpointEntries.d.ts +8 -0
  209. package/types/ui/Signal/index.d.ts +35 -12
  210. package/types/ui/Signal/signalText.d.ts +178 -0
  211. package/types/ui/System/CSR.d.ts +2 -2
  212. package/types/ui/System/Client.d.ts +4 -3
  213. package/types/ui/System/Common.d.ts +27 -6
  214. package/types/ui/System/SSR.d.ts +6 -6
  215. package/types/ui/Tooltip.d.ts +4 -2
  216. package/types/ui/index.d.ts +2 -1
  217. package/types/ui/overlayLayer.d.ts +6 -0
  218. package/types/ui/overlayPosition.d.ts +17 -0
  219. package/types/vendor/@akanjs/native/packages/cli/src/api.d.ts +14 -3
  220. package/types/vendor/@akanjs/native/packages/cli/src/commands/update.d.ts +1 -1
  221. package/types/vendor/@akanjs/native/packages/cli/src/config.d.ts +30 -5
  222. package/types/vendor/@akanjs/native/packages/cli/src/lib/compat.d.ts +8 -0
  223. package/types/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.d.ts +5 -0
  224. package/types/vendor/@akanjs/native/packages/cli/src/lib/distribution.d.ts +22 -0
  225. package/types/vendor/@akanjs/native/packages/cli/src/lib/project.d.ts +4 -0
  226. package/types/vendor/@akanjs/native/packages/cli/src/lib/publish.d.ts +16 -10
  227. package/types/vendor/@akanjs/native/packages/cli/src/lib/updates.d.ts +51 -7
  228. package/types/vendor/@akanjs/native/packages/cli/src/lib/vectors.d.ts +1 -1
  229. package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.d.ts +12 -4
  230. package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows.d.ts +5 -0
  231. package/types/vendor/@akanjs/native/packages/core/src/kernel.d.ts +36 -0
  232. package/types/vendor/@akanjs/native/packages/desktop/src/dispatcher.d.ts +6 -0
  233. package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +2 -0
  234. package/types/vendor/@akanjs/native/packages/desktop/src/server.d.ts +11 -0
  235. package/types/vendor/@akanjs/native/plugins/external-view/src/desktop.d.ts +17 -0
  236. package/types/vendor/@akanjs/native/plugins/external-view/src/index.d.ts +132 -0
  237. package/types/vendor/@akanjs/native/plugins/external-view/src.d.ts +1 -0
  238. package/types/vendor/@akanjs/native/plugins/single-instance/src/socket.d.ts +1 -1
  239. package/types/vendor/@akanjs/native/plugins/updates/src/index.d.ts +8 -0
  240. package/types/vendor/@akanjs/native/plugins/window/src/desktop.d.ts +4 -1
  241. package/types/vendor/@akanjs/native/plugins/window/src/index.d.ts +49 -0
  242. package/types/vendor/use-agentic/AgentActivity.d.ts +3 -1
  243. package/types/vendor/use-agentic/AgenticSurface.d.ts +2 -2
  244. package/types/vendor/use-agentic/types.d.ts +2 -0
  245. package/types/webkit/CsrStack.d.ts +1 -1
  246. package/types/webkit/EmbeddedLayout.d.ts +10 -0
  247. package/types/webkit/McpAppAgent.d.ts +14 -0
  248. package/types/webkit/McpAppApprovals.d.ts +8 -0
  249. package/types/webkit/McpAppBridge.d.ts +101 -0
  250. package/types/webkit/McpAppView.d.ts +21 -0
  251. package/types/webkit/RenderLayer.d.ts +3 -1
  252. package/types/webkit/index.d.ts +1 -0
  253. package/types/webkit/useLocation.d.ts +1 -1
  254. package/types/webkit/useVisualViewportFrame.d.ts +13 -0
  255. package/ui/Agent/Chat.tsx +29 -10
  256. package/ui/Agent/Composer.tsx +2 -1
  257. package/ui/Agent/EmbedApproval.tsx +17 -0
  258. package/ui/Agent/RichInput.tsx +1 -1
  259. package/ui/Agent/index.ts +2 -0
  260. package/ui/Agent/useKeyboardFrame.ts +10 -0
  261. package/ui/Agent/useScreenActions.ts +45 -0
  262. package/ui/BottomSheet.tsx +82 -53
  263. package/ui/Constant/Doc.tsx +113 -60
  264. package/ui/Constant/index.ts +2 -2
  265. package/ui/Constant/schemaDoc.ts +86 -26
  266. package/ui/Dialog/LegacyModal.tsx +53 -52
  267. package/ui/Dialog/Modal.tsx +93 -49
  268. package/ui/Dialog/modalSurface.ts +61 -0
  269. package/ui/DragAction.tsx +1 -1
  270. package/ui/DraggableList.tsx +1 -1
  271. package/ui/Dropdown.tsx +4 -6
  272. package/ui/KeyboardAvoiding.tsx +1 -1
  273. package/ui/Layout/BottomInset.tsx +32 -16
  274. package/ui/Layout/BottomTab.tsx +42 -16
  275. package/ui/Layout/FrameSlotFallback.tsx +59 -0
  276. package/ui/Layout/Navbar.tsx +56 -15
  277. package/ui/Layout/Sider.tsx +1 -1
  278. package/ui/Layout/TopInset.tsx +22 -17
  279. package/ui/Link/Action.tsx +15 -5
  280. package/ui/Link/Anchor.tsx +25 -13
  281. package/ui/Link/activePath.ts +25 -0
  282. package/ui/Link/index.tsx +1 -1
  283. package/ui/Load/Pagination.tsx +1 -1
  284. package/ui/Load/Units.tsx +1 -1
  285. package/ui/Loading/ProgressBar.tsx +1 -1
  286. package/ui/Modal.tsx +9 -0
  287. package/ui/Model/EditModal.tsx +16 -1
  288. package/ui/Model/New.tsx +25 -2
  289. package/ui/Model/NewWrapper_Client.tsx +2 -0
  290. package/ui/Model/ViewEditModal.tsx +25 -10
  291. package/ui/Model/ViewModal.tsx +16 -1
  292. package/ui/Model/newFormOrigin.ts +45 -0
  293. package/ui/Popconfirm.tsx +5 -7
  294. package/ui/Portal.tsx +4 -7
  295. package/ui/Reference/origin.ts +31 -0
  296. package/ui/ScreenNavigator.tsx +1 -1
  297. package/ui/Select.tsx +14 -14
  298. package/ui/Signal/Arg.tsx +2 -2
  299. package/ui/Signal/Doc.tsx +125 -63
  300. package/ui/Signal/Endpoint.tsx +11 -10
  301. package/ui/Signal/Listener.tsx +7 -10
  302. package/ui/Signal/Object.tsx +7 -14
  303. package/ui/Signal/Response.tsx +24 -24
  304. package/ui/Signal/RestApi.tsx +63 -52
  305. package/ui/Signal/WebSocket.tsx +65 -72
  306. package/ui/Signal/endpointEntries.ts +25 -0
  307. package/ui/Signal/index.ts +23 -6
  308. package/ui/Signal/signalText.ts +59 -0
  309. package/ui/System/CSR.tsx +41 -9
  310. package/ui/System/Client.tsx +37 -5
  311. package/ui/System/Common.tsx +76 -32
  312. package/ui/System/SSR.tsx +73 -31
  313. package/ui/Toast.tsx +1 -1
  314. package/ui/Tooltip.tsx +84 -30
  315. package/ui/index.ts +11 -1
  316. package/ui/overlayLayer.ts +25 -2
  317. package/ui/overlayPosition.ts +90 -0
  318. package/ui/recipe/inputRecipe.ts +8 -1
  319. package/ui/styles.css +152 -0
  320. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeActivity.kt +22 -2
  321. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeKernel.kt +37 -0
  322. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeUpdateReports.kt +169 -0
  323. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeUpdates.kt +110 -38
  324. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeVectors.kt +20 -0
  325. package/vendor/@akanjs/native/native/desktop/Cargo.lock +16 -16
  326. package/vendor/@akanjs/native/native/desktop/src/external.rs +651 -0
  327. package/vendor/@akanjs/native/native/desktop/src/json.rs +23 -0
  328. package/vendor/@akanjs/native/native/desktop/src/lib.rs +228 -5
  329. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeApp.swift +2 -1
  330. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeKernel.swift +47 -1
  331. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeUpdateReports.swift +145 -0
  332. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeUpdates.swift +112 -43
  333. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeVectors.swift +18 -0
  334. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeViewController.swift +24 -2
  335. package/vendor/@akanjs/native/packages/cli/src/api.ts +22 -6
  336. package/vendor/@akanjs/native/packages/cli/src/commands/build.ts +24 -8
  337. package/vendor/@akanjs/native/packages/cli/src/commands/update.ts +11 -9
  338. package/vendor/@akanjs/native/packages/cli/src/config.ts +35 -7
  339. package/vendor/@akanjs/native/packages/cli/src/lib/compat.ts +2 -0
  340. package/vendor/@akanjs/native/packages/cli/src/lib/configkeys.ts +6 -4
  341. package/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.ts +11 -1
  342. package/vendor/@akanjs/native/packages/cli/src/lib/distribution.ts +73 -0
  343. package/vendor/@akanjs/native/packages/cli/src/lib/project.ts +15 -3
  344. package/vendor/@akanjs/native/packages/cli/src/lib/publish.ts +70 -23
  345. package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +159 -23
  346. package/vendor/@akanjs/native/packages/cli/src/lib/vectors.ts +2 -0
  347. package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +9 -4
  348. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.ts +1 -1
  349. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop.ts +4 -2
  350. package/vendor/@akanjs/native/packages/cli/src/platforms/ios.ts +9 -4
  351. package/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.ts +60 -21
  352. package/vendor/@akanjs/native/packages/cli/src/platforms/windows.ts +14 -3
  353. package/vendor/@akanjs/native/packages/core/src/kernel.ts +49 -0
  354. package/vendor/@akanjs/native/packages/core/vectors/updates.json +31 -0
  355. package/vendor/@akanjs/native/packages/desktop/src/dispatcher.ts +13 -5
  356. package/vendor/@akanjs/native/packages/desktop/src/main.ts +3 -0
  357. package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +2 -0
  358. package/vendor/@akanjs/native/packages/desktop/src/server.ts +70 -6
  359. package/vendor/@akanjs/native/plugins/external-view/native-plugin.json +23 -0
  360. package/vendor/@akanjs/native/plugins/external-view/src/desktop.ts +321 -0
  361. package/vendor/@akanjs/native/plugins/external-view/src/index.ts +106 -0
  362. package/vendor/@akanjs/native/plugins/single-instance/src/desktop.ts +4 -0
  363. package/vendor/@akanjs/native/plugins/single-instance/src/socket.ts +12 -5
  364. package/vendor/@akanjs/native/plugins/updates/android/UpdatesPlugin.kt +133 -41
  365. package/vendor/@akanjs/native/plugins/updates/ios/UpdatesPlugin.swift +101 -36
  366. package/vendor/@akanjs/native/plugins/updates/native-plugin.json +4 -2
  367. package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +15 -1
  368. package/vendor/@akanjs/native/plugins/updates/src/index.ts +7 -1
  369. package/vendor/@akanjs/native/plugins/window/native-plugin.json +4 -0
  370. package/vendor/@akanjs/native/plugins/window/src/desktop.ts +68 -1
  371. package/vendor/@akanjs/native/plugins/window/src/index.ts +47 -0
  372. package/vendor/use-agentic/AgentActivity.tsx +4 -2
  373. package/vendor/use-agentic/AgenticSurface.ts +3 -3
  374. package/vendor/use-agentic/ToolRunner.ts +8 -1
  375. package/vendor/use-agentic/types.ts +2 -0
  376. package/webkit/CsrRouteTable.ts +9 -1
  377. package/webkit/CsrStack.ts +9 -2
  378. package/webkit/EmbeddedLayout.tsx +77 -0
  379. package/webkit/McpAppAgent.ts +138 -0
  380. package/webkit/McpAppApprovals.ts +56 -0
  381. package/webkit/McpAppBridge.ts +291 -0
  382. package/webkit/McpAppView.ts +258 -0
  383. package/webkit/RenderLayer.tsx +20 -5
  384. package/webkit/bootCsr.tsx +54 -5
  385. package/webkit/index.ts +1 -0
  386. package/webkit/useCsrValues.ts +16 -10
  387. package/webkit/useFrameRuntime.ts +10 -1
  388. package/webkit/useLocation.ts +4 -3
  389. package/webkit/useVisualViewportFrame.tsx +52 -0
  390. package/service/predefinedAdaptor/sql/driver/libsql.ts +0 -45
  391. package/types/service/predefinedAdaptor/sql/driver/libsql.d.ts +0 -20
  392. package/types/ui/Agent/useKeyboardInset.d.ts +0 -1
  393. package/types/ui/ServerPortal.d.ts +0 -15
  394. package/ui/Agent/useKeyboardInset.ts +0 -19
  395. package/ui/ServerPortal.tsx +0 -49
@@ -6,12 +6,12 @@ import { NoDocumentError } from "akanjs/document";
6
6
  import type { InjectRegistry, LiveRegistry } from "akanjs/service";
7
7
  import type { Endpoint, EndpointCls } from "../../signal/endpoint";
8
8
  import type { EndpointInfo } from "../../signal/endpointInfo";
9
- import { Exception } from "../../signal/exception";
9
+ import { Exception, isExceptionLike } from "../../signal/exception";
10
10
  import type { GuardCls } from "../../signal/guard";
11
11
  import { McpDocument, type McpExposedEndpoint, type McpToolResult } from "../../signal/mcp";
12
12
  import type { MiddlewareCls } from "../../signal/middleware";
13
13
  import { SignalContext } from "../../signal/signalContext";
14
- import { McpExecutionContext } from "./McpExecutionContext";
14
+ import { McpArgumentError, McpExecutionContext } from "./McpExecutionContext";
15
15
 
16
16
  export class McpAuthRequiredError extends Error {}
17
17
 
@@ -38,25 +38,44 @@ export class McpDispatcher {
38
38
  this.#props = props;
39
39
  }
40
40
 
41
- async call(exposed: McpExposedEndpoint, args: Record<string, unknown>, req: Request): Promise<McpToolResult> {
41
+ async call(
42
+ exposed: McpExposedEndpoint,
43
+ args: Record<string, unknown>,
44
+ req: Request,
45
+ { forView = false }: { forView?: boolean } = {},
46
+ ): Promise<McpToolResult> {
42
47
  const found = this.#index().get(exposed.key);
43
48
  if (!found) return McpDispatcher.#failure(`Tool "${exposed.key}" is declared but not mounted on this server.`);
44
49
  try {
45
- const value = McpDispatcher.#readable(exposed, await this.#exec(exposed.key, found, args, req));
50
+ const wire = await this.#exec(exposed.key, found, args, req);
51
+ const value = McpDispatcher.#readable(exposed, wire);
46
52
  const structuredContent = McpDocument.structuredContent(exposed.endpoint, value);
47
53
  return {
48
54
  content: this.#content(structuredContent, value),
49
55
  ...(structuredContent === undefined ? {} : { structuredContent }),
56
+ ...(forView ? { _meta: { "akanjs/value": wire ?? null } } : {}),
50
57
  isError: false,
51
58
  };
52
59
  } catch (error) {
53
60
  const status = McpDispatcher.#statusOf(error);
54
61
 
55
62
  if ((status === 401 || status === 403) && !req.headers.get("authorization")) throw new McpAuthRequiredError();
56
- return McpDispatcher.#failure(this.#message(error, status, exposed.refName));
63
+ const failure = McpDispatcher.#failure(this.#message(error, status, exposed.refName));
64
+ const restorable = forView ? McpDispatcher.#restorable(error, status) : null;
65
+ return restorable ? { ...failure, _meta: { "akanjs/error": restorable } } : failure;
57
66
  }
58
67
  }
59
68
 
69
+ static #restorable(error: unknown, status: number | undefined) {
70
+ if (!status || status >= 500 || status === 401 || status === 403 || error instanceof NoDocumentError) return null;
71
+ const data = (error as { data?: unknown }).data;
72
+ return {
73
+ error: error instanceof Error ? error.message : String(error),
74
+ statusCode: status,
75
+ ...(data && typeof data === "object" ? { data } : {}),
76
+ };
77
+ }
78
+
60
79
  async filterForAccount<T extends { name: string }>(items: T[], req: Request): Promise<T[]> {
61
80
  const index = this.#index();
62
81
 
@@ -115,6 +134,10 @@ export class McpDispatcher {
115
134
  });
116
135
  }
117
136
 
137
+ isEndpoint(name: string) {
138
+ return this.#index().has(name);
139
+ }
140
+
118
141
  #index() {
119
142
  if (this.#endpoints) return this.#endpoints;
120
143
  const endpoints = new Map<string, { endpointInfo: EndpointInfo; endpoint: Endpoint }>();
@@ -146,8 +169,9 @@ export class McpDispatcher {
146
169
  }
147
170
 
148
171
  static #statusOf(error: unknown): number | undefined {
149
- const status = (error as { statusCode?: unknown } | null)?.statusCode;
150
- return typeof status === "number" ? status : undefined;
172
+ if (isExceptionLike(error) || error instanceof McpArgumentError || error instanceof NoDocumentError)
173
+ return error.statusCode;
174
+ return undefined;
151
175
  }
152
176
 
153
177
  #content(structuredContent: unknown, value: unknown): McpToolResult["content"] {
@@ -7,7 +7,9 @@ import {
7
7
  MCP_META_CLIENT_CAPABILITIES,
8
8
  MCP_META_PROTOCOL_VERSION,
9
9
  MCP_META_SERVER_INFO,
10
+ MCP_MODERN_VERSION,
10
11
  MCP_SUPPORTED_VERSIONS,
12
+ MCP_UI_EXTENSION,
11
13
  McpDocument,
12
14
  type McpEra,
13
15
  McpErrorCode,
@@ -15,14 +17,17 @@ import {
15
17
  type McpJsonRpcRequest,
16
18
  type McpOutputSchemaMode,
17
19
  McpProgress,
20
+ type McpProtocolVersion,
18
21
  type McpSignalCost,
19
22
  type McpToolResult,
20
23
  } from "../../signal/mcp";
24
+ import type { PromptMessage } from "../../signal/mcp/Msg";
21
25
  import type { McpPrompt } from "../../signal/mcp/mcpProtocol";
22
- import type { PagePromptEntry, PagePromptSource } from "../../signal/mcp/pagePrompt";
26
+ import type { PagePromptEntry, PagePromptRun, PagePromptSource } from "../../signal/mcp/pagePrompt";
23
27
  import type { MiddlewareCls } from "../../signal/middleware";
24
28
  import { FetchSerializer } from "../../signal/serializer";
25
29
  import type { HttpRoutes } from "../types";
30
+ import { type McpAppShellSource, McpApps } from "./McpApps";
26
31
  import { McpAuth, type McpAuthOption } from "./McpAuth";
27
32
  import { McpAuthRequiredError, McpDispatcher } from "./McpDispatcher";
28
33
  import { McpEventStream } from "./McpEventStream";
@@ -47,6 +52,9 @@ export interface McpRouterProps {
47
52
  outputSchema?: McpOutputSchemaMode;
48
53
  auth?: McpAuthOption;
49
54
  rateLimit?: McpRateLimitOption | false;
55
+ apps?: boolean;
56
+ appShell?: McpAppShellSource;
57
+ modern?: boolean;
50
58
  }
51
59
 
52
60
  interface McpCall {
@@ -63,6 +71,8 @@ interface McpErrorOptions {
63
71
  headers?: Record<string, string>;
64
72
  }
65
73
 
74
+ type McpPageRun = { refusal: string } | { run: Extract<PagePromptRun, { ok: true }> | null; messages: PromptMessage[] };
75
+
66
76
  interface McpCacheHint {
67
77
  ttlMs: number;
68
78
  cacheScope: "public" | "private";
@@ -85,7 +95,10 @@ export class McpRouter {
85
95
  readonly #dispatcher: McpDispatcher;
86
96
  readonly #auth: McpAuth;
87
97
  readonly #limiter: McpRateLimiter | null;
98
+ readonly #apps: McpApps | null;
99
+ readonly #versions: readonly McpProtocolVersion[];
88
100
  #document: McpDocument | null = null;
101
+ #pageListFailed = false;
89
102
 
90
103
  constructor(props: McpRouterProps) {
91
104
  this.#props = props;
@@ -94,6 +107,10 @@ export class McpRouter {
94
107
 
95
108
  this.#dispatcher = new McpDispatcher({ ...props, legacyTextBlock, language: props.language ?? defaultLanguage });
96
109
  this.#auth = new McpAuth({ ...props.auth, path: props.path ?? "/mcp" });
110
+ this.#apps = props.apps && props.pagePrompts ? new McpApps(props.appShell ?? null) : null;
111
+
112
+ const modern = props.modern ?? !this.#apps?.rendersUi;
113
+ this.#versions = modern ? MCP_SUPPORTED_VERSIONS : MCP_SUPPORTED_VERSIONS.filter((v) => v !== MCP_MODERN_VERSION);
97
114
  this.#limiter =
98
115
  props.rateLimit === false
99
116
  ? null
@@ -108,7 +125,7 @@ export class McpRouter {
108
125
  [this.#props.path ?? "/mcp"]: {
109
126
  POST: async (req: Request) => this.#cors(req, await this.#post(req)),
110
127
  OPTIONS: (req: Request) => this.#preflight(req),
111
-
128
+
112
129
  GET: (req: Request) => this.#cors(req, notAllowed()),
113
130
  DELETE: (req: Request) => this.#cors(req, notAllowed()),
114
131
  },
@@ -121,7 +138,8 @@ export class McpRouter {
121
138
  const document = this.#getDocument();
122
139
  const { tools, resourceTemplates, refusals, undescribed } = document;
123
140
  const cost = document.listingCost;
124
- const counts = `tools=${tools.length} resourceTemplates=${resourceTemplates.length}`;
141
+ const appTools = document.appTools.length ? ` appTools=${document.appTools.length}` : "";
142
+ const counts = `tools=${tools.length}${appTools} resourceTemplates=${resourceTemplates.length}`;
125
143
  const readOnly = this.#props.readOnly ? " (read-only deployment)" : "";
126
144
  McpRouter.logger.debug(`MCP catalogue: ${counts}${readOnly} · listing ${McpRouter.#kb(cost.bytes)}`);
127
145
  if (cost.bySignal.length) McpRouter.logger.debug(`MCP catalogue cost: ${McpRouter.#costLine(cost.bySignal)}`);
@@ -142,6 +160,10 @@ export class McpRouter {
142
160
  this.#reportPagePrompts();
143
161
  this.#reportUnverifiable(tools.map((tool) => tool.name));
144
162
  for (const { key, reason } of refusals) McpRouter.logger.verbose(`MCP did not expose "${key}": ${reason}`);
163
+ for (const { name } of document.appTools)
164
+ McpRouter.logger.verbose(
165
+ `MCP kept "${name}" for the views an MCP Apps host renders: it declares \`mcp: false\`, so no model is shown it.`,
166
+ );
145
167
  for (const { key, reason } of undescribed)
146
168
  McpRouter.logger.warn(`MCP exposed "${key}" with no description: ${reason}`);
147
169
  } catch (error) {
@@ -185,6 +207,7 @@ export class McpRouter {
185
207
  resolveDescription: (key) => lookup.text(key),
186
208
  readOnly: this.#props.readOnly,
187
209
  outputSchema: this.#props.outputSchema,
210
+ apps: !!this.#apps?.rendersUi,
188
211
  });
189
212
  return this.#document;
190
213
  }
@@ -212,11 +235,21 @@ export class McpRouter {
212
235
 
213
236
  const meta = McpRouter.#meta(params);
214
237
  const era: McpEra = method !== "initialize" && meta && MCP_META_PROTOCOL_VERSION in meta ? "modern" : "legacy";
215
- const rejection = era === "modern" ? McpRouter.#validateModern(req, method, params, meta ?? {}, id) : null;
238
+ const discoverable = method !== "server/discover" || this.#versions.includes(MCP_MODERN_VERSION);
239
+ const rejection =
240
+ era === "modern" && discoverable ? this.#validateModern(req, method, params, meta ?? {}, id) : null;
216
241
  if (rejection) return rejection;
217
242
 
243
+ const started = Date.now();
218
244
  try {
219
- return await this.#dispatch({ id, method, params, era, req });
245
+ const call = { id, method, params, era, req };
246
+ const res = await this.#dispatch(call);
247
+ const subject = typeof params.name === "string" ? params.name : typeof params.uri === "string" ? params.uri : "";
248
+ const client = `${era}${this.#apps ? (this.#uiCapable(call) ? ", ui" : ", text") : ""}`;
249
+ McpRouter.logger.verbose(
250
+ `MCP ${method}${subject ? ` ${subject}` : ""} (${client}) → ${res.status} (${Date.now() - started}ms)`,
251
+ );
252
+ return res;
220
253
  } catch (error) {
221
254
  if (error instanceof McpAuthRequiredError) return this.#auth.unauthorized(req);
222
255
  McpRouter.logger.error(
@@ -231,40 +264,54 @@ export class McpRouter {
231
264
  switch (call.method) {
232
265
  case "initialize":
233
266
 
234
- return this.#result(call, {
235
- protocolVersion: McpRouter.#negotiate(call.params.protocolVersion),
236
- capabilities: this.#capabilities(document),
237
- serverInfo: this.#serverInfo(),
238
- ...(this.#props.instructions ? { instructions: this.#props.instructions } : {}),
239
- });
267
+ return this.#result(
268
+ call,
269
+ {
270
+ protocolVersion: this.#negotiate(call.params.protocolVersion),
271
+ capabilities: this.#capabilities(document),
272
+ serverInfo: this.#serverInfo(),
273
+ ...(this.#props.instructions ? { instructions: this.#props.instructions } : {}),
274
+ },
275
+ undefined,
276
+ this.#uiSession(call),
277
+ );
240
278
  case "ping":
241
279
 
242
280
  return this.#result(call, {});
243
281
  case "server/discover":
282
+
283
+ if (!this.#versions.includes(MCP_MODERN_VERSION))
284
+ return McpRouter.#error(call.id, McpErrorCode.methodNotFound, this.#methodNotFound(call.method));
244
285
  return this.#result(
245
286
  call,
246
287
  {
247
- supportedVersions: MCP_SUPPORTED_VERSIONS,
288
+ supportedVersions: this.#versions,
248
289
  capabilities: this.#capabilities(document),
249
290
  ...(this.#props.instructions ? { instructions: this.#props.instructions } : {}),
250
291
  },
251
292
  discoverCache,
252
293
  );
253
294
  case "tools/list":
254
- return await this.#list(call, "tools", document.tools);
295
+ return await this.#list(call, "tools", [...document.tools, ...(await this.#appTools(call, document))]);
255
296
  case "resources/list":
256
- return await this.#list(call, "resources", document.resources);
297
+ return await this.#list(call, "resources", [...document.resources, ...(await this.#appResources(call))]);
257
298
  case "resources/templates/list":
258
299
  return await this.#list(call, "resourceTemplates", document.resourceTemplates);
259
300
  case "prompts/list":
260
- return await this.#list(
261
- call,
262
- "prompts",
263
- ((await this.#props.pagePrompts?.list()) ?? []).map(McpRouter.#promptOf),
264
- );
301
+ return await this.#list(call, "prompts", (await this.#pageEntries()).map(McpRouter.#promptOf));
265
302
  case "tools/call": {
266
303
  const slot = await this.#acquire(call);
267
- return "refused" in slot ? slot.refused : await this.#toolsCall(call, document, slot.release);
304
+ if ("refused" in slot) return slot.refused;
305
+ let release = slot.release;
306
+ try {
307
+ const page = await this.#pageToolOf(call.params.name);
308
+ if (page) return await this.#pageToolCall(call, document, page);
309
+
310
+ release = () => {};
311
+ return await this.#toolsCall(call, document, slot.release);
312
+ } finally {
313
+ release();
314
+ }
268
315
  }
269
316
  case "prompts/get":
270
317
  return await this.#limited(call, () => this.#promptsGet(call, document));
@@ -272,7 +319,7 @@ export class McpRouter {
272
319
  return await this.#limited(call, () => this.#resourcesRead(call, document));
273
320
  default:
274
321
 
275
- return McpRouter.#error(call.id, McpErrorCode.methodNotFound, McpRouter.#methodNotFound(call.method), {
322
+ return McpRouter.#error(call.id, McpErrorCode.methodNotFound, this.#methodNotFound(call.method), {
276
323
  status: call.era === "modern" ? 404 : 200,
277
324
  });
278
325
  }
@@ -318,13 +365,16 @@ export class McpRouter {
318
365
  try {
319
366
  const name = call.params.name;
320
367
  if (typeof name !== "string") return McpRouter.#error(call.id, McpErrorCode.invalidParams, "Missing tool name.");
321
- const exposed = document.findTool(name);
368
+
369
+ const exposed = document.isAppOnly(name) && !this.#uiCapable(call) ? undefined : document.findTool(name);
322
370
 
323
371
  if (!exposed) return McpRouter.#error(call.id, McpErrorCode.invalidParams, `Unknown tool: ${name}.`);
324
372
  const args = McpRouter.#arguments(call.params);
325
373
  if (!args) return McpRouter.#error(call.id, McpErrorCode.invalidParams, McpRouter.#badArguments);
326
374
  const progressToken = McpRouter.#progressToken(call);
327
- if (progressToken === undefined) return this.#result(call, await this.#dispatcher.call(exposed, args, call.req));
375
+ const option = { forView: this.#forView(call) };
376
+ if (progressToken === undefined)
377
+ return this.#result(call, await this.#dispatcher.call(exposed, args, call.req, option));
328
378
  streaming = true;
329
379
  return await this.#streamedToolCall(call, exposed, args, progressToken, release);
330
380
  } finally {
@@ -340,7 +390,8 @@ export class McpRouter {
340
390
  release: () => void,
341
391
  ) {
342
392
  const channel = new McpProgress();
343
- const settled = McpProgress.run(channel, async () => await this.#dispatcher.call(exposed, args, call.req))
393
+ const option = { forView: this.#forView(call) };
394
+ const settled = McpProgress.run(channel, async () => await this.#dispatcher.call(exposed, args, call.req, option))
344
395
  .then(
345
396
  (result) => ({ result }),
346
397
  (error: unknown) => ({ error }),
@@ -394,10 +445,13 @@ export class McpRouter {
394
445
  }
395
446
 
396
447
  #capabilities(document: McpDocument) {
448
+ const ui = !!this.#apps?.rendersUi;
397
449
  return {
398
- ...(document.tools.length ? { tools: {} } : {}),
399
- ...(document.resources.length || document.resourceTemplates.length ? { resources: {} } : {}),
450
+ ...(document.tools.length || this.#apps ? { tools: {} } : {}),
451
+ ...(document.resources.length || document.resourceTemplates.length || ui ? { resources: {} } : {}),
400
452
  ...(this.#props.pagePrompts ? { prompts: {} } : {}),
453
+
454
+ ...(ui ? { extensions: { [MCP_UI_EXTENSION]: {} } } : {}),
401
455
  };
402
456
  }
403
457
 
@@ -409,6 +463,13 @@ export class McpRouter {
409
463
  .then((entries) => {
410
464
  const names = entries.map((entry) => entry.name).join(", ");
411
465
  McpRouter.logger.debug(`MCP page prompts: ${entries.length}${entries.length ? ` (${names})` : ""}`);
466
+ if (!this.#apps || !entries.length) return;
467
+ for (const { name } of entries.filter((entry) => this.#isEndpointName(entry.name)))
468
+ McpRouter.logger.warn(
469
+ `MCP did not publish page "${name}" as a tool: an endpoint already takes that name, so it stays a prompt only. Rename the prompt.`,
470
+ );
471
+ const ui = this.#apps.rendersUi ? "rendered from the CSR shell by an MCP Apps host" : "with no view to render";
472
+ McpRouter.logger.debug(`MCP page tools: ${ui}`);
412
473
  })
413
474
  .catch((error: unknown) => {
414
475
  McpRouter.logger.warn(
@@ -435,12 +496,33 @@ export class McpRouter {
435
496
  async #promptsGet(call: McpCall, document: McpDocument) {
436
497
  const name = call.params.name;
437
498
  if (typeof name !== "string") return McpRouter.#error(call.id, McpErrorCode.invalidParams, "Missing prompt name.");
499
+ const entry = await this.#pageEntry(name);
500
+ if (!entry) return McpRouter.#error(call.id, McpErrorCode.invalidParams, `Unknown prompt: ${name}.`);
501
+ const page = await this.#runPage(call, document, entry);
502
+ if (page instanceof Response) return page;
503
+ if ("refusal" in page) return McpRouter.#error(call.id, McpErrorCode.invalidParams, page.refusal);
504
+ return this.#result(call, { description: entry.description, messages: page.messages });
505
+ }
506
+
507
+ async #pageToolCall(call: McpCall, document: McpDocument, entry: PagePromptEntry) {
508
+ const apps = this.#apps;
509
+ const page = await this.#runPage(call, document, entry);
510
+ if (page instanceof Response) return page;
511
+ if ("refusal" in page)
512
+ return this.#result(call, { content: [{ type: "text", text: page.refusal }], isError: true });
513
+ if (!page.run || !apps) return this.#result(call, { content: page.messages.map((message) => message.content) });
514
+ const origin = this.#auth.publicOrigin(call.req);
515
+ const forView = this.#uiCapable(call) ? { account: McpApps.accountOf(call.req) } : null;
516
+ return this.#result(call, apps.resultOf(page.run, page.messages, origin, forView));
517
+ }
518
+
519
+ async #runPage(call: McpCall, document: McpDocument, entry: PagePromptEntry): Promise<Response | McpPageRun> {
438
520
  const source = this.#props.pagePrompts;
439
- const entry = source ? (await source.list()).find((candidate) => candidate.name === name) : undefined;
440
- if (!source || !entry) return McpRouter.#error(call.id, McpErrorCode.invalidParams, `Unknown prompt: ${name}.`);
521
+ const { name } = entry;
522
+ if (!source) return { refusal: `Unknown prompt: ${name}.` };
441
523
  const args = McpRouter.#arguments(call.params);
442
- if (!args) return McpRouter.#error(call.id, McpErrorCode.invalidParams, McpRouter.#badArguments);
443
- const strings = Object.fromEntries(Object.entries(args).map(([key, value]) => [key, String(value)]));
524
+ const strings = args ? McpRouter.#pageArguments(args) : null;
525
+ if (!strings) return McpRouter.#error(call.id, McpErrorCode.invalidParams, McpRouter.#badArguments);
444
526
  const composer = new PagePromptComposer({
445
527
  document,
446
528
  budget: this.#props.promptBudget ?? PagePromptComposer.defaultBudget,
@@ -455,8 +537,7 @@ export class McpRouter {
455
537
  const missing = entry.arguments
456
538
  .filter((arg) => arg.required && strings[arg.name] === undefined)
457
539
  .map((arg) => arg.name);
458
- if (missing.length)
459
- return this.#result(call, { description: entry.description, messages: composer.missing(entry, missing) });
540
+ if (missing.length) return { run: null, messages: composer.missing(entry, missing) };
460
541
  const run = await source.run({
461
542
  name,
462
543
  arguments: strings,
@@ -476,14 +557,95 @@ export class McpRouter {
476
557
  : run.reason === "not-found"
477
558
  ? "No screen exists for these arguments."
478
559
  : "The page failed to load.";
479
- return McpRouter.#error(call.id, McpErrorCode.invalidParams, message);
560
+ return { refusal: message };
561
+ }
562
+ return { run, messages: await composer.compose(entry, run) };
563
+ }
564
+
565
+ static #pageArguments(args: Record<string, unknown>): Record<string, string> | null {
566
+ const strings: Record<string, string> = {};
567
+ const plain = (value: unknown) => ["string", "number", "boolean"].includes(typeof value);
568
+ for (const [key, value] of Object.entries(args)) {
569
+ if (value === null || value === undefined) continue;
570
+ if (plain(value)) strings[key] = String(value);
571
+ else if (Array.isArray(value) && value.every(plain)) strings[key] = value.join(",");
572
+ else return null;
573
+ }
574
+ return strings;
575
+ }
576
+
577
+ async #pageEntries(): Promise<PagePromptEntry[]> {
578
+ const source = this.#props.pagePrompts;
579
+ if (!source) return [];
580
+ try {
581
+ const entries = await source.list();
582
+ this.#pageListFailed = false;
583
+ return entries;
584
+ } catch (error) {
585
+ if (!this.#pageListFailed)
586
+ McpRouter.logger.warn(
587
+ `MCP page prompts could not be listed, so they are left out: ${error instanceof Error ? error.message : error}`,
588
+ );
589
+ this.#pageListFailed = true;
590
+ return [];
480
591
  }
481
- return this.#result(call, { description: entry.description, messages: await composer.compose(entry, run) });
592
+ }
593
+
594
+ async #pageEntry(name: unknown) {
595
+ if (typeof name !== "string") return undefined;
596
+ return (await this.#pageEntries()).find((candidate) => candidate.name === name);
597
+ }
598
+
599
+ #isEndpointName(name: string) {
600
+ return !!this.#getDocument().findTool(name) || this.#dispatcher.isEndpoint(name);
601
+ }
602
+
603
+ async #pageTools() {
604
+ if (!this.#apps) return [];
605
+ return (await this.#pageEntries()).filter((entry) => !this.#isEndpointName(entry.name));
606
+ }
607
+
608
+ async #pageToolOf(name: unknown) {
609
+ if (!this.#apps || typeof name !== "string" || this.#isEndpointName(name)) return undefined;
610
+ return await this.#pageEntry(name);
611
+ }
612
+
613
+ async #appTools(call: McpCall, document: McpDocument) {
614
+ const apps = this.#apps;
615
+ if (!apps) return [];
616
+ const pages = (await this.#pageTools()).map((entry) => apps.toolOf(entry));
617
+ return this.#uiCapable(call) ? [...document.appTools, ...pages] : pages;
618
+ }
619
+
620
+ async #appResources(call: McpCall) {
621
+ const apps = this.#apps;
622
+ if (!apps?.rendersUi || !this.#uiCapable(call)) return [];
623
+ return apps.resourcesOf(await this.#pageEntries());
624
+ }
625
+
626
+ #uiCapable(call: McpCall) {
627
+ if (!this.#apps?.rendersUi) return false;
628
+ if (call.era === "modern") return McpApps.declaresUi(McpRouter.#meta(call.params)?.[MCP_META_CLIENT_CAPABILITIES]);
629
+ return call.req.headers.get("mcp-session-id")?.startsWith(McpApps.sessionPrefix) ?? false;
630
+ }
631
+
632
+ #forView(call: McpCall) {
633
+ return this.#uiCapable(call) && McpRouter.#meta(call.params)?.["akanjs/view"] === true;
634
+ }
635
+
636
+ #uiSession(call: McpCall): Record<string, string> | undefined {
637
+ if (!this.#apps?.rendersUi || !McpApps.declaresUi(call.params.capabilities)) return undefined;
638
+ return { "mcp-session-id": `${McpApps.sessionPrefix}${crypto.randomUUID()}` };
482
639
  }
483
640
 
484
641
  async #resourcesRead(call: McpCall, document: McpDocument) {
485
642
  const uri = call.params.uri;
486
643
  if (typeof uri !== "string") return McpRouter.#error(call.id, McpErrorCode.invalidParams, "Missing resource uri.");
644
+ if (this.#apps && uri.startsWith(McpApps.scheme)) {
645
+ const contents = await this.#apps.read(uri, this.#auth.publicOrigin(call.req));
646
+ if (!contents) return McpRouter.#error(call.id, McpErrorCode.invalidParams, `Unknown resource: ${uri}.`);
647
+ return this.#result(call, { contents: [contents] });
648
+ }
487
649
  const resolved = document.resolveResource(uri);
488
650
  if (!resolved) return McpRouter.#error(call.id, McpErrorCode.invalidParams, `Unknown resource: ${uri}.`);
489
651
  const result = await this.#dispatcher.call(resolved.exposed, resolved.args, call.req);
@@ -517,7 +679,7 @@ export class McpRouter {
517
679
  new Response(null, {
518
680
  status: 204,
519
681
  headers: {
520
- "access-control-allow-methods": "POST, OPTIONS",
682
+ "access-control-allow-methods": "POST, GET, DELETE, OPTIONS",
521
683
  "access-control-allow-headers":
522
684
  req.headers.get("access-control-request-headers") ?? "authorization, content-type",
523
685
  "access-control-max-age": "600",
@@ -531,6 +693,7 @@ export class McpRouter {
531
693
  if (!origin || !this.#originAllowed(req)) return res;
532
694
  res.headers.set("access-control-allow-origin", origin);
533
695
  res.headers.set("vary", "origin");
696
+ if (res.headers.has("mcp-session-id")) res.headers.set("access-control-expose-headers", "mcp-session-id");
534
697
  return res;
535
698
  }
536
699
 
@@ -539,8 +702,8 @@ export class McpRouter {
539
702
  return { name: `${env.appName}-mcp`, version: this.#props.version ?? "0.0.0" };
540
703
  }
541
704
 
542
- #result(call: McpCall, result: object, cache?: McpCacheHint) {
543
- return Response.json(this.#envelope(call, result, cache));
705
+ #result(call: McpCall, result: object, cache?: McpCacheHint, headers?: Record<string, string>) {
706
+ return Response.json(this.#envelope(call, result, cache), { headers });
544
707
  }
545
708
 
546
709
  #envelope(call: McpCall, result: object, cache?: McpCacheHint) {
@@ -577,18 +740,18 @@ export class McpRouter {
577
740
  return meta && typeof meta === "object" ? (meta as Record<string, unknown>) : null;
578
741
  }
579
742
 
580
- static #negotiate(requested: unknown) {
743
+ #negotiate(requested: unknown) {
581
744
  if (typeof requested !== "string") return MCP_LEGACY_VERSION;
582
- if (MCP_SUPPORTED_VERSIONS.includes(requested as (typeof MCP_SUPPORTED_VERSIONS)[number])) return requested;
583
- const [newest] = MCP_SUPPORTED_VERSIONS;
584
- return requested > newest ? newest : MCP_SUPPORTED_VERSIONS[MCP_SUPPORTED_VERSIONS.length - 1];
745
+ if (this.#versions.includes(requested as McpProtocolVersion)) return requested;
746
+ const [newest] = this.#versions;
747
+ return requested > newest ? newest : this.#versions[this.#versions.length - 1];
585
748
  }
586
749
 
587
- static #methodNotFound(method: string) {
588
- return `Method not found: ${method}. This server speaks MCP ${MCP_SUPPORTED_VERSIONS.join(", ")}.`;
750
+ #methodNotFound(method: string) {
751
+ return `Method not found: ${method}. This server speaks MCP ${this.#versions.join(", ")}.`;
589
752
  }
590
753
 
591
- static #validateModern(
754
+ #validateModern(
592
755
  req: Request,
593
756
  method: string,
594
757
  params: Record<string, unknown>,
@@ -598,10 +761,10 @@ export class McpRouter {
598
761
  const version = meta[MCP_META_PROTOCOL_VERSION];
599
762
  if (typeof version !== "string" || !(MCP_META_CLIENT_CAPABILITIES in meta))
600
763
  return McpRouter.#error(id, McpErrorCode.invalidParams, "Missing required `_meta` fields.", { status: 400 });
601
- if (!MCP_SUPPORTED_VERSIONS.includes(version as (typeof MCP_SUPPORTED_VERSIONS)[number]))
764
+ if (!this.#versions.includes(version as McpProtocolVersion))
602
765
  return McpRouter.#error(id, McpErrorCode.unsupportedProtocolVersion, "Unsupported protocol version.", {
603
766
  status: 400,
604
- data: { requested: version, supported: MCP_SUPPORTED_VERSIONS },
767
+ data: { requested: version, supported: this.#versions },
605
768
  });
606
769
  const named = params.name ?? params.uri;
607
770
  const mismatch =
@@ -1,4 +1,5 @@
1
- import { createPublicKey, type KeyObject, verify } from "node:crypto";
1
+ import { type KeyObject, verify } from "node:crypto";
2
+ import { Ed25519Key } from "../ed25519Key";
2
3
 
3
4
  export interface OpsTokenClaims {
4
5
  aud: string;
@@ -29,15 +30,7 @@ export class OpsTokenVerifier {
29
30
  }
30
31
 
31
32
  static parsePublicKey(value: string): KeyObject {
32
- const trimmed = value.trim();
33
- if (trimmed.startsWith("{")) return createPublicKey({ key: JSON.parse(trimmed) as JsonWebKey, format: "jwk" });
34
- const pem = trimmed.includes("-----BEGIN") ? trimmed.replace(/\\n/g, "\n") : null;
35
- if (pem) return createPublicKey(pem);
36
- const raw = Buffer.from(trimmed, "base64url");
37
- if (raw.length === 32)
38
- return createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x: raw.toString("base64url") }, format: "jwk" });
39
- if (raw.length === 44) return createPublicKey({ key: raw, format: "der", type: "spki" });
40
- throw new Error("AKAN_OPS_PUBLIC_KEY must be a PEM, a JWK, base64 SPKI DER, or a raw 32-byte base64url key");
33
+ return Ed25519Key.parsePublic(value, "AKAN_OPS_PUBLIC_KEY");
41
34
  }
42
35
 
43
36
  verifyRequest(req: Request, nowSec = Math.floor(Date.now() / 1000)): OpsTokenVerdict {
@@ -31,6 +31,7 @@ import {
31
31
  DatabaseAdaptorRole,
32
32
  type DocumentStore,
33
33
  ServiceModel,
34
+ type UpsertByIdOptions,
34
35
  } from "akanjs/service";
35
36
  import { Exception, getCurrentTrace, traceDataLoaderBatch } from "akanjs/signal";
36
37
 
@@ -293,6 +294,8 @@ export class DatabaseResolver {
293
294
  updateById: (id: string, update: DocumentUpdateInput, options?: DocumentUpdateOptions) =>
294
295
  timedQuery(() => store.updateOneByQuery({ id }, update, options)),
295
296
  removeById: (id: string) => timedQuery(() => store.removeOneByQuery({ id })),
297
+ upsertById: (data: Record<string, unknown> & { id: string }, options?: UpsertByIdOptions) =>
298
+ timedQuery(() => store.upsertById(data, options)),
296
299
 
297
300
  countDocuments: (query: QueryOf<any>) => timedQuery(() => store.count(query)),
298
301
  bulkWrite: (