akanjs 3.1.0-rc.2 → 3.1.0-rc.21

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 (392) hide show
  1. package/base/baseEnv.ts +5 -2
  2. package/client/device.ts +1 -1
  3. package/client/frameConfig.ts +2 -2
  4. package/client/href.ts +35 -0
  5. package/client/index.ts +1 -0
  6. package/client/makePageProto.tsx +3 -2
  7. package/client/router.ts +6 -4
  8. package/client/rscNavigation.ts +1 -1
  9. package/client/transitionTypes.ts +0 -4
  10. package/client/translator.ts +16 -0
  11. package/client/types.ts +3 -2
  12. package/client/viewportMeta.ts +23 -8
  13. package/client/webManifest.ts +5 -3
  14. package/common/TrustedProxy.ts +14 -0
  15. package/common/codeAgentWire.ts +8 -1
  16. package/common/index.ts +1 -0
  17. package/common/interpolateTranslation.ts +17 -3
  18. package/common/isEmail.ts +1 -1
  19. package/common/localeConfig.ts +10 -4
  20. package/common/markdownSpans.ts +1 -1
  21. package/common/restClient.ts +3 -1
  22. package/common/routeConvention.ts +4 -4
  23. package/common/trimSlashes.ts +11 -0
  24. package/common/types.ts +1 -1
  25. package/constant/fieldInfo.ts +2 -2
  26. package/constant/fieldPlan.ts +80 -0
  27. package/constant/index.ts +3 -0
  28. package/constant/inputParser.ts +148 -0
  29. package/constant/invalidInputError.ts +13 -0
  30. package/constant/serialize.ts +36 -20
  31. package/constant/types.ts +1 -1
  32. package/constant/via.ts +2 -0
  33. package/dictionary/base.dictionary.ts +4 -0
  34. package/dictionary/trans.ts +8 -0
  35. package/document/database.ts +3 -6
  36. package/document/documentSchema.ts +1 -1
  37. package/document/noDocumentError.ts +6 -1
  38. package/fetch/client/fetchClient.ts +2 -1
  39. package/fetch/client/sliceInitHandle.ts +2 -3
  40. package/fetch/fetchType/appliedReturn.type.ts +3 -1
  41. package/fetch/types.ts +4 -2
  42. package/index.ts +2 -0
  43. package/package.json +31 -21
  44. package/server/akanApp.ts +15 -3
  45. package/server/akanServer.ts +34 -14
  46. package/server/artifact/routeClientCache.ts +4 -5
  47. package/server/artifact/routeSeedIndexStore.ts +3 -20
  48. package/server/artifact/routeSeedMatcher.ts +70 -0
  49. package/server/console.ts +1 -1
  50. package/server/di/diLifecycle.ts +16 -7
  51. package/server/imageOptimizer.ts +1 -1
  52. package/server/index.ts +1 -0
  53. package/server/machine/machineAccount.ts +28 -3
  54. package/server/machine/machineToken.ts +27 -3
  55. package/server/mcp/McpDispatcher.ts +2 -3
  56. package/server/mcp/McpExecutionContext.ts +9 -3
  57. package/server/migration/docPath.ts +121 -0
  58. package/server/migration/index.ts +15 -0
  59. package/server/migration/migrationChangeLog.ts +86 -0
  60. package/server/migration/migrationChanges.ts +70 -0
  61. package/server/migration/migrationCommand.ts +179 -0
  62. package/server/migration/migrationContext.ts +53 -0
  63. package/server/migration/migrationDefinition.ts +87 -0
  64. package/server/migration/migrationError.ts +45 -0
  65. package/server/migration/migrationLedger.ts +172 -0
  66. package/server/migration/migrationLock.ts +103 -0
  67. package/server/migration/migrationParams.ts +122 -0
  68. package/server/migration/migrationPulse.ts +39 -0
  69. package/server/migration/migrationRunner.ts +525 -0
  70. package/server/migration/migrationScope.ts +93 -0
  71. package/server/migration/migrationTable.ts +258 -0
  72. package/server/migration/migrations.ts +57 -0
  73. package/server/ops/opsCommand.ts +30 -1
  74. package/server/resolver/CascadeRunner.ts +15 -2
  75. package/server/resolver/signal.resolver.ts +35 -55
  76. package/server/routeState.ts +0 -6
  77. package/server/rscClient.tsx +22 -37
  78. package/server/rscNavigationState.ts +3 -5
  79. package/server/rscScrollRestoration.ts +116 -0
  80. package/server/rscWorker.tsx +12 -19
  81. package/server/sitemap.ts +4 -4
  82. package/server/tunnel/TunnelAgent.ts +9 -1
  83. package/server/webRouter.ts +17 -2
  84. package/service/agent.service.ts +21 -1
  85. package/service/endpointCacheKeys.ts +35 -0
  86. package/service/index.ts +1 -0
  87. package/service/injectInfo.ts +2 -2
  88. package/service/predefinedAdaptor/anthropicLlm.ts +37 -17
  89. package/service/predefinedAdaptor/database.adaptor.ts +15 -0
  90. package/service/predefinedAdaptor/documentTransfer.ts +50 -0
  91. package/service/predefinedAdaptor/endpointCacheControl.adaptor.ts +19 -0
  92. package/service/predefinedAdaptor/index.ts +1 -0
  93. package/service/predefinedAdaptor/llm.adaptor.ts +7 -0
  94. package/service/predefinedAdaptor/openaiDialect.ts +53 -17
  95. package/service/predefinedAdaptor/openaiLlm.ts +1 -1
  96. package/service/predefinedAdaptor/sql/MigrationTables.ts +90 -0
  97. package/service/predefinedAdaptor/sql/RawDocumentTable.ts +200 -0
  98. package/service/predefinedAdaptor/sql/SqlDocumentStore.ts +6 -2
  99. package/service/predefinedAdaptor/sql/SqliteInsightSession.ts +4 -1
  100. package/service/predefinedAdaptor/sql/dialect/postgres.ts +0 -1
  101. package/service/predefinedAdaptor/sql/dialect/sqlite.ts +0 -1
  102. package/service/predefinedAdaptor/sql/types.ts +3 -1
  103. package/service/predefinedAdaptor/storage.adaptor.ts +19 -0
  104. package/signal/endpointCache.ts +23 -7
  105. package/signal/endpointErrorContract.ts +37 -0
  106. package/signal/endpointIdempotency.ts +5 -3
  107. package/signal/endpointInfo.ts +4 -1
  108. package/signal/endpointRateLimit.ts +6 -2
  109. package/signal/exception.ts +4 -1
  110. package/signal/index.ts +1 -0
  111. package/signal/mcp/McpDocument.ts +16 -1
  112. package/signal/mcp/McpUriTemplate.ts +1 -1
  113. package/signal/middlewareChain.ts +105 -0
  114. package/signal/openapi/openapi.ts +46 -2
  115. package/signal/serializer/fetch.serializer.ts +1 -0
  116. package/signal/signalContext.ts +110 -82
  117. package/signal/slice.ts +2 -2
  118. package/signal/trace.ts +8 -2
  119. package/signal/types.ts +13 -0
  120. package/store/action.ts +102 -42
  121. package/store/agent/ScreenImage.ts +166 -0
  122. package/store/agent/ScreenReader.ts +2 -1
  123. package/store/agent/StoreSurfaceSource.ts +41 -2
  124. package/store/agent/index.ts +2 -1
  125. package/store/databaseStateNames.ts +1 -0
  126. package/store/formUploadOf.ts +41 -0
  127. package/store/index.ts +1 -0
  128. package/store/liveInsert.ts +2 -2
  129. package/store/state.ts +9 -1
  130. package/store/stateBuilder.ts +8 -2
  131. package/store/storeInstance.ts +12 -3
  132. package/store/withSelector.ts +2 -2
  133. package/types/client/href.d.ts +11 -0
  134. package/types/client/index.d.ts +1 -0
  135. package/types/client/rscNavigation.d.ts +1 -1
  136. package/types/client/transitionTypes.d.ts +0 -2
  137. package/types/client/translator.d.ts +2 -0
  138. package/types/common/codeAgentWire.d.ts +7 -0
  139. package/types/common/index.d.ts +1 -0
  140. package/types/common/trimSlashes.d.ts +2 -0
  141. package/types/common/types.d.ts +1 -1
  142. package/types/constant/fieldInfo.d.ts +2 -2
  143. package/types/constant/fieldPlan.d.ts +33 -0
  144. package/types/constant/index.d.ts +3 -0
  145. package/types/constant/inputParser.d.ts +11 -0
  146. package/types/constant/invalidInputError.d.ts +8 -0
  147. package/types/constant/types.d.ts +1 -1
  148. package/types/dictionary/base.dictionary.d.ts +1 -1
  149. package/types/dictionary/dictionary.d.ts +3 -3
  150. package/types/dictionary/trans.d.ts +3 -0
  151. package/types/document/database.d.ts +2 -3
  152. package/types/document/documentSchema.d.ts +1 -1
  153. package/types/document/noDocumentError.d.ts +6 -1
  154. package/types/fetch/fetchType/appliedReturn.type.d.ts +3 -1
  155. package/types/fetch/types.d.ts +2 -2
  156. package/types/index.d.ts +5 -0
  157. package/types/server/akanServer.d.ts +1 -1
  158. package/types/server/artifact/routeSeedMatcher.d.ts +8 -0
  159. package/types/server/di/diLifecycle.d.ts +1 -0
  160. package/types/server/index.d.ts +1 -0
  161. package/types/server/machine/machineAccount.d.ts +1 -0
  162. package/types/server/machine/machineToken.d.ts +9 -0
  163. package/types/server/migration/docPath.d.ts +20 -0
  164. package/types/server/migration/index.d.ts +15 -0
  165. package/types/server/migration/migrationChangeLog.d.ts +27 -0
  166. package/types/server/migration/migrationChanges.d.ts +27 -0
  167. package/types/server/migration/migrationCommand.d.ts +33 -0
  168. package/types/server/migration/migrationContext.d.ts +28 -0
  169. package/types/server/migration/migrationDefinition.d.ts +42 -0
  170. package/types/server/migration/migrationError.d.ts +15 -0
  171. package/types/server/migration/migrationLedger.d.ts +51 -0
  172. package/types/server/migration/migrationLock.d.ts +34 -0
  173. package/types/server/migration/migrationParams.d.ts +41 -0
  174. package/types/server/migration/migrationPulse.d.ts +15 -0
  175. package/types/server/migration/migrationRunner.d.ts +93 -0
  176. package/types/server/migration/migrationScope.d.ts +42 -0
  177. package/types/server/migration/migrationTable.d.ts +52 -0
  178. package/types/server/migration/migrations.d.ts +12 -0
  179. package/types/server/migration.d.ts +1 -0
  180. package/types/server/ops/opsCommand.d.ts +10 -1
  181. package/types/server/routeState.d.ts +1 -4
  182. package/types/server/rscNavigationState.d.ts +2 -3
  183. package/types/server/rscScrollRestoration.d.ts +14 -0
  184. package/types/server/sitemap.d.ts +1 -1
  185. package/types/service/agent.service.d.ts +2 -0
  186. package/types/service/endpointCacheKeys.d.ts +8 -0
  187. package/types/service/index.d.ts +1 -0
  188. package/types/service/injectInfo.d.ts +2 -2
  189. package/types/service/predefinedAdaptor/anthropicLlm.d.ts +9 -4
  190. package/types/service/predefinedAdaptor/database.adaptor.d.ts +8 -1
  191. package/types/service/predefinedAdaptor/documentTransfer.d.ts +1 -0
  192. package/types/service/predefinedAdaptor/endpointCacheControl.adaptor.d.ts +9 -0
  193. package/types/service/predefinedAdaptor/index.d.ts +1 -0
  194. package/types/service/predefinedAdaptor/llm.adaptor.d.ts +7 -0
  195. package/types/service/predefinedAdaptor/openaiDialect.d.ts +20 -5
  196. package/types/service/predefinedAdaptor/sql/MigrationTables.d.ts +17 -0
  197. package/types/service/predefinedAdaptor/sql/RawDocumentTable.d.ts +38 -0
  198. package/types/service/predefinedAdaptor/sql/types.d.ts +1 -0
  199. package/types/service/predefinedAdaptor/storage.adaptor.d.ts +8 -0
  200. package/types/signal/endpointCache.d.ts +2 -0
  201. package/types/signal/endpointErrorContract.d.ts +10 -0
  202. package/types/signal/endpointIdempotency.d.ts +1 -0
  203. package/types/signal/endpointRateLimit.d.ts +1 -1
  204. package/types/signal/exception.d.ts +4 -1
  205. package/types/signal/index.d.ts +1 -0
  206. package/types/signal/middlewareChain.d.ts +11 -0
  207. package/types/signal/signalContext.d.ts +2 -6
  208. package/types/signal/slice.d.ts +1 -1
  209. package/types/signal/trace.d.ts +1 -1
  210. package/types/signal/types.d.ts +12 -0
  211. package/types/store/action.d.ts +2 -0
  212. package/types/store/agent/ScreenImage.d.ts +27 -0
  213. package/types/store/agent/StoreSurfaceSource.d.ts +1 -1
  214. package/types/store/agent/index.d.ts +2 -1
  215. package/types/store/databaseStateNames.d.ts +1 -0
  216. package/types/store/formUploadOf.d.ts +9 -0
  217. package/types/store/index.d.ts +1 -0
  218. package/types/store/state.d.ts +7 -1
  219. package/types/store/stateBuilder.d.ts +2 -1
  220. package/types/store/storeInstance.d.ts +2 -2
  221. package/types/store/withSelector.d.ts +1 -1
  222. package/types/ui/Agent/Composer.d.ts +2 -0
  223. package/types/ui/Agent/Menu.d.ts +2 -0
  224. package/types/ui/CsrImage.d.ts +2 -0
  225. package/types/ui/Data/CardList.d.ts +1 -1
  226. package/types/ui/Data/Dashboard.d.ts +1 -1
  227. package/types/ui/Data/Insight.d.ts +1 -1
  228. package/types/ui/Data/Item.d.ts +2 -2
  229. package/types/ui/Data/ListContainer.d.ts +1 -1
  230. package/types/ui/Data/Pagination.d.ts +1 -1
  231. package/types/ui/Data/TableList.d.ts +1 -1
  232. package/types/ui/Field/Relation.d.ts +13 -10
  233. package/types/ui/Field/index.d.ts +4 -4
  234. package/types/ui/Field/useRelationOptions.d.ts +3 -1
  235. package/types/ui/Field/useRelationWindow.d.ts +14 -0
  236. package/types/ui/Image.d.ts +3 -1
  237. package/types/ui/Load/View.d.ts +1 -1
  238. package/types/ui/Pagination.d.ts +1 -1
  239. package/types/ui/Signal/Arg.d.ts +1 -1
  240. package/types/ui/System/CSR.d.ts +1 -1
  241. package/types/ui/System/Client.d.ts +1 -1
  242. package/types/ui/System/SSR.d.ts +1 -1
  243. package/types/vendor/@akanjs/native/packages/core/src/plugin.d.ts +3 -3
  244. package/types/vendor/@akanjs/native/packages/desktop/src/page-veto.d.ts +1 -1
  245. package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +1 -1
  246. package/types/vendor/@akanjs/native/plugins/auth-session/src/desktop.d.ts +2 -2
  247. package/types/vendor/@akanjs/native/plugins/auth-session/src/index.d.ts +1 -1
  248. package/types/vendor/@akanjs/native/plugins/autostart/src/desktop.d.ts +2 -2
  249. package/types/vendor/@akanjs/native/plugins/autostart/src/index.d.ts +1 -1
  250. package/types/vendor/@akanjs/native/plugins/badge/src/desktop.d.ts +1 -1
  251. package/types/vendor/@akanjs/native/plugins/badge/src/index.d.ts +1 -1
  252. package/types/vendor/@akanjs/native/plugins/badge/src/web.d.ts +1 -1
  253. package/types/vendor/@akanjs/native/plugins/biometric/src/index.d.ts +1 -1
  254. package/types/vendor/@akanjs/native/plugins/camera/src/desktop.d.ts +1 -1
  255. package/types/vendor/@akanjs/native/plugins/camera/src/index.d.ts +1 -1
  256. package/types/vendor/@akanjs/native/plugins/camera/src/web.d.ts +1 -1
  257. package/types/vendor/@akanjs/native/plugins/clipboard/src/desktop.d.ts +2 -2
  258. package/types/vendor/@akanjs/native/plugins/clipboard/src/index.d.ts +1 -1
  259. package/types/vendor/@akanjs/native/plugins/clipboard/src/web.d.ts +1 -1
  260. package/types/vendor/@akanjs/native/plugins/contacts/src/index.d.ts +1 -1
  261. package/types/vendor/@akanjs/native/plugins/device/src/desktop.d.ts +2 -2
  262. package/types/vendor/@akanjs/native/plugins/device/src/index.d.ts +1 -1
  263. package/types/vendor/@akanjs/native/plugins/device/src/web.d.ts +1 -1
  264. package/types/vendor/@akanjs/native/plugins/dialog/src/desktop.d.ts +1 -1
  265. package/types/vendor/@akanjs/native/plugins/dialog/src/index.d.ts +1 -1
  266. package/types/vendor/@akanjs/native/plugins/dialog/src/web.d.ts +1 -1
  267. package/types/vendor/@akanjs/native/plugins/dock/src/desktop.d.ts +1 -1
  268. package/types/vendor/@akanjs/native/plugins/dock/src/index.d.ts +1 -1
  269. package/types/vendor/@akanjs/native/plugins/file-picker/src/desktop.d.ts +2 -2
  270. package/types/vendor/@akanjs/native/plugins/file-picker/src/web.d.ts +1 -1
  271. package/types/vendor/@akanjs/native/plugins/filesystem/src/desktop.d.ts +2 -2
  272. package/types/vendor/@akanjs/native/plugins/filesystem/src/web.d.ts +1 -1
  273. package/types/vendor/@akanjs/native/plugins/haptics/src/index.d.ts +1 -1
  274. package/types/vendor/@akanjs/native/plugins/haptics/src/web.d.ts +1 -1
  275. package/types/vendor/@akanjs/native/plugins/http/src/desktop.d.ts +2 -2
  276. package/types/vendor/@akanjs/native/plugins/http/src/web.d.ts +1 -1
  277. package/types/vendor/@akanjs/native/plugins/keep-awake/src/desktop.d.ts +2 -2
  278. package/types/vendor/@akanjs/native/plugins/keep-awake/src/index.d.ts +1 -1
  279. package/types/vendor/@akanjs/native/plugins/keep-awake/src/web.d.ts +1 -1
  280. package/types/vendor/@akanjs/native/plugins/opener/src/desktop.d.ts +2 -2
  281. package/types/vendor/@akanjs/native/plugins/opener/src/index.d.ts +1 -1
  282. package/types/vendor/@akanjs/native/plugins/opener/src/web.d.ts +1 -1
  283. package/types/vendor/@akanjs/native/plugins/preferences/src/desktop.d.ts +1 -1
  284. package/types/vendor/@akanjs/native/plugins/preferences/src/index.d.ts +1 -1
  285. package/types/vendor/@akanjs/native/plugins/preferences/src/web.d.ts +1 -1
  286. package/types/vendor/@akanjs/native/plugins/secure-storage/src/desktop.d.ts +2 -2
  287. package/types/vendor/@akanjs/native/plugins/secure-storage/src/index.d.ts +1 -1
  288. package/types/vendor/@akanjs/native/plugins/share/src/index.d.ts +1 -1
  289. package/types/vendor/@akanjs/native/plugins/share/src/web.d.ts +1 -1
  290. package/types/vendor/@akanjs/native/plugins/single-instance/src/desktop.d.ts +2 -2
  291. package/types/vendor/@akanjs/native/plugins/splash-screen/src/index.d.ts +1 -1
  292. package/types/vendor/@akanjs/native/plugins/splash-screen/src/web.d.ts +1 -1
  293. package/types/vendor/@akanjs/native/plugins/sqlite/src/desktop.d.ts +2 -2
  294. package/types/vendor/@akanjs/native/plugins/toast/src/index.d.ts +1 -1
  295. package/types/vendor/@akanjs/native/plugins/toast/src/web.d.ts +1 -1
  296. package/types/vendor/@akanjs/native/plugins/window/src/index.d.ts +2 -2
  297. package/types/vendor/@akanjs/native/plugins/window-state/src/desktop.d.ts +2 -2
  298. package/types/vendor/@akanjs/native/plugins/window-state/src/index.d.ts +1 -1
  299. package/types/vendor/use-agentic/Compaction.d.ts +3 -1
  300. package/types/vendor/use-agentic/Reference.d.ts +9 -1
  301. package/types/vendor/use-agentic/ToolOutput.d.ts +6 -1
  302. package/types/vendor/use-agentic/ToolReturn.d.ts +18 -0
  303. package/types/vendor/use-agentic/Transcript.d.ts +7 -0
  304. package/types/vendor/use-agentic/index.d.ts +1 -0
  305. package/types/vendor/use-agentic/types.d.ts +6 -0
  306. package/types/webkit/useDebounce.d.ts +1 -1
  307. package/ui/Agent/Chat.tsx +1 -0
  308. package/ui/Agent/Composer.tsx +2 -0
  309. package/ui/Agent/Menu.tsx +5 -1
  310. package/ui/Agent/agentSessionOf.ts +15 -8
  311. package/ui/Agent/mentionDraft.ts +2 -3
  312. package/ui/Agent/useReferenceMenu.ts +1 -0
  313. package/ui/Agent/useSlashMenu.ts +1 -0
  314. package/ui/Clipboard.tsx +1 -0
  315. package/ui/CsrImage.tsx +3 -1
  316. package/ui/Data/CardList.tsx +1 -1
  317. package/ui/Data/Dashboard.tsx +1 -1
  318. package/ui/Data/Insight.tsx +1 -1
  319. package/ui/Data/Item.tsx +5 -2
  320. package/ui/Data/ListContainer.tsx +2 -2
  321. package/ui/Data/Pagination.tsx +1 -1
  322. package/ui/Data/TableList.tsx +1 -1
  323. package/ui/DraggableList.tsx +1 -0
  324. package/ui/Field/Collection.tsx +4 -0
  325. package/ui/Field/Relation.tsx +33 -14
  326. package/ui/Field/useRelationOptions.ts +33 -5
  327. package/ui/Field/useRelationWindow.ts +50 -0
  328. package/ui/Image.tsx +4 -4
  329. package/ui/Input.tsx +1 -0
  330. package/ui/Layout/Sider.tsx +1 -1
  331. package/ui/Link/Anchor.tsx +7 -5
  332. package/ui/Load/Units.tsx +17 -7
  333. package/ui/Load/View.tsx +2 -2
  334. package/ui/Model/Edit.tsx +1 -1
  335. package/ui/Model/EditModal.tsx +11 -5
  336. package/ui/Model/New.tsx +1 -1
  337. package/ui/Model/SureToRemove.tsx +1 -0
  338. package/ui/Model/ViewEditModal.tsx +17 -5
  339. package/ui/Model/ViewModal.tsx +2 -2
  340. package/ui/ObjectId.tsx +5 -1
  341. package/ui/Pagination.tsx +1 -1
  342. package/ui/Signal/Arg.tsx +1 -3
  343. package/ui/Signal/Doc.tsx +5 -1
  344. package/ui/System/CSR.tsx +1 -1
  345. package/ui/System/Client.tsx +1 -1
  346. package/ui/System/Reconnect.tsx +1 -1
  347. package/ui/System/SSR.tsx +3 -36
  348. package/ui/ToggleSelect.tsx +2 -0
  349. package/ui/styles.css +10 -103
  350. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeBridge.swift +3 -2
  351. package/vendor/@akanjs/native/packages/cli/src/lib/addons.ts +4 -1
  352. package/vendor/@akanjs/native/packages/cli/src/lib/apk.ts +2 -2
  353. package/vendor/@akanjs/native/packages/cli/src/lib/codegen.ts +1 -1
  354. package/vendor/@akanjs/native/packages/cli/src/lib/csp.ts +4 -3
  355. package/vendor/@akanjs/native/packages/cli/src/lib/googleservices.ts +7 -1
  356. package/vendor/@akanjs/native/packages/cli/src/lib/hmr.ts +8 -5
  357. package/vendor/@akanjs/native/packages/cli/src/lib/html.ts +18 -3
  358. package/vendor/@akanjs/native/packages/cli/src/lib/manifestmerge.ts +1 -1
  359. package/vendor/@akanjs/native/packages/cli/src/lib/plist.ts +2 -4
  360. package/vendor/@akanjs/native/packages/cli/src/lib/toolchains.ts +1 -1
  361. package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +10 -4
  362. package/vendor/@akanjs/native/packages/cli/src/lib/xml.ts +4 -3
  363. package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +3 -3
  364. package/vendor/@akanjs/native/packages/core/src/kernel.ts +3 -3
  365. package/vendor/@akanjs/native/packages/core/src/live.ts +1 -0
  366. package/vendor/@akanjs/native/packages/core/src/plugin.ts +5 -3
  367. package/vendor/@akanjs/native/packages/desktop/src/host.ts +13 -5
  368. package/vendor/@akanjs/native/packages/desktop/src/lifecycle.ts +1 -0
  369. package/vendor/@akanjs/native/packages/desktop/src/page-veto.ts +1 -1
  370. package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +4 -1
  371. package/vendor/@akanjs/native/plugins/camera/src/web.ts +3 -3
  372. package/vendor/@akanjs/native/plugins/file-picker/src/index.ts +4 -1
  373. package/vendor/@akanjs/native/plugins/local-notifications/src/web.ts +1 -1
  374. package/vendor/@akanjs/native/plugins/secure-storage/src/desktop.ts +1 -1
  375. package/vendor/@akanjs/native/plugins/share/src/options.ts +1 -1
  376. package/vendor/@akanjs/native/plugins/single-instance/src/desktop.ts +3 -2
  377. package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +4 -1
  378. package/vendor/@akanjs/native/plugins/window/src/index.ts +2 -2
  379. package/vendor/use-agentic/Compaction.ts +38 -7
  380. package/vendor/use-agentic/Reference.ts +16 -9
  381. package/vendor/use-agentic/ToolOutput.ts +25 -3
  382. package/vendor/use-agentic/ToolReturn.ts +32 -0
  383. package/vendor/use-agentic/ToolRunner.ts +15 -13
  384. package/vendor/use-agentic/Transcript.ts +38 -2
  385. package/vendor/use-agentic/WIRE.md +20 -0
  386. package/vendor/use-agentic/index.ts +1 -0
  387. package/vendor/use-agentic/types.ts +6 -0
  388. package/webkit/McpAppAgent.ts +12 -2
  389. package/webkit/RenderLayer.tsx +23 -4
  390. package/webkit/useDebounce.ts +23 -14
  391. package/client/viewTransition.ts +0 -10
  392. package/types/client/viewTransition.d.ts +0 -3
@@ -168,6 +168,8 @@ export class AkanServer {
168
168
  shutdownTimeoutMs = AkanServer.#defaultShutdownTimeoutMs();
169
169
 
170
170
  #di: DiLifecycle;
171
+ #openApiDocument: ReturnType<typeof createOpenApiDocument> | null = null;
172
+ readonly #initTimings = new Map<string, number>();
171
173
  #localPublish: LocalPublish | null = null;
172
174
  readonly #binaryPubsub = new BinaryPubsub();
173
175
  #metricsTimer: Timer | null = null;
@@ -324,7 +326,16 @@ export class AkanServer {
324
326
  };
325
327
  }
326
328
 
327
- async init({ routes: initRoutes = true, web }: { routes?: boolean; web?: AkanWebOption } = {}) {
329
+ async init(option: { routes?: boolean; web?: AkanWebOption } = {}) {
330
+ const start = performance.now();
331
+ this.#initTimings.clear();
332
+ await this.#init(option);
333
+ const stages = [...this.#di.initTimings, ...this.#initTimings].map(([stage, ms]) => `${stage} ${ms.toFixed(1)}`);
334
+ this.logger.debug(`Initialized in ${(performance.now() - start).toFixed(1)}ms (${stages.join(" · ")})`);
335
+ return this;
336
+ }
337
+
338
+ async #init({ routes: initRoutes = true, web }: { routes?: boolean; web?: AkanWebOption }) {
328
339
  if (this.status !== "stopped") throw new Error("AkanServer is not able to init. It is already running.");
329
340
  this.status = "initializing";
330
341
  this.#assertPrefixClearsBasePaths();
@@ -340,7 +351,7 @@ export class AkanServer {
340
351
  routes,
341
352
  routeOptions,
342
353
  wsRoutes,
343
- builtinRoutes: this.#createBuiltinRoutes(null),
354
+ builtinRoutes: this.#timedBuiltinRoutes(null),
344
355
  renderEnvRoutes: {},
345
356
  hmrHub: null,
346
357
  webRouter: null,
@@ -354,6 +365,7 @@ export class AkanServer {
354
365
  this.logger.debug("web off: serving api only (AKAN_SSR=false, or a build with `web: false`)");
355
366
  return noWeb();
356
367
  }
368
+ const webStart = performance.now();
357
369
  const { WebRouter } = await import("./webRouter");
358
370
  const webRouter = await WebRouter.create({
359
371
  web: requestedWeb,
@@ -368,12 +380,13 @@ export class AkanServer {
368
380
  this.web = webRouter.web;
369
381
  this.logger.verbose(`web on: ssr=${this.web.ssr} csr=${this.web.csr}`);
370
382
  const { renderEnvRoutes, hmrHub } = await webRouter.initializeRoute();
383
+ this.#initTimings.set("web", performance.now() - webStart);
371
384
  const webProxyRunner = WebProxyRunner.create(this.#di.webProxies);
372
385
  this.#prepared = {
373
386
  routes,
374
387
  routeOptions,
375
388
  wsRoutes,
376
- builtinRoutes: this.#createBuiltinRoutes(webRouter),
389
+ builtinRoutes: this.#timedBuiltinRoutes(webRouter),
377
390
  renderEnvRoutes,
378
391
  hmrHub,
379
392
  webRouter,
@@ -666,21 +679,18 @@ export class AkanServer {
666
679
  }
667
680
  }
668
681
 
682
+ #timedBuiltinRoutes(webRouter: WebRouter | null): HttpRoutes {
683
+ const start = performance.now();
684
+ const builtinRoutes = this.#createBuiltinRoutes(webRouter);
685
+ this.#initTimings.set("builtinRoutes", performance.now() - start);
686
+ return builtinRoutes;
687
+ }
688
+
669
689
  #createBuiltinRoutes(webRouter: WebRouter | null): HttpRoutes {
670
690
  const { appName } = getEnv();
671
691
  const openapiRoutes: HttpRoutes = this.openapi
672
692
  ? {
673
- "/openapi.json": {
674
- GET: () =>
675
- Response.json(
676
- createOpenApiDocument(FetchSerializer.serializeRegistry(this.#di.live).signal, {
677
- title: `${appName} API`,
678
- version: "0.0.0",
679
- servers: this.#getOpenApiServers(),
680
- resolveDescription: AkanServer.#createDescriptionResolver(),
681
- }),
682
- ),
683
- },
693
+ "/openapi.json": { GET: () => Response.json(this.#getOpenApiDocument(appName)) },
684
694
  }
685
695
  : {};
686
696
 
@@ -802,6 +812,16 @@ export class AkanServer {
802
812
  this.#logForwarder = null;
803
813
  }
804
814
 
815
+ #getOpenApiDocument(appName: string) {
816
+ this.#openApiDocument ??= createOpenApiDocument(FetchSerializer.serializeRegistry(this.#di.live).signal, {
817
+ title: `${appName} API`,
818
+ version: "0.0.0",
819
+ servers: this.#getOpenApiServers(),
820
+ resolveDescription: AkanServer.#createDescriptionResolver(),
821
+ });
822
+ return this.#openApiDocument;
823
+ }
824
+
805
825
  static #createDescriptionResolver() {
806
826
  const lookup = new DictionaryLookup();
807
827
  return (key: string) => lookup.text(key);
@@ -105,13 +105,12 @@ export class RouteClientCache {
105
105
  continue;
106
106
  }
107
107
  const generation = this.merged.generation;
108
- const promise = this.#runBuild(routeId, seeds, generation);
109
- this.#building.set(routeId, { generation, promise });
108
+ const pending: PendingBuild = { generation, promise: this.#runBuild(routeId, seeds, generation) };
109
+ this.#building.set(routeId, pending);
110
110
  try {
111
- await promise;
111
+ await pending.promise;
112
112
  } finally {
113
- const current = this.#building.get(routeId);
114
- if (current?.promise === promise) this.#building.delete(routeId);
113
+ if (this.#building.get(routeId) === pending) this.#building.delete(routeId);
115
114
  this.#prune();
116
115
  }
117
116
  }
@@ -1,6 +1,5 @@
1
1
  import path from "node:path";
2
- import { matchRoutePattern } from "akanjs/common";
3
- import { matchRoutePrefix } from "../../common/routeConvention";
2
+ import { RouteSeedMatcher } from "./routeSeedMatcher";
4
3
 
5
4
  export interface RouteSeedEntry {
6
5
  routeId: string;
@@ -60,27 +59,11 @@ export class RouteSeedIndexStore {
60
59
  }
61
60
 
62
61
  static match(pathname: string, entries: RouteSeedEntry[]): MatchedRoute | null {
63
- for (const entry of entries) {
64
- const params = matchRoutePattern(entry.pattern ?? entry.routeId, pathname);
65
- if (params) return { entry, params };
66
- }
67
- return null;
62
+ return RouteSeedMatcher.of(entries).match(pathname);
68
63
  }
69
64
 
70
65
  static matchPrefix(pathname: string, entries: RouteSeedEntry[]): MatchedRoute | null {
71
- const candidates = entries
72
- .map((entry) => ({
73
- entry,
74
- params: matchRoutePrefix(entry.pattern ?? entry.routeId, pathname),
75
- }))
76
- .filter((entry): entry is { entry: RouteSeedEntry; params: Record<string, string> } => Boolean(entry.params))
77
- .sort((a, b) => {
78
- const lengthDelta =
79
- b.entry.pattern.split("/").filter(Boolean).length - a.entry.pattern.split("/").filter(Boolean).length;
80
- if (lengthDelta !== 0) return lengthDelta;
81
- return a.entry.pattern < b.entry.pattern ? -1 : a.entry.pattern > b.entry.pattern ? 1 : 0;
82
- });
83
- return candidates[0] ?? null;
66
+ return RouteSeedMatcher.of(entries).matchPrefix(pathname);
84
67
  }
85
68
 
86
69
  static #normalizeArtifactPath(artifactPath: string, artifactDir: string): string {
@@ -0,0 +1,70 @@
1
+ import type { MatchedRoute, RouteSeedEntry } from "./routeSeedIndexStore";
2
+
3
+ interface CompiledEntry {
4
+ entry: RouteSeedEntry;
5
+ parts: string[];
6
+ }
7
+
8
+ export class RouteSeedMatcher {
9
+ static readonly #byEntries = new WeakMap<RouteSeedEntry[], RouteSeedMatcher>();
10
+
11
+ static of(entries: RouteSeedEntry[]): RouteSeedMatcher {
12
+ const cached = RouteSeedMatcher.#byEntries.get(entries);
13
+ if (cached && cached.#size === entries.length) return cached;
14
+ const matcher = new RouteSeedMatcher(entries);
15
+ RouteSeedMatcher.#byEntries.set(entries, matcher);
16
+ return matcher;
17
+ }
18
+
19
+ readonly #size: number;
20
+ readonly #inOrder: CompiledEntry[];
21
+
22
+ readonly #bySpecificity: CompiledEntry[];
23
+
24
+ constructor(entries: RouteSeedEntry[]) {
25
+ this.#size = entries.length;
26
+ this.#inOrder = entries.map((entry) => ({ entry, parts: RouteSeedMatcher.#split(entry.pattern ?? entry.routeId) }));
27
+ this.#bySpecificity = [...this.#inOrder].sort((a, b) => {
28
+ const lengthDelta = b.parts.length - a.parts.length;
29
+ if (lengthDelta !== 0) return lengthDelta;
30
+ const aPattern = a.entry.pattern ?? a.entry.routeId;
31
+ const bPattern = b.entry.pattern ?? b.entry.routeId;
32
+ return aPattern < bPattern ? -1 : aPattern > bPattern ? 1 : 0;
33
+ });
34
+ }
35
+
36
+ static #split(text: string) {
37
+ return text.split("/").filter(Boolean);
38
+ }
39
+
40
+ static #paramsOf(parts: string[], pathParts: string[]): Record<string, string> | null {
41
+ const params: Record<string, string> = {};
42
+ for (let idx = 0; idx < parts.length; idx += 1) {
43
+ const part = parts[idx] as string;
44
+ const value = pathParts[idx] as string;
45
+ if (part.startsWith(":")) params[part.slice(1)] = decodeURIComponent(value);
46
+ else if (part !== value) return null;
47
+ }
48
+ return params;
49
+ }
50
+
51
+ match(pathname: string): MatchedRoute | null {
52
+ const pathParts = RouteSeedMatcher.#split(pathname);
53
+ for (const { entry, parts } of this.#inOrder) {
54
+ if (parts.length !== pathParts.length) continue;
55
+ const params = RouteSeedMatcher.#paramsOf(parts, pathParts);
56
+ if (params) return { entry, params };
57
+ }
58
+ return null;
59
+ }
60
+
61
+ matchPrefix(pathname: string): MatchedRoute | null {
62
+ const pathParts = RouteSeedMatcher.#split(pathname);
63
+ for (const { entry, parts } of this.#bySpecificity) {
64
+ if (parts.length > pathParts.length) continue;
65
+ const params = RouteSeedMatcher.#paramsOf(parts, pathParts);
66
+ if (params) return { entry, params };
67
+ }
68
+ return null;
69
+ }
70
+ }
package/server/console.ts CHANGED
@@ -21,7 +21,7 @@ export interface AkanConsoleOptions {
21
21
  /** `level=warn grep="payment failed" endpoint=mutation:*` → a query object the socket parses. */
22
22
  export const parseAkanConsoleQuery = (args: string): Record<string, string> => {
23
23
  const query: Record<string, string> = {};
24
- for (const match of args.matchAll(/([A-Za-z]+)=(?:"([^"]*)"|'([^']*)'|(\S+))/g)) {
24
+ for (const match of args.matchAll(/(?<![A-Za-z])([A-Za-z]+)=(?:"([^"]*)"|'([^']*)'|(\S+))/g)) {
25
25
  const [, key, doubleQuoted, singleQuoted, bare] = match;
26
26
  if (key) query[key] = doubleQuoted ?? singleQuoted ?? bare ?? "";
27
27
  }
@@ -68,6 +68,7 @@ export class DiLifecycle {
68
68
  readonly #middleware = new Map<string, MiddlewareCls>();
69
69
  readonly webProxies: WebProxyRegistration[] = [];
70
70
  readonly disabledModules = new Map<string, string>();
71
+ readonly initTimings = new Map<string, number>();
71
72
  readonly #predefinedAdaptor;
72
73
  readonly #cascade = new CascadeRunner();
73
74
 
@@ -401,21 +402,22 @@ export class DiLifecycle {
401
402
  }
402
403
 
403
404
  async #initializeAll(): Promise<SignalRoutes> {
404
- await this.#initializeUses();
405
- await this.#initializeAdaptor();
406
- await this.#initializeServerSignal();
407
- await this.#initializeService();
408
- await this.#initializeInternal();
405
+ this.initTimings.clear();
406
+ await this.#initStage("uses", () => this.#initializeUses());
407
+ await this.#initStage("adaptors", () => this.#initializeAdaptor());
408
+ await this.#initStage("serverSignals", () => this.#initializeServerSignal());
409
+ await this.#initStage("services", () => this.#initializeService());
410
+ await this.#initStage("internals", () => this.#initializeInternal());
409
411
  const {
410
412
  routes: sliceRoutes,
411
413
  wsRoutes: sliceWsRoutes,
412
414
  routeOptions: sliceRouteOptions,
413
- } = await this.#initializeSlice();
415
+ } = await this.#initStage("slices", () => this.#initializeSlice());
414
416
  const {
415
417
  routes: endpointRoutes,
416
418
  wsRoutes: endpointWsRoutes,
417
419
  routeOptions: endpointRouteOptions,
418
- } = await this.#initializeEndpoint();
420
+ } = await this.#initStage("endpoints", () => this.#initializeEndpoint());
419
421
  const routes: SignalRoutes["routes"] = {};
420
422
  SignalResolver.mergeHttpRoutes(routes, sliceRoutes);
421
423
  SignalResolver.mergeHttpRoutes(routes, endpointRoutes);
@@ -442,6 +444,13 @@ export class DiLifecycle {
442
444
  await this.#timed("Destroying uses...", "Destroy uses", () => this.destroyUses());
443
445
  }
444
446
 
447
+ async #initStage<T>(stage: string, run: () => Promise<T>): Promise<T> {
448
+ const start = performance.now();
449
+ const result = await run();
450
+ this.initTimings.set(stage, performance.now() - start);
451
+ return result;
452
+ }
453
+
445
454
  async #timed(startMessage: string, doneLabel: string, run: () => Promise<unknown>) {
446
455
  const now = Date.now();
447
456
  this.logger.verbose(startMessage);
@@ -294,7 +294,7 @@ export class ImageOptimizer {
294
294
 
295
295
  async #getOptimizedImage(source: ImageSource, params: ParsedImageRequest): Promise<OptimizedImage> {
296
296
  const inputType = ImageOptimizer.#detectContentType(source.buffer) || source.contentType;
297
- if (!inputType || !inputType.startsWith("image/") || inputType.includes(",")) {
297
+ if (!inputType.startsWith("image/") || inputType.includes(",")) {
298
298
  throw new ImageOptimizerError(400, "The requested resource is not a valid image");
299
299
  }
300
300
  if (inputType === ImageOptimizer.#svg && !this.#config.dangerouslyAllowSVG) {
package/server/index.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./decorators";
8
8
  export * from "./devtools";
9
9
  export type { ChangeBatch, ChangeKind } from "./hmr/wsHub";
10
10
  export * from "./machine";
11
+ export * from "./migration";
11
12
  export * from "./nativeFile";
12
13
  export * from "./oauth";
13
14
  export * from "./processMetricsCollector";
@@ -1,6 +1,12 @@
1
1
  import { getEnv } from "akanjs/base";
2
- import type { Middleware, SignalContext } from "akanjs/signal";
3
- import { MachineToken } from "./machineToken";
2
+ import type { MachineIdentity, Middleware, SignalContext } from "akanjs/signal";
3
+ import { type MachineProof, MachineToken } from "./machineToken";
4
+
5
+ interface VerifiedMachine {
6
+ authorization: string | null;
7
+ epoch: number;
8
+ proof: MachineProof | null;
9
+ }
4
10
 
5
11
  interface AccountHolder {
6
12
  headers?: Headers;
@@ -10,12 +16,18 @@ interface AccountHolder {
10
16
  export class MachineAccount implements Middleware {
11
17
  static readonly refName = "MachineAccount";
12
18
 
19
+ static readonly #verifiedBySocket = new WeakMap<object, VerifiedMachine>();
20
+
13
21
  use() {
14
22
  return async (context: SignalContext, next: () => Promise<unknown>) => {
15
23
  const holder = (
16
24
  context.transport === "http" ? context.getHttpContext().req : context.getWebSocketContext().ws.data
17
25
  ) as AccountHolder;
18
- const machine = MachineToken.fromAuthorization(holder.headers?.get("authorization"));
26
+ const authorization = holder.headers?.get("authorization") ?? null;
27
+ const machine =
28
+ context.transport === "websocket"
29
+ ? MachineAccount.#verifiedOnSocket(holder, authorization)
30
+ : MachineToken.fromAuthorization(authorization);
19
31
  const { machine: _unverified, ...account } = holder.account ?? {};
20
32
  if (machine) {
21
33
  const { appName, environment } = getEnv();
@@ -24,4 +36,17 @@ export class MachineAccount implements Middleware {
24
36
  return await next();
25
37
  };
26
38
  }
39
+
40
+ static #verifiedOnSocket(socket: object, authorization: string | null): MachineIdentity | null {
41
+ const epoch = MachineToken.keyEpoch();
42
+ const verified = MachineAccount.#verifiedBySocket.get(socket);
43
+ const reusable =
44
+ verified?.authorization === authorization &&
45
+ verified.epoch === epoch &&
46
+ (verified.proof?.expiresAt === undefined || verified.proof.expiresAt > Date.now() / 1000);
47
+ if (verified && reusable) return verified.proof?.identity ?? null;
48
+ const proof = MachineToken.proofOf(authorization);
49
+ MachineAccount.#verifiedBySocket.set(socket, { authorization, epoch, proof });
50
+ return proof?.identity ?? null;
51
+ }
27
52
  }
@@ -12,7 +12,15 @@ export interface MachineTokenIssueOptions {
12
12
  audience?: string;
13
13
  }
14
14
 
15
- export type MachineTokenVerdict = { ok: true; identity: MachineIdentity } | { ok: false; reason: string };
15
+ export type MachineTokenVerdict =
16
+ | { ok: true; identity: MachineIdentity; expiresAt?: number }
17
+ | { ok: false; reason: string };
18
+
19
+ /** What a bearer machine token proves, and the second it lapses at when it was issued with an expiry. */
20
+ export interface MachineProof {
21
+ identity: MachineIdentity;
22
+ expiresAt?: number;
23
+ }
16
24
 
17
25
  interface KeyPair {
18
26
  privateKey: KeyObject | null;
@@ -23,6 +31,7 @@ export class MachineToken {
23
31
  static readonly type = "akan-machine+jwt";
24
32
  static readonly #logger = new Logger("MachineToken");
25
33
  static #keys: { source: string; pair: KeyPair } | null = null;
34
+ static #keyEpoch = 0;
26
35
  static #warnedKeyless = false;
27
36
 
28
37
  static audience() {
@@ -43,9 +52,16 @@ export class MachineToken {
43
52
  : null;
44
53
  const pair = { privateKey, publicKey };
45
54
  MachineToken.#keys = { source, pair };
55
+ MachineToken.#keyEpoch += 1;
46
56
  return pair;
47
57
  }
48
58
 
59
+ /** Moves whenever the keys read from the env change, so a verdict kept from before is known to be stale. */
60
+ static keyEpoch() {
61
+ MachineToken.#keyPair();
62
+ return MachineToken.#keyEpoch;
63
+ }
64
+
49
65
  static canIssue() {
50
66
  return !!MachineToken.#keyPair().privateKey;
51
67
  }
@@ -86,15 +102,23 @@ export class MachineToken {
86
102
  if (exp !== undefined && (typeof exp !== "number" || exp <= nowSec)) return { ok: false, reason: "expired" };
87
103
  const identity = { kind, id: sub, version: ver } as MachineIdentity;
88
104
  if (!MachineToken.#isIdentity(identity)) return { ok: false, reason: "sub, kind and ver are required" };
89
- return { ok: true, identity: { kind: identity.kind, id: identity.id, version: identity.version } };
105
+ return {
106
+ ok: true,
107
+ identity: { kind: identity.kind, id: identity.id, version: identity.version },
108
+ ...(exp !== undefined ? { expiresAt: exp as number } : {}),
109
+ };
90
110
  }
91
111
 
92
112
  /** The identity a bearer machine token proves, or `null`: absent, another kind of token, or one that fails. */
93
113
  static fromAuthorization(authorization: string | null | undefined): MachineIdentity | null {
114
+ return MachineToken.proofOf(authorization)?.identity ?? null;
115
+ }
116
+
117
+ static proofOf(authorization: string | null | undefined): MachineProof | null {
94
118
  const token = bearerTokenOf(authorization);
95
119
  if (!token || !MachineToken.isMachineToken(token)) return null;
96
120
  const verdict = MachineToken.verify(token);
97
- if (verdict.ok) return verdict.identity;
121
+ if (verdict.ok) return verdict.expiresAt === undefined ? { identity: verdict.identity } : verdict;
98
122
  if (!MachineToken.canVerify() && !MachineToken.#warnedKeyless) {
99
123
  MachineToken.#warnedKeyless = true;
100
124
  MachineToken.#logger.error(
@@ -72,7 +72,7 @@ export class McpDispatcher {
72
72
  }
73
73
 
74
74
  static #restorable(error: unknown, status: number | undefined) {
75
- if (!status || status >= 500 || status === 401 || status === 403 || error instanceof NoDocumentError) return null;
75
+ if (!status || status >= 500 || status === 401 || status === 403) return null;
76
76
  return isExceptionLike(error) ? error.toJSON() : null;
77
77
  }
78
78
 
@@ -169,8 +169,7 @@ export class McpDispatcher {
169
169
  }
170
170
 
171
171
  static #statusOf(error: unknown): number | undefined {
172
- if (isExceptionLike(error) || error instanceof McpArgumentError || error instanceof NoDocumentError)
173
- return error.statusCode;
172
+ if (isExceptionLike(error) || error instanceof McpArgumentError) return error.statusCode;
174
173
  return undefined;
175
174
  }
176
175
 
@@ -1,6 +1,6 @@
1
1
  import { type Cls, PrimitiveRegistry, type PrimitiveScalar } from "akanjs/base";
2
2
  import { isMcpDescribableArg } from "akanjs/common";
3
- import { deserialize, serialize } from "akanjs/constant";
3
+ import { InputParser, InvalidInputError, serialize } from "akanjs/constant";
4
4
  import type { EndpointInfo } from "../../signal/endpointInfo";
5
5
  import { HttpExecutionContext } from "../../signal/signalContext";
6
6
 
@@ -28,13 +28,15 @@ export class McpExecutionContext extends HttpExecutionContext {
28
28
 
29
29
  override parseArg(arg: McpArg, value: unknown): unknown {
30
30
  try {
31
- return deserialize(arg.argRef, arg.arrDepth, value, {
31
+ return InputParser.parse(arg.argRef, arg.arrDepth, value, {
32
32
  key: arg.name,
33
33
  nullable: arg.option?.nullable,
34
34
  enum: arg.enum,
35
35
  });
36
- } catch {
36
+ } catch (error) {
37
37
 
38
+ if (error instanceof InvalidInputError && error.path !== arg.name)
39
+ throw new McpArgumentError(McpExecutionContext.#fieldMessage(error));
38
40
  throw new McpArgumentError(McpExecutionContext.#argumentMessage(arg, value));
39
41
  }
40
42
  }
@@ -58,6 +60,10 @@ export class McpExecutionContext extends HttpExecutionContext {
58
60
  return isMcpDescribableArg({ refName });
59
61
  }
60
62
 
63
+ static #fieldMessage({ path, expected }: InvalidInputError) {
64
+ return expected ? `Invalid field "${path}": expected ${expected}.` : `Missing required field "${path}".`;
65
+ }
66
+
61
67
  static #argumentMessage(arg: McpArg, value: unknown) {
62
68
  if (value === null) return `Missing required argument "${arg.name}".`;
63
69
  if (arg.enum) return `Invalid argument "${arg.name}": expected one of ${arg.enum.values.join(", ")}.`;
@@ -0,0 +1,121 @@
1
+ import { sanitizeJson } from "akanjs/document";
2
+ import { stableJson } from "akanjs/service";
3
+
4
+ /** What a path holds: `[value]`, or `[]` when it holds nothing — a stored `null` is a value. */
5
+ export type DocSlot = [unknown] | [];
6
+
7
+ /** Dot paths over a parsed `_doc`; a numeric segment indexes an array. */
8
+ export class DocPath {
9
+ static readonly #unsafe = new Set(["__proto__", "constructor", "prototype"]);
10
+
11
+ static readonly #index = /^(0|[1-9]\d*)$/;
12
+
13
+ static segments(path: string) {
14
+ const segments = path.split(".");
15
+ if (segments.some((segment) => !segment || DocPath.#unsafe.has(segment)))
16
+ throw new Error(`Invalid document path "${path}"`);
17
+ return segments;
18
+ }
19
+
20
+ static read(doc: Record<string, unknown>, path: string): DocSlot {
21
+ let node: unknown = doc;
22
+ for (const segment of DocPath.segments(path)) {
23
+ if (!node || typeof node !== "object" || !DocPath.#holds(node, segment)) return [];
24
+ node = (node as Record<string, unknown>)[segment];
25
+ }
26
+ return [node];
27
+ }
28
+
29
+ /** Whether every container above `path` is still there, so that writing it would change nothing else. */
30
+ static hasParent(doc: Record<string, unknown>, path: string) {
31
+ const segments = DocPath.segments(path);
32
+ let node: unknown = doc;
33
+ for (const segment of segments.slice(0, -1)) {
34
+ if (!node || typeof node !== "object" || !DocPath.#holds(node, segment)) return false;
35
+ node = (node as Record<string, unknown>)[segment];
36
+ }
37
+ return !!node && typeof node === "object";
38
+ }
39
+
40
+ /**
41
+ * The paths a write of `paths` changes as whole values: each path, or the nearest one above it that the write
42
+ * creates, replaces a `null` at, or appends to as an array, so the logged slot holds everything to put back.
43
+ */
44
+ static anchors(doc: Record<string, unknown>, paths: string[]) {
45
+ const anchors = [...new Set(paths.map((path) => DocPath.#anchor(doc, path)))];
46
+ return anchors.filter((anchor) => !anchors.some((other) => anchor.startsWith(`${other}.`)));
47
+ }
48
+
49
+ static #anchor(doc: Record<string, unknown>, path: string) {
50
+ const segments = DocPath.segments(path);
51
+ let node: unknown = doc;
52
+ for (const [idx, segment] of segments.entries()) {
53
+ if (Array.isArray(node) && !DocPath.#holds(node, segment)) return segments.slice(0, idx).join(".");
54
+ if (idx === segments.length - 1) break;
55
+ const next = DocPath.#holds(node as object, segment) ? (node as Record<string, unknown>)[segment] : undefined;
56
+ if (!next || typeof next !== "object") return segments.slice(0, idx + 1).join(".");
57
+ node = next;
58
+ }
59
+ return path;
60
+ }
61
+
62
+ static #holds(node: object, segment: string) {
63
+ if (!Array.isArray(node)) return Object.hasOwn(node, segment);
64
+ return DocPath.#index.test(segment) && Number(segment) < node.length;
65
+ }
66
+
67
+ static write(doc: Record<string, unknown>, path: string, value: unknown) {
68
+ const segments = DocPath.segments(path);
69
+ let node: Record<string, unknown> | unknown[] = doc;
70
+ for (const segment of segments.slice(0, -1)) {
71
+ const next = DocPath.#holds(node, segment) ? (node as Record<string, unknown>)[segment] : undefined;
72
+ if (next && typeof next === "object") {
73
+ node = next as Record<string, unknown>;
74
+ continue;
75
+ }
76
+ if (next !== undefined && next !== null)
77
+ throw new Error(`Cannot write "${path}": "${segment}" holds a ${typeof next}, not an object`);
78
+ const created: Record<string, unknown> = {};
79
+ DocPath.#assign(node, segment, created, path);
80
+ node = created;
81
+ }
82
+ DocPath.#assign(node, segments[segments.length - 1] ?? "", sanitizeJson(value) ?? null, path);
83
+ }
84
+
85
+ static remove(doc: Record<string, unknown>, path: string) {
86
+ const segments = DocPath.segments(path);
87
+ let node: unknown = doc;
88
+ for (const segment of segments.slice(0, -1)) {
89
+ if (!node || typeof node !== "object" || !DocPath.#holds(node, segment)) return;
90
+ node = (node as Record<string, unknown>)[segment];
91
+ }
92
+ if (!node || typeof node !== "object") return;
93
+
94
+ if (Array.isArray(node)) throw new Error(`Cannot unset "${path}" inside an array; set the whole array instead`);
95
+ delete (node as Record<string, unknown>)[segments[segments.length - 1] ?? ""];
96
+ }
97
+
98
+ static same(a: DocSlot, b: DocSlot) {
99
+ if (a.length !== b.length) return false;
100
+ return !a.length || stableJson(a[0]) === stableJson(b[0]);
101
+ }
102
+
103
+ /** Two paths of one write where one sits inside the other would log a value the other already changed. */
104
+ static assertDisjoint(paths: string[]) {
105
+ for (const path of paths) {
106
+ const inner = paths.find((other) => other.startsWith(`${path}.`));
107
+ if (inner) throw new Error(`"${path}" and "${inner}" overlap; write them in separate calls`);
108
+ }
109
+ }
110
+
111
+ static #assign(node: Record<string, unknown> | unknown[], segment: string, value: unknown, path: string) {
112
+ if (!Array.isArray(node)) {
113
+ node[segment] = value;
114
+ return;
115
+ }
116
+ const idx = DocPath.#index.test(segment) ? Number(segment) : -1;
117
+ if (idx < 0 || idx > node.length)
118
+ throw new Error(`Cannot write "${path}": "${segment}" is not an index within the array`);
119
+ node[idx] = value;
120
+ }
121
+ }
@@ -0,0 +1,15 @@
1
+ export * from "./docPath";
2
+ export * from "./migrationChangeLog";
3
+ export * from "./migrationChanges";
4
+ export * from "./migrationCommand";
5
+ export * from "./migrationContext";
6
+ export * from "./migrationDefinition";
7
+ export * from "./migrationError";
8
+ export * from "./migrationLedger";
9
+ export * from "./migrationLock";
10
+ export * from "./migrationParams";
11
+ export * from "./migrationPulse";
12
+ export * from "./migrationRunner";
13
+ export * from "./migrationScope";
14
+ export * from "./migrations";
15
+ export * from "./migrationTable";