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
@@ -2,6 +2,7 @@ import { adapt } from "../adapt";
2
2
  import type {
3
3
  AgentWireAttachment,
4
4
  AgentWireMessage,
5
+ AgentWireToolResult,
5
6
  LlmAccepts,
6
7
  LlmAdaptor,
7
8
  LlmLimits,
@@ -14,12 +15,14 @@ import { LlmOverflow } from "./llmOverflow";
14
15
  import { eachSseData } from "./sseData";
15
16
 
16
17
  type AnthropicSource = { type: "base64"; media_type: string; data: string } | { type: "url"; url: string };
17
- type AnthropicBlock =
18
+ type AnthropicContentBlock =
18
19
  | { type: "text"; text: string }
19
20
  | { type: "image"; source: AnthropicSource }
20
- | { type: "document"; source: AnthropicSource }
21
+ | { type: "document"; source: AnthropicSource };
22
+ type AnthropicBlock =
23
+ | AnthropicContentBlock
21
24
  | { type: "tool_use"; id: string; name: string; input: Record<string, unknown> }
22
- | { type: "tool_result"; tool_use_id: string; content: string };
25
+ | { type: "tool_result"; tool_use_id: string; content: string | AnthropicContentBlock[] };
23
26
  interface AnthropicMessage {
24
27
  role: "user" | "assistant";
25
28
  content: AnthropicBlock[];
@@ -76,7 +79,7 @@ export class AnthropicLlm
76
79
  }
77
80
 
78
81
  async chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null> {
79
- const model = this.llmOption.model;
82
+ const model = request.model || this.llmOption.model;
80
83
  if (!this.llmOption.apiKey || !model) {
81
84
  this.logger.warn(
82
85
  "AnthropicLlm needs both apiKey and model — set them with option.setLlm(). Agent turns are unavailable.",
@@ -221,15 +224,7 @@ export class AnthropicLlm
221
224
  if (message.role === "tool")
222
225
  return {
223
226
  role: "user",
224
- content: (message.toolResults ?? []).map((result) => ({
225
- type: "tool_result" as const,
226
- tool_use_id: result.id,
227
- content: JSON.stringify({
228
- ...(result.result !== undefined ? { result: result.result } : {}),
229
- ...(result.changes?.length ? { changes: result.changes } : {}),
230
- ...(result.error ? { error: result.error } : {}),
231
- }),
232
- })),
227
+ content: (message.toolResults ?? []).map((result) => AnthropicLlm.toolResult(result, accepts)),
233
228
  };
234
229
  if (message.role === "assistant")
235
230
  return {
@@ -248,9 +243,36 @@ export class AnthropicLlm
248
243
  }
249
244
 
250
245
  static userContent(message: AgentWireMessage, accepts?: LlmAccepts): AnthropicBlock[] {
251
- const attachments = message.attachments ?? [];
252
246
  const notes: string[] = [];
253
- const blocks = attachments.flatMap((attachment): AnthropicBlock[] => {
247
+ const blocks = AnthropicLlm.attachmentBlocks(message.attachments ?? [], accepts, notes);
248
+ const text = [message.text, ...notes].filter(Boolean).join("\n\n");
249
+ return [...(text ? [{ type: "text" as const, text }] : []), ...blocks];
250
+ }
251
+
252
+ /** A string while the call returned no file, so a transcript without one posts what it always did. */
253
+ static toolResult(result: AgentWireToolResult, accepts?: LlmAccepts): AnthropicBlock {
254
+ const payload = JSON.stringify({
255
+ ...(result.result !== undefined ? { result: result.result } : {}),
256
+ ...(result.changes?.length ? { changes: result.changes } : {}),
257
+ ...(result.error ? { error: result.error } : {}),
258
+ });
259
+ if (!result.attachments?.length) return { type: "tool_result", tool_use_id: result.id, content: payload };
260
+ const notes: string[] = [];
261
+ const blocks = AnthropicLlm.attachmentBlocks(result.attachments, accepts, notes);
262
+ return {
263
+ type: "tool_result",
264
+ tool_use_id: result.id,
265
+ content: [{ type: "text", text: [payload, ...notes].join("\n\n") }, ...blocks],
266
+ };
267
+ }
268
+
269
+ /** Pushes a note for each file no block can carry, for the caller to fold into the text beside them. */
270
+ static attachmentBlocks(
271
+ attachments: AgentWireAttachment[],
272
+ accepts: LlmAccepts | undefined,
273
+ notes: string[],
274
+ ): AnthropicContentBlock[] {
275
+ return attachments.flatMap((attachment): AnthropicContentBlock[] => {
254
276
  if (attachment.text)
255
277
  return [
256
278
  {
@@ -271,8 +293,6 @@ export class AnthropicLlm
271
293
  notes.push(`[Attachment not read: ${attachment.name} (${attachment.mimeType}) — this API has no block for it.]`);
272
294
  return [];
273
295
  });
274
- const text = [message.text, ...notes].filter(Boolean).join("\n\n");
275
- return [...(text ? [{ type: "text" as const, text }] : []), ...blocks];
276
296
  }
277
297
 
278
298
  static typed(source: AnthropicSource, mimeType: string): AnthropicSource {
@@ -19,8 +19,10 @@ import {
19
19
  SearchIndex,
20
20
  } from "./searchIndex";
21
21
  import { PostgresDialect } from "./sql/dialect/postgres";
22
+ import { SqliteDialect } from "./sql/dialect/sqlite";
22
23
  import { BunSqliteClient } from "./sql/driver/bunSqlite";
23
24
  import { PostgresAkanClient } from "./sql/driver/postgres";
25
+ import { MigrationTables } from "./sql/MigrationTables";
24
26
  import { PendingStoreEnsures } from "./sql/PendingStoreEnsures";
25
27
  import { PostgresInsightSession } from "./sql/PostgresInsightSession";
26
28
  import { SqlDocumentStore } from "./sql/SqlDocumentStore";
@@ -41,6 +43,13 @@ import { defaultSqliteFile } from "./sqlitePath";
41
43
 
42
44
  export { PostgresDialect } from "./sql/dialect/postgres";
43
45
  export { SqliteDialect } from "./sql/dialect/sqlite";
46
+ export { type MigrationLedgerTable, MigrationTables } from "./sql/MigrationTables";
47
+ export {
48
+ RawDocumentTable,
49
+ type RawFilter,
50
+ type RawFilterOperators,
51
+ type RawFindOptions,
52
+ } from "./sql/RawDocumentTable";
44
53
  export { SqlDocumentStore } from "./sql/SqlDocumentStore";
45
54
  export type {
46
55
  AkanSqlClient,
@@ -55,8 +64,10 @@ export type {
55
64
  SqlDialect,
56
65
  SqliteDatabaseConfig,
57
66
  SqlResultRows,
67
+ TransferRow,
58
68
  UpsertByIdOptions,
59
69
  } from "./sql/types";
70
+ export { descriptorHash, stableJson } from "./sql/values";
60
71
 
61
72
  const searchConfigOf = (env: SqliteEnv): Required<SearchConfig> => ({
62
73
  enabled: env.database?.search?.enabled ?? parseSearchEnabled(process.env.AKAN_SEARCH_ENABLED),
@@ -87,6 +98,7 @@ export class SqliteDatabase
87
98
  }))
88
99
  implements DatabaseAdaptor
89
100
  {
101
+ readonly dialect = new SqliteDialect();
90
102
  #db!: Database;
91
103
  #client!: BunSqliteClient;
92
104
  #stores = new Map<string, SqlDocumentStore>();
@@ -111,6 +123,7 @@ export class SqliteDatabase
111
123
  this.#db.run(
112
124
  `CREATE TABLE IF NOT EXISTS "_akan_meta" ("key" TEXT PRIMARY KEY NOT NULL, "value" TEXT NOT NULL, "updatedAt" INTEGER NOT NULL)`,
113
125
  );
126
+ for (const statement of MigrationTables.schema(this.dialect)) this.#db.run(statement);
114
127
  this.#searchIndex = new SearchIndex(this, this.config.search);
115
128
  await this.#searchIndex.ensureSchema();
116
129
  this.scheduler.registerCron(OPTIMIZE_CRON_KEY, OPTIMIZE_CRON, async () => {
@@ -246,6 +259,7 @@ export class PostgresDatabase
246
259
  }))
247
260
  implements DatabaseAdaptor
248
261
  {
262
+ readonly dialect = new PostgresDialect();
249
263
  #sql!: Sql;
250
264
  #client!: PostgresAkanClient;
251
265
  #stores = new Map<string, SqlDocumentStore>();
@@ -278,6 +292,7 @@ export class PostgresDatabase
278
292
  await this.getConnection().execute(
279
293
  `CREATE TABLE IF NOT EXISTS "_akan_meta" ("key" TEXT PRIMARY KEY NOT NULL, "value" TEXT NOT NULL, "updatedAt" BIGINT NOT NULL)`,
280
294
  );
295
+ for (const statement of MigrationTables.schema(this.dialect)) await this.getConnection().execute(statement);
281
296
  await this.getConnection().execute(PostgresDialect.schemaSetup());
282
297
  await this.#grantInsightSchema();
283
298
  });
@@ -1,6 +1,7 @@
1
1
  import { mkdir, readdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { Logger } from "akanjs/common";
4
+ import { type MigrationLedgerTable, MigrationTables } from "./sql/MigrationTables";
4
5
  import type { DatabaseAdaptor, TransferRow } from "./sql/types";
5
6
 
6
7
  export interface TransferReport {
@@ -11,6 +12,7 @@ export interface TransferReport {
11
12
  /**
12
13
  * Model tables to one NDJSON file each and back, rows as stored. `_akan_meta`, the search mirror, the cache and the
13
14
  * queue stay behind: the target writes its own meta and rebuilds the mirror; sessions and pending jobs do not move.
15
+ * The migration ledger moves with the rows, or the target would run again the scripts its data already went through.
14
16
  */
15
17
  export class DocumentTransfer {
16
18
  static readonly #chunk = 1000;
@@ -39,9 +41,35 @@ export class DocumentTransfer {
39
41
  await writer.end();
40
42
  reports.push({ table: store.table, rows });
41
43
  }
44
+ for (const table of MigrationTables.ledger) {
45
+ const report = await this.#exportLedger(dir, table);
46
+ if (report) reports.push(report);
47
+ }
42
48
  return reports;
43
49
  }
44
50
 
51
+ async #exportLedger(dir: string, table: MigrationLedgerTable): Promise<TransferReport | null> {
52
+ let writer: Bun.FileSink | null = null;
53
+ let rows = 0;
54
+ let after: Record<string, unknown> | null = null;
55
+ for (;;) {
56
+ const chunk = await MigrationTables.exportRows(
57
+ this.#database.getConnection(),
58
+ table,
59
+ after,
60
+ DocumentTransfer.#chunk,
61
+ );
62
+ if (chunk.length) writer ??= Bun.file(path.join(dir, `${table.name}.ndjson`)).writer();
63
+ for (const row of chunk) writer?.write(`${JSON.stringify(row)}\n`);
64
+ rows += chunk.length;
65
+ const last = chunk.at(-1);
66
+ if (!last || chunk.length < DocumentTransfer.#chunk) break;
67
+ after = last;
68
+ }
69
+ await writer?.end();
70
+ return writer ? { table: table.name, rows } : null;
71
+ }
72
+
45
73
  async importFrom(dir: string): Promise<TransferReport[]> {
46
74
  const files = new Set((await readdir(dir)).filter((file) => file.endsWith(".ndjson")));
47
75
  const search = this.#database.getSearchIndex();
@@ -66,10 +94,32 @@ export class DocumentTransfer {
66
94
  this.#logger.warn(`Another process holds the search rebuild of ${store.table}; it catches up once that ends`);
67
95
  reports.push({ table: store.table, rows });
68
96
  }
97
+ for (const table of MigrationTables.ledger) {
98
+ const file = `${table.name}.ndjson`;
99
+ if (files.delete(file)) reports.push(await this.#importLedger(path.join(dir, file), table));
100
+ }
69
101
  for (const file of files) this.#logger.warn(`${file} matches no model of this app; skipped`);
70
102
  return reports;
71
103
  }
72
104
 
105
+ async #importLedger(file: string, table: MigrationLedgerTable): Promise<TransferReport> {
106
+ const write = async (chunk: Record<string, unknown>[]) =>
107
+ await this.#database.transaction(
108
+ async () => await MigrationTables.importRows(this.#database.getConnection(), table, chunk),
109
+ );
110
+ let rows = 0;
111
+ let chunk: Record<string, unknown>[] = [];
112
+ for await (const line of DocumentTransfer.#lines(file)) {
113
+ chunk.push(JSON.parse(line) as Record<string, unknown>);
114
+ if (chunk.length < DocumentTransfer.#chunk) continue;
115
+ await write(chunk);
116
+ rows += chunk.length;
117
+ chunk = [];
118
+ }
119
+ if (chunk.length) await write(chunk);
120
+ return { table: table.name, rows: rows + chunk.length };
121
+ }
122
+
73
123
  #stores() {
74
124
  const stores = this.#database.stores?.();
75
125
  if (!stores) throw new Error("This database adaptor keeps no model stores to transfer.");
@@ -0,0 +1,19 @@
1
+ import { adapt } from "../adapt";
2
+ import { EndpointCacheKeys } from "../endpointCacheKeys";
3
+ import { CacheAdaptorRole } from "./role.adaptor";
4
+
5
+ /** Drops an endpoint's `{ cache }` answers before their TTL, across instances: every entry, or the one for `args`. */
6
+ export class EndpointCacheControl extends adapt("endpointCacheControl", ({ plug }) => ({
7
+ cache: plug(CacheAdaptorRole),
8
+ })) {
9
+ /** `args`: every declared argument in order, `null` for an omitted search one; not for slice lists. */
10
+ async invalidate(endpoint: string, args?: unknown[]): Promise<boolean> {
11
+ try {
12
+ await EndpointCacheKeys.invalidate(this.cache, endpoint, args);
13
+ return true;
14
+ } catch (error) {
15
+ this.logger.error(`Cache invalidation failed for ${endpoint}: ${String(error)}`);
16
+ return false;
17
+ }
18
+ }
19
+ }
@@ -3,6 +3,7 @@ export * from "./cache.adaptor";
3
3
  export * from "./compress.adaptor";
4
4
  export * from "./database.adaptor";
5
5
  export * from "./documentTransfer";
6
+ export * from "./endpointCacheControl.adaptor";
6
7
  export * from "./insightQuery";
7
8
  export * from "./llm.adaptor";
8
9
  export * from "./llmOverflow";
@@ -10,6 +10,8 @@ export interface AgentWireToolResult {
10
10
  result?: unknown;
11
11
  changes?: unknown[];
12
12
  error?: string;
13
+ /** Files the call handed the model, as content beside the JSON; one this model cannot read arrives as a `text` note. */
14
+ attachments?: AgentWireAttachment[];
13
15
  }
14
16
 
15
17
  /** Exactly one carrier reaches the model: `data` (inlined bytes), `url` (fetched by the provider) or `text`. */
@@ -68,6 +70,11 @@ export interface LlmTurnRequest {
68
70
  tools: AgentWireTool[];
69
71
  context: AgentWireContext[];
70
72
  instructions?: string;
73
+ /**
74
+ * This turn's model in place of `LlmOption.model`. `accepts`, `maxTokens` and `contextWindow` stay the option's, so a
75
+ * model that differs in them needs an adaptor of its own. Set by server code only: `runAgentTurn` takes no model.
76
+ */
77
+ model?: string;
71
78
  }
72
79
 
73
80
  export interface LlmTurnAnswer {
@@ -1,4 +1,11 @@
1
- import type { AgentWireMessage, LlmAccepts, LlmTurnAnswer, LlmTurnRequest, LlmUsage } from "./llm.adaptor";
1
+ import type {
2
+ AgentWireAttachment,
3
+ AgentWireMessage,
4
+ LlmAccepts,
5
+ LlmTurnAnswer,
6
+ LlmTurnRequest,
7
+ LlmUsage,
8
+ } from "./llm.adaptor";
2
9
  import { eachSseData } from "./sseData";
3
10
 
4
11
  export interface OpenaiToolCall {
@@ -25,7 +32,8 @@ interface OpenaiStreamChunk {
25
32
  finish_reason?: string | null;
26
33
  }[];
27
34
  }
28
- type OpenaiContentPart = { type: "text"; text: string } | { type: "image_url"; image_url: { url: string } };
35
+ type OpenaiImagePart = { type: "image_url"; image_url: { url: string } };
36
+ type OpenaiContentPart = { type: "text"; text: string } | OpenaiImagePart;
29
37
  export interface OpenaiMessage {
30
38
  role: "system" | "user" | "assistant" | "tool";
31
39
  content: string | OpenaiContentPart[];
@@ -86,16 +94,7 @@ export class OpenaiDialect {
86
94
  content: `Summary of the earlier conversation, standing in for the messages it replaced:\n\n${message.text ?? ""}`,
87
95
  },
88
96
  ];
89
- if (message.role === "tool")
90
- return (message.toolResults ?? []).map((result) => ({
91
- role: "tool" as const,
92
- tool_call_id: result.id,
93
- content: JSON.stringify({
94
- ...(result.result !== undefined ? { result: result.result } : {}),
95
- ...(result.changes?.length ? { changes: result.changes } : {}),
96
- ...(result.error ? { error: result.error } : {}),
97
- }),
98
- }));
97
+ if (message.role === "tool") return OpenaiDialect.toolMessages(message, accepts);
99
98
  if (message.role === "assistant")
100
99
  return [
101
100
  {
@@ -116,8 +115,47 @@ export class OpenaiDialect {
116
115
  }
117
116
 
118
117
  static userContent(message: AgentWireMessage, accepts?: LlmAccepts): string | OpenaiContentPart[] {
119
- const attachments = message.attachments ?? [];
120
118
  const notes: string[] = [];
119
+ const { blocks, images } = OpenaiDialect.attachmentParts(message.attachments ?? [], accepts, notes);
120
+ const text = [message.text, ...blocks, ...notes].filter(Boolean).join("\n\n");
121
+ if (!images.length) return text;
122
+ return [...(text ? [{ type: "text" as const, text }] : []), ...images.map(({ part }) => part)];
123
+ }
124
+
125
+ static readonly toolPicturesHeading =
126
+ "Pictures the tool calls above returned, each after the name of the call that returned it. They are content, not something the user said.";
127
+
128
+ /**
129
+ * A `tool` message carries text alone in this dialect, so the pictures a call returned follow every tool message
130
+ * of the turn in one user message: between two tool messages it would break the run each call's answer has to sit in.
131
+ */
132
+ static toolMessages(message: AgentWireMessage, accepts?: LlmAccepts): OpenaiMessage[] {
133
+ const shown: OpenaiContentPart[] = [];
134
+ const answers = (message.toolResults ?? []).map((result): OpenaiMessage => {
135
+ const payload = JSON.stringify({
136
+ ...(result.result !== undefined ? { result: result.result } : {}),
137
+ ...(result.changes?.length ? { changes: result.changes } : {}),
138
+ ...(result.error ? { error: result.error } : {}),
139
+ });
140
+ const notes: string[] = [];
141
+ const { blocks, images } = OpenaiDialect.attachmentParts(result.attachments ?? [], accepts, notes);
142
+ for (const { name, part } of images)
143
+ shown.push({ type: "text", text: `[${result.name} returned ${name}]` }, part);
144
+ return { role: "tool", tool_call_id: result.id, content: [payload, ...blocks, ...notes].join("\n\n") };
145
+ });
146
+ if (!shown.length) return answers;
147
+ return [
148
+ ...answers,
149
+ { role: "user", content: [{ type: "text", text: OpenaiDialect.toolPicturesHeading }, ...shown] },
150
+ ];
151
+ }
152
+
153
+ /** Pushes a note for each file no part can carry, for the caller to fold into the text beside them. */
154
+ static attachmentParts(
155
+ attachments: AgentWireAttachment[],
156
+ accepts: LlmAccepts | undefined,
157
+ notes: string[],
158
+ ): { blocks: string[]; images: { name: string; part: OpenaiImagePart }[] } {
121
159
 
122
160
  const blocks = attachments.flatMap((attachment) =>
123
161
  attachment.text ? [`--- attachment: ${attachment.name} (${attachment.mimeType}) ---\n${attachment.text}`] : [],
@@ -138,11 +176,9 @@ export class OpenaiDialect {
138
176
  }
139
177
 
140
178
  const url = attachment.data ? `data:${mimeType};base64,${attachment.data}` : (attachment.url ?? "");
141
- return url ? [{ type: "image_url" as const, image_url: { url } }] : [];
179
+ return url ? [{ name: attachment.name, part: { type: "image_url" as const, image_url: { url } } }] : [];
142
180
  });
143
- const text = [message.text, ...blocks, ...notes].filter(Boolean).join("\n\n");
144
- if (!images.length) return text;
145
- return [...(text ? [{ type: "text" as const, text }] : []), ...images];
181
+ return { blocks, images };
146
182
  }
147
183
 
148
184
  static async consumeStream(
@@ -31,7 +31,7 @@ export class OpenaiLlm
31
31
  }
32
32
 
33
33
  async chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null> {
34
- const model = this.llmOption.model;
34
+ const model = request.model || this.llmOption.model;
35
35
  if (!this.llmOption.apiKey || !model) {
36
36
  this.logger.warn(
37
37
  "OpenaiLlm needs both apiKey and model — set them with option.setLlm(). Agent turns are unavailable.",
@@ -0,0 +1,90 @@
1
+ import type { AkanSqlClient, SqlDialect } from "./types";
2
+ import { quoteIdent } from "./values";
3
+
4
+ export interface MigrationLedgerTable {
5
+ name: string;
6
+ key: readonly string[];
7
+ columns: readonly string[];
8
+ }
9
+
10
+ /** The data-migration ledger, kept beside the rows it describes so each environment records what was applied to it. */
11
+ export class MigrationTables {
12
+ static readonly run = "_akan_migration_run";
13
+ static readonly change = "_akan_migration_change";
14
+ static readonly ledger: readonly MigrationLedgerTable[] = [
15
+ {
16
+ name: MigrationTables.run,
17
+ key: ["id"],
18
+ columns: [
19
+ "id",
20
+ "migrationId",
21
+ "kind",
22
+ "status",
23
+ "target",
24
+ "checksum",
25
+ "buildId",
26
+ "params",
27
+ "planHash",
28
+ "summary",
29
+ "actor",
30
+ "checkpoint",
31
+ "startedAt",
32
+ "finishedAt",
33
+ "error",
34
+ ],
35
+ },
36
+ {
37
+ name: MigrationTables.change,
38
+ key: ["runId", "seq"],
39
+ columns: ["runId", "seq", "tableName", "docId", "op", "before", "after"],
40
+ },
41
+ ];
42
+
43
+ static schema(dialect: Pick<SqlDialect, "timestampType">) {
44
+ const ts = dialect.timestampType();
45
+ const run = quoteIdent(MigrationTables.run);
46
+ return [
47
+ `CREATE TABLE IF NOT EXISTS ${run} ("id" TEXT PRIMARY KEY NOT NULL, "migrationId" TEXT NOT NULL, "kind" TEXT NOT NULL, "status" TEXT NOT NULL, "target" TEXT, "checksum" TEXT NOT NULL, "buildId" TEXT, "params" TEXT, "planHash" TEXT, "summary" TEXT, "actor" TEXT, "checkpoint" TEXT, "startedAt" ${ts} NOT NULL, "finishedAt" ${ts}, "error" TEXT)`,
48
+ `CREATE INDEX IF NOT EXISTS ${quoteIdent(`${MigrationTables.run}_migrationId`)} ON ${run} ("migrationId", "startedAt")`,
49
+ `CREATE TABLE IF NOT EXISTS ${quoteIdent(MigrationTables.change)} ("runId" TEXT NOT NULL, "seq" INTEGER NOT NULL, "tableName" TEXT NOT NULL, "docId" TEXT NOT NULL, "op" TEXT NOT NULL, "before" TEXT NOT NULL, "after" TEXT NOT NULL, PRIMARY KEY ("runId", "seq"))`,
50
+ ];
51
+ }
52
+
53
+ /** Up to `limit` rows after the key of `after`, in key order. */
54
+ static async exportRows(
55
+ client: AkanSqlClient,
56
+ table: MigrationLedgerTable,
57
+ after: Record<string, unknown> | null,
58
+ limit: number,
59
+ ) {
60
+ const keyset = MigrationTables.#after(table, after);
61
+ return await client
62
+ .prepare(
63
+ `SELECT ${table.columns.map(quoteIdent).join(", ")} FROM ${quoteIdent(table.name)} WHERE ${keyset.sql} ORDER BY ${table.key.map(quoteIdent).join(", ")} LIMIT ${Math.trunc(limit)}`,
64
+ )
65
+ .all<Record<string, unknown>>(...keyset.params);
66
+ }
67
+
68
+ static async importRows(client: AkanSqlClient, table: MigrationLedgerTable, rows: Record<string, unknown>[]) {
69
+ const columns = table.columns.map(quoteIdent);
70
+ const updates = table.columns
71
+ .filter((column) => !table.key.includes(column))
72
+ .map((column) => `${quoteIdent(column)} = excluded.${quoteIdent(column)}`);
73
+ const statement = client.prepare(
74
+ `INSERT INTO ${quoteIdent(table.name)} (${columns.join(", ")}) VALUES (${columns.map(() => "?").join(", ")}) ON CONFLICT (${table.key.map(quoteIdent).join(", ")}) DO UPDATE SET ${updates.join(", ")}`,
75
+ );
76
+ for (const row of rows) await statement.run(...table.columns.map((column) => row[column] ?? null));
77
+ }
78
+
79
+ static #after(table: MigrationLedgerTable, after: Record<string, unknown> | null) {
80
+ if (!after) return { sql: "1 = 1", params: [] as unknown[] };
81
+ const terms = table.key.map((column, idx) => {
82
+ const equal = table.key.slice(0, idx);
83
+ return {
84
+ sql: `(${[...equal.map((prefix) => `${quoteIdent(prefix)} = ?`), `${quoteIdent(column)} > ?`].join(" AND ")})`,
85
+ params: [...equal.map((prefix) => after[prefix]), after[column]],
86
+ };
87
+ });
88
+ return { sql: `(${terms.map((term) => term.sql).join(" OR ")})`, params: terms.flatMap((term) => term.params) };
89
+ }
90
+ }