@alneas/eaos-server 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.ja.md +49 -0
  4. package/README.md +46 -2
  5. package/dist/agentic/agent-jobs.d.ts +333 -0
  6. package/dist/agentic/agent-jobs.js +15 -0
  7. package/dist/agentic/agent-jobs.js.map +1 -0
  8. package/dist/agentic/agent-node.d.ts +40 -0
  9. package/dist/agentic/agent-node.js +7 -0
  10. package/dist/agentic/agent-node.js.map +1 -0
  11. package/dist/agentic/agent-runner.d.ts +33 -0
  12. package/dist/agentic/agent-runner.js +7 -0
  13. package/dist/agentic/agent-runner.js.map +1 -0
  14. package/dist/agentic/ai-broker.d.ts +169 -0
  15. package/dist/agentic/ai-broker.js +8 -0
  16. package/dist/agentic/ai-broker.js.map +1 -0
  17. package/dist/agentic/atomic-checkpointer.d.ts +137 -0
  18. package/dist/agentic/atomic-checkpointer.js +9 -0
  19. package/dist/agentic/atomic-checkpointer.js.map +1 -0
  20. package/dist/agentic/autonomous-worker.d.ts +122 -0
  21. package/dist/agentic/autonomous-worker.js +10 -0
  22. package/dist/agentic/autonomous-worker.js.map +1 -0
  23. package/dist/agentic/event-bridge.d.ts +350 -0
  24. package/dist/agentic/event-bridge.js +9 -0
  25. package/dist/agentic/event-bridge.js.map +1 -0
  26. package/dist/agentic/executor.d.ts +91 -0
  27. package/dist/agentic/executor.js +12 -0
  28. package/dist/agentic/executor.js.map +1 -0
  29. package/dist/agentic/graph-projection.d.ts +119 -0
  30. package/dist/agentic/graph-projection.js +7 -0
  31. package/dist/agentic/graph-projection.js.map +1 -0
  32. package/dist/agentic/graph.d.ts +524 -0
  33. package/dist/agentic/graph.js +7 -0
  34. package/dist/agentic/graph.js.map +1 -0
  35. package/dist/agentic/index.d.ts +28 -0
  36. package/dist/agentic/index.js +87 -0
  37. package/dist/agentic/index.js.map +1 -0
  38. package/dist/agentic/local-runner.d.ts +106 -0
  39. package/dist/agentic/local-runner.js +7 -0
  40. package/dist/agentic/local-runner.js.map +1 -0
  41. package/dist/agentic/remote-executor.d.ts +67 -0
  42. package/dist/agentic/remote-executor.js +8 -0
  43. package/dist/agentic/remote-executor.js.map +1 -0
  44. package/dist/agentic/types.d.ts +157 -0
  45. package/dist/agentic/types.js +7 -0
  46. package/dist/agentic/types.js.map +1 -0
  47. package/dist/agentic/workflow-catalog.d.ts +152 -0
  48. package/dist/agentic/workflow-catalog.js +7 -0
  49. package/dist/agentic/workflow-catalog.js.map +1 -0
  50. package/dist/agentic/workflow-compiler.d.ts +44 -0
  51. package/dist/agentic/workflow-compiler.js +8 -0
  52. package/dist/agentic/workflow-compiler.js.map +1 -0
  53. package/dist/agentic/workflow-coordinator.d.ts +170 -0
  54. package/dist/agentic/workflow-coordinator.js +8 -0
  55. package/dist/agentic/workflow-coordinator.js.map +1 -0
  56. package/dist/agentic/workflow-manager.d.ts +91 -0
  57. package/dist/agentic/workflow-manager.js +7 -0
  58. package/dist/agentic/workflow-manager.js.map +1 -0
  59. package/dist/agentic/workflow-registry.d.ts +334 -0
  60. package/dist/agentic/workflow-registry.js +7 -0
  61. package/dist/agentic/workflow-registry.js.map +1 -0
  62. package/dist/artifacts-CteHmCMI.d.ts +614 -0
  63. package/dist/auth-hooks/api-key.d.ts +75 -0
  64. package/dist/auth-hooks/api-key.js +7 -0
  65. package/dist/auth-hooks/api-key.js.map +1 -0
  66. package/dist/auth-hooks/index.d.ts +80 -0
  67. package/dist/auth-hooks/index.js +28 -0
  68. package/dist/auth-hooks/index.js.map +1 -0
  69. package/dist/browser-auth/account-memberships.d.ts +213 -0
  70. package/dist/browser-auth/account-memberships.js +13 -0
  71. package/dist/browser-auth/account-memberships.js.map +1 -0
  72. package/dist/browser-auth/index.d.ts +8 -0
  73. package/dist/browser-auth/index.js +59 -0
  74. package/dist/browser-auth/index.js.map +1 -0
  75. package/dist/browser-auth/kratos-session.d.ts +37 -0
  76. package/dist/browser-auth/kratos-session.js +7 -0
  77. package/dist/browser-auth/kratos-session.js.map +1 -0
  78. package/dist/browser-auth/platform-session.d.ts +120 -0
  79. package/dist/browser-auth/platform-session.js +7 -0
  80. package/dist/browser-auth/platform-session.js.map +1 -0
  81. package/dist/browser-auth/public-memberships.d.ts +22 -0
  82. package/dist/browser-auth/public-memberships.js +7 -0
  83. package/dist/browser-auth/public-memberships.js.map +1 -0
  84. package/dist/cache/index.d.ts +181 -0
  85. package/dist/cache/index.js +197 -0
  86. package/dist/cache/index.js.map +1 -0
  87. package/dist/chunk-32746UQZ.js +131 -0
  88. package/dist/chunk-32746UQZ.js.map +1 -0
  89. package/dist/chunk-3NLSWP2Y.js +223 -0
  90. package/dist/chunk-3NLSWP2Y.js.map +1 -0
  91. package/dist/chunk-3P4XTTQH.js +346 -0
  92. package/dist/chunk-3P4XTTQH.js.map +1 -0
  93. package/dist/chunk-3VITSHN3.js +15 -0
  94. package/dist/chunk-3VITSHN3.js.map +1 -0
  95. package/dist/chunk-46UWPEW2.js +226 -0
  96. package/dist/chunk-46UWPEW2.js.map +1 -0
  97. package/dist/chunk-4BARRLJR.js +180 -0
  98. package/dist/chunk-4BARRLJR.js.map +1 -0
  99. package/dist/chunk-4VORUFKR.js +45 -0
  100. package/dist/chunk-4VORUFKR.js.map +1 -0
  101. package/dist/chunk-55D4ERWO.js +1 -0
  102. package/dist/chunk-55D4ERWO.js.map +1 -0
  103. package/dist/chunk-5TBBZIND.js +18 -0
  104. package/dist/chunk-5TBBZIND.js.map +1 -0
  105. package/dist/chunk-5WOZWPZA.js +211 -0
  106. package/dist/chunk-5WOZWPZA.js.map +1 -0
  107. package/dist/chunk-6CBVZ6CT.js +168 -0
  108. package/dist/chunk-6CBVZ6CT.js.map +1 -0
  109. package/dist/chunk-6XZXYNJR.js +74 -0
  110. package/dist/chunk-6XZXYNJR.js.map +1 -0
  111. package/dist/chunk-753HWDSC.js +222 -0
  112. package/dist/chunk-753HWDSC.js.map +1 -0
  113. package/dist/chunk-7AHSS7SO.js +81 -0
  114. package/dist/chunk-7AHSS7SO.js.map +1 -0
  115. package/dist/chunk-7FTJN4SA.js +1 -0
  116. package/dist/chunk-7FTJN4SA.js.map +1 -0
  117. package/dist/chunk-AVDMLTPF.js +24 -0
  118. package/dist/chunk-AVDMLTPF.js.map +1 -0
  119. package/dist/chunk-BKAHUEIT.js +95 -0
  120. package/dist/chunk-BKAHUEIT.js.map +1 -0
  121. package/dist/chunk-CJ7OFEF7.js +134 -0
  122. package/dist/chunk-CJ7OFEF7.js.map +1 -0
  123. package/dist/chunk-EJKWDZIU.js +111 -0
  124. package/dist/chunk-EJKWDZIU.js.map +1 -0
  125. package/dist/chunk-F2J6IQ6I.js +247 -0
  126. package/dist/chunk-F2J6IQ6I.js.map +1 -0
  127. package/dist/chunk-F3O7CELI.js +23 -0
  128. package/dist/chunk-F3O7CELI.js.map +1 -0
  129. package/dist/chunk-F4IITPGX.js +221 -0
  130. package/dist/chunk-F4IITPGX.js.map +1 -0
  131. package/dist/chunk-FD6VC2NA.js +66 -0
  132. package/dist/chunk-FD6VC2NA.js.map +1 -0
  133. package/dist/chunk-FRRRWAHO.js +14 -0
  134. package/dist/chunk-FRRRWAHO.js.map +1 -0
  135. package/dist/chunk-HCKAGLLB.js +17 -0
  136. package/dist/chunk-HCKAGLLB.js.map +1 -0
  137. package/dist/chunk-HVC7FG6B.js +191 -0
  138. package/dist/chunk-HVC7FG6B.js.map +1 -0
  139. package/dist/chunk-HXFVOR7Z.js +496 -0
  140. package/dist/chunk-HXFVOR7Z.js.map +1 -0
  141. package/dist/chunk-IJWYS2PF.js +122 -0
  142. package/dist/chunk-IJWYS2PF.js.map +1 -0
  143. package/dist/chunk-INCHXAFK.js +1395 -0
  144. package/dist/chunk-INCHXAFK.js.map +1 -0
  145. package/dist/chunk-JT6BRGQM.js +1 -0
  146. package/dist/chunk-JT6BRGQM.js.map +1 -0
  147. package/dist/chunk-L6PMAEMB.js +115 -0
  148. package/dist/chunk-L6PMAEMB.js.map +1 -0
  149. package/dist/chunk-LOUGW6MU.js +126 -0
  150. package/dist/chunk-LOUGW6MU.js.map +1 -0
  151. package/dist/chunk-LYPZPE53.js +129 -0
  152. package/dist/chunk-LYPZPE53.js.map +1 -0
  153. package/dist/chunk-NNCCN7JP.js +186 -0
  154. package/dist/chunk-NNCCN7JP.js.map +1 -0
  155. package/dist/chunk-PBC3MZUL.js +212 -0
  156. package/dist/chunk-PBC3MZUL.js.map +1 -0
  157. package/dist/chunk-R4ADP2DC.js +20 -0
  158. package/dist/chunk-R4ADP2DC.js.map +1 -0
  159. package/dist/chunk-RHN4Y6VS.js +44 -0
  160. package/dist/chunk-RHN4Y6VS.js.map +1 -0
  161. package/dist/chunk-SDJNYPYK.js +770 -0
  162. package/dist/chunk-SDJNYPYK.js.map +1 -0
  163. package/dist/chunk-UGNTCOVR.js +28 -0
  164. package/dist/chunk-UGNTCOVR.js.map +1 -0
  165. package/dist/chunk-VC2PCK2S.js +31 -0
  166. package/dist/chunk-VC2PCK2S.js.map +1 -0
  167. package/dist/chunk-VF5YDZJC.js +305 -0
  168. package/dist/chunk-VF5YDZJC.js.map +1 -0
  169. package/dist/chunk-VISRDVTK.js +675 -0
  170. package/dist/chunk-VISRDVTK.js.map +1 -0
  171. package/dist/chunk-W6O3LVBY.js +102 -0
  172. package/dist/chunk-W6O3LVBY.js.map +1 -0
  173. package/dist/chunk-WFEAKJLR.js +47 -0
  174. package/dist/chunk-WFEAKJLR.js.map +1 -0
  175. package/dist/chunk-XIEY2OF4.js +67 -0
  176. package/dist/chunk-XIEY2OF4.js.map +1 -0
  177. package/dist/chunk-XITLHDG3.js +37 -0
  178. package/dist/chunk-XITLHDG3.js.map +1 -0
  179. package/dist/chunk-XMWPYZWZ.js +61 -0
  180. package/dist/chunk-XMWPYZWZ.js.map +1 -0
  181. package/dist/chunk-XUP6CNOM.js +34 -0
  182. package/dist/chunk-XUP6CNOM.js.map +1 -0
  183. package/dist/chunk-YABTQZDJ.js +25 -0
  184. package/dist/chunk-YABTQZDJ.js.map +1 -0
  185. package/dist/chunk-YMHVRBUU.js +199 -0
  186. package/dist/chunk-YMHVRBUU.js.map +1 -0
  187. package/dist/chunk-YMJ7BRKU.js +510 -0
  188. package/dist/chunk-YMJ7BRKU.js.map +1 -0
  189. package/dist/chunk-ZC3XWU7B.js +28 -0
  190. package/dist/chunk-ZC3XWU7B.js.map +1 -0
  191. package/dist/chunk-ZHMTD5KV.js +90 -0
  192. package/dist/chunk-ZHMTD5KV.js.map +1 -0
  193. package/dist/chunk-ZWZDLOE7.js +160 -0
  194. package/dist/chunk-ZWZDLOE7.js.map +1 -0
  195. package/dist/db-package/db/local-first-sqlite-adapter.d.ts +432 -0
  196. package/dist/db-package/db/local-first-sqlite-adapter.js +7 -0
  197. package/dist/db-package/db/local-first-sqlite-adapter.js.map +1 -0
  198. package/dist/db-package/index.d.ts +7 -0
  199. package/dist/db-package/index.js +16 -0
  200. package/dist/db-package/index.js.map +1 -0
  201. package/dist/db-package/migration/aggregator.d.ts +86 -0
  202. package/dist/db-package/migration/aggregator.js +7 -0
  203. package/dist/db-package/migration/aggregator.js.map +1 -0
  204. package/dist/db-package/migration/index.d.ts +3 -0
  205. package/dist/db-package/migration/index.js +8 -0
  206. package/dist/db-package/migration/index.js.map +1 -0
  207. package/dist/engine.d.ts +205 -0
  208. package/dist/engine.js +20 -0
  209. package/dist/engine.js.map +1 -0
  210. package/dist/entitlements/index.d.ts +313 -0
  211. package/dist/entitlements/index.js +23 -0
  212. package/dist/entitlements/index.js.map +1 -0
  213. package/dist/execution/chat.d.ts +7 -0
  214. package/dist/execution/chat.js +7 -0
  215. package/dist/execution/chat.js.map +1 -0
  216. package/dist/execution/index.d.ts +342 -0
  217. package/dist/execution/index.js +66 -0
  218. package/dist/execution/index.js.map +1 -0
  219. package/dist/execution/tool-agent.d.ts +7 -0
  220. package/dist/execution/tool-agent.js +8 -0
  221. package/dist/execution/tool-agent.js.map +1 -0
  222. package/dist/extensions/index.d.ts +172 -0
  223. package/dist/extensions/index.js +95 -0
  224. package/dist/extensions/index.js.map +1 -0
  225. package/dist/health/index.d.ts +35 -0
  226. package/dist/health/index.js +7 -0
  227. package/dist/health/index.js.map +1 -0
  228. package/dist/index.d.ts +43 -0
  229. package/dist/index.js +161 -0
  230. package/dist/index.js.map +1 -0
  231. package/dist/lifecycle/index.d.ts +133 -0
  232. package/dist/lifecycle/index.js +13 -0
  233. package/dist/lifecycle/index.js.map +1 -0
  234. package/dist/lifecycle-engine/backend-migration.d.ts +2 -0
  235. package/dist/lifecycle-engine/backend-migration.js +11 -0
  236. package/dist/lifecycle-engine/backend-migration.js.map +1 -0
  237. package/dist/lifecycle-engine/baseline.d.ts +2 -0
  238. package/dist/lifecycle-engine/baseline.js +9 -0
  239. package/dist/lifecycle-engine/baseline.js.map +1 -0
  240. package/dist/lifecycle-engine/index.d.ts +1497 -0
  241. package/dist/lifecycle-engine/index.js +41 -0
  242. package/dist/lifecycle-engine/index.js.map +1 -0
  243. package/dist/lifecycle-engine/platform/artifacts.d.ts +4 -0
  244. package/dist/lifecycle-engine/platform/artifacts.js +7 -0
  245. package/dist/lifecycle-engine/platform/artifacts.js.map +1 -0
  246. package/dist/lifecycle-engine/platform/control-plane.d.ts +12 -0
  247. package/dist/lifecycle-engine/platform/control-plane.js +2 -0
  248. package/dist/lifecycle-engine/platform/control-plane.js.map +1 -0
  249. package/dist/lifecycle-engine/platform/database-router.d.ts +118 -0
  250. package/dist/lifecycle-engine/platform/database-router.js +7 -0
  251. package/dist/lifecycle-engine/platform/database-router.js.map +1 -0
  252. package/dist/lifecycle-engine/platform/deployment-placements.d.ts +464 -0
  253. package/dist/lifecycle-engine/platform/deployment-placements.js +16 -0
  254. package/dist/lifecycle-engine/platform/deployment-placements.js.map +1 -0
  255. package/dist/lifecycle-engine/platform/deployment.d.ts +4 -0
  256. package/dist/lifecycle-engine/platform/deployment.js +17 -0
  257. package/dist/lifecycle-engine/platform/deployment.js.map +1 -0
  258. package/dist/lifecycle-engine/platform/index.d.ts +737 -0
  259. package/dist/lifecycle-engine/platform/index.js +60 -0
  260. package/dist/lifecycle-engine/platform/index.js.map +1 -0
  261. package/dist/lifecycle-engine/platform/runtime.d.ts +80 -0
  262. package/dist/lifecycle-engine/platform/runtime.js +11 -0
  263. package/dist/lifecycle-engine/platform/runtime.js.map +1 -0
  264. package/dist/lifecycle-engine/platform/site-publication.d.ts +102 -0
  265. package/dist/lifecycle-engine/platform/site-publication.js +7 -0
  266. package/dist/lifecycle-engine/platform/site-publication.js.map +1 -0
  267. package/dist/lifecycle-engine/platform/user-directory.d.ts +139 -0
  268. package/dist/lifecycle-engine/platform/user-directory.js +13 -0
  269. package/dist/lifecycle-engine/platform/user-directory.js.map +1 -0
  270. package/dist/mcp.d.ts +92 -0
  271. package/dist/mcp.js +10 -0
  272. package/dist/mcp.js.map +1 -0
  273. package/dist/middleware/auth.d.ts +118 -0
  274. package/dist/middleware/auth.js +7 -0
  275. package/dist/middleware/auth.js.map +1 -0
  276. package/dist/middleware/error-handler.d.ts +35 -0
  277. package/dist/middleware/error-handler.js +7 -0
  278. package/dist/middleware/error-handler.js.map +1 -0
  279. package/dist/middleware/module-guard.d.ts +33 -0
  280. package/dist/middleware/module-guard.js +7 -0
  281. package/dist/middleware/module-guard.js.map +1 -0
  282. package/dist/platform-admin/index.d.ts +37 -0
  283. package/dist/platform-admin/index.js +11 -0
  284. package/dist/platform-admin/index.js.map +1 -0
  285. package/dist/platform-admin/store.d.ts +346 -0
  286. package/dist/platform-admin/store.js +7 -0
  287. package/dist/platform-admin/store.js.map +1 -0
  288. package/dist/plugin-data/annotations.d.ts +6 -0
  289. package/dist/plugin-data/annotations.js +12 -0
  290. package/dist/plugin-data/annotations.js.map +1 -0
  291. package/dist/plugin-data/atomic-context.d.ts +41 -0
  292. package/dist/plugin-data/atomic-context.js +9 -0
  293. package/dist/plugin-data/atomic-context.js.map +1 -0
  294. package/dist/plugin-data/atomic.d.ts +6 -0
  295. package/dist/plugin-data/atomic.js +26 -0
  296. package/dist/plugin-data/atomic.js.map +1 -0
  297. package/dist/plugin-data/audit.d.ts +6 -0
  298. package/dist/plugin-data/audit.js +12 -0
  299. package/dist/plugin-data/audit.js.map +1 -0
  300. package/dist/plugin-data/commands.d.ts +6 -0
  301. package/dist/plugin-data/commands.js +8 -0
  302. package/dist/plugin-data/commands.js.map +1 -0
  303. package/dist/plugin-data/composite.d.ts +6 -0
  304. package/dist/plugin-data/composite.js +8 -0
  305. package/dist/plugin-data/composite.js.map +1 -0
  306. package/dist/plugin-data/delivery.d.ts +6 -0
  307. package/dist/plugin-data/delivery.js +16 -0
  308. package/dist/plugin-data/delivery.js.map +1 -0
  309. package/dist/plugin-data/index.d.ts +2798 -0
  310. package/dist/plugin-data/index.js +102 -0
  311. package/dist/plugin-data/index.js.map +1 -0
  312. package/dist/plugin-data/json-documents.d.ts +6 -0
  313. package/dist/plugin-data/json-documents.js +16 -0
  314. package/dist/plugin-data/json-documents.js.map +1 -0
  315. package/dist/plugin-data/outbox.d.ts +6 -0
  316. package/dist/plugin-data/outbox.js +16 -0
  317. package/dist/plugin-data/outbox.js.map +1 -0
  318. package/dist/plugin-data/scoped-records.d.ts +6 -0
  319. package/dist/plugin-data/scoped-records.js +10 -0
  320. package/dist/plugin-data/scoped-records.js.map +1 -0
  321. package/dist/plugin-sdk.d.ts +41 -0
  322. package/dist/plugin-sdk.js +10 -0
  323. package/dist/plugin-sdk.js.map +1 -0
  324. package/dist/sql-lifecycle/index.d.ts +138 -0
  325. package/dist/sql-lifecycle/index.js +167 -0
  326. package/dist/sql-lifecycle/index.js.map +1 -0
  327. package/dist/storage/index.d.ts +2 -0
  328. package/dist/storage/index.js +13 -0
  329. package/dist/storage/index.js.map +1 -0
  330. package/dist/storage/s3-compatible.d.ts +139 -0
  331. package/dist/storage/s3-compatible.js +11 -0
  332. package/dist/storage/s3-compatible.js.map +1 -0
  333. package/dist/tenant.d.ts +108 -0
  334. package/dist/tenant.js +9 -0
  335. package/dist/tenant.js.map +1 -0
  336. package/dist/workspace-context.d.ts +119 -0
  337. package/dist/workspace-context.js +9 -0
  338. package/dist/workspace-context.js.map +1 -0
  339. package/docs/api.md +30560 -0
  340. package/docs/db/README.md +49 -0
  341. package/docs/db/docs/api.md +1613 -0
  342. package/docs/db/docs/guide.md +47 -0
  343. package/docs/entitlements.md +60 -0
  344. package/docs/guide.md +92 -0
  345. package/docs/index.md +57 -0
  346. package/docs/ja/db/README.md +46 -0
  347. package/docs/ja/db/docs/guide.md +53 -0
  348. package/docs/ja/guide.md +46 -0
  349. package/docs/ja/lifecycle/README.md +46 -0
  350. package/docs/ja/lifecycle/docs/guide.md +45 -0
  351. package/docs/ja/storage/README.md +46 -0
  352. package/docs/ja/storage/docs/guide.md +43 -0
  353. package/docs/lifecycle/README.md +49 -0
  354. package/docs/lifecycle/docs/api.md +3770 -0
  355. package/docs/lifecycle/docs/baseline.md +50 -0
  356. package/docs/lifecycle/docs/guide.md +47 -0
  357. package/docs/storage/README.md +49 -0
  358. package/docs/storage/docs/api.md +470 -0
  359. package/docs/storage/docs/guide.md +47 -0
  360. package/package.json +354 -4
@@ -0,0 +1,510 @@
1
+ // src/platform-admin/store.ts
2
+ import { assertBackendMigrationCutover, canonical, normalizeLifecycleState, planBackendMigration } from "@alneas/eaos-server/lifecycle-engine";
3
+ var key = (...parts) => JSON.stringify(parts);
4
+ var identifier = (value, name) => {
5
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/.test(value)) throw new Error(`Invalid ${name}`);
6
+ return value;
7
+ };
8
+ var text = (value, name, max = 256) => {
9
+ if (!value.trim() || value.length > max) throw new Error(`Invalid ${name}`);
10
+ return value;
11
+ };
12
+ var timestamp = (value, name) => {
13
+ if (!Number.isFinite(Date.parse(value))) throw new Error(`Invalid ${name}`);
14
+ return value;
15
+ };
16
+ function materializeBackend(state, backendId) {
17
+ const backend = state.backends[backendId];
18
+ if (!backend) return null;
19
+ return { ...backend, ...state.platform.backendMetadata[backendId] };
20
+ }
21
+ function targetOf(backend) {
22
+ return { id: backend.id, databaseId: backend.databaseId, dialect: backend.dialect, mode: backend.mode, ...backend.tenantId === void 0 ? {} : { tenantId: backend.tenantId } };
23
+ }
24
+ function placement(state, tenantId) {
25
+ const record = state.platform.placements[tenantId];
26
+ if (!record) return null;
27
+ const backend = materializeBackend(state, record.backendId);
28
+ if (!backend) throw new Error(`Tenant placement references unknown backend: ${record.backendId}`);
29
+ return { tenantId, backend, routingRevision: record.routingRevision, changedAt: record.changedAt };
30
+ }
31
+ function validateBackend(backend) {
32
+ identifier(backend.id, "backend id");
33
+ identifier(backend.databaseId, "database id");
34
+ if (!["sqlite", "postgres", "oracle"].includes(backend.dialect) || !["shared", "dedicated"].includes(backend.mode)) throw new Error("Invalid backend target");
35
+ if (backend.mode === "dedicated") identifier(backend.tenantId ?? "", "dedicated backend tenant");
36
+ if (backend.mode === "shared" && backend.tenantId !== void 0) throw new Error("Shared backend cannot bind a tenant");
37
+ }
38
+ var LifecyclePlatformControlStore = class {
39
+ /**
40
+ * Captures the shared authoritative lifecycle ledger and clock.
41
+ * @param lifecycle - Host store providing consistent reads and exclusive writer callbacks.
42
+ * @param now - Clock for mutation timestamps; defaults to a fresh Date.
43
+ */
44
+ constructor(lifecycle, now = () => /* @__PURE__ */ new Date()) {
45
+ this.lifecycle = lifecycle;
46
+ this.now = now;
47
+ }
48
+ lifecycle;
49
+ now;
50
+ async read() {
51
+ return normalizeLifecycleState(await this.lifecycle.read());
52
+ }
53
+ async mutate(fn) {
54
+ return this.lifecycle.withLock(async (writer) => {
55
+ const state = normalizeLifecycleState(await writer.read());
56
+ const result = await fn(state);
57
+ state.revision += 1;
58
+ await writer.write(state);
59
+ return result;
60
+ });
61
+ }
62
+ /**
63
+ * Lists tenant records from the authoritative normalized lifecycle snapshot.
64
+ * @returns Tenant records with cloned domains arrays, or an empty array.
65
+ * @throws Host read/normalization failure.
66
+ * @example
67
+ * ```typescript
68
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
69
+ * export async function listTenants(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["listTenants"]>) {
70
+ * return store.listTenants(...args);
71
+ * }
72
+ * ```
73
+ */
74
+ async listTenants() {
75
+ const state = await this.read();
76
+ return Object.values(state.platform.tenants).map((tenant) => ({ ...tenant, domains: [...tenant.domains] }));
77
+ }
78
+ /**
79
+ * Creates an active tenant and its initial backend routing record under the lifecycle writer lock.
80
+ * @param input - Valid scope ID, nonblank name, nonempty domain strings, and registered initial backendId; a dedicated backend must bind the same tenant.
81
+ * @returns Created tenant record with clock timestamps; initial routing revision is one.
82
+ * @throws Invalid input, duplicate tenant, missing/mismatched backend, or host lock/write/clock failure.
83
+ * @example
84
+ * ```typescript
85
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
86
+ * export async function createTenant(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["createTenant"]>) {
87
+ * return store.createTenant(...args);
88
+ * }
89
+ * ```
90
+ */
91
+ async createTenant(input) {
92
+ const id = identifier(input.id, "tenant id");
93
+ const name = text(input.name, "tenant name");
94
+ const backendId = identifier(input.backendId, "initial backend id");
95
+ if (!Array.isArray(input.domains) || input.domains.length === 0 || input.domains.some((domain) => typeof domain !== "string" || !domain.trim())) throw new Error("Invalid tenant domains");
96
+ return this.mutate((state) => {
97
+ if (state.platform.tenants[id]) throw new Error("Tenant already exists");
98
+ const backend = materializeBackend(state, backendId);
99
+ if (!backend) throw new Error("Initial backend not found");
100
+ if (backend.mode === "dedicated" && backend.tenantId !== id) throw new Error("Initial backend tenant mismatch");
101
+ const at = this.now().toISOString();
102
+ const tenant = { id, name, active: true, domains: [...input.domains], createdAt: at, updatedAt: at };
103
+ state.platform.tenants[id] = tenant;
104
+ state.platform.placements[id] = { tenantId: id, backendId, routingRevision: 1, changedAt: at };
105
+ return tenant;
106
+ });
107
+ }
108
+ /**
109
+ * Updates an existing tenant name, active flag, or domains and refreshes updatedAt.
110
+ * @param tenantId - Existing valid tenant scope ID.
111
+ * @param patch - Optional nonblank name, boolean active, and nonempty nonblank domains; omitted fields remain unchanged.
112
+ * @returns Updated tenant with cloned domains.
113
+ * @throws Missing tenant, invalid supplied fields, or host lock/write/clock failure.
114
+ * @example
115
+ * ```typescript
116
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
117
+ * export async function updateTenant(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["updateTenant"]>) {
118
+ * return store.updateTenant(...args);
119
+ * }
120
+ * ```
121
+ */
122
+ async updateTenant(tenantId, patch) {
123
+ identifier(tenantId, "tenant id");
124
+ return this.mutate((state) => {
125
+ const current = state.platform.tenants[tenantId];
126
+ if (!current) throw new Error("Tenant not found");
127
+ if (patch.name !== void 0) current.name = text(patch.name, "tenant name");
128
+ if (patch.active !== void 0) {
129
+ if (typeof patch.active !== "boolean") throw new Error("Invalid tenant active state");
130
+ current.active = patch.active;
131
+ }
132
+ if (patch.domains !== void 0) {
133
+ if (!Array.isArray(patch.domains) || patch.domains.length === 0 || patch.domains.some((domain) => typeof domain !== "string" || !domain.trim())) throw new Error("Invalid tenant domains");
134
+ current.domains = [...patch.domains];
135
+ }
136
+ current.updatedAt = this.now().toISOString();
137
+ return { ...current, domains: [...current.domains] };
138
+ });
139
+ }
140
+ /**
141
+ * Registers an immutable backend placement identity and replaceable public metadata.
142
+ * @param backend - Valid backend/database IDs, dialect/mode, optional dedicated tenant binding, and metadata.
143
+ * @returns Materialized registered target with metadata.
144
+ * @throws Invalid target, changed placement for an existing ID, database dialect conflict, or host store failure.
145
+ * @example
146
+ * ```typescript
147
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
148
+ * export async function registerBackend(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["registerBackend"]>) {
149
+ * return store.registerBackend(...args);
150
+ * }
151
+ * ```
152
+ */
153
+ async registerBackend(backend) {
154
+ validateBackend(backend);
155
+ return this.mutate((state) => {
156
+ const existing = state.backends[backend.id];
157
+ const target = { id: backend.id, databaseId: backend.databaseId, dialect: backend.dialect, mode: backend.mode, ...backend.tenantId === void 0 ? {} : { tenantId: backend.tenantId } };
158
+ if (existing && canonical(existing) !== canonical(target)) throw new Error("Backend placement is immutable; register a new backend ID");
159
+ for (const other of Object.values(state.backends)) if (other.id !== backend.id && other.databaseId === backend.databaseId && other.dialect !== backend.dialect) throw new Error("Database dialect conflict");
160
+ state.backends[backend.id] = target;
161
+ const { id: _id, databaseId: _databaseId, dialect: _dialect, mode: _mode, tenantId: _tenantId, ...metadata } = backend;
162
+ state.platform.backendMetadata[backend.id] = metadata;
163
+ return { ...target, ...metadata };
164
+ });
165
+ }
166
+ /**
167
+ * Materializes registered backend targets with their public metadata.
168
+ * @returns Backend list, or an empty array.
169
+ * @throws Host read/normalization failure.
170
+ * @example
171
+ * ```typescript
172
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
173
+ * export async function listBackends(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["listBackends"]>) {
174
+ * return store.listBackends(...args);
175
+ * }
176
+ * ```
177
+ */
178
+ async listBackends() {
179
+ const state = await this.read();
180
+ return Object.keys(state.backends).map((id) => materializeBackend(state, id)).filter(Boolean);
181
+ }
182
+ /**
183
+ * Reads a registered backend target and its public metadata.
184
+ * @param backendId - Valid registered backend scope ID.
185
+ * @returns Materialized backend, or null when unregistered.
186
+ * @throws Invalid ID or host read failure.
187
+ * @example
188
+ * ```typescript
189
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
190
+ * export async function getBackend(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["getBackend"]>) {
191
+ * return store.getBackend(...args);
192
+ * }
193
+ * ```
194
+ */
195
+ async getBackend(backendId) {
196
+ identifier(backendId, "backend id");
197
+ return materializeBackend(await this.read(), backendId);
198
+ }
199
+ /**
200
+ * Resolves a tenant routing record into its registered backend target.
201
+ * @param tenantId - Valid tenant scope ID.
202
+ * @returns Placement with routing revision/time and backend, or null when absent.
203
+ * @throws Invalid ID, dangling backend reference, or host read failure.
204
+ * @example
205
+ * ```typescript
206
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
207
+ * export async function getTenantPlacement(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["getTenantPlacement"]>) {
208
+ * return store.getTenantPlacement(...args);
209
+ * }
210
+ * ```
211
+ */
212
+ async getTenantPlacement(tenantId) {
213
+ identifier(tenantId, "tenant id");
214
+ return placement(await this.read(), tenantId);
215
+ }
216
+ /**
217
+ * Persists an immutable migration plan after checking registered backend identities.
218
+ * @param plan - Reviewed plan matching currently registered source/target; identical saved plans may be accepted before completion.
219
+ * @returns No value; resolves after storing the plan and initial planned record if absent.
220
+ * @throws Unregistered/changed backend, conflicting reused plan ID, already completed plan, clone or host store failure.
221
+ * @example
222
+ * ```typescript
223
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
224
+ * export async function saveMigrationPlan(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["saveMigrationPlan"]>) {
225
+ * return store.saveMigrationPlan(...args);
226
+ * }
227
+ * ```
228
+ */
229
+ async saveMigrationPlan(plan) {
230
+ await this.mutate((state) => {
231
+ if (!state.backends[plan.request.source.id] || !state.backends[plan.request.target.id]) throw new Error("Migration backend is not registered");
232
+ if (canonical(targetOf(state.backends[plan.request.source.id])) !== canonical(targetOf(plan.request.source)) || canonical(targetOf(state.backends[plan.request.target.id])) !== canonical(targetOf(plan.request.target))) throw new Error("Migration backend changed since planning");
233
+ const existing = state.platform.migrationPlans[plan.id];
234
+ if (existing && canonical(existing) !== canonical(plan)) throw new Error("Migration plan ID already contains a different plan");
235
+ const current = state.platform.migrationRecords[plan.id];
236
+ if (current?.status === "cutover" || current?.status === "rolled-back") throw new Error("Migration plan has already completed");
237
+ state.platform.migrationPlans[plan.id] = structuredClone(plan);
238
+ state.platform.migrationRecords[plan.id] ??= { status: "planned", updatedAt: plan.request.requestedAt };
239
+ });
240
+ }
241
+ /**
242
+ * Reads a cloned persisted migration plan by ID.
243
+ * @param migrationId - Valid migration scope ID.
244
+ * @returns Plan clone, or null when absent.
245
+ * @throws Invalid ID or host read/clone failure.
246
+ * @example
247
+ * ```typescript
248
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
249
+ * export async function getMigrationPlan(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["getMigrationPlan"]>) {
250
+ * return store.getMigrationPlan(...args);
251
+ * }
252
+ * ```
253
+ */
254
+ async getMigrationPlan(migrationId) {
255
+ identifier(migrationId, "migration id");
256
+ const state = await this.read();
257
+ const plan = state.platform.migrationPlans[migrationId];
258
+ return plan ? structuredClone(plan) : null;
259
+ }
260
+ /**
261
+ * Reads the persisted migration execution/reconciliation record.
262
+ * @param migrationId - Valid migration scope ID.
263
+ * @returns Cloned status record, or null when absent.
264
+ * @throws Invalid ID or host read/clone failure.
265
+ * @example
266
+ * ```typescript
267
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
268
+ * export async function getMigrationStatus(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["getMigrationStatus"]>) {
269
+ * return store.getMigrationStatus(...args);
270
+ * }
271
+ * ```
272
+ */
273
+ async getMigrationStatus(migrationId) {
274
+ identifier(migrationId, "migration id");
275
+ const record = (await this.read()).platform.migrationRecords[migrationId];
276
+ return record ? structuredClone(record) : null;
277
+ }
278
+ /**
279
+ * Binds an execution token and transitions a tenant migration record to running.
280
+ * @param input - Verified tenantId, persisted migrationId, and unique host executionId; plan scope must include the tenant.
281
+ * @returns Cloned running record, or completed cutover/rolled-back record unchanged.
282
+ * @throws Missing plan, tenant mismatch, conflicting active token, reconciling state, invalid IDs, or host store failure.
283
+ * @example
284
+ * ```typescript
285
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
286
+ * export async function beginMigrationExecution(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["beginMigrationExecution"]>) {
287
+ * return store.beginMigrationExecution(...args);
288
+ * }
289
+ * ```
290
+ */
291
+ async beginMigrationExecution(input) {
292
+ identifier(input.tenantId, "tenant id");
293
+ identifier(input.migrationId, "migration id");
294
+ identifier(input.executionId, "execution id");
295
+ return this.mutate((state) => {
296
+ const plan = state.platform.migrationPlans[input.migrationId];
297
+ const record = state.platform.migrationRecords[input.migrationId];
298
+ if (!plan || !record) throw new Error("Migration plan not found");
299
+ if (plan.request.scope.kind !== "tenants" || !plan.request.scope.tenantIds.includes(input.tenantId)) throw new Error("Migration plan tenant mismatch");
300
+ if (record.status === "cutover" || record.status === "rolled-back") return structuredClone(record);
301
+ if ((record.status === "running" || record.status === "verified") && record.executionId !== input.executionId) throw new Error("Migration execution already in progress");
302
+ if (record.status === "reconciling") throw new Error("Migration requires reconciliation before retry");
303
+ record.status = "running";
304
+ record.executionId = input.executionId;
305
+ record.error = void 0;
306
+ record.updatedAt = this.now().toISOString();
307
+ return structuredClone(record);
308
+ });
309
+ }
310
+ /**
311
+ * Records verified migration evidence and cutover data for the active execution token.
312
+ * @param input - Tenant, exact persisted plan, active executionId, verification report, and matching validated cutover.
313
+ * @returns Cloned verified migration record.
314
+ * @throws Invalid cutover/report, nonpersisted/changed plan, tenant/token/state mismatch, changed retry verification, or host store failure.
315
+ * @example
316
+ * ```typescript
317
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
318
+ * export async function recordMigrationVerification(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["recordMigrationVerification"]>) {
319
+ * return store.recordMigrationVerification(...args);
320
+ * }
321
+ * ```
322
+ */
323
+ async recordMigrationVerification(input) {
324
+ identifier(input.tenantId, "tenant id");
325
+ identifier(input.executionId, "execution id");
326
+ assertBackendMigrationCutover(input.plan, input.verification, input.cutover);
327
+ return this.mutate((state) => {
328
+ const saved = state.platform.migrationPlans[input.plan.id];
329
+ const record = state.platform.migrationRecords[input.plan.id];
330
+ if (!saved || canonical(saved) !== canonical(input.plan) || !record) throw new Error("Migration plan is not the persisted plan");
331
+ if (input.plan.request.scope.kind !== "tenants" || !input.plan.request.scope.tenantIds.includes(input.tenantId)) throw new Error("Migration plan tenant mismatch");
332
+ if (record.executionId !== input.executionId || !["running", "verified"].includes(record.status)) throw new Error("Migration execution is not active");
333
+ if (record.status === "verified" && canonical(record.verification) !== canonical(input.verification)) throw new Error("Migration verification changed during retry");
334
+ record.status = "verified";
335
+ record.verification = structuredClone(input.verification);
336
+ record.cutover = structuredClone(input.cutover);
337
+ record.updatedAt = this.now().toISOString();
338
+ return structuredClone(record);
339
+ });
340
+ }
341
+ /**
342
+ * Records a failed or reconciling migration status with host diagnostic text.
343
+ * @param input - Persisted migrationId, optional expected executionId, failure status, and nonblank message up to 2048 characters.
344
+ * @returns Cloned updated failure record.
345
+ * @throws Missing/completed migration, mismatched token, invalid input, or host store/clock failure.
346
+ * @example
347
+ * ```typescript
348
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
349
+ * export async function markMigrationFailure(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["markMigrationFailure"]>) {
350
+ * return store.markMigrationFailure(...args);
351
+ * }
352
+ * ```
353
+ */
354
+ async markMigrationFailure(input) {
355
+ identifier(input.migrationId, "migration id");
356
+ text(input.message, "migration failure", 2048);
357
+ return this.mutate((state) => {
358
+ const record = state.platform.migrationRecords[input.migrationId];
359
+ if (!record) throw new Error("Migration plan not found");
360
+ if (input.executionId && record.executionId !== input.executionId) throw new Error("Migration execution token mismatch");
361
+ if (record.status === "cutover" || record.status === "rolled-back") throw new Error("Completed migration cannot be marked failed");
362
+ record.status = input.status;
363
+ record.error = { message: input.message, occurredAt: this.now().toISOString() };
364
+ record.updatedAt = this.now().toISOString();
365
+ return structuredClone(record);
366
+ });
367
+ }
368
+ /**
369
+ * Applies an operator reconciliation status action and records its note.
370
+ * @param input - Persisted migrationId, action, and nonblank note up to 2048 characters; retry only permits failed/reconciling state and clears execution/verification/cutover.
371
+ * @returns Cloned updated migration record.
372
+ * @throws Missing record, retry from an ineligible state, completed record for mark-failed/mark-reconciling, invalid text, or host store failure.
373
+ * @example
374
+ * ```typescript
375
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
376
+ * export async function reconcileMigration(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["reconcileMigration"]>) {
377
+ * return store.reconcileMigration(...args);
378
+ * }
379
+ * ```
380
+ */
381
+ async reconcileMigration(input) {
382
+ identifier(input.migrationId, "migration id");
383
+ text(input.note, "reconciliation note", 2048);
384
+ return this.mutate((state) => {
385
+ const record = state.platform.migrationRecords[input.migrationId];
386
+ if (!record) throw new Error("Migration plan not found");
387
+ if (input.action === "retry") {
388
+ if (!["failed", "reconciling"].includes(record.status)) throw new Error("Only failed or reconciling migrations can be retried");
389
+ record.status = "planned";
390
+ record.executionId = void 0;
391
+ record.verification = void 0;
392
+ record.cutover = void 0;
393
+ } else if (input.action === "mark-failed") {
394
+ if (record.status === "cutover" || record.status === "rolled-back") throw new Error("Completed migration cannot be marked failed");
395
+ record.status = "failed";
396
+ } else if (input.action === "mark-reconciling") {
397
+ if (record.status === "cutover" || record.status === "rolled-back") throw new Error("Completed migration cannot be reconciled");
398
+ record.status = "reconciling";
399
+ }
400
+ record.error = { message: input.note, occurredAt: this.now().toISOString() };
401
+ record.updatedAt = this.now().toISOString();
402
+ return structuredClone(record);
403
+ });
404
+ }
405
+ /**
406
+ * Creates a reverse migration plan for a completed cutover without executing rollback.
407
+ * @param input - Verified tenantId, completed migrationId, nonblank reason up to 1024 characters, and parseable requestedAt timestamp.
408
+ * @returns New planned reverse migration linked to the original record.
409
+ * @throws Incomplete/already rollback-planned migration, tenant no longer on migrated target, invalid input/planning, or host store failure.
410
+ * @example
411
+ * ```typescript
412
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
413
+ * export async function createRollbackPlan(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["createRollbackPlan"]>) {
414
+ * return store.createRollbackPlan(...args);
415
+ * }
416
+ * ```
417
+ */
418
+ async createRollbackPlan(input) {
419
+ identifier(input.tenantId, "tenant id");
420
+ identifier(input.migrationId, "migration id");
421
+ text(input.reason, "rollback reason", 1024);
422
+ timestamp(input.requestedAt, "rollback requestedAt");
423
+ return this.mutate((state) => {
424
+ const original = state.platform.migrationRecords[input.migrationId];
425
+ const originalPlan = state.platform.migrationPlans[input.migrationId];
426
+ if (!original || !originalPlan || original.status !== "cutover") throw new Error("Only a completed migration can be rolled back");
427
+ if (original.rollbackPlanId) throw new Error("Migration rollback already exists");
428
+ const current = placement(state, input.tenantId);
429
+ if (!current || current.backend.id !== originalPlan.request.target.id) throw new Error("Current tenant placement is not the migrated target");
430
+ const rollback = planBackendMigration({
431
+ migrationId: `rollback-${crypto.randomUUID()}`,
432
+ source: originalPlan.request.target,
433
+ target: originalPlan.request.source,
434
+ scope: originalPlan.request.scope,
435
+ pluginIds: originalPlan.request.pluginIds,
436
+ requestedAt: input.requestedAt,
437
+ reason: input.reason
438
+ });
439
+ state.platform.migrationPlans[rollback.id] = structuredClone(rollback);
440
+ state.platform.migrationRecords[rollback.id] = { status: "planned", updatedAt: input.requestedAt, rollbackOf: input.migrationId };
441
+ original.rollbackPlanId = rollback.id;
442
+ original.updatedAt = this.now().toISOString();
443
+ return rollback;
444
+ });
445
+ }
446
+ /**
447
+ * Commits a verified migration routing change and transfers active plugin activations to the target backend.
448
+ * @param input - Tenant included by the exact persisted plan and its previously recorded cutover proof.
449
+ * @returns New target placement, or current placement for an already-cutover record.
450
+ * @throws Unverified/stale/changed plan, invalid cutover or nonadvancing routing revision, target tenant mismatch, missing planned active plugin or target installation, or host lock/write failure.
451
+ * @example
452
+ * ```typescript
453
+ * import { LifecyclePlatformControlStore } from "@alneas/eaos-server/platform-admin/store";
454
+ * export async function recordTenantPlacement(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore["recordTenantPlacement"]>) {
455
+ * return store.recordTenantPlacement(...args);
456
+ * }
457
+ * ```
458
+ */
459
+ async recordTenantPlacement(input) {
460
+ identifier(input.tenantId, "tenant id");
461
+ return this.mutate((state) => {
462
+ const { plan, cutover } = input;
463
+ const saved = state.platform.migrationPlans[plan.id];
464
+ const record = state.platform.migrationRecords[plan.id];
465
+ if (!saved || canonical(saved) !== canonical(plan) || !record) throw new Error("Migration plan is not the persisted plan");
466
+ if (plan.request.scope.kind !== "tenants" || !plan.request.scope.tenantIds.includes(input.tenantId)) throw new Error("Migration plan tenant mismatch");
467
+ if (record.status === "cutover") return placement(state, input.tenantId);
468
+ if (record.status !== "verified" || !record.executionId || !record.verification || !record.cutover || canonical(record.cutover) !== canonical(cutover)) throw new Error("Migration must be verified before cutover");
469
+ if (cutover.migrationId !== plan.request.migrationId || cutover.targetBackendId !== plan.request.target.id || cutover.sourceRetained !== true || !Number.isSafeInteger(cutover.routingRevision) || cutover.routingRevision < 0 || !Number.isFinite(Date.parse(cutover.cutoverAt))) throw new Error("Invalid migration cutover");
470
+ const current = placement(state, input.tenantId);
471
+ if (!current || current.backend.id !== plan.request.source.id || current.backend.databaseId !== plan.request.source.databaseId) throw new Error("Migration plan is stale");
472
+ if (cutover.routingRevision <= current.routingRevision) throw new Error("Migration routing revision must advance");
473
+ const target = materializeBackend(state, plan.request.target.id);
474
+ if (!target || canonical(targetOf(target)) !== canonical(targetOf(plan.request.target))) throw new Error("Migration target backend changed");
475
+ if (target.mode === "dedicated" && target.tenantId !== input.tenantId) throw new Error("Migration target tenant mismatch");
476
+ const active = Object.entries(state.activations).filter(([, activation]) => activation.backendId === plan.request.source.id && activation.tenantId === input.tenantId && activation.enabled);
477
+ const planned = new Set(plan.request.pluginIds);
478
+ for (const [, activation] of active) {
479
+ if (!planned.has(activation.pluginId)) throw new Error(`Migration plan does not include active plugin: ${activation.pluginId}`);
480
+ const installation = state.installations[key(plan.request.target.id, activation.pluginId)];
481
+ if (!installation || installation.status !== "installed") throw new Error(`Target backend is missing installed plugin: ${activation.pluginId}`);
482
+ }
483
+ for (const [activationKey, activation] of active) {
484
+ activation.enabled = false;
485
+ const targetKey = key(plan.request.target.id, input.tenantId, activation.pluginId);
486
+ const installation = state.installations[key(plan.request.target.id, activation.pluginId)];
487
+ state.activations[targetKey] = { ...activation, backendId: plan.request.target.id, digest: installation.digest, enabled: true };
488
+ state.activations[activationKey] = activation;
489
+ }
490
+ state.platform.placements[input.tenantId] = { tenantId: input.tenantId, backendId: plan.request.target.id, routingRevision: cutover.routingRevision, changedAt: timestamp(cutover.cutoverAt, "cutover time") };
491
+ record.status = "cutover";
492
+ record.updatedAt = this.now().toISOString();
493
+ record.cutover = structuredClone(cutover);
494
+ if (record.rollbackOf) {
495
+ const original = state.platform.migrationRecords[record.rollbackOf];
496
+ if (original) {
497
+ original.status = "rolled-back";
498
+ original.updatedAt = this.now().toISOString();
499
+ original.rollbackPlanId = plan.id;
500
+ }
501
+ }
502
+ return placement(state, input.tenantId);
503
+ });
504
+ }
505
+ };
506
+
507
+ export {
508
+ LifecyclePlatformControlStore
509
+ };
510
+ //# sourceMappingURL=chunk-YMJ7BRKU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/platform-admin/store.ts"],"sourcesContent":["import { assertBackendMigrationCutover, canonical, normalizeLifecycleState, planBackendMigration, type BackendMigrationPlan, type BackendMigrationCutover, type BackendMigrationVerificationReport, type BackendTarget, type LifecyclePlatformMigrationRecord, type LifecycleStore, type LifecycleState } from '@alneas/eaos-server/lifecycle-engine'\nimport type { PlatformBackendRecord, PlatformControlStore, PlatformMigrationReconcileAction, PlatformTenantCreateInput, PlatformTenantPatch, PlatformTenantRecord, TenantBackendPlacement } from '@alneas/eaos-server/platform'\n\nconst key = (...parts: string[]) => JSON.stringify(parts)\nconst identifier = (value: string, name: string) => {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/.test(value)) throw new Error(`Invalid ${name}`)\n return value\n}\nconst text = (value: string, name: string, max = 256) => {\n if (!value.trim() || value.length > max) throw new Error(`Invalid ${name}`)\n return value\n}\nconst timestamp = (value: string, name: string) => {\n if (!Number.isFinite(Date.parse(value))) throw new Error(`Invalid ${name}`)\n return value\n}\n\nfunction materializeBackend(state: LifecycleState, backendId: string): PlatformBackendRecord | null {\n const backend = state.backends[backendId]\n if (!backend) return null\n return { ...backend, ...state.platform.backendMetadata[backendId] }\n}\n\nfunction targetOf(backend: PlatformBackendRecord | BackendTarget): BackendTarget {\n return { id: backend.id, databaseId: backend.databaseId, dialect: backend.dialect, mode: backend.mode, ...(backend.tenantId === undefined ? {} : { tenantId: backend.tenantId }) }\n}\n\nfunction placement(state: LifecycleState, tenantId: string): TenantBackendPlacement | null {\n const record = state.platform.placements[tenantId]\n if (!record) return null\n const backend = materializeBackend(state, record.backendId)\n if (!backend) throw new Error(`Tenant placement references unknown backend: ${record.backendId}`)\n return { tenantId, backend, routingRevision: record.routingRevision, changedAt: record.changedAt }\n}\n\nfunction validateBackend(backend: PlatformBackendRecord): void {\n identifier(backend.id, 'backend id')\n identifier(backend.databaseId, 'database id')\n if (!['sqlite', 'postgres', 'oracle'].includes(backend.dialect) || !['shared', 'dedicated'].includes(backend.mode)) throw new Error('Invalid backend target')\n if (backend.mode === 'dedicated') identifier(backend.tenantId ?? '', 'dedicated backend tenant')\n if (backend.mode === 'shared' && backend.tenantId !== undefined) throw new Error('Shared backend cannot bind a tenant')\n}\n\n/**\n * Platform control facade backed by the same LifecycleStore snapshot and lock.\n * Use this with SqlLifecycleStore for distributed hosts; it intentionally does\n * not create a second platform database or a second placement authority.\n * @remarks Mutations normalize one locked lifecycle snapshot, increment its revision, and persist it; transaction/CAS/lock recovery depend on the host LifecycleStore. This facade performs no caller authentication, SQL/infra provisioning, remote migration, or automatic retry. Authorize operators before invoking it and reconcile uncertain store failures.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * import type { LifecycleStore } from \"@alneas/eaos-server/lifecycle-engine\";\n * export function controlStore(lifecycle: LifecycleStore) { return new LifecyclePlatformControlStore(lifecycle); }\n * ```\n */\nexport class LifecyclePlatformControlStore implements PlatformControlStore {\n /**\n * Captures the shared authoritative lifecycle ledger and clock.\n * @param lifecycle - Host store providing consistent reads and exclusive writer callbacks.\n * @param now - Clock for mutation timestamps; defaults to a fresh Date.\n */\n constructor(private readonly lifecycle: LifecycleStore, private readonly now: () => Date = () => new Date()) {}\n\n private async read(): Promise<LifecycleState> { return normalizeLifecycleState(await this.lifecycle.read()) }\n\n private async mutate<T>(fn: (state: LifecycleState) => Promise<T> | T): Promise<T> {\n return this.lifecycle.withLock(async writer => {\n const state = normalizeLifecycleState(await writer.read())\n const result = await fn(state)\n state.revision += 1\n await writer.write(state)\n return result\n })\n }\n\n /**\n * Lists tenant records from the authoritative normalized lifecycle snapshot.\n * @returns Tenant records with cloned domains arrays, or an empty array.\n * @throws Host read/normalization failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function listTenants(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"listTenants\"]>) {\n * return store.listTenants(...args);\n * }\n * ```\n */\n async listTenants(): Promise<readonly PlatformTenantRecord[]> {\n const state = await this.read()\n return Object.values(state.platform.tenants).map(tenant => ({ ...tenant, domains: [...tenant.domains] }))\n }\n\n /**\n * Creates an active tenant and its initial backend routing record under the lifecycle writer lock.\n * @param input - Valid scope ID, nonblank name, nonempty domain strings, and registered initial backendId; a dedicated backend must bind the same tenant.\n * @returns Created tenant record with clock timestamps; initial routing revision is one.\n * @throws Invalid input, duplicate tenant, missing/mismatched backend, or host lock/write/clock failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function createTenant(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"createTenant\"]>) {\n * return store.createTenant(...args);\n * }\n * ```\n */\n async createTenant(input: PlatformTenantCreateInput): Promise<PlatformTenantRecord> {\n const id = identifier(input.id, 'tenant id')\n const name = text(input.name, 'tenant name')\n const backendId = identifier(input.backendId, 'initial backend id')\n if (!Array.isArray(input.domains) || input.domains.length === 0 || input.domains.some(domain => typeof domain !== 'string' || !domain.trim())) throw new Error('Invalid tenant domains')\n return this.mutate(state => {\n if (state.platform.tenants[id]) throw new Error('Tenant already exists')\n const backend = materializeBackend(state, backendId)\n if (!backend) throw new Error('Initial backend not found')\n if (backend.mode === 'dedicated' && backend.tenantId !== id) throw new Error('Initial backend tenant mismatch')\n const at = this.now().toISOString()\n const tenant = { id, name, active: true, domains: [...input.domains], createdAt: at, updatedAt: at }\n state.platform.tenants[id] = tenant\n state.platform.placements[id] = { tenantId: id, backendId, routingRevision: 1, changedAt: at }\n return tenant\n })\n }\n\n /**\n * Updates an existing tenant name, active flag, or domains and refreshes updatedAt.\n * @param tenantId - Existing valid tenant scope ID.\n * @param patch - Optional nonblank name, boolean active, and nonempty nonblank domains; omitted fields remain unchanged.\n * @returns Updated tenant with cloned domains.\n * @throws Missing tenant, invalid supplied fields, or host lock/write/clock failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function updateTenant(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"updateTenant\"]>) {\n * return store.updateTenant(...args);\n * }\n * ```\n */\n async updateTenant(tenantId: string, patch: PlatformTenantPatch): Promise<PlatformTenantRecord> {\n identifier(tenantId, 'tenant id')\n return this.mutate(state => {\n const current = state.platform.tenants[tenantId]\n if (!current) throw new Error('Tenant not found')\n if (patch.name !== undefined) current.name = text(patch.name, 'tenant name')\n if (patch.active !== undefined) {\n if (typeof patch.active !== 'boolean') throw new Error('Invalid tenant active state')\n current.active = patch.active\n }\n if (patch.domains !== undefined) {\n if (!Array.isArray(patch.domains) || patch.domains.length === 0 || patch.domains.some(domain => typeof domain !== 'string' || !domain.trim())) throw new Error('Invalid tenant domains')\n current.domains = [...patch.domains]\n }\n current.updatedAt = this.now().toISOString()\n return { ...current, domains: [...current.domains] }\n })\n }\n\n /**\n * Registers an immutable backend placement identity and replaceable public metadata.\n * @param backend - Valid backend/database IDs, dialect/mode, optional dedicated tenant binding, and metadata.\n * @returns Materialized registered target with metadata.\n * @throws Invalid target, changed placement for an existing ID, database dialect conflict, or host store failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function registerBackend(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"registerBackend\"]>) {\n * return store.registerBackend(...args);\n * }\n * ```\n */\n async registerBackend(backend: PlatformBackendRecord): Promise<PlatformBackendRecord> {\n validateBackend(backend)\n return this.mutate(state => {\n const existing = state.backends[backend.id]\n const target: BackendTarget = { id: backend.id, databaseId: backend.databaseId, dialect: backend.dialect, mode: backend.mode, ...(backend.tenantId === undefined ? {} : { tenantId: backend.tenantId }) }\n if (existing && canonical(existing) !== canonical(target)) throw new Error('Backend placement is immutable; register a new backend ID')\n for (const other of Object.values(state.backends)) if (other.id !== backend.id && other.databaseId === backend.databaseId && other.dialect !== backend.dialect) throw new Error('Database dialect conflict')\n state.backends[backend.id] = target\n const { id: _id, databaseId: _databaseId, dialect: _dialect, mode: _mode, tenantId: _tenantId, ...metadata } = backend\n state.platform.backendMetadata[backend.id] = metadata\n return { ...target, ...metadata }\n })\n }\n\n /**\n * Materializes registered backend targets with their public metadata.\n * @returns Backend list, or an empty array.\n * @throws Host read/normalization failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function listBackends(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"listBackends\"]>) {\n * return store.listBackends(...args);\n * }\n * ```\n */\n async listBackends(): Promise<readonly PlatformBackendRecord[]> {\n const state = await this.read()\n return Object.keys(state.backends).map(id => materializeBackend(state, id)!).filter(Boolean)\n }\n\n /**\n * Reads a registered backend target and its public metadata.\n * @param backendId - Valid registered backend scope ID.\n * @returns Materialized backend, or null when unregistered.\n * @throws Invalid ID or host read failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function getBackend(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"getBackend\"]>) {\n * return store.getBackend(...args);\n * }\n * ```\n */\n async getBackend(backendId: string): Promise<PlatformBackendRecord | null> {\n identifier(backendId, 'backend id')\n return materializeBackend(await this.read(), backendId)\n }\n\n /**\n * Resolves a tenant routing record into its registered backend target.\n * @param tenantId - Valid tenant scope ID.\n * @returns Placement with routing revision/time and backend, or null when absent.\n * @throws Invalid ID, dangling backend reference, or host read failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function getTenantPlacement(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"getTenantPlacement\"]>) {\n * return store.getTenantPlacement(...args);\n * }\n * ```\n */\n async getTenantPlacement(tenantId: string): Promise<TenantBackendPlacement | null> {\n identifier(tenantId, 'tenant id')\n return placement(await this.read(), tenantId)\n }\n\n /**\n * Persists an immutable migration plan after checking registered backend identities.\n * @param plan - Reviewed plan matching currently registered source/target; identical saved plans may be accepted before completion.\n * @returns No value; resolves after storing the plan and initial planned record if absent.\n * @throws Unregistered/changed backend, conflicting reused plan ID, already completed plan, clone or host store failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function saveMigrationPlan(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"saveMigrationPlan\"]>) {\n * return store.saveMigrationPlan(...args);\n * }\n * ```\n */\n async saveMigrationPlan(plan: BackendMigrationPlan): Promise<void> {\n await this.mutate(state => {\n if (!state.backends[plan.request.source.id] || !state.backends[plan.request.target.id]) throw new Error('Migration backend is not registered')\n if (canonical(targetOf(state.backends[plan.request.source.id])) !== canonical(targetOf(plan.request.source)) || canonical(targetOf(state.backends[plan.request.target.id])) !== canonical(targetOf(plan.request.target))) throw new Error('Migration backend changed since planning')\n const existing = state.platform.migrationPlans[plan.id]\n if (existing && canonical(existing) !== canonical(plan)) throw new Error('Migration plan ID already contains a different plan')\n const current = state.platform.migrationRecords[plan.id]\n if (current?.status === 'cutover' || current?.status === 'rolled-back') throw new Error('Migration plan has already completed')\n state.platform.migrationPlans[plan.id] = structuredClone(plan)\n state.platform.migrationRecords[plan.id] ??= { status: 'planned', updatedAt: plan.request.requestedAt }\n })\n }\n\n /**\n * Reads a cloned persisted migration plan by ID.\n * @param migrationId - Valid migration scope ID.\n * @returns Plan clone, or null when absent.\n * @throws Invalid ID or host read/clone failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function getMigrationPlan(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"getMigrationPlan\"]>) {\n * return store.getMigrationPlan(...args);\n * }\n * ```\n */\n async getMigrationPlan(migrationId: string): Promise<BackendMigrationPlan | null> {\n identifier(migrationId, 'migration id')\n const state = await this.read()\n const plan = state.platform.migrationPlans[migrationId]\n return plan ? structuredClone(plan) : null\n }\n\n /**\n * Reads the persisted migration execution/reconciliation record.\n * @param migrationId - Valid migration scope ID.\n * @returns Cloned status record, or null when absent.\n * @throws Invalid ID or host read/clone failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function getMigrationStatus(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"getMigrationStatus\"]>) {\n * return store.getMigrationStatus(...args);\n * }\n * ```\n */\n async getMigrationStatus(migrationId: string): Promise<LifecyclePlatformMigrationRecord | null> {\n identifier(migrationId, 'migration id')\n const record = (await this.read()).platform.migrationRecords[migrationId]\n return record ? structuredClone(record) : null\n }\n\n /**\n * Binds an execution token and transitions a tenant migration record to running.\n * @param input - Verified tenantId, persisted migrationId, and unique host executionId; plan scope must include the tenant.\n * @returns Cloned running record, or completed cutover/rolled-back record unchanged.\n * @throws Missing plan, tenant mismatch, conflicting active token, reconciling state, invalid IDs, or host store failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function beginMigrationExecution(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"beginMigrationExecution\"]>) {\n * return store.beginMigrationExecution(...args);\n * }\n * ```\n */\n async beginMigrationExecution(input: { \n /**\n * Verified tenant included in the persisted migration plan tenant scope; mismatch rejects before recording execution.\n */\n tenantId: string; \n /**\n * Identity of an already persisted migration plan and its corresponding status record.\n */\n migrationId: string; \n /**\n * Host execution token bound to this run; a different token cannot replace an active running/verified execution.\n */\n executionId: string }): Promise<LifecyclePlatformMigrationRecord> {\n identifier(input.tenantId, 'tenant id'); identifier(input.migrationId, 'migration id'); identifier(input.executionId, 'execution id')\n return this.mutate(state => {\n const plan = state.platform.migrationPlans[input.migrationId]\n const record = state.platform.migrationRecords[input.migrationId]\n if (!plan || !record) throw new Error('Migration plan not found')\n if (plan.request.scope.kind !== 'tenants' || !plan.request.scope.tenantIds.includes(input.tenantId)) throw new Error('Migration plan tenant mismatch')\n if (record.status === 'cutover' || record.status === 'rolled-back') return structuredClone(record)\n if ((record.status === 'running' || record.status === 'verified') && record.executionId !== input.executionId) throw new Error('Migration execution already in progress')\n if (record.status === 'reconciling') throw new Error('Migration requires reconciliation before retry')\n record.status = 'running'\n record.executionId = input.executionId\n record.error = undefined\n record.updatedAt = this.now().toISOString()\n return structuredClone(record)\n })\n }\n\n /**\n * Records verified migration evidence and cutover data for the active execution token.\n * @param input - Tenant, exact persisted plan, active executionId, verification report, and matching validated cutover.\n * @returns Cloned verified migration record.\n * @throws Invalid cutover/report, nonpersisted/changed plan, tenant/token/state mismatch, changed retry verification, or host store failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function recordMigrationVerification(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"recordMigrationVerification\"]>) {\n * return store.recordMigrationVerification(...args);\n * }\n * ```\n */\n async recordMigrationVerification(input: { \n /**\n * Verified tenant included in the exact persisted plan tenant scope.\n */\n tenantId: string; \n /**\n * Exact persisted migration plan; canonical contents must match the saved plan rather than a modified caller copy.\n */\n plan: BackendMigrationPlan; \n /**\n * Current execution token recorded by beginMigrationExecution; only running/verified records with this token may accept evidence.\n */\n executionId: string; \n /**\n * Passing source/target verification report validated against the plan and cutover; a verified retry must reproduce the recorded report.\n */\n verification: BackendMigrationVerificationReport; \n /**\n * Matching validated cutover proof recorded with the report for a later explicit routing commit; recording verification does not itself switch placement.\n */\n cutover: BackendMigrationCutover }): Promise<LifecyclePlatformMigrationRecord> {\n identifier(input.tenantId, 'tenant id'); identifier(input.executionId, 'execution id')\n assertBackendMigrationCutover(input.plan, input.verification, input.cutover)\n return this.mutate(state => {\n const saved = state.platform.migrationPlans[input.plan.id]\n const record = state.platform.migrationRecords[input.plan.id]\n if (!saved || canonical(saved) !== canonical(input.plan) || !record) throw new Error('Migration plan is not the persisted plan')\n if (input.plan.request.scope.kind !== 'tenants' || !input.plan.request.scope.tenantIds.includes(input.tenantId)) throw new Error('Migration plan tenant mismatch')\n if (record.executionId !== input.executionId || !['running', 'verified'].includes(record.status)) throw new Error('Migration execution is not active')\n if (record.status === 'verified' && canonical(record.verification) !== canonical(input.verification)) throw new Error('Migration verification changed during retry')\n record.status = 'verified'\n record.verification = structuredClone(input.verification)\n record.cutover = structuredClone(input.cutover)\n record.updatedAt = this.now().toISOString()\n return structuredClone(record)\n })\n }\n\n /**\n * Records a failed or reconciling migration status with host diagnostic text.\n * @param input - Persisted migrationId, optional expected executionId, failure status, and nonblank message up to 2048 characters.\n * @returns Cloned updated failure record.\n * @throws Missing/completed migration, mismatched token, invalid input, or host store/clock failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function markMigrationFailure(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"markMigrationFailure\"]>) {\n * return store.markMigrationFailure(...args);\n * }\n * ```\n */\n async markMigrationFailure(input: { \n /**\n * Persisted migration record to mark failed or reconciling; completed cutover/rolled-back records cannot be changed through this method.\n */\n migrationId: string; \n /**\n * Optional expected active execution token; a truthy supplied value must match, while omission skips this token check.\n */\n executionId?: string; \n /**\n * Failure disposition to persist: failed permits explicit retry preparation, while reconciling requires operator outcome review before retry.\n */\n status: 'failed' | 'reconciling'; \n /**\n * Nonblank diagnostic text up to 2048 characters, stored with a generated occurrence timestamp; exclude secrets and customer payloads.\n */\n message: string }): Promise<LifecyclePlatformMigrationRecord> {\n identifier(input.migrationId, 'migration id'); text(input.message, 'migration failure', 2048)\n return this.mutate(state => {\n const record = state.platform.migrationRecords[input.migrationId]\n if (!record) throw new Error('Migration plan not found')\n if (input.executionId && record.executionId !== input.executionId) throw new Error('Migration execution token mismatch')\n if (record.status === 'cutover' || record.status === 'rolled-back') throw new Error('Completed migration cannot be marked failed')\n record.status = input.status\n record.error = { message: input.message, occurredAt: this.now().toISOString() }\n record.updatedAt = this.now().toISOString()\n return structuredClone(record)\n })\n }\n\n /**\n * Applies an operator reconciliation status action and records its note.\n * @param input - Persisted migrationId, action, and nonblank note up to 2048 characters; retry only permits failed/reconciling state and clears execution/verification/cutover.\n * @returns Cloned updated migration record.\n * @throws Missing record, retry from an ineligible state, completed record for mark-failed/mark-reconciling, invalid text, or host store failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function reconcileMigration(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"reconcileMigration\"]>) {\n * return store.reconcileMigration(...args);\n * }\n * ```\n */\n async reconcileMigration(input: { \n /**\n * Persisted migration whose operator reconciliation state is being updated.\n */\n migrationId: string; \n /**\n * Explicit retry, mark-failed or mark-reconciling action; retry requires failed/reconciling state and clears execution, verification and cutover data.\n */\n action: PlatformMigrationReconcileAction; \n /**\n * Nonblank operator rationale up to 2048 characters, persisted as timestamped diagnostic text; this does not independently verify external outcomes.\n */\n note: string }): Promise<LifecyclePlatformMigrationRecord> {\n identifier(input.migrationId, 'migration id'); text(input.note, 'reconciliation note', 2048)\n return this.mutate(state => {\n const record = state.platform.migrationRecords[input.migrationId]\n if (!record) throw new Error('Migration plan not found')\n if (input.action === 'retry') {\n if (!['failed', 'reconciling'].includes(record.status)) throw new Error('Only failed or reconciling migrations can be retried')\n record.status = 'planned'; record.executionId = undefined; record.verification = undefined; record.cutover = undefined\n } else if (input.action === 'mark-failed') {\n if (record.status === 'cutover' || record.status === 'rolled-back') throw new Error('Completed migration cannot be marked failed')\n record.status = 'failed'\n } else if (input.action === 'mark-reconciling') {\n if (record.status === 'cutover' || record.status === 'rolled-back') throw new Error('Completed migration cannot be reconciled')\n record.status = 'reconciling'\n }\n record.error = { message: input.note, occurredAt: this.now().toISOString() }\n record.updatedAt = this.now().toISOString()\n return structuredClone(record)\n })\n }\n\n /**\n * Creates a reverse migration plan for a completed cutover without executing rollback.\n * @param input - Verified tenantId, completed migrationId, nonblank reason up to 1024 characters, and parseable requestedAt timestamp.\n * @returns New planned reverse migration linked to the original record.\n * @throws Incomplete/already rollback-planned migration, tenant no longer on migrated target, invalid input/planning, or host store failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function createRollbackPlan(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"createRollbackPlan\"]>) {\n * return store.createRollbackPlan(...args);\n * }\n * ```\n */\n async createRollbackPlan(input: { \n /**\n * Verified tenant currently placed on the completed migration target; the current placement must still match before a reverse plan is created.\n */\n tenantId: string; \n /**\n * Completed cutover migration to reverse; an existing rollback plan prevents creating another one.\n */\n migrationId: string; \n /**\n * Nonblank rollback planning rationale up to 1024 characters, copied to the new reverse migration request.\n */\n reason: string; \n /**\n * Parseable rollback request timestamp copied to the new plan/status record; no rollback is executed by planning.\n */\n requestedAt: string }): Promise<BackendMigrationPlan> {\n identifier(input.tenantId, 'tenant id'); identifier(input.migrationId, 'migration id'); text(input.reason, 'rollback reason', 1024)\n timestamp(input.requestedAt, 'rollback requestedAt')\n return this.mutate(state => {\n const original = state.platform.migrationRecords[input.migrationId]\n const originalPlan = state.platform.migrationPlans[input.migrationId]\n if (!original || !originalPlan || original.status !== 'cutover') throw new Error('Only a completed migration can be rolled back')\n if (original.rollbackPlanId) throw new Error('Migration rollback already exists')\n const current = placement(state, input.tenantId)\n if (!current || current.backend.id !== originalPlan.request.target.id) throw new Error('Current tenant placement is not the migrated target')\n const rollback = planBackendMigration({\n migrationId: `rollback-${crypto.randomUUID()}`,\n source: originalPlan.request.target,\n target: originalPlan.request.source,\n scope: originalPlan.request.scope,\n pluginIds: originalPlan.request.pluginIds,\n requestedAt: input.requestedAt,\n reason: input.reason,\n })\n state.platform.migrationPlans[rollback.id] = structuredClone(rollback)\n state.platform.migrationRecords[rollback.id] = { status: 'planned', updatedAt: input.requestedAt, rollbackOf: input.migrationId }\n original.rollbackPlanId = rollback.id\n original.updatedAt = this.now().toISOString()\n return rollback\n })\n }\n\n /**\n * Commits a verified migration routing change and transfers active plugin activations to the target backend.\n * @param input - Tenant included by the exact persisted plan and its previously recorded cutover proof.\n * @returns New target placement, or current placement for an already-cutover record.\n * @throws Unverified/stale/changed plan, invalid cutover or nonadvancing routing revision, target tenant mismatch, missing planned active plugin or target installation, or host lock/write failure.\n * @example\n * ```typescript\n * import { LifecyclePlatformControlStore } from \"@alneas/eaos-server/platform-admin/store\";\n * export async function recordTenantPlacement(store: LifecyclePlatformControlStore, ...args: Parameters<LifecyclePlatformControlStore[\"recordTenantPlacement\"]>) {\n * return store.recordTenantPlacement(...args);\n * }\n * ```\n */\n async recordTenantPlacement(input: { \n /**\n * Verified tenant included in the plan whose persisted routing placement and active plugin bindings will be moved.\n */\n tenantId: string; \n /**\n * Exact persisted verified migration plan; current source/target backend identities and installations are rechecked before commit.\n */\n plan: BackendMigrationPlan; \n /**\n * Previously recorded verification proof with source retained and an advancing routing revision; its canonical contents must match the saved cutover.\n */\n cutover: BackendMigrationCutover }): Promise<TenantBackendPlacement> {\n identifier(input.tenantId, 'tenant id')\n return this.mutate(state => {\n const { plan, cutover } = input\n const saved = state.platform.migrationPlans[plan.id]\n const record = state.platform.migrationRecords[plan.id]\n if (!saved || canonical(saved) !== canonical(plan) || !record) throw new Error('Migration plan is not the persisted plan')\n if (plan.request.scope.kind !== 'tenants' || !plan.request.scope.tenantIds.includes(input.tenantId)) throw new Error('Migration plan tenant mismatch')\n if (record.status === 'cutover') return placement(state, input.tenantId)!\n if (record.status !== 'verified' || !record.executionId || !record.verification || !record.cutover || canonical(record.cutover) !== canonical(cutover)) throw new Error('Migration must be verified before cutover')\n if (cutover.migrationId !== plan.request.migrationId || cutover.targetBackendId !== plan.request.target.id || cutover.sourceRetained !== true || !Number.isSafeInteger(cutover.routingRevision) || cutover.routingRevision < 0 || !Number.isFinite(Date.parse(cutover.cutoverAt))) throw new Error('Invalid migration cutover')\n const current = placement(state, input.tenantId)\n if (!current || current.backend.id !== plan.request.source.id || current.backend.databaseId !== plan.request.source.databaseId) throw new Error('Migration plan is stale')\n if (cutover.routingRevision <= current.routingRevision) throw new Error('Migration routing revision must advance')\n const target = materializeBackend(state, plan.request.target.id)\n if (!target || canonical(targetOf(target)) !== canonical(targetOf(plan.request.target))) throw new Error('Migration target backend changed')\n if (target.mode === 'dedicated' && target.tenantId !== input.tenantId) throw new Error('Migration target tenant mismatch')\n\n const active = Object.entries(state.activations).filter(([, activation]) => activation.backendId === plan.request.source.id && activation.tenantId === input.tenantId && activation.enabled)\n const planned = new Set(plan.request.pluginIds)\n for (const [, activation] of active) {\n if (!planned.has(activation.pluginId)) throw new Error(`Migration plan does not include active plugin: ${activation.pluginId}`)\n const installation = state.installations[key(plan.request.target.id, activation.pluginId)]\n if (!installation || installation.status !== 'installed') throw new Error(`Target backend is missing installed plugin: ${activation.pluginId}`)\n }\n for (const [activationKey, activation] of active) {\n activation.enabled = false\n const targetKey = key(plan.request.target.id, input.tenantId, activation.pluginId)\n const installation = state.installations[key(plan.request.target.id, activation.pluginId)]\n state.activations[targetKey] = { ...activation, backendId: plan.request.target.id, digest: installation.digest, enabled: true }\n state.activations[activationKey] = activation\n }\n state.platform.placements[input.tenantId] = { tenantId: input.tenantId, backendId: plan.request.target.id, routingRevision: cutover.routingRevision, changedAt: timestamp(cutover.cutoverAt, 'cutover time') }\n record.status = 'cutover'\n record.updatedAt = this.now().toISOString()\n record.cutover = structuredClone(cutover)\n if (record.rollbackOf) {\n const original = state.platform.migrationRecords[record.rollbackOf]\n if (original) { original.status = 'rolled-back'; original.updatedAt = this.now().toISOString(); original.rollbackPlanId = plan.id }\n }\n return placement(state, input.tenantId)!\n })\n }\n}\n"],"mappings":"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","names":[]}