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
@@ -86,6 +86,8 @@ export interface AkanNativeConfig {
86
86
  /** Painted before the page loads, to avoid a white flash (SH-3). */
87
87
  backgroundColor?: string;
88
88
  backgroundColorDark?: string;
89
+ /** The web inspector in a release build too (a debug build always has it): internal test builds only. */
90
+ devtools?: boolean;
89
91
  };
90
92
  /** Overrides for permission usage texts, e.g. { NSCameraUsageDescription: "..." }. */
91
93
  usageDescriptions?: Record<string, string>;
@@ -112,10 +114,20 @@ export interface AkanNativeConfig {
112
114
  permissions?: { camera?: string | true; microphone?: string | true; location?: string | true };
113
115
  /**
114
116
  * Over-the-air updates (UP-2 web bundles on iOS / Android, UP-1 app updates on macOS), used by
115
- * @akanjs/native/plugins/updates. `akan-native update keygen` makes the signing key and prints `publicKey`;
116
- * `akan-native update publish <platform>` writes signed releases for `url`.
117
+ * @akanjs/native/plugins/updates. `akan-native update keygen` makes the signing key and prints its public key;
118
+ * `akan-native update publish <platform>` writes signed releases for `url`. `publicKeys` lists the keys a phone
119
+ * trusts, the online signing key first and offline spares after (a key revokes only keys before it); `publicKey` is
120
+ * the one-key form, and a desktop app trusts the first. `report.url` is where a phone posts what became of each
121
+ * release, at its next launch or return to the foreground.
117
122
  */
118
- updates?: { url: string; publicKey: string; channel?: string; readyTimeout?: number };
123
+ updates?: {
124
+ url: string;
125
+ publicKey?: string;
126
+ publicKeys?: string[];
127
+ channel?: string;
128
+ readyTimeout?: number;
129
+ report?: { url: string };
130
+ };
119
131
  /** Links that open the app, delivered through the app plugin's urlOpen (and getLaunchUrl). */
120
132
  deepLinks?: {
121
133
  /** Custom URL schemes (myapp://...). */
@@ -250,10 +262,10 @@ export interface AkanNativeConfig {
250
262
  recovery?: "errorPage" | "reload";
251
263
  /**
252
264
  * The main window from its first frame: `fullscreen` (borderless, on the display the window opens on)
253
- * and `skipTaskbar` (no taskbar button; Windows and Linux). A plugin's launch phase may still decide
254
- * otherwise (DesktopContext.launch.setWindow). Default false for both.
265
+ * `skipTaskbar` (no taskbar button; Windows and Linux) and `frameless` (no title bar or border). A plugin's
266
+ * launch phase may still decide otherwise (DesktopContext.launch.setWindow). Default false for all three.
255
267
  */
256
- window?: { fullscreen?: boolean; skipTaskbar?: boolean };
268
+ window?: { fullscreen?: boolean; skipTaskbar?: boolean; frameless?: boolean };
257
269
  /**
258
270
  * Windows: "auto" answers the page's getDisplayMedia() with the first screen at once, without the picker or a
259
271
  * user gesture: a remote-support session on an unattended screen. It is Chromium's switch for automated media
@@ -262,13 +274,29 @@ export interface AkanNativeConfig {
262
274
  * offered. macOS and Linux ignore it.
263
275
  */
264
276
  screenCapture?: "picker" | "auto";
277
+ /**
278
+ * Windows installer: "bootstrapper" (default) carries Microsoft's 2 MB setup that downloads the WebView2
279
+ * Runtime when the PC has none; "standalone" carries the whole runtime (~200 MB), for a PC that is offline or
280
+ * behind a proxy at install. Either runs only where no runtime is installed.
281
+ */
282
+ webview2?: "bootstrapper" | "standalone";
283
+ /** Windows: the installed app's Publisher (Apps & features) and its executable's company name (default: the app name). */
284
+ publisher?: string;
265
285
  /**
266
286
  * A server the app starts beside its window (akanjs `native.desktop.server`). `dir` is copied to
267
287
  * the app's resources (`server/`), and `entry` there runs on the app's own Bun with `env`, bound to
268
288
  * a loopback port picked at launch; the page reads its URL as PUBLIC_AKAN_SERVER_URL. The launcher
269
289
  * sets PORT, JWT_SECRET, the data folders (`<app local data>/server`) and the listen host itself.
290
+ * `restart`: crashes in a row before it gives up (5), or "forever"; `watchdog`: its health route asked every
291
+ * `intervalMs`, `failures` missed in a row restarting it.
270
292
  */
271
- server?: { dir: string; entry: string; env?: Record<string, string> };
293
+ server?: {
294
+ dir: string;
295
+ entry: string;
296
+ env?: Record<string, string>;
297
+ restart?: number | "forever";
298
+ watchdog?: { intervalMs: number; failures: number };
299
+ };
272
300
  /**
273
301
  * A folder of executables the app carries (akanjs `bin`): copied to the app's resources (`bin/`) and put
274
302
  * first on the app's PATH at launch, so its plugins and its server find them by name before the computer's.
@@ -35,6 +35,8 @@ export interface BundleInfo {
35
35
  nativeApi: { hash: string; inputs: NativeApi };
36
36
  /** sha256 of the web files (index.html as served and public/), for update integrity later. */
37
37
  web: { hash: string; files: number };
38
+ /** A phone build with updates: what its binary reads (updates.json), the floor of every release's sequence included. */
39
+ updates?: { protocol: 2; url: string; channel: string; keyIds: string[]; embeddedSequence: number };
38
40
  }
39
41
 
40
42
  /** "0.1.4" → "0.1", "1.2.0" → "1". */
@@ -16,11 +16,11 @@ const KNOWN: Shape = {
16
16
  },
17
17
  },
18
18
  env: { defaults: true, platforms: { web: true, macos: true, windows: true, linux: true, ios: true, android: true } },
19
- shell: { backgroundColor: true, backgroundColorDark: true },
19
+ shell: { backgroundColor: true, backgroundColorDark: true, devtools: true },
20
20
  usageDescriptions: true,
21
21
  privacy: { tracking: true, trackingDomains: true, collectedDataTypes: true, accessedApis: true },
22
22
  permissions: { camera: true, microphone: true, location: true },
23
- updates: { url: true, publicKey: true, channel: true, readyTimeout: true },
23
+ updates: { url: true, publicKey: true, publicKeys: true, channel: true, readyTimeout: true, report: { url: true } },
24
24
  deepLinks: { schemes: true, domains: { "[]": { host: true, pathPrefixes: true } } },
25
25
  native: {
26
26
  ios: { infoPlist: true, entitlements: true },
@@ -33,9 +33,11 @@ const KNOWN: Shape = {
33
33
  desktop: {
34
34
  quitOnLastWindowClosed: true,
35
35
  recovery: true,
36
- window: { fullscreen: true, skipTaskbar: true },
36
+ window: { fullscreen: true, skipTaskbar: true, frameless: true },
37
37
  screenCapture: true,
38
- server: { dir: true, entry: true, env: true },
38
+ webview2: true,
39
+ publisher: true,
40
+ server: { dir: true, entry: true, env: true, restart: true, watchdog: { intervalMs: true, failures: true } },
39
41
  bin: true,
40
42
  dmg: {
41
43
  background: true,
@@ -10,6 +10,8 @@ export interface DesktopServerConfig {
10
10
  dir: string;
11
11
  entry: string;
12
12
  env: Record<string, string>;
13
+ restart?: number | "forever";
14
+ watchdog?: { intervalMs: number; failures: number };
13
15
  }
14
16
 
15
17
  const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -54,5 +56,13 @@ export function validateDesktopServer(
54
56
  else if (typeof value !== "string") problems.push(`desktop.server.env.${key} must be a string`);
55
57
  else env[key] = value;
56
58
  }
57
- return problems.length === before && dir ? { dir, entry, env } : null;
59
+ const { restart, watchdog } = server;
60
+ if (restart !== undefined && restart !== "forever" && !(Number.isInteger(restart) && restart > 0))
61
+ problems.push('desktop.server.restart must be "forever" or a count of crashes in a row from 1');
62
+ const positive = (value: unknown) => Number.isInteger(value) && (value as number) > 0;
63
+ if (watchdog !== undefined && !(watchdog && positive(watchdog.intervalMs) && positive(watchdog.failures)))
64
+ problems.push("desktop.server.watchdog must be { intervalMs, failures }, both whole numbers from 1");
65
+ return problems.length === before && dir
66
+ ? { dir, entry, env, ...(restart !== undefined ? { restart } : {}), ...(watchdog ? { watchdog } : {}) }
67
+ : null;
58
68
  }
@@ -0,0 +1,73 @@
1
+ import { basename } from "node:path";
2
+ import { CliError } from "./log.ts";
3
+ import { type MacosNotarization, type MacosSigning, macosDistributionFromEnv } from "./macossigning.ts";
4
+ import { type WindowsSigning, windowsSigningFromEnv } from "./windowssigning.ts";
5
+
6
+ export interface DistributionRequest {
7
+ /** Sign the app with the identity the env names (Developer ID on macOS, Authenticode on Windows). */
8
+ sign?: boolean;
9
+ /** macOS: upload the signed app to Apple's notary service. */
10
+ notarize?: boolean;
11
+ }
12
+
13
+ export interface Distribution {
14
+ macos?: { signing?: MacosSigning; notarize?: MacosNotarization };
15
+ windows?: { signing?: WindowsSigning };
16
+ /** One line saying who signs and where the app goes, for before the build; null when nothing is signed. */
17
+ notice: string | null;
18
+ /** The env names that configure a signature this build was not asked to make. */
19
+ unused: string[];
20
+ }
21
+
22
+ const SIGNING_ENV =
23
+ /^AKAN_NATIVE_(?:MACOS_(?:IDENTITY|CERTIFICATE|NOTARY_PROFILE|NOTARY_KEY)|WINDOWS_(?:CERTIFICATE|THUMBPRINT|SIGN_COMMAND))$/;
24
+
25
+ export function requestedDistribution(
26
+ platform: string,
27
+ profile: "debug" | "release",
28
+ { sign = false, notarize = false }: DistributionRequest,
29
+ env: Record<string, string | undefined> = process.env,
30
+ ): Distribution {
31
+ const unused = Object.keys(env)
32
+ .filter((name) => SIGNING_ENV.test(name) && env[name]?.trim())
33
+ .sort();
34
+ if (!sign && !notarize) return { notice: null, unused };
35
+ if (platform !== "macos" && platform !== "windows")
36
+ throw new CliError(`--sign and --notarize are for a macOS or Windows app, not ${platform}`);
37
+ if (profile !== "release") throw new CliError("--sign and --notarize take a release build");
38
+ if (notarize && platform !== "macos") throw new CliError("--notarize is Apple's: a Windows app is only signed");
39
+ if (notarize && !sign) throw new CliError("--notarize takes --sign: Apple notarizes a signed app only");
40
+ if (platform === "windows") {
41
+ const signing = windowsSigningFromEnv(env);
42
+ if (!signing)
43
+ throw new CliError(
44
+ "--sign needs the identity: AKAN_NATIVE_WINDOWS_CERTIFICATE (+ _PASSWORD), AKAN_NATIVE_WINDOWS_THUMBPRINT or AKAN_NATIVE_WINDOWS_SIGN_COMMAND",
45
+ );
46
+ const by = signing.command
47
+ ? `the signing command ${basename(signing.command[0] ?? "")}, which may send each file to its signing service`
48
+ : signing.thumbprint
49
+ ? `the certificate ${signing.thumbprint}`
50
+ : `the certificate in ${basename(signing.certificate?.path ?? "")}`;
51
+ return { windows: { signing }, notice: `Signs the Windows app with ${by}.`, unused: [] };
52
+ }
53
+ const { signing, notarize: notarization } = macosDistributionFromEnv(env);
54
+ if (!signing)
55
+ throw new CliError(
56
+ "--sign needs the identity: AKAN_NATIVE_MACOS_IDENTITY, or AKAN_NATIVE_MACOS_CERTIFICATE (+ _PASSWORD)",
57
+ );
58
+ if (notarize && !notarization)
59
+ throw new CliError(
60
+ "--notarize needs the credentials: AKAN_NATIVE_MACOS_NOTARY_PROFILE, or AKAN_NATIVE_MACOS_NOTARY_KEY + _KEY_ID",
61
+ );
62
+ const identity = signing.identity ?? `the certificate in ${basename(signing.certificate?.path ?? "")}`;
63
+ const notary = notarization?.profile
64
+ ? `notarytool profile ${notarization.profile}`
65
+ : `API key ${notarization?.keyId}`;
66
+ return {
67
+ macos: { signing, ...(notarize && notarization ? { notarize: notarization } : {}) },
68
+ notice: notarize
69
+ ? `Signs the macOS app as ${identity} and uploads it to Apple's notary service (${notary}).`
70
+ : `Signs the macOS app as ${identity}; nothing is uploaded without --notarize.`,
71
+ unused: [],
72
+ };
73
+ }
@@ -25,15 +25,17 @@ export interface ResolvedConfig
25
25
  web: Required<Pick<AkanNativeConfig["web"], "dir" | "base">> & { build?: string; devEntry?: string };
26
26
  plugins: string[];
27
27
  env: EnvConfig;
28
- shell: { backgroundColor: string; backgroundColorDark: string };
28
+ shell: { backgroundColor: string; backgroundColorDark: string; devtools: boolean };
29
29
  usageDescriptions: Record<string, string>;
30
30
  permissions: PermissionsConfig;
31
31
  deepLinks: { schemes: string[]; domains: { host: string; pathPrefixes: string[] }[] };
32
32
  desktop: {
33
33
  quitOnLastWindowClosed: boolean;
34
34
  recovery: "errorPage" | "reload";
35
- window: { fullscreen: boolean; skipTaskbar: boolean };
35
+ window: { fullscreen: boolean; skipTaskbar: boolean; frameless: boolean };
36
36
  screenCapture: "picker" | "auto";
37
+ webview2: "bootstrapper" | "standalone";
38
+ publisher?: string;
37
39
  server?: DesktopServerConfig;
38
40
  /** Absolute. */
39
41
  bin?: string;
@@ -201,13 +203,19 @@ export function projectFromConfig(raw: AkanNativeConfig, appDir: string, options
201
203
  const recovery = raw.desktop?.recovery;
202
204
  if (recovery !== undefined && recovery !== "errorPage" && recovery !== "reload")
203
205
  problems.push(`desktop.recovery must be "errorPage" or "reload" (got ${JSON.stringify(recovery)})`);
204
- for (const key of ["fullscreen", "skipTaskbar"] as const) {
206
+ for (const key of ["fullscreen", "skipTaskbar", "frameless"] as const) {
205
207
  const value = raw.desktop?.window?.[key];
206
208
  if (value !== undefined && typeof value !== "boolean") problems.push(`desktop.window.${key} must be a boolean`);
207
209
  }
208
210
  const screenCapture = raw.desktop?.screenCapture;
209
211
  if (screenCapture !== undefined && screenCapture !== "picker" && screenCapture !== "auto")
210
212
  problems.push(`desktop.screenCapture must be "picker" or "auto" (got ${JSON.stringify(screenCapture)})`);
213
+ const webview2 = raw.desktop?.webview2;
214
+ if (webview2 !== undefined && webview2 !== "bootstrapper" && webview2 !== "standalone")
215
+ problems.push(`desktop.webview2 must be "bootstrapper" or "standalone" (got ${JSON.stringify(webview2)})`);
216
+ const publisher = raw.desktop?.publisher;
217
+ if (publisher !== undefined && (typeof publisher !== "string" || !publisher.trim() || /["\r\n]/.test(publisher)))
218
+ problems.push("desktop.publisher must be a name on one line, without a double quote");
211
219
  if (raw.android?.autoplay !== undefined && typeof raw.android.autoplay !== "boolean")
212
220
  problems.push("android.autoplay must be a boolean");
213
221
  const bin = raw.desktop?.bin;
@@ -253,6 +261,7 @@ export function projectFromConfig(raw: AkanNativeConfig, appDir: string, options
253
261
  const shell = {
254
262
  backgroundColor: raw.shell?.backgroundColor ?? "#ffffff",
255
263
  backgroundColorDark: raw.shell?.backgroundColorDark ?? raw.shell?.backgroundColor ?? "#000000",
264
+ devtools: raw.shell?.devtools === true,
256
265
  };
257
266
  const icon = typeof raw.icon === "string" ? { image: raw.icon } : raw.icon;
258
267
  const splashColor = raw.splash?.backgroundColor;
@@ -279,9 +288,12 @@ export function projectFromConfig(raw: AkanNativeConfig, appDir: string, options
279
288
  quitOnLastWindowClosed: raw.desktop?.quitOnLastWindowClosed ?? true,
280
289
  recovery: raw.desktop?.recovery === "reload" ? "reload" : "errorPage",
281
290
  screenCapture: raw.desktop?.screenCapture === "auto" ? "auto" : "picker",
291
+ webview2: raw.desktop?.webview2 === "standalone" ? "standalone" : "bootstrapper",
292
+ ...(typeof raw.desktop?.publisher === "string" ? { publisher: raw.desktop.publisher.trim() } : {}),
282
293
  window: {
283
294
  fullscreen: raw.desktop?.window?.fullscreen === true,
284
295
  skipTaskbar: raw.desktop?.window?.skipTaskbar === true,
296
+ frameless: raw.desktop?.window?.frameless === true,
285
297
  },
286
298
  ...(desktopServer ? { server: desktopServer } : {}),
287
299
  ...(binDir ? { bin: binDir } : {}),
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { assertSameServer, publishAppUpdate } from "../platforms/desktop-update.ts";
6
6
  import { BUNDLE_FILE, readBundleInfo } from "./compat.ts";
@@ -8,9 +8,12 @@ import { CliError, log } from "./log.ts";
8
8
  import type { BuildContext } from "./prepare.ts";
9
9
  import {
10
10
  assertChannel,
11
+ type DesktopArch,
11
12
  hostArch,
13
+ sealManifest,
12
14
  signingKey,
13
15
  signManifest,
16
+ type UpdateEnvelope,
14
17
  type UpdateManifest,
15
18
  updateKeyPath,
16
19
  webManifest,
@@ -23,17 +26,34 @@ export interface PublishedRelease {
23
26
  /** `<out>/<os>-<arch>` for a desktop app, `<out>/<platform>` for a phone's web bundle. */
24
27
  dir: string;
25
28
  manifest: UpdateManifest;
29
+ /** The file installed apps read: `<dir>/<channel>.json`, or a phone's `<dir>/<channel>/<nativeApi>.json`. */
30
+ file: string;
31
+ }
32
+
33
+ /** The largest sequence published to `channel` in `dir`: a desktop's `<channel>.json`, every `<channel>/*.json` of a phone. */
34
+ function publishedSequence(dir: string, channel: string): number | null {
35
+ const sequences: unknown[] = [];
36
+ const v1 = join(dir, `${channel}.json`);
37
+ if (existsSync(v1)) sequences.push((JSON.parse(readFileSync(v1, "utf8")) as Partial<UpdateManifest>).sequence);
38
+ const v2 = join(dir, channel);
39
+ if (existsSync(v2))
40
+ for (const name of readdirSync(v2).filter((name) => name.endsWith(".json"))) {
41
+ const envelope = JSON.parse(readFileSync(join(v2, name), "utf8")) as Partial<UpdateEnvelope>;
42
+ const manifest = JSON.parse(Buffer.from(envelope.manifest ?? "", "base64").toString("utf8") || "{}");
43
+ sequences.push((manifest as Partial<UpdateManifest>).sequence);
44
+ }
45
+ const numbers = sequences.filter((sequence): sequence is number => typeof sequence === "number");
46
+ return numbers.length ? Math.max(...numbers) : null;
26
47
  }
27
48
 
28
49
  /**
29
- * The publish time in seconds, and past the release `<channel>.json` in `dir` already names: apps take only a larger
30
- * sequence, so a clock behind the last publisher's would make this release look older to every one of them.
50
+ * The publish time in seconds, and past every release of the channel in `dir`: apps take only a larger sequence, so a
51
+ * clock behind the last publisher's would make this release look older to every one of them. A phone's native APIs
52
+ * share one count, so a binary moving to the next generation never meets a smaller number.
31
53
  */
32
54
  export function nextSequence(dir: string, channel: string, now = Math.floor(Date.now() / 1000)): number {
33
- const path = join(dir, `${channel}.json`);
34
- if (!existsSync(path)) return now;
35
- const previous = (JSON.parse(readFileSync(path, "utf8")) as Partial<UpdateManifest>).sequence;
36
- if (typeof previous !== "number" || previous < now) return now;
55
+ const previous = publishedSequence(dir, channel);
56
+ if (previous === null || previous < now) return now;
37
57
  if (previous > now)
38
58
  log.warn(
39
59
  `the ${channel} release already here has sequence ${previous}, later than this computer's clock (${now}): publishing as ${previous + 1}. Check the clock of the computer that publishes.`,
@@ -41,10 +61,10 @@ export function nextSequence(dir: string, channel: string, now = Math.floor(Date
41
61
  return previous + 1;
42
62
  }
43
63
 
44
- /** `<out>/<os>-<arch>` for a desktop release, `<out>/<platform>` for a phone's web bundle. */
45
- export function releaseDir(out: string, platform: ReleasePlatform): string {
64
+ /** `<out>/<os>-<arch>` for a desktop release (the arch it was built for), `<out>/<platform>` for a phone's web bundle. */
65
+ export function releaseDir(out: string, platform: ReleasePlatform, arch?: DesktopArch): string {
46
66
  const desktop = platform === "macos" || platform === "windows" || platform === "linux";
47
- return join(out, desktop ? `${platform}-${hostArch()}` : platform);
67
+ return join(out, desktop ? `${platform}-${arch ?? hostArch()}` : platform);
48
68
  }
49
69
 
50
70
  /** Refuses before the build a desktop release the apps of its channel would refuse for its server (assertSameServer). */
@@ -53,16 +73,25 @@ export function assertServerOfChannel(
53
73
  platform: ReleasePlatform,
54
74
  out: string,
55
75
  channel: string,
76
+ arch?: DesktopArch,
56
77
  ): void {
57
78
  if (platform === "macos" || platform === "windows" || platform === "linux")
58
- assertSameServer(releaseDir(out, platform), channel, !!config.desktop?.server);
79
+ assertSameServer(releaseDir(out, platform, arch), channel, !!config.desktop?.server);
59
80
  }
60
81
 
61
- /** Refuses before the build a release that could not be signed: no key on this machine, or another app's. */
62
- export function assertSigningKey(config: { app: { id: string }; updates?: { publicKey: string } | null }): void {
82
+ /**
83
+ * Refuses before the build a release that could not be signed: no key on this machine, another app's, or for a desktop
84
+ * app one the app does not trust (it trusts the first of updates.publicKeys).
85
+ */
86
+ export function assertSigningKey(
87
+ config: { app: { id: string }; updates?: { publicKeys: string[] } | null },
88
+ platform?: ReleasePlatform,
89
+ ): void {
63
90
  if (!config.updates)
64
- throw new CliError("akan-native.config.ts has no updates: { url, publicKey } (run `akan-native update keygen`)");
65
- signingKey(updateKeyPath(config.app.id), config.updates.publicKey);
91
+ throw new CliError("akan-native.config.ts has no updates: { url, publicKeys } (run `akan-native update keygen`)");
92
+ const { index } = signingKey(updateKeyPath(config.app.id), config.updates.publicKeys);
93
+ if (index !== 0 && (platform === "macos" || platform === "windows" || platform === "linux"))
94
+ throw new CliError("a desktop app trusts the first of updates.publicKeys only: sign with that key");
66
95
  }
67
96
 
68
97
  /**
@@ -77,7 +106,16 @@ function writeSigned(dir: string, channel: string, bytes: Uint8Array, signature:
77
106
  renameSync(`${json}.tmp`, json);
78
107
  }
79
108
 
80
- /** Writes the release of `artifact` (the app a release build made) and its signed `<channel>.json` under `out`. */
109
+ /** A phone's envelope replaces the last one in a single rename, so no reader meets half of either. */
110
+ function writeEnvelope(dir: string, channel: string, nativeApi: string, envelope: UpdateEnvelope): string {
111
+ const file = join(dir, channel, `${nativeApi}.json`);
112
+ mkdirSync(join(dir, channel), { recursive: true });
113
+ writeFileSync(`${file}.tmp`, `${JSON.stringify(envelope)}\n`);
114
+ renameSync(`${file}.tmp`, file);
115
+ return file;
116
+ }
117
+
118
+ /** Writes the release of `artifact` (the app a release build made) and its signed manifest under `out`. */
81
119
  export async function publishRelease(
82
120
  ctx: BuildContext,
83
121
  platform: ReleasePlatform,
@@ -87,12 +125,12 @@ export async function publishRelease(
87
125
  ): Promise<PublishedRelease> {
88
126
  const { config } = ctx.project;
89
127
  if (!config.updates)
90
- throw new CliError("akan-native.config.ts has no updates: { url, publicKey } (run `akan-native update keygen`)");
128
+ throw new CliError("akan-native.config.ts has no updates: { url, publicKeys } (run `akan-native update keygen`)");
91
129
  const desktop = platform === "macos" || platform === "windows" || platform === "linux" ? platform : null;
92
130
 
93
- const dir = releaseDir(out, platform);
131
+ const dir = releaseDir(out, platform, ctx.arch);
94
132
  assertChannel(channel);
95
- assertSigningKey(config);
133
+ assertSigningKey(config, platform);
96
134
  const keyPath = updateKeyPath(config.app.id);
97
135
  const sequence = nextSequence(dir, channel);
98
136
 
@@ -113,9 +151,18 @@ export async function publishRelease(
113
151
  });
114
152
  }
115
153
  const bytes = new TextEncoder().encode(`${JSON.stringify(manifest, null, 2)}\n`);
116
- const signature = `${signManifest(bytes, keyPath, config.updates.publicKey)}\n`;
117
154
  mkdirSync(dir, { recursive: true });
118
- writeSigned(dir, channel, bytes, signature);
119
- for (const file of leftovers) rmSync(file, { force: true });
120
- return { dir, manifest };
155
+ let file: string;
156
+ if (desktop) {
157
+ writeSigned(dir, channel, bytes, `${signManifest(bytes, keyPath, config.updates.publicKeys)}\n`);
158
+ file = join(dir, `${channel}.json`);
159
+ } else
160
+ file = writeEnvelope(
161
+ dir,
162
+ channel,
163
+ manifest.nativeApi ?? "",
164
+ sealManifest(bytes, keyPath, config.updates.publicKeys),
165
+ );
166
+ for (const leftover of leftovers) rmSync(leftover, { force: true });
167
+ return { dir, manifest, file };
121
168
  }