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
@@ -11,12 +11,18 @@ import { akanNativeHome } from "./toolchains.ts";
11
11
  export interface UpdatesConfig {
12
12
  /** Base URL of the update files, e.g. "https://example.com/updates". http:// only for localhost / 10.0.2.2 in dev builds. */
13
13
  url: string;
14
- /** Raw 32-byte Ed25519 public key, base64 (`akan-native update keygen` prints it). */
15
- publicKey: string;
14
+ /**
15
+ * Raw 32-byte Ed25519 public keys, base64 (`akan-native update keygen` prints one): the keys a phone binary trusts, the
16
+ * online signing key first and offline spares after it, since a key may revoke only keys listed before it. A desktop
17
+ * app trusts the first.
18
+ */
19
+ publicKeys: string[];
16
20
  /** Manifest name under <platform>/. Default "production". */
17
21
  channel: string;
18
22
  /** How long a newly applied bundle has to call notifyReady() before it is rolled back, ms. Default 10000. */
19
23
  readyTimeout: number;
24
+ /** Where a phone posts what became of each release (downloaded, applied, confirmed, rolled back, failed); null: no reports. */
25
+ reportUrl: string | null;
20
26
  }
21
27
 
22
28
  export interface UpdateFile {
@@ -35,7 +41,8 @@ export function hostArch(): DesktopArch {
35
41
  }
36
42
 
37
43
  export interface UpdateManifest {
38
- schema: 1;
44
+ /** 2 for a phone's web bundle, which travels in an UpdateEnvelope; 1 for a desktop app. */
45
+ schema: 1 | 2;
39
46
  kind: "web" | "app";
40
47
  app: string;
41
48
  platform: Platform;
@@ -60,6 +67,19 @@ export interface UpdateManifest {
60
67
  patches?: { from: string; url: string; sha256: string; size: number }[];
61
68
  /** App updates: whether the app carries a server; an installed app refuses a release that differs from itself. */
62
69
  server?: boolean;
70
+ /** Web bundles: keyIds the phone stops trusting for good; each listed before the signer's key in its updates.publicKeys. */
71
+ revokeKeys?: string[];
72
+ /** Web bundles: with a new revocation, compare this release with the binary's own bundle instead of the running one. */
73
+ resetSequence?: boolean;
74
+ }
75
+
76
+ /** A phone's `<platform>/<channel>/<nativeApi>.json`: one object, so a new manifest never meets an old signature. */
77
+ export interface UpdateEnvelope {
78
+ /** The manifest's exact bytes, base64. */
79
+ manifest: string;
80
+ keyId: string;
81
+ /** Ed25519 over the manifest bytes, base64. */
82
+ signature: string;
63
83
  }
64
84
 
65
85
  /** Every file of a web bundle as the app serves it: index.html with the init script and CSP, public/, env.runtime.json. */
@@ -106,7 +126,7 @@ export function webManifest(release: {
106
126
  files: UpdateFile[];
107
127
  }): UpdateManifest {
108
128
  return {
109
- schema: 1,
129
+ schema: 2,
110
130
  kind: "web",
111
131
  app: release.app.id,
112
132
  platform: release.platform,
@@ -122,15 +142,15 @@ export function webManifest(release: {
122
142
 
123
143
  /** A channel is a file name in the release folder and a string an app's config compares: lowercase, no separators. */
124
144
  const CHANNEL_NAME = /^[a-z0-9][a-z0-9._-]{0,40}$/;
125
- /** `<channel>.json` of these would overwrite what an unsigned phone update (packUpdate) writes to the same folder. */
126
- const RESERVED_CHANNELS = ["bundle", "manifest.template", "compat"];
145
+ /** These would land on what an unsigned phone update (packUpdate) writes to the same folder, or on its `files/`. */
146
+ const RESERVED_CHANNELS = ["bundle", "manifest.template", "compat", "pack", "files", "app"];
127
147
 
128
148
  /** Refuses a channel no app could be configured for: it would be written but never taken. */
129
149
  export function assertChannel(channel: string): void {
130
150
  if (!CHANNEL_NAME.test(channel))
131
151
  throw new CliError(`channel "${channel}" is not a short lowercase name like "production" or "pilot"`);
132
152
  if (RESERVED_CHANNELS.includes(channel))
133
- throw new CliError(`channel "${channel}" would overwrite ${channel}.json of an unsigned update: name another`);
153
+ throw new CliError(`channel "${channel}" is a name the update folder already uses: name another`);
134
154
  }
135
155
 
136
156
  export function validateUpdates(raw: unknown, problems: string[]): UpdatesConfig | null {
@@ -140,10 +160,10 @@ export function validateUpdates(raw: unknown, problems: string[]): UpdatesConfig
140
160
  return null;
141
161
  }
142
162
  const r = raw as Record<string, unknown>;
143
- if (typeof r.url !== "string" || !/^https?:\/\/[^/]+/.test(r.url))
144
- problems.push("updates.url must be an http(s) URL");
145
- if (typeof r.publicKey !== "string" || Buffer.from(r.publicKey, "base64").length !== 32)
146
- problems.push("updates.publicKey must be a base64 Ed25519 public key (akan-native update keygen)");
163
+
164
+ if (typeof r.url !== "string" || !/^https?:\/\/[^/?#]+[^?#]*$/.test(r.url))
165
+ problems.push("updates.url must be an http(s) URL without a query or fragment");
166
+ const publicKeys = updatePublicKeys(r, problems);
147
167
  if (
148
168
  r.channel !== undefined &&
149
169
  (typeof r.channel !== "string" || !CHANNEL_NAME.test(r.channel) || RESERVED_CHANNELS.includes(r.channel))
@@ -151,18 +171,56 @@ export function validateUpdates(raw: unknown, problems: string[]): UpdatesConfig
151
171
  problems.push('updates.channel must be a short name like "production"');
152
172
  if (r.readyTimeout !== undefined && (typeof r.readyTimeout !== "number" || r.readyTimeout < 1000))
153
173
  problems.push("updates.readyTimeout must be a number of milliseconds >= 1000");
174
+ const reportUrl = updateReportUrl(r.report, problems);
154
175
  for (const key of Object.keys(r))
155
- if (!["url", "publicKey", "channel", "readyTimeout"].includes(key))
176
+ if (!["url", "publicKey", "publicKeys", "channel", "readyTimeout", "report"].includes(key))
156
177
  problems.push(`updates.${key} is not supported`);
157
- if (typeof r.url !== "string" || typeof r.publicKey !== "string") return null;
178
+ if (typeof r.url !== "string" || !publicKeys) return null;
158
179
  return {
159
180
  url: r.url.replace(/\/+$/, ""),
160
- publicKey: r.publicKey,
181
+ publicKeys,
161
182
  channel: (r.channel as string | undefined) ?? "production",
162
183
  readyTimeout: (r.readyTimeout as number | undefined) ?? 10_000,
184
+ reportUrl,
163
185
  };
164
186
  }
165
187
 
188
+ /** `report: { url }`, posted to as it is: the address is the receiver's, a path of its own included. */
189
+ function updateReportUrl(raw: unknown, problems: string[]): string | null {
190
+ if (raw === undefined) return null;
191
+ const url = raw && typeof raw === "object" && !Array.isArray(raw) ? (raw as Record<string, unknown>).url : undefined;
192
+ if (typeof url !== "string" || !/^https?:\/\/[^/?#]+[^#]*$/.test(url) || Object.keys(raw as object).length !== 1) {
193
+ problems.push("updates.report must be { url } with an http(s) URL");
194
+ return null;
195
+ }
196
+ return url.replace(/\/+$/, "");
197
+ }
198
+
199
+ /** `publicKeys` (1–3, no repeats) or the one-key `publicKey`, never both. */
200
+ function updatePublicKeys(r: Record<string, unknown>, problems: string[]): string[] | null {
201
+ if (r.publicKey !== undefined && r.publicKeys !== undefined) {
202
+ problems.push("updates takes publicKey or publicKeys, not both");
203
+ return null;
204
+ }
205
+ const keys = r.publicKeys ?? (r.publicKey === undefined ? undefined : [r.publicKey]);
206
+ const isKey = (key: unknown) => typeof key === "string" && Buffer.from(key, "base64").length === 32;
207
+ if (!Array.isArray(keys) || keys.length < 1 || keys.length > 3 || !keys.every(isKey)) {
208
+ problems.push(
209
+ "updates.publicKeys must be 1 to 3 base64 Ed25519 public keys (akan-native update keygen), or publicKey one",
210
+ );
211
+ return null;
212
+ }
213
+ if (new Set(keys.map(keyIdOf)).size !== keys.length) {
214
+ problems.push("updates.publicKeys lists a key twice");
215
+ return null;
216
+ }
217
+ return keys as string[];
218
+ }
219
+
220
+ /** What an envelope names its signer by: the first 8 bytes of the raw public key's SHA-256, in hex. */
221
+ export const keyIdOf = (publicKey: string) =>
222
+ createHash("sha256").update(Buffer.from(publicKey, "base64")).digest().subarray(0, 8).toString("hex");
223
+
166
224
  /** Where the signing key of an app lives: AKAN_NATIVE_UPDATE_KEY (a file path), else ~/.akan/native/keys/<app id>.update.key. */
167
225
  export function updateKeyPath(appId: string, env: Record<string, string | undefined> = process.env): string {
168
226
  return env.AKAN_NATIVE_UPDATE_KEY ?? join(akanNativeHome(env), "keys", `${appId}.update.key`);
@@ -189,16 +247,60 @@ function publicKeyOf(privateKey: ReturnType<typeof createPrivateKey>): string {
189
247
  return der.subarray(der.length - 32).toString("base64");
190
248
  }
191
249
 
192
- /** The key at `keyPath`, refused unless it is the one whose public half the apps were built with. */
193
- export function signingKey(keyPath: string, expectedPublicKey: string) {
250
+ /** The key at `keyPath` and where it sits in `publicKeys`, refused unless the apps were built to trust it. */
251
+ export function signingKey(keyPath: string, publicKeys: readonly string[]) {
194
252
  const key = readPrivateKey(keyPath);
195
- if (publicKeyOf(key) !== expectedPublicKey)
196
- throw new CliError(`the key at ${keyPath} does not match updates.publicKey in akan-native.config.ts`);
197
- return key;
253
+ const publicKey = publicKeyOf(key);
254
+ const index = publicKeys.indexOf(publicKey);
255
+ if (index < 0) throw new CliError(`the key at ${keyPath} is not one of updates.publicKeys in akan-native.config.ts`);
256
+ return { key, keyId: keyIdOf(publicKey), index };
257
+ }
258
+
259
+ /** A desktop app's base64 signature (protocol v1), with the key the app trusts: the first of updates.publicKeys. */
260
+ export function signManifest(bytes: Uint8Array, keyPath: string, publicKeys: readonly string[]): string {
261
+ const { key, index } = signingKey(keyPath, publicKeys);
262
+ if (index !== 0)
263
+ throw new CliError(
264
+ `a desktop app trusts the first of updates.publicKeys only, and the key at ${keyPath} is not it`,
265
+ );
266
+ return sign(null, bytes, key).toString("base64");
198
267
  }
199
268
 
200
- export function signManifest(bytes: Uint8Array, keyPath: string, expectedPublicKey: string): string {
201
- return sign(null, bytes, signingKey(keyPath, expectedPublicKey)).toString("base64");
269
+ /** A phone's envelope (protocol v2) for the manifest's exact bytes, signed with any key of `publicKeys`. */
270
+ export function sealManifest(bytes: Uint8Array, keyPath: string, publicKeys: readonly string[]): UpdateEnvelope {
271
+ const { key, keyId } = signingKey(keyPath, publicKeys);
272
+ return {
273
+ manifest: Buffer.from(bytes).toString("base64"),
274
+ keyId,
275
+ signature: sign(null, bytes, key).toString("base64"),
276
+ };
277
+ }
278
+
279
+ /**
280
+ * The manifest bytes of an envelope, verified as a phone verifies it against `publicKeys` (minus `revoked`). What it
281
+ * then decides (revocation, sequence) is AkanNativeKernel.updateDecision, kernel.ts updateDecision.
282
+ */
283
+ export function openEnvelope(
284
+ text: string,
285
+ publicKeys: readonly string[],
286
+ revoked: readonly string[] = [],
287
+ ): { manifest: Uint8Array; keyId: string } {
288
+ let envelope: Partial<UpdateEnvelope>;
289
+ try {
290
+ envelope = JSON.parse(text) as Partial<UpdateEnvelope>;
291
+ } catch {
292
+ throw new CliError("the update envelope is not JSON");
293
+ }
294
+ const { manifest, keyId, signature } = envelope;
295
+ if (typeof manifest !== "string" || typeof keyId !== "string" || typeof signature !== "string")
296
+ throw new CliError("the update envelope needs manifest, keyId and signature");
297
+ const publicKey = publicKeys.find((key) => keyIdOf(key) === keyId);
298
+ if (!publicKey || revoked.includes(keyId))
299
+ throw new CliError(`the update envelope is signed by key ${keyId}, which is not trusted`);
300
+ const bytes = Buffer.from(manifest, "base64");
301
+ if (!verifyManifest(bytes, signature, publicKey))
302
+ throw new CliError("the update envelope's signature does not verify");
303
+ return { manifest: new Uint8Array(bytes), keyId };
202
304
  }
203
305
 
204
306
  /** Verifies like the apps do: raw public key, base64 signature over the exact manifest bytes. */
@@ -226,17 +328,51 @@ export function updatesResource(
226
328
  platform: Platform,
227
329
  nativeApi: string | undefined,
228
330
  dev: boolean,
331
+ embeddedSequence = Math.floor(Date.now() / 1000),
229
332
  ): string {
230
333
  return JSON.stringify({
231
334
  app: app.id,
232
335
  version: app.version,
233
336
  platform,
234
337
  nativeApi: nativeApi ?? null,
235
- embeddedSequence: Math.floor(Date.now() / 1000),
338
+ embeddedSequence,
236
339
  dev,
237
340
  url: updates.url,
238
- publicKey: updates.publicKey,
341
+ protocol: platform === "ios" || platform === "android" ? 2 : 1,
342
+ publicKeys: updates.publicKeys,
343
+
344
+ publicKey: updates.publicKeys[0],
239
345
  channel: updates.channel,
240
346
  readyTimeout: updates.readyTimeout,
347
+ ...(updates.reportUrl && (platform === "ios" || platform === "android") ? { reportUrl: updates.reportUrl } : {}),
241
348
  });
242
349
  }
350
+
351
+ /**
352
+ * updates.json of a phone build, and the same facts in the build's bundle.json: a signer that registers the store build
353
+ * checks the binary reads its URL and keys, and takes `embeddedSequence` as the floor every release must pass.
354
+ */
355
+ export function writePhoneUpdates(
356
+ path: string,
357
+ outDir: string,
358
+ updates: UpdatesConfig,
359
+ app: { id: string; version: string },
360
+ platform: "ios" | "android",
361
+ nativeApi: string | undefined,
362
+ dev: boolean,
363
+ ): void {
364
+ const embeddedSequence = Math.floor(Date.now() / 1000);
365
+ writeFileSync(path, updatesResource(updates, app, platform, nativeApi, dev, embeddedSequence));
366
+ const bundlePath = join(outDir, "bundle.json");
367
+ if (!existsSync(bundlePath)) return;
368
+ const bundle = JSON.parse(readFileSync(bundlePath, "utf8")) as Record<string, unknown>;
369
+ bundle.updates = {
370
+ protocol: 2,
371
+ url: updates.url,
372
+ channel: updates.channel,
373
+ keyIds: updates.publicKeys.map(keyIdOf),
374
+ embeddedSequence,
375
+ ...(updates.reportUrl ? { reportUrl: updates.reportUrl } : {}),
376
+ };
377
+ writeFileSync(bundlePath, `${JSON.stringify(bundle, null, 2)}\n`);
378
+ }
@@ -14,6 +14,7 @@ export const VECTOR_FILES = [
14
14
  "acl",
15
15
  "retained",
16
16
  "ed25519",
17
+ "updates",
17
18
  ] as const;
18
19
 
19
20
  /**
@@ -33,6 +34,7 @@ export function vectorCounts(): Record<string, number> {
33
34
  acl: (v.acl.cases as { checks: unknown[] }[]).reduce((sum, c) => sum + 1 + c.checks.length, 0),
34
35
  retained: n(v.retained.cases),
35
36
  ed25519: n(v.ed25519.cases),
37
+ updates: n(v.updates.keyIds) + n(v.updates.decisions) + n(v.updates.urls),
36
38
  };
37
39
  }
38
40
 
@@ -63,7 +63,7 @@ import { androidFeaturesFor, androidPermissionsFor } from "../lib/permissions.ts
63
63
  import { type AndroidSigning, type BuildContext, SigningError } from "../lib/prepare.ts";
64
64
  import type { AndroidManifest, ResolvedConfig } from "../lib/project.ts";
65
65
  import { PACKAGE_ROOT } from "../lib/root.ts";
66
- import { updatesResource } from "../lib/updates.ts";
66
+ import { writePhoneUpdates } from "../lib/updates.ts";
67
67
  import { kotlinVectorData } from "../lib/vectors.ts";
68
68
 
69
69
  const SHELL_SRC = join(PACKAGE_ROOT, "native", "android", "src");
@@ -488,9 +488,14 @@ export async function buildAndroid(ctx: BuildContext): Promise<string> {
488
488
  const boot = makeNativeBoot(ctx, "android");
489
489
  writeFileSync(join(assets, "akan-native", "boot.json"), JSON.stringify(boot));
490
490
  if (config.updates)
491
- writeFileSync(
491
+ writePhoneUpdates(
492
492
  join(assets, "akan-native", "updates.json"),
493
- updatesResource(config.updates, config.app, "android", boot.nativeApi, ctx.dev),
493
+ ctx.outDir,
494
+ config.updates,
495
+ config.app,
496
+ "android",
497
+ boot.nativeApi,
498
+ ctx.dev,
494
499
  );
495
500
  writeFileSync(join(assets, "akan-native", "env.runtime.json"), JSON.stringify(ctx.env, null, 2));
496
501
  writeFileSync(
@@ -498,7 +503,7 @@ export async function buildAndroid(ctx: BuildContext): Promise<string> {
498
503
  JSON.stringify({
499
504
  backgroundColor: config.shell.backgroundColor,
500
505
  backgroundColorDark: config.shell.backgroundColorDark,
501
- devtools: ctx.dev,
506
+ devtools: ctx.dev || config.shell.devtools,
502
507
  splash: { autoHide: config.splash.autoHide, timeout: config.splash.timeout },
503
508
 
504
509
  externalSchemes: config.security?.shell?.externalSchemes ?? [],
@@ -95,7 +95,7 @@ export async function publishAppUpdate(
95
95
  build: (
96
96
  JSON.parse(readFileSync(join(resourcesOf(os, app), "updates.json"), "utf8")) as { embeddedSequence: number }
97
97
  ).embeddedSequence,
98
- arch: hostArch(),
98
+ arch: ctx.arch ?? hostArch(),
99
99
  files: [{ path: basename(app), sha256: tarSha, size: tar.length }],
100
100
  archive: { sha256: tarSha, url: `app/${tarSha}.tar.gz`, size: gz.length, gzSha256: sha256(gz) },
101
101
  patches,
@@ -232,7 +232,8 @@ export function writeDesktopResources(
232
232
  `the server's native addons would not load on a user's computer:\n - ${addons.problems.join("\n - ")}`,
233
233
  );
234
234
  cpSync(server.dir, join(resources, "server"), { recursive: true, verbatimSymlinks: true });
235
- writeFileSync(join(resources, "server.json"), JSON.stringify({ entry: server.entry, env: server.env }));
235
+ const { entry, env, restart, watchdog } = server;
236
+ writeFileSync(join(resources, "server.json"), JSON.stringify({ entry, env, restart, watchdog }));
236
237
  writeFileSync(join(resources, "server.bunfig.toml"), "");
237
238
  }
238
239
  if (config.desktop.bin)
@@ -243,12 +244,13 @@ export function writeDesktopResources(
243
244
  title: config.app.name,
244
245
  backgroundColor: config.shell.backgroundColor,
245
246
  backgroundColorDark: config.shell.backgroundColorDark,
246
- devtools: ctx.dev,
247
+ devtools: ctx.dev || config.shell.devtools,
247
248
  quitOnLastWindowClosed: config.desktop.quitOnLastWindowClosed,
248
249
  recovery: config.desktop.recovery,
249
250
  screenCapture: config.desktop.screenCapture,
250
251
  fullscreen: config.desktop.window.fullscreen,
251
252
  skipTaskbar: config.desktop.window.skipTaskbar,
253
+ frameless: config.desktop.window.frameless,
252
254
 
253
255
  deepLinks: config.deepLinks.schemes,
254
256
 
@@ -52,7 +52,7 @@ import { type BuildContext, SigningError } from "../lib/prepare.ts";
52
52
  import { privacyApiProblems, privacyManifest } from "../lib/privacy.ts";
53
53
  import type { IosManifest } from "../lib/project.ts";
54
54
  import { PACKAGE_ROOT } from "../lib/root.ts";
55
- import { updatesResource } from "../lib/updates.ts";
55
+ import { writePhoneUpdates } from "../lib/updates.ts";
56
56
  import { swiftVectorData } from "../lib/vectors.ts";
57
57
 
58
58
  const SHELL_SRC = join(PACKAGE_ROOT, "native", "ios", "Sources");
@@ -192,9 +192,14 @@ export async function buildIos(ctx: BuildContext): Promise<string> {
192
192
  const boot = makeNativeBoot(ctx, "ios");
193
193
  writeFileSync(join(appPath, "boot.json"), JSON.stringify(boot));
194
194
  if (config.updates)
195
- writeFileSync(
195
+ writePhoneUpdates(
196
196
  join(appPath, "updates.json"),
197
- updatesResource(config.updates, config.app, "ios", boot.nativeApi, ctx.dev),
197
+ ctx.outDir,
198
+ config.updates,
199
+ config.app,
200
+ "ios",
201
+ boot.nativeApi,
202
+ ctx.dev,
198
203
  );
199
204
  writeFileSync(join(appPath, "env.runtime.json"), JSON.stringify(ctx.env, null, 2));
200
205
  writeFileSync(
@@ -202,7 +207,7 @@ export async function buildIos(ctx: BuildContext): Promise<string> {
202
207
  JSON.stringify({
203
208
  backgroundColor: config.shell.backgroundColor,
204
209
  backgroundColorDark: config.shell.backgroundColorDark,
205
- devtools: ctx.dev,
210
+ devtools: ctx.dev || config.shell.devtools,
206
211
  splash: { autoHide: config.splash.autoHide, timeout: config.splash.timeout },
207
212
 
208
213
  externalSchemes: config.security?.shell?.externalSchemes ?? [],
@@ -12,6 +12,11 @@ import { windowsVersion } from "./windows.ts";
12
12
 
13
13
  /** Microsoft's permanent link to the Evergreen Bootstrapper (MicrosoftEdgeWebview2Setup.exe). */
14
14
  export const WEBVIEW2_BOOTSTRAPPER_URL = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
15
+ /** The Evergreen Standalone Installer per CPU (MicrosoftEdgeWebView2RuntimeInstaller<X64|ARM64>.exe). */
16
+ export const WEBVIEW2_STANDALONE_URLS = {
17
+ x64: "https://go.microsoft.com/fwlink/?linkid=2124701",
18
+ arm64: "https://go.microsoft.com/fwlink/?linkid=2099616",
19
+ } as const;
15
20
  /** The WebView2 Runtime's EdgeUpdate client id; its `pv` value is the installed version. */
16
21
  const WEBVIEW2_CLIENT = "{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";
17
22
  /** MAX_PATH less its NUL: what a PC without long paths enabled (the Windows default) can open or unpack. */
@@ -39,6 +44,8 @@ export interface InstallerInput {
39
44
  /** deepLinks.schemes: the uninstaller removes those the app registered for its own executable. */
40
45
  schemes: string[];
41
46
  icon?: string;
47
+ /** desktop.publisher: the Publisher Apps & features lists, and the setup program's company name. */
48
+ publisher?: string;
42
49
  bootstrapper: string;
43
50
  stopScript: string;
44
51
  outFile: string;
@@ -108,7 +115,7 @@ VIAddVersionKey "ProductName" "\${APP_NAME}"
108
115
  VIAddVersionKey "ProductVersion" "${nsis(input.version)}"
109
116
  VIAddVersionKey "FileVersion" "${version}"
110
117
  VIAddVersionKey "FileDescription" "\${APP_NAME} Setup"
111
-
118
+ ${input.publisher ? `VIAddVersionKey "CompanyName" "${nsis(input.publisher)}"\n` : ""}
112
119
  ${icon}!define MUI_FINISHPAGE_RUN "$INSTDIR\\\${EXE}"
113
120
  !insertmacro MUI_PAGE_INSTFILES
114
121
  !insertmacro MUI_PAGE_FINISH
@@ -399,7 +406,7 @@ ${moveIn(input.entries)}
399
406
  CreateShortcut "$SMPROGRAMS\\\${APP_NAME}.lnk" "$INSTDIR\\\${EXE}"
400
407
  WriteRegStr HKCU "\${UNINSTALL_KEY}" "DisplayName" "\${APP_NAME}"
401
408
  WriteRegStr HKCU "\${UNINSTALL_KEY}" "DisplayVersion" "${nsis(input.version)}"
402
- WriteRegStr HKCU "\${UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\\\${EXE}"
409
+ ${input.publisher ? ` WriteRegStr HKCU "\${UNINSTALL_KEY}" "Publisher" "${nsis(input.publisher)}"\n` : ""} WriteRegStr HKCU "\${UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\\\${EXE}"
403
410
  WriteRegStr HKCU "\${UNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
404
411
  WriteRegStr HKCU "\${UNINSTALL_KEY}" "UninstallString" '"$INSTDIR.uninstall.exe"'
405
412
  WriteRegStr HKCU "\${UNINSTALL_KEY}" "QuietUninstallString" '"$INSTDIR.uninstall.exe" /S'
@@ -525,16 +532,22 @@ export function findMakensis(env: Record<string, string | undefined> = process.e
525
532
  return null;
526
533
  }
527
534
 
528
- /** The Evergreen Bootstrapper, downloaded once into the akan-native cache and checked. */
529
- async function webview2Bootstrapper(): Promise<string> {
530
- const file = join(akanNativeHome(), "cache", "webview2", "MicrosoftEdgeWebview2Setup.exe");
535
+ /** The WebView2 setup the installer embeds, downloaded once into the akan-native cache and checked. */
536
+ async function webview2Setup(mode: "bootstrapper" | "standalone", arch: "x64" | "arm64"): Promise<string> {
537
+ const [name, url, minBytes] =
538
+ mode === "standalone"
539
+ ? [`MicrosoftEdgeWebView2RuntimeInstaller${arch.toUpperCase()}.exe`, WEBVIEW2_STANDALONE_URLS[arch], 50_000_000]
540
+ : ["MicrosoftEdgeWebview2Setup.exe", WEBVIEW2_BOOTSTRAPPER_URL, 100_000];
541
+ const file = join(akanNativeHome(), "cache", "webview2", name);
531
542
  if (!existsSync(file)) {
532
- log.info(`downloading the WebView2 Evergreen Bootstrapper (${WEBVIEW2_BOOTSTRAPPER_URL})`);
533
- const response = await fetch(WEBVIEW2_BOOTSTRAPPER_URL, { redirect: "follow" });
534
- if (!response.ok) throw new CliError(`the WebView2 bootstrapper download answered ${response.status}`);
543
+ log.info(
544
+ `downloading the WebView2 ${mode === "standalone" ? `Runtime for ${arch}` : "Evergreen Bootstrapper"} (${url})`,
545
+ );
546
+ const response = await fetch(url, { redirect: "follow" });
547
+ if (!response.ok) throw new CliError(`the WebView2 ${mode} download answered ${response.status}`);
535
548
  const bytes = new Uint8Array(await response.arrayBuffer());
536
- if (bytes.length < 100_000 || bytes[0] !== 0x4d || bytes[1] !== 0x5a)
537
- throw new CliError("the WebView2 bootstrapper download is not a Windows program");
549
+ if (bytes.length < minBytes || bytes[0] !== 0x4d || bytes[1] !== 0x5a)
550
+ throw new CliError(`the WebView2 ${mode} download is not a Windows program`);
538
551
  mkdirSync(join(file, ".."), { recursive: true });
539
552
  writeFileSync(file, bytes);
540
553
  }
@@ -592,7 +605,7 @@ export async function buildWindowsInstaller(ctx: BuildContext, folder: string):
592
605
  log.warn(
593
606
  `${deepest} reaches about ${longest} characters under %LOCALAPPDATA%\\Programs while an update unpacks: Windows refuses paths over ${WINDOWS_MAX_PATH} unless long paths are enabled, so the installer or an update fails on such a PC. Shorten app.name or that path.`,
594
607
  );
595
- const bootstrapper = await webview2Bootstrapper();
608
+ const bootstrapper = await webview2Setup(config.desktop.webview2, ctx.arch ?? hostArch());
596
609
  const size = folderSize(folder);
597
610
  writeFileSync(
598
611
  script,
@@ -607,6 +620,7 @@ export async function buildWindowsInstaller(ctx: BuildContext, folder: string):
607
620
  space: { install: size.disk, unpack: size.bytes + statSync(bootstrapper).size },
608
621
  schemes: config.deepLinks.schemes,
609
622
  ...(existsSync(icon) ? { icon } : {}),
623
+ ...(config.desktop.publisher ? { publisher: config.desktop.publisher } : {}),
610
624
  bootstrapper,
611
625
  stopScript,
612
626
  outFile,
@@ -35,6 +35,19 @@ export function windowsVersion(version: string, build: number): string {
35
35
  return [...parts, Math.max(0, Math.floor(build))].join(".");
36
36
  }
37
37
 
38
+ export function windowsVersionInfo(
39
+ app: { name: string; version: string; build: number },
40
+ publisher?: string,
41
+ ): string[] {
42
+ return [
43
+ `--windows-title=${app.name}`,
44
+ `--windows-description=${app.name}`,
45
+ `--windows-version=${windowsVersion(app.version, app.build)}`,
46
+
47
+ `--windows-publisher=${publisher ?? app.name}`,
48
+ ];
49
+ }
50
+
38
51
  const exePath = (ctx: BuildContext, dir: string) => join(dir, `${ctx.project.config.app.fileName}.exe`);
39
52
 
40
53
  export async function buildWindows(ctx: BuildContext): Promise<string> {
@@ -57,9 +70,7 @@ export async function buildWindows(ctx: BuildContext): Promise<string> {
57
70
  const flags = [
58
71
 
59
72
  "--windows-hide-console",
60
- `--windows-title=${config.app.name}`,
61
- `--windows-description=${config.app.name}`,
62
- `--windows-version=${windowsVersion(config.app.version, config.app.build)}`,
73
+ ...windowsVersionInfo(config.app, config.desktop.publisher),
63
74
  ];
64
75
  if (art) {
65
76
  const icon = join(outDir, "gen", "app.ico");
@@ -279,3 +279,52 @@ export function decideNavigation(
279
279
  if (!topLevel) return FRAME_SCHEMES.includes(scheme) ? "load" : "drop";
280
280
  return externalSchemes(extra).includes(scheme) ? "open" : "drop";
281
281
  }
282
+
283
+ export interface UpdateDecisionInput {
284
+ /** The binary's keyIds, in `updates.publicKeys` order. */
285
+ ring: readonly string[];
286
+ /** keyIds state.json has revoked. */
287
+ revoked: readonly string[];
288
+ /** The envelope's keyId, whose signature over the manifest verified. */
289
+ signer: string;
290
+ revokeKeys: readonly string[];
291
+ resetSequence: boolean;
292
+ sequence: number;
293
+ /** The binary's own bundle (updates.json `embeddedSequence`). */
294
+ embedded: number;
295
+ /** The bundle running now, null for the binary's own. */
296
+ running: { sequence: number; keyId: string } | null;
297
+ }
298
+
299
+ export type UpdateDecision =
300
+ | { kind: "untrusted" | "revoked" | "self-revoke" | "revoke-later" }
301
+ | { kind: "take" | "stale"; baseline: number; revoke: string[] };
302
+
303
+ /**
304
+ * Whether a web bundle manifest is taken (updates protocol v2, vectors/updates.json). A key may revoke only keys listed
305
+ * before it, so a leaked online key — listed first — cannot revoke the offline spares that recover from it, and
306
+ * `resetSequence` counts only on a manifest that newly revokes a key, so replaying it cannot roll anyone back. A bundle a
307
+ * revoked key signed sets no bar, and revocations apply even when the release itself is not newer.
308
+ */
309
+ export function updateDecision(input: UpdateDecisionInput): UpdateDecision {
310
+ const { ring, revoked, signer, revokeKeys } = input;
311
+ const index = ring.indexOf(signer);
312
+ if (index < 0) return { kind: "untrusted" };
313
+ if (revoked.includes(signer)) return { kind: "revoked" };
314
+ if (revokeKeys.includes(signer)) return { kind: "self-revoke" };
315
+ if (revokeKeys.some((id) => ring.indexOf(id) > index)) return { kind: "revoke-later" };
316
+ const revoke = ring.filter((id) => revokeKeys.includes(id) && !revoked.includes(id));
317
+ const running = input.running && ![...revoked, ...revoke].includes(input.running.keyId) ? input.running.sequence : 0;
318
+ const baseline = input.resetSequence && revoke.length ? input.embedded : Math.max(input.embedded, running);
319
+ return { kind: input.sequence > baseline ? "take" : "stale", baseline, revoke };
320
+ }
321
+
322
+ /** One answer of updateDecision as the vectors write it. */
323
+ export const updateDecisionWire = (decision: UpdateDecision) =>
324
+ decision.kind === "take" || decision.kind === "stale"
325
+ ? `${decision.kind}:${decision.baseline}:${decision.revoke.join(",")}`
326
+ : decision.kind;
327
+
328
+ /** The v2 envelope of a channel for one native API: one file per binary generation, so each takes its own fixes. */
329
+ export const updateManifestUrl = (url: string, platform: string, channel: string, nativeApi: string) =>
330
+ `${url}/${platform}/${channel}/${nativeApi}.json`;
@@ -0,0 +1,31 @@
1
+ {
2
+ "about": "Web bundle updates, protocol v2 (architecture.md \"업데이트\"). keyIds: [raw Ed25519 public key in base64, its keyId: the first 8 bytes of its sha256 in hex]. decisions: [the binary's keyIds in updates.publicKeys order, keyIds state.json has revoked, the envelope's keyId, the manifest's revokeKeys, its resetSequence, its sequence, the binary's embeddedSequence, the running bundle as [sequence, keyId] or null for the app's own, the answer, why] for a manifest whose signature verified; the answer is untrusted | revoked | self-revoke | revoke-later, or take|stale:<the sequence it had to beat>:<keyIds it newly revokes, comma-separated>, revocations applying even to a stale manifest. urls: [updates.url, platform, channel, nativeApi, the envelope's URL].",
3
+ "keyIds": [
4
+ ["BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc=", "4bb06f8e4e3a7715"],
5
+ ["11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=", "21fe31dfa154a261"],
6
+ ["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "66687aadf862bd77"]
7
+ ],
8
+ "decisions": [
9
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "a1a1a1a1a1a1a1a1", [], false, 200, 100, null, "take:100:", "signed by the first key, nothing running but the app's own bundle"],
10
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "d4d4d4d4d4d4d4d4", [], false, 200, 100, null, "untrusted", "a key the binary does not carry"],
11
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], ["a1a1a1a1a1a1a1a1"], "a1a1a1a1a1a1a1a1", [], false, 200, 100, null, "revoked", "a key revoked earlier signs nothing"],
12
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "b2b2b2b2b2b2b2b2", ["b2b2b2b2b2b2b2b2"], false, 200, 100, null, "self-revoke", "a key never revokes itself"],
13
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "a1a1a1a1a1a1a1a1", ["b2b2b2b2b2b2b2b2"], false, 200, 100, null, "revoke-later", "a key revokes only keys listed before it"],
14
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "b2b2b2b2b2b2b2b2", ["a1a1a1a1a1a1a1a1"], false, 300, 100, [500, "a1a1a1a1a1a1a1a1"], "take:100:a1a1a1a1a1a1a1a1", "the bundle a revoked key signed no longer sets the bar"],
15
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "b2b2b2b2b2b2b2b2", ["a1a1a1a1a1a1a1a1"], true, 300, 100, [500, "b2b2b2b2b2b2b2b2"], "take:100:a1a1a1a1a1a1a1a1", "resetSequence with a new revocation compares with the app's own bundle"],
16
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], ["a1a1a1a1a1a1a1a1"], "b2b2b2b2b2b2b2b2", ["a1a1a1a1a1a1a1a1"], true, 300, 100, [500, "b2b2b2b2b2b2b2b2"], "stale:500:", "replayed: nothing new revoked, so the reset does not apply"],
17
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "b2b2b2b2b2b2b2b2", ["a1a1a1a1a1a1a1a1", "d4d4d4d4d4d4d4d4"], false, 200, 100, null, "take:100:a1a1a1a1a1a1a1a1", "an id this binary does not carry is ignored"],
18
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "a1a1a1a1a1a1a1a1", [], false, 100, 100, null, "stale:100:", "no newer than the app's own bundle"],
19
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "a1a1a1a1a1a1a1a1", [], false, 150, 100, [150, "a1a1a1a1a1a1a1a1"], "stale:150:", "the bundle already running"],
20
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "c3c3c3c3c3c3c3c3", ["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2"], false, 120, 100, null, "take:100:a1a1a1a1a1a1a1a1,b2b2b2b2b2b2b2b2", "the last key revokes both before it"],
21
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "b2b2b2b2b2b2b2b2", ["a1a1a1a1a1a1a1a1", "a1a1a1a1a1a1a1a1"], false, 200, 100, null, "take:100:a1a1a1a1a1a1a1a1", "listed twice, revoked once"],
22
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "a1a1a1a1a1a1a1a1", [], false, 160, 100, [150, "b2b2b2b2b2b2b2b2"], "take:150:", "another trusted key's bundle sets the bar"],
23
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], ["a1a1a1a1a1a1a1a1"], "c3c3c3c3c3c3c3c3", ["b2b2b2b2b2b2b2b2"], false, 200, 100, [900, "a1a1a1a1a1a1a1a1"], "take:100:b2b2b2b2b2b2b2b2", "a bundle of a key revoked before still runs this session but sets no bar"],
24
+ [["a1a1a1a1a1a1a1a1", "b2b2b2b2b2b2b2b2", "c3c3c3c3c3c3c3c3"], [], "a1a1a1a1a1a1a1a1", [], true, 300, 100, [500, "a1a1a1a1a1a1a1a1"], "stale:500:", "resetSequence without a revocation does nothing"],
25
+ [["a1a1a1a1a1a1a1a1"], [], "a1a1a1a1a1a1a1a1", [], false, 200, 100, null, "take:100:", "a ring of one"]
26
+ ],
27
+ "urls": [
28
+ ["https://asset.akamir.com/ota/inst1/pathA", "ios", "main", "0123456789abcdef", "https://asset.akamir.com/ota/inst1/pathA/ios/main/0123456789abcdef.json"],
29
+ ["http://10.0.2.2:8790", "android", "pilot", "fedcba9876543210", "http://10.0.2.2:8790/android/pilot/fedcba9876543210.json"]
30
+ ]
31
+ }
@@ -49,6 +49,7 @@ interface ShellConfig {
49
49
  /** desktop.window: the main window from its first frame, unless the launch phase says otherwise. */
50
50
  fullscreen?: boolean;
51
51
  skipTaskbar?: boolean;
52
+ frameless?: boolean;
52
53
  }
53
54
 
54
55
  const finite = (v: unknown): v is number => typeof v === "number" && Number.isFinite(v);
@@ -62,6 +63,7 @@ export function launchBounds(window: LaunchWindow): LaunchWindow {
62
63
  if (window.maximized === true) out.maximized = true;
63
64
  if (typeof window.fullscreen === "boolean") out.fullscreen = window.fullscreen;
64
65
  if (typeof window.skipTaskbar === "boolean") out.skipTaskbar = window.skipTaskbar;
66
+ if (typeof window.frameless === "boolean") out.frameless = window.frameless;
65
67
  return out;
66
68
  }
67
69
 
@@ -154,6 +156,7 @@ export async function startMain(workerUrl: string): Promise<never> {
154
156
  height: shell.height ?? 720,
155
157
  fullscreen: shell.fullscreen === true,
156
158
  skipTaskbar: shell.skipTaskbar === true,
159
+ frameless: shell.frameless === true,
157
160
  ...bounds,
158
161
  appDir: paths.appDir,
159
162
  initJs,
@@ -170,6 +170,8 @@ export interface LaunchWindow {
170
170
  fullscreen?: boolean;
171
171
  /** No taskbar button (Windows, Linux; macOS has none). */
172
172
  skipTaskbar?: boolean;
173
+ /** No title bar or border. */
174
+ frameless?: boolean;
173
175
  }
174
176
 
175
177
  /** What the launch phase decided; sent to the main thread with "ready". */