alchemy 2.0.0-beta.84 → 2.0.0-beta.85

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 (758) hide show
  1. package/THIRD_PARTY_LICENSES.md +2 -2
  2. package/bin/cli.js +14 -6
  3. package/bin/register-oxc.js +16 -12
  4. package/lib/AdoptPolicy.d.ts +73 -0
  5. package/lib/AdoptPolicy.d.ts.map +1 -1
  6. package/lib/AdoptPolicy.js +54 -0
  7. package/lib/AdoptPolicy.js.map +1 -1
  8. package/lib/Alchemist/AuthRegistry.d.ts +31 -0
  9. package/lib/Alchemist/AuthRegistry.d.ts.map +1 -0
  10. package/lib/Alchemist/AuthRegistry.js +95 -0
  11. package/lib/Alchemist/AuthRegistry.js.map +1 -0
  12. package/lib/Alchemist/Drift.d.ts +70 -0
  13. package/lib/Alchemist/Drift.d.ts.map +1 -0
  14. package/lib/Alchemist/Drift.js +54 -0
  15. package/lib/Alchemist/Drift.js.map +1 -0
  16. package/lib/Alchemist/Entrypoint.d.ts +27 -3
  17. package/lib/Alchemist/Entrypoint.d.ts.map +1 -1
  18. package/lib/Alchemist/Entrypoint.js +34 -3
  19. package/lib/Alchemist/Entrypoint.js.map +1 -1
  20. package/lib/Alchemist/Errors.d.ts +1 -1
  21. package/lib/Alchemist/Errors.d.ts.map +1 -1
  22. package/lib/Alchemist/Errors.js +1 -1
  23. package/lib/Alchemist/Errors.js.map +1 -1
  24. package/lib/Alchemist/Logs.d.ts +46 -0
  25. package/lib/Alchemist/Logs.d.ts.map +1 -0
  26. package/lib/Alchemist/{routes/logs.js → Logs.js} +21 -26
  27. package/lib/Alchemist/Logs.js.map +1 -0
  28. package/lib/Alchemist/Nuke.d.ts +69 -0
  29. package/lib/Alchemist/Nuke.d.ts.map +1 -0
  30. package/lib/Alchemist/Nuke.js +35 -0
  31. package/lib/Alchemist/Nuke.js.map +1 -0
  32. package/lib/Alchemist/Operations.d.ts +168 -0
  33. package/lib/Alchemist/Operations.d.ts.map +1 -0
  34. package/lib/Alchemist/Operations.js +165 -0
  35. package/lib/Alchemist/Operations.js.map +1 -0
  36. package/lib/Alchemist/Profile.d.ts +132 -0
  37. package/lib/Alchemist/Profile.d.ts.map +1 -0
  38. package/lib/Alchemist/{routes/profile.js → Profile.js} +20 -21
  39. package/lib/Alchemist/Profile.js.map +1 -0
  40. package/lib/Alchemist/{routes/provider.d.ts → Provider.d.ts} +4 -4
  41. package/lib/Alchemist/Provider.d.ts.map +1 -0
  42. package/lib/Alchemist/{routes/provider.js → Provider.js} +7 -6
  43. package/lib/Alchemist/Provider.js.map +1 -0
  44. package/lib/Alchemist/Runtime.d.ts +10 -6
  45. package/lib/Alchemist/Runtime.d.ts.map +1 -1
  46. package/lib/Alchemist/Runtime.js +38 -2
  47. package/lib/Alchemist/Runtime.js.map +1 -1
  48. package/lib/Alchemist/{routes/state.d.ts → State.d.ts} +36 -16
  49. package/lib/Alchemist/State.d.ts.map +1 -0
  50. package/lib/Alchemist/{routes/state.js → State.js} +50 -15
  51. package/lib/Alchemist/State.js.map +1 -0
  52. package/lib/Alchemist/index.d.ts +11 -10
  53. package/lib/Alchemist/index.d.ts.map +1 -1
  54. package/lib/Alchemist/index.js +10 -9
  55. package/lib/Alchemist/index.js.map +1 -1
  56. package/lib/Apply.d.ts +2 -8
  57. package/lib/Apply.d.ts.map +1 -1
  58. package/lib/Apply.js +364 -184
  59. package/lib/Apply.js.map +1 -1
  60. package/lib/Auth/AuthProvider.d.ts +24 -11
  61. package/lib/Auth/AuthProvider.d.ts.map +1 -1
  62. package/lib/Auth/AuthProvider.js +28 -12
  63. package/lib/Auth/AuthProvider.js.map +1 -1
  64. package/lib/Auth/BrowserOAuth.d.ts +6 -8
  65. package/lib/Auth/BrowserOAuth.d.ts.map +1 -1
  66. package/lib/Auth/BrowserOAuth.js +25 -41
  67. package/lib/Auth/BrowserOAuth.js.map +1 -1
  68. package/lib/Auth/Credentials.d.ts.map +1 -1
  69. package/lib/Auth/Credentials.js +2 -2
  70. package/lib/Auth/Credentials.js.map +1 -1
  71. package/lib/Auth/Demand.d.ts +4 -4
  72. package/lib/Auth/Demand.d.ts.map +1 -1
  73. package/lib/Auth/Demand.js +16 -10
  74. package/lib/Auth/Demand.js.map +1 -1
  75. package/lib/Auth/Env.d.ts +2 -1
  76. package/lib/Auth/Env.d.ts.map +1 -1
  77. package/lib/Auth/Env.js +4 -2
  78. package/lib/Auth/Env.js.map +1 -1
  79. package/lib/Auth/Inspect.d.ts +2 -2
  80. package/lib/Auth/Inspect.d.ts.map +1 -1
  81. package/lib/Auth/Inspect.js +3 -1
  82. package/lib/Auth/Inspect.js.map +1 -1
  83. package/lib/Auth/Lock.d.ts.map +1 -1
  84. package/lib/Auth/Lock.js +4 -8
  85. package/lib/Auth/Lock.js.map +1 -1
  86. package/lib/Auth/OAuthFlow.d.ts +3 -12
  87. package/lib/Auth/OAuthFlow.d.ts.map +1 -1
  88. package/lib/Auth/OAuthFlow.js +7 -17
  89. package/lib/Auth/OAuthFlow.js.map +1 -1
  90. package/lib/Auth/Paths.d.ts +2 -1
  91. package/lib/Auth/Paths.d.ts.map +1 -1
  92. package/lib/Auth/Paths.js +3 -2
  93. package/lib/Auth/Paths.js.map +1 -1
  94. package/lib/Auth/Profile.d.ts +10 -0
  95. package/lib/Auth/Profile.d.ts.map +1 -1
  96. package/lib/Auth/Profile.js +19 -2
  97. package/lib/Auth/Profile.js.map +1 -1
  98. package/lib/Auth/Registry.d.ts +20 -0
  99. package/lib/Auth/Registry.d.ts.map +1 -0
  100. package/lib/Auth/Registry.js +17 -0
  101. package/lib/Auth/Registry.js.map +1 -0
  102. package/lib/Auth/Resolve.d.ts +34 -2
  103. package/lib/Auth/Resolve.d.ts.map +1 -1
  104. package/lib/Auth/Resolve.js +51 -3
  105. package/lib/Auth/Resolve.js.map +1 -1
  106. package/lib/Auth/StoredAuthProvider.d.ts +1 -1
  107. package/lib/Auth/StoredAuthProvider.d.ts.map +1 -1
  108. package/lib/Auth/StoredAuthProvider.js +1 -2
  109. package/lib/Auth/StoredAuthProvider.js.map +1 -1
  110. package/lib/Binding.d.ts.map +1 -1
  111. package/lib/Binding.js +3 -1
  112. package/lib/Binding.js.map +1 -1
  113. package/lib/Bundle/Bundle.d.ts +5 -0
  114. package/lib/Bundle/Bundle.d.ts.map +1 -1
  115. package/lib/Bundle/Bundle.js +36 -6
  116. package/lib/Bundle/Bundle.js.map +1 -1
  117. package/lib/Bundle/NamespaceImportPlugin.d.ts +55 -0
  118. package/lib/Bundle/NamespaceImportPlugin.d.ts.map +1 -0
  119. package/lib/Bundle/NamespaceImportPlugin.js +226 -0
  120. package/lib/Bundle/NamespaceImportPlugin.js.map +1 -0
  121. package/lib/Bundle/index.d.ts +1 -0
  122. package/lib/Bundle/index.d.ts.map +1 -1
  123. package/lib/Bundle/index.js +1 -0
  124. package/lib/Bundle/index.js.map +1 -1
  125. package/lib/Cli/Format.d.ts.map +1 -1
  126. package/lib/Cli/Format.js +2 -1
  127. package/lib/Cli/Format.js.map +1 -1
  128. package/lib/Cli/GlobalLog.d.ts +72 -26
  129. package/lib/Cli/GlobalLog.d.ts.map +1 -1
  130. package/lib/Cli/GlobalLog.js +151 -59
  131. package/lib/Cli/GlobalLog.js.map +1 -1
  132. package/lib/Cli/LoggingCli.d.ts.map +1 -1
  133. package/lib/Cli/LoggingCli.js +24 -18
  134. package/lib/Cli/LoggingCli.js.map +1 -1
  135. package/lib/Cli/PlainCliFormatter.d.ts.map +1 -1
  136. package/lib/Cli/PlainCliFormatter.js +4 -1
  137. package/lib/Cli/PlainCliFormatter.js.map +1 -1
  138. package/lib/Cli/Present.d.ts +14 -0
  139. package/lib/Cli/Present.d.ts.map +1 -0
  140. package/lib/Cli/Present.js +22 -0
  141. package/lib/Cli/Present.js.map +1 -0
  142. package/lib/Cli/SigilRenderer.d.ts +58 -0
  143. package/lib/Cli/SigilRenderer.d.ts.map +1 -0
  144. package/lib/Cli/SigilRenderer.js +39 -0
  145. package/lib/Cli/SigilRenderer.js.map +1 -0
  146. package/lib/Cli/checkVersion.d.ts +11 -14
  147. package/lib/Cli/checkVersion.d.ts.map +1 -1
  148. package/lib/Cli/checkVersion.js +19 -77
  149. package/lib/Cli/checkVersion.js.map +1 -1
  150. package/lib/Cli/commands/confirm.d.ts +2 -2
  151. package/lib/Cli/commands/confirm.d.ts.map +1 -1
  152. package/lib/Cli/commands/confirm.js +3 -3
  153. package/lib/Cli/commands/confirm.js.map +1 -1
  154. package/lib/Cli/commands/deploy.d.ts +4 -4
  155. package/lib/Cli/commands/deploy.d.ts.map +1 -1
  156. package/lib/Cli/commands/deploy.js +40 -39
  157. package/lib/Cli/commands/deploy.js.map +1 -1
  158. package/lib/Cli/commands/dev.d.ts.map +1 -1
  159. package/lib/Cli/commands/dev.js +41 -3
  160. package/lib/Cli/commands/dev.js.map +1 -1
  161. package/lib/Cli/commands/drift.d.ts +2 -2
  162. package/lib/Cli/commands/drift.d.ts.map +1 -1
  163. package/lib/Cli/commands/drift.js +14 -13
  164. package/lib/Cli/commands/drift.js.map +1 -1
  165. package/lib/Cli/commands/errors.d.ts.map +1 -1
  166. package/lib/Cli/commands/errors.js +2 -1
  167. package/lib/Cli/commands/errors.js.map +1 -1
  168. package/lib/Cli/commands/instrument.d.ts +15 -5
  169. package/lib/Cli/commands/instrument.d.ts.map +1 -1
  170. package/lib/Cli/commands/instrument.js +33 -8
  171. package/lib/Cli/commands/instrument.js.map +1 -1
  172. package/lib/Cli/commands/logs.d.ts +1 -1
  173. package/lib/Cli/commands/logs.d.ts.map +1 -1
  174. package/lib/Cli/commands/logs.js +22 -22
  175. package/lib/Cli/commands/logs.js.map +1 -1
  176. package/lib/Cli/commands/nuke.d.ts +3 -2
  177. package/lib/Cli/commands/nuke.d.ts.map +1 -1
  178. package/lib/Cli/commands/nuke.js +19 -17
  179. package/lib/Cli/commands/nuke.js.map +1 -1
  180. package/lib/Cli/commands/profile/commands.d.ts +3 -2
  181. package/lib/Cli/commands/profile/commands.d.ts.map +1 -1
  182. package/lib/Cli/commands/profile/commands.js +26 -27
  183. package/lib/Cli/commands/profile/commands.js.map +1 -1
  184. package/lib/Cli/commands/profile/flows.d.ts +6 -5
  185. package/lib/Cli/commands/profile/flows.d.ts.map +1 -1
  186. package/lib/Cli/commands/profile/flows.js +19 -17
  187. package/lib/Cli/commands/profile/flows.js.map +1 -1
  188. package/lib/Cli/commands/profile/hub.d.ts +1 -2
  189. package/lib/Cli/commands/profile/hub.d.ts.map +1 -1
  190. package/lib/Cli/commands/profile/hub.js +15 -17
  191. package/lib/Cli/commands/profile/hub.js.map +1 -1
  192. package/lib/Cli/commands/provider.d.ts +3 -1
  193. package/lib/Cli/commands/provider.d.ts.map +1 -1
  194. package/lib/Cli/commands/provider.js +4 -4
  195. package/lib/Cli/commands/provider.js.map +1 -1
  196. package/lib/Cli/commands/render.d.ts +2 -4
  197. package/lib/Cli/commands/render.d.ts.map +1 -1
  198. package/lib/Cli/commands/render.js +33 -56
  199. package/lib/Cli/commands/render.js.map +1 -1
  200. package/lib/Cli/commands/state.d.ts +1 -2
  201. package/lib/Cli/commands/state.d.ts.map +1 -1
  202. package/lib/Cli/commands/state.js +74 -27
  203. package/lib/Cli/commands/state.js.map +1 -1
  204. package/lib/Cli/components/capabilities.d.ts +4 -0
  205. package/lib/Cli/components/capabilities.d.ts.map +1 -0
  206. package/lib/Cli/components/capabilities.js +18 -0
  207. package/lib/Cli/components/capabilities.js.map +1 -0
  208. package/lib/Cli/components/types.d.ts +2 -81
  209. package/lib/Cli/components/types.d.ts.map +1 -1
  210. package/lib/Cli/components/types.js +1 -3
  211. package/lib/Cli/components/types.js.map +1 -1
  212. package/lib/Cli/components/ui/Environment.d.ts +3 -3
  213. package/lib/Cli/components/ui/Environment.d.ts.map +1 -1
  214. package/lib/Cli/components/ui/Environment.js.map +1 -1
  215. package/lib/Cli/components/ui/Interactive.d.ts +17 -4
  216. package/lib/Cli/components/ui/Interactive.d.ts.map +1 -1
  217. package/lib/Cli/components/ui/Interactive.js +7 -11
  218. package/lib/Cli/components/ui/Interactive.js.map +1 -1
  219. package/lib/Cli/components/ui/Layout.d.ts +1 -1
  220. package/lib/Cli/components/ui/Layout.d.ts.map +1 -1
  221. package/lib/Cli/components/ui/Layout.js +1 -1
  222. package/lib/Cli/components/ui/Layout.js.map +1 -1
  223. package/lib/Cli/components/ui/Typography.d.ts +1 -1
  224. package/lib/Cli/components/ui/Typography.d.ts.map +1 -1
  225. package/lib/Cli/components/ui/Typography.js +1 -1
  226. package/lib/Cli/components/ui/Typography.js.map +1 -1
  227. package/lib/Cli/components/ui/index.d.ts +2 -2
  228. package/lib/Cli/components/ui/index.js +2 -2
  229. package/lib/Cli/components/view/ApprovePlan.d.ts +1 -1
  230. package/lib/Cli/components/view/ApprovePlan.d.ts.map +1 -1
  231. package/lib/Cli/components/view/ApprovePlan.js +2 -1
  232. package/lib/Cli/components/view/ApprovePlan.js.map +1 -1
  233. package/lib/Cli/components/view/Format.d.ts +5 -0
  234. package/lib/Cli/components/view/Format.d.ts.map +1 -0
  235. package/lib/Cli/components/view/Format.js +39 -0
  236. package/lib/Cli/components/view/Format.js.map +1 -0
  237. package/lib/Cli/components/view/Help.d.ts +2 -2
  238. package/lib/Cli/components/view/Help.d.ts.map +1 -1
  239. package/lib/Cli/components/view/Help.js +7 -5
  240. package/lib/Cli/components/view/Help.js.map +1 -1
  241. package/lib/Cli/components/view/Logo.js +1 -1
  242. package/lib/Cli/components/view/Logo.js.map +1 -1
  243. package/lib/Cli/components/view/Nuke.d.ts +8 -9
  244. package/lib/Cli/components/view/Nuke.d.ts.map +1 -1
  245. package/lib/Cli/components/view/Nuke.js +49 -52
  246. package/lib/Cli/components/view/Nuke.js.map +1 -1
  247. package/lib/Cli/components/view/PlanDecision.d.ts +1 -1
  248. package/lib/Cli/components/view/PlanDecision.d.ts.map +1 -1
  249. package/lib/Cli/components/view/PlanDecision.js +1 -1
  250. package/lib/Cli/components/view/PlanDecision.js.map +1 -1
  251. package/lib/Cli/components/view/PlanRow.js +1 -1
  252. package/lib/Cli/components/view/PlanRow.js.map +1 -1
  253. package/lib/Cli/components/view/PlanTree.d.ts +1 -1
  254. package/lib/Cli/components/view/PlanTree.d.ts.map +1 -1
  255. package/lib/Cli/components/view/PlanTree.js +1 -1
  256. package/lib/Cli/components/view/PlanView.js +1 -1
  257. package/lib/Cli/components/view/PlanView.js.map +1 -1
  258. package/lib/Cli/components/view/Profile.d.ts +1 -1
  259. package/lib/Cli/components/view/Profile.js +2 -2
  260. package/lib/Cli/components/view/Profile.js.map +1 -1
  261. package/lib/Cli/components/view/ProfileDashboard.d.ts +4 -4
  262. package/lib/Cli/components/view/ProfileDashboard.d.ts.map +1 -1
  263. package/lib/Cli/components/view/ProfileDashboard.js +9 -8
  264. package/lib/Cli/components/view/ProfileDashboard.js.map +1 -1
  265. package/lib/Cli/components/view/Prompts.d.ts +3 -3
  266. package/lib/Cli/components/view/Prompts.d.ts.map +1 -1
  267. package/lib/Cli/components/view/Prompts.js +11 -18
  268. package/lib/Cli/components/view/Prompts.js.map +1 -1
  269. package/lib/Cli/components/view/Runtime.d.ts +5 -5
  270. package/lib/Cli/components/view/Runtime.d.ts.map +1 -1
  271. package/lib/Cli/components/view/Runtime.js +136 -219
  272. package/lib/Cli/components/view/Runtime.js.map +1 -1
  273. package/lib/Cli/components/view/SigilCli.d.ts +2 -2
  274. package/lib/Cli/components/view/SigilCli.d.ts.map +1 -1
  275. package/lib/Cli/components/view/SigilCli.js +7 -7
  276. package/lib/Cli/components/view/SigilCli.js.map +1 -1
  277. package/lib/Cli/components/view/StateExplorer.d.ts +1 -1
  278. package/lib/Cli/components/view/StateExplorer.d.ts.map +1 -1
  279. package/lib/Cli/components/view/StateExplorer.js +2 -1
  280. package/lib/Cli/components/view/StateExplorer.js.map +1 -1
  281. package/lib/Cli/components/view/statusStyle.d.ts +2 -2
  282. package/lib/Cli/components/view/statusStyle.d.ts.map +1 -1
  283. package/lib/Cli/components/view/statusStyle.js +1 -1
  284. package/lib/Cli/components/view/statusStyle.js.map +1 -1
  285. package/lib/Cli/exec.d.ts +6 -1
  286. package/lib/Cli/exec.d.ts.map +1 -1
  287. package/lib/Cli/exec.js +29 -34
  288. package/lib/Cli/exec.js.map +1 -1
  289. package/lib/Cli/main.d.ts.map +1 -1
  290. package/lib/Cli/main.js +35 -26
  291. package/lib/Cli/main.js.map +1 -1
  292. package/lib/Cli/selectCli.d.ts +2 -2
  293. package/lib/Cli/selectCli.d.ts.map +1 -1
  294. package/lib/Cli/selectCli.js +2 -2
  295. package/lib/Cli/selectCli.js.map +1 -1
  296. package/lib/Command/Command.js +1 -1
  297. package/lib/Command/Command.js.map +1 -1
  298. package/lib/Command/Dev.d.ts +58 -4
  299. package/lib/Command/Dev.d.ts.map +1 -1
  300. package/lib/Command/Dev.js +87 -30
  301. package/lib/Command/Dev.js.map +1 -1
  302. package/lib/Command/Local.d.ts +1 -1
  303. package/lib/Command/Memo.js +1 -1
  304. package/lib/Command/Memo.js.map +1 -1
  305. package/lib/Command/Providers.d.ts +1 -1
  306. package/lib/Command/Providers.d.ts.map +1 -1
  307. package/lib/Contributions.d.ts +2 -3
  308. package/lib/Contributions.d.ts.map +1 -1
  309. package/lib/Contributions.js +38 -6
  310. package/lib/Contributions.js.map +1 -1
  311. package/lib/DNS/Adapter.d.ts +204 -0
  312. package/lib/DNS/Adapter.d.ts.map +1 -0
  313. package/lib/DNS/Adapter.js +112 -0
  314. package/lib/DNS/Adapter.js.map +1 -0
  315. package/lib/DNS/index.d.ts +2 -0
  316. package/lib/DNS/index.d.ts.map +1 -0
  317. package/lib/DNS/index.js +2 -0
  318. package/lib/DNS/index.js.map +1 -0
  319. package/lib/Deploy.d.ts +7 -2
  320. package/lib/Deploy.d.ts.map +1 -1
  321. package/lib/Deploy.js +8 -3
  322. package/lib/Deploy.js.map +1 -1
  323. package/lib/Destroy.d.ts +5 -8
  324. package/lib/Destroy.d.ts.map +1 -1
  325. package/lib/Destroy.js +10 -7
  326. package/lib/Destroy.js.map +1 -1
  327. package/lib/Diff.d.ts.map +1 -1
  328. package/lib/Diff.js +14 -4
  329. package/lib/Diff.js.map +1 -1
  330. package/lib/Drift.d.ts +7 -7
  331. package/lib/Drift.d.ts.map +1 -1
  332. package/lib/Drift.js +184 -101
  333. package/lib/Drift.js.map +1 -1
  334. package/lib/EvalStack.d.ts +23 -0
  335. package/lib/EvalStack.d.ts.map +1 -0
  336. package/lib/EvalStack.js +47 -0
  337. package/lib/EvalStack.js.map +1 -0
  338. package/lib/Events.d.ts +210 -0
  339. package/lib/Events.d.ts.map +1 -0
  340. package/lib/Events.js +244 -0
  341. package/lib/Events.js.map +1 -0
  342. package/lib/Interaction.d.ts +159 -48
  343. package/lib/Interaction.d.ts.map +1 -1
  344. package/lib/Interaction.js +139 -58
  345. package/lib/Interaction.js.map +1 -1
  346. package/lib/Local/LocalProvider.d.ts.map +1 -1
  347. package/lib/Local/LocalProvider.js +31 -9
  348. package/lib/Local/LocalProvider.js.map +1 -1
  349. package/lib/Local/RpcProvider.d.ts.map +1 -1
  350. package/lib/Local/RpcProvider.js +10 -1
  351. package/lib/Local/RpcProvider.js.map +1 -1
  352. package/lib/Local/RpcProviderProxy.d.ts +16 -0
  353. package/lib/Local/RpcProviderProxy.d.ts.map +1 -1
  354. package/lib/Local/RpcProviderProxy.js +19 -10
  355. package/lib/Local/RpcProviderProxy.js.map +1 -1
  356. package/lib/Local/RpcSerialization.d.ts +3 -2
  357. package/lib/Local/RpcSerialization.d.ts.map +1 -1
  358. package/lib/Local/RpcSerialization.js +13 -10
  359. package/lib/Local/RpcSerialization.js.map +1 -1
  360. package/lib/Local/RpcServer.d.ts +2 -1
  361. package/lib/Local/RpcServer.d.ts.map +1 -1
  362. package/lib/Local/RpcServer.js +19 -14
  363. package/lib/Local/RpcServer.js.map +1 -1
  364. package/lib/Local/RpcServerBun.d.ts.map +1 -1
  365. package/lib/Local/RpcServerBun.js +8 -4
  366. package/lib/Local/RpcServerBun.js.map +1 -1
  367. package/lib/Local/RpcServerEnvironment.d.ts +2 -3
  368. package/lib/Local/RpcServerEnvironment.d.ts.map +1 -1
  369. package/lib/Local/RpcServerEnvironment.js +2 -2
  370. package/lib/Local/RpcServerEnvironment.js.map +1 -1
  371. package/lib/Local/RpcServerNode.d.ts.map +1 -1
  372. package/lib/Local/RpcServerNode.js +5 -1
  373. package/lib/Local/RpcServerNode.js.map +1 -1
  374. package/lib/Local/RpcServerSession.d.ts +1 -1
  375. package/lib/Local/RpcServerSession.d.ts.map +1 -1
  376. package/lib/Local/RpcServerSession.js.map +1 -1
  377. package/lib/Local/RpcSpawner.d.ts +6 -8
  378. package/lib/Local/RpcSpawner.d.ts.map +1 -1
  379. package/lib/Local/RpcSpawner.js +45 -36
  380. package/lib/Local/RpcSpawner.js.map +1 -1
  381. package/lib/Local/Sidecar.d.ts +23 -0
  382. package/lib/Local/Sidecar.d.ts.map +1 -1
  383. package/lib/Local/Sidecar.js +14 -9
  384. package/lib/Local/Sidecar.js.map +1 -1
  385. package/lib/Nuke.d.ts +5 -23
  386. package/lib/Nuke.d.ts.map +1 -1
  387. package/lib/Nuke.js +48 -13
  388. package/lib/Nuke.js.map +1 -1
  389. package/lib/Output.d.ts +19 -1
  390. package/lib/Output.d.ts.map +1 -1
  391. package/lib/Output.js +96 -3
  392. package/lib/Output.js.map +1 -1
  393. package/lib/Plan.d.ts +5 -1
  394. package/lib/Plan.d.ts.map +1 -1
  395. package/lib/Plan.js +111 -33
  396. package/lib/Plan.js.map +1 -1
  397. package/lib/Platform.d.ts.map +1 -1
  398. package/lib/Platform.js +31 -7
  399. package/lib/Platform.js.map +1 -1
  400. package/lib/Provider.d.ts +45 -0
  401. package/lib/Provider.d.ts.map +1 -1
  402. package/lib/Provider.js +2 -2
  403. package/lib/Provider.js.map +1 -1
  404. package/lib/Report.d.ts +17 -195
  405. package/lib/Report.d.ts.map +1 -1
  406. package/lib/Report.js +39 -12
  407. package/lib/Report.js.map +1 -1
  408. package/lib/Runtime/ManagedHttpShutdown.d.ts +17 -0
  409. package/lib/Runtime/ManagedHttpShutdown.d.ts.map +1 -1
  410. package/lib/Runtime/ManagedHttpShutdown.js +11 -2
  411. package/lib/Runtime/ManagedHttpShutdown.js.map +1 -1
  412. package/lib/RuntimeContext.js +1 -1
  413. package/lib/RuntimeContext.js.map +1 -1
  414. package/lib/Stack.d.ts +49 -29
  415. package/lib/Stack.d.ts.map +1 -1
  416. package/lib/Stack.js +25 -31
  417. package/lib/Stack.js.map +1 -1
  418. package/lib/State/BucketState.d.ts.map +1 -1
  419. package/lib/State/BucketState.js +43 -14
  420. package/lib/State/BucketState.js.map +1 -1
  421. package/lib/State/LocalState.d.ts.map +1 -1
  422. package/lib/State/LocalState.js +3 -3
  423. package/lib/State/LocalState.js.map +1 -1
  424. package/lib/State/Provisioning.d.ts +5 -0
  425. package/lib/State/Provisioning.d.ts.map +1 -1
  426. package/lib/State/Provisioning.js +3 -1
  427. package/lib/State/Provisioning.js.map +1 -1
  428. package/lib/State/ResourceState.d.ts +2 -0
  429. package/lib/State/ResourceState.d.ts.map +1 -1
  430. package/lib/State/State.d.ts +26 -0
  431. package/lib/State/State.d.ts.map +1 -1
  432. package/lib/State/StateEncoding.d.ts +7 -0
  433. package/lib/State/StateEncoding.d.ts.map +1 -1
  434. package/lib/State/StateEncoding.js +19 -0
  435. package/lib/State/StateEncoding.js.map +1 -1
  436. package/lib/State/index.js +2 -2
  437. package/lib/State/index.js.map +1 -1
  438. package/lib/Telemetry/Layer.d.ts +2 -5
  439. package/lib/Telemetry/Layer.d.ts.map +1 -1
  440. package/lib/Telemetry/Layer.js +3 -23
  441. package/lib/Telemetry/Layer.js.map +1 -1
  442. package/lib/Telemetry/Metrics.d.ts +1 -1
  443. package/lib/Telemetry/Metrics.d.ts.map +1 -1
  444. package/lib/TelemetryRelay.js +1 -1
  445. package/lib/TelemetryRelay.js.map +1 -1
  446. package/lib/TelemetryRuntime.d.ts +1 -1
  447. package/lib/TelemetryRuntime.d.ts.map +1 -1
  448. package/lib/TelemetryRuntime.js +4 -3
  449. package/lib/TelemetryRuntime.js.map +1 -1
  450. package/lib/Util/ConsoleSink.d.ts +23 -2
  451. package/lib/Util/ConsoleSink.d.ts.map +1 -1
  452. package/lib/Util/ConsoleSink.js +54 -14
  453. package/lib/Util/ConsoleSink.js.map +1 -1
  454. package/lib/Util/LogAnnotation.d.ts +19 -0
  455. package/lib/Util/LogAnnotation.d.ts.map +1 -0
  456. package/lib/Util/LogAnnotation.js +19 -0
  457. package/lib/Util/LogAnnotation.js.map +1 -0
  458. package/lib/Util/LogRecord.d.ts +281 -0
  459. package/lib/Util/LogRecord.d.ts.map +1 -0
  460. package/lib/Util/LogRecord.js +267 -0
  461. package/lib/Util/LogRecord.js.map +1 -0
  462. package/lib/Util/Node.d.ts +9 -0
  463. package/lib/Util/Node.d.ts.map +1 -1
  464. package/lib/Util/Node.js +10 -6
  465. package/lib/Util/Node.js.map +1 -1
  466. package/lib/Util/PlatformServices.d.ts +3 -2
  467. package/lib/Util/PlatformServices.d.ts.map +1 -1
  468. package/lib/Util/PlatformServices.js +6 -2
  469. package/lib/Util/PlatformServices.js.map +1 -1
  470. package/lib/Util/ResourceOutput.d.ts +18 -10
  471. package/lib/Util/ResourceOutput.d.ts.map +1 -1
  472. package/lib/Util/ResourceOutput.js +22 -23
  473. package/lib/Util/ResourceOutput.js.map +1 -1
  474. package/lib/Util/Shutdown.d.ts +10 -0
  475. package/lib/Util/Shutdown.d.ts.map +1 -0
  476. package/lib/Util/Shutdown.js +32 -0
  477. package/lib/Util/Shutdown.js.map +1 -0
  478. package/lib/Util/Terminal.d.ts +2 -4
  479. package/lib/Util/Terminal.d.ts.map +1 -1
  480. package/lib/Util/Terminal.js +3 -11
  481. package/lib/Util/Terminal.js.map +1 -1
  482. package/lib/Util/TraceParent.d.ts +32 -0
  483. package/lib/Util/TraceParent.d.ts.map +1 -0
  484. package/lib/Util/TraceParent.js +42 -0
  485. package/lib/Util/TraceParent.js.map +1 -0
  486. package/lib/Util/base64.d.ts +7 -0
  487. package/lib/Util/base64.d.ts.map +1 -0
  488. package/lib/Util/base64.js +24 -0
  489. package/lib/Util/base64.js.map +1 -0
  490. package/lib/Util/cached-function.d.ts +5 -0
  491. package/lib/Util/cached-function.d.ts.map +1 -1
  492. package/lib/Util/cached-function.js +13 -8
  493. package/lib/Util/cached-function.js.map +1 -1
  494. package/lib/Util/data.d.ts +1 -1
  495. package/lib/Util/data.d.ts.map +1 -1
  496. package/lib/Util/data.js +1 -1
  497. package/lib/Util/data.js.map +1 -1
  498. package/lib/Util/equal.d.ts.map +1 -1
  499. package/lib/Util/equal.js +3 -2
  500. package/lib/Util/equal.js.map +1 -1
  501. package/lib/Util/extraFiles.d.ts.map +1 -1
  502. package/lib/Util/extraFiles.js +5 -5
  503. package/lib/Util/extraFiles.js.map +1 -1
  504. package/lib/Util/interactive.js +1 -1
  505. package/lib/Website/AstroOutput.d.ts +42 -0
  506. package/lib/Website/AstroOutput.d.ts.map +1 -0
  507. package/lib/Website/AstroOutput.js +34 -0
  508. package/lib/Website/AstroOutput.js.map +1 -0
  509. package/lib/Website/FrontendCore.d.ts +1 -1
  510. package/lib/Workflows.d.ts +9 -0
  511. package/lib/Workflows.d.ts.map +1 -1
  512. package/lib/Workflows.js +8 -0
  513. package/lib/Workflows.js.map +1 -1
  514. package/lib/index.d.ts +1 -0
  515. package/lib/index.d.ts.map +1 -1
  516. package/lib/index.js +1 -0
  517. package/lib/index.js.map +1 -1
  518. package/package.json +21 -28
  519. package/src/AdoptPolicy.ts +76 -0
  520. package/src/Alchemist/AuthRegistry.ts +164 -0
  521. package/src/Alchemist/Drift.ts +103 -0
  522. package/src/Alchemist/Entrypoint.ts +51 -3
  523. package/src/Alchemist/Errors.ts +1 -1
  524. package/src/Alchemist/{routes/logs.ts → Logs.ts} +28 -30
  525. package/src/Alchemist/Nuke.ts +90 -0
  526. package/src/Alchemist/Operations.ts +309 -0
  527. package/src/Alchemist/{routes/profile.ts → Profile.ts} +22 -22
  528. package/src/Alchemist/{routes/provider.ts → Provider.ts} +7 -6
  529. package/src/Alchemist/Runtime.ts +46 -12
  530. package/src/Alchemist/{routes/state.ts → State.ts} +78 -21
  531. package/src/Alchemist/index.ts +32 -15
  532. package/src/Apply.ts +513 -274
  533. package/src/Auth/AuthProvider.ts +76 -23
  534. package/src/Auth/BrowserOAuth.ts +37 -60
  535. package/src/Auth/Credentials.ts +2 -4
  536. package/src/Auth/Demand.ts +27 -18
  537. package/src/Auth/Env.ts +13 -8
  538. package/src/Auth/Inspect.ts +5 -2
  539. package/src/Auth/Lock.ts +4 -8
  540. package/src/Auth/OAuthFlow.ts +12 -26
  541. package/src/Auth/Paths.ts +3 -2
  542. package/src/Auth/Profile.ts +30 -2
  543. package/src/Auth/Registry.ts +27 -0
  544. package/src/Auth/Resolve.ts +75 -3
  545. package/src/Auth/StoredAuthProvider.ts +1 -2
  546. package/src/Binding.ts +3 -4
  547. package/src/Bundle/Bundle.ts +58 -7
  548. package/src/Bundle/NamespaceImportPlugin.ts +259 -0
  549. package/src/Bundle/index.ts +1 -0
  550. package/src/Cli/Format.ts +2 -1
  551. package/src/Cli/GlobalLog.ts +206 -68
  552. package/src/Cli/LoggingCli.ts +33 -20
  553. package/src/Cli/PlainCliFormatter.ts +4 -1
  554. package/src/Cli/Present.ts +34 -0
  555. package/src/Cli/SigilRenderer.ts +75 -0
  556. package/src/Cli/checkVersion.ts +25 -78
  557. package/src/Cli/commands/confirm.ts +3 -3
  558. package/src/Cli/commands/deploy.ts +53 -44
  559. package/src/Cli/commands/dev.ts +65 -7
  560. package/src/Cli/commands/drift.ts +20 -16
  561. package/src/Cli/commands/errors.ts +2 -3
  562. package/src/Cli/commands/instrument.ts +39 -8
  563. package/src/Cli/commands/logs.ts +22 -30
  564. package/src/Cli/commands/nuke.ts +25 -26
  565. package/src/Cli/commands/profile/commands.ts +34 -34
  566. package/src/Cli/commands/profile/flows.ts +26 -20
  567. package/src/Cli/commands/profile/hub.ts +16 -18
  568. package/src/Cli/commands/provider.ts +4 -4
  569. package/src/Cli/commands/render.ts +43 -71
  570. package/src/Cli/commands/state.ts +113 -33
  571. package/src/Cli/components/capabilities.ts +20 -0
  572. package/src/Cli/components/types.ts +13 -99
  573. package/src/Cli/components/ui/Environment.tsx +5 -5
  574. package/src/Cli/components/ui/Interactive.tsx +24 -15
  575. package/src/Cli/components/ui/Layout.tsx +1 -1
  576. package/src/Cli/components/ui/Typography.tsx +1 -1
  577. package/src/Cli/components/ui/index.ts +2 -2
  578. package/src/Cli/components/view/ApprovePlan.tsx +2 -1
  579. package/src/Cli/components/view/Format.tsx +58 -0
  580. package/src/Cli/components/view/Help.tsx +14 -17
  581. package/src/Cli/components/view/Logo.tsx +1 -1
  582. package/src/Cli/components/view/Nuke.tsx +74 -49
  583. package/src/Cli/components/view/PlanDecision.tsx +1 -1
  584. package/src/Cli/components/view/PlanRow.tsx +1 -1
  585. package/src/Cli/components/view/PlanTree.ts +2 -2
  586. package/src/Cli/components/view/PlanView.tsx +2 -2
  587. package/src/Cli/components/view/Profile.tsx +2 -2
  588. package/src/Cli/components/view/ProfileDashboard.tsx +12 -11
  589. package/src/Cli/components/view/Prompts.tsx +37 -75
  590. package/src/Cli/components/view/Runtime.tsx +132 -238
  591. package/src/Cli/components/view/SigilCli.tsx +12 -12
  592. package/src/Cli/components/view/StateExplorer.tsx +2 -1
  593. package/src/Cli/components/view/statusStyle.ts +2 -2
  594. package/src/Cli/exec.ts +48 -41
  595. package/src/Cli/main.ts +52 -33
  596. package/src/Cli/selectCli.ts +3 -3
  597. package/src/Command/Command.ts +1 -1
  598. package/src/Command/Dev.ts +129 -36
  599. package/src/Command/Memo.ts +1 -1
  600. package/src/Contributions.ts +42 -8
  601. package/src/DNS/Adapter.ts +289 -0
  602. package/src/DNS/index.ts +1 -0
  603. package/src/Deploy.ts +11 -3
  604. package/src/Destroy.ts +19 -13
  605. package/src/Diff.ts +17 -4
  606. package/src/Drift.ts +256 -127
  607. package/src/EvalStack.ts +97 -0
  608. package/src/Events.ts +296 -0
  609. package/src/Interaction.ts +332 -97
  610. package/src/Local/LocalProvider.ts +40 -9
  611. package/src/Local/RpcProvider.ts +11 -1
  612. package/src/Local/RpcProviderProxy.ts +29 -21
  613. package/src/Local/RpcSerialization.ts +32 -17
  614. package/src/Local/RpcServer.ts +25 -17
  615. package/src/Local/RpcServerBun.ts +10 -6
  616. package/src/Local/RpcServerEnvironment.ts +2 -2
  617. package/src/Local/RpcServerNode.ts +8 -1
  618. package/src/Local/RpcServerSession.ts +2 -2
  619. package/src/Local/RpcSpawner.ts +61 -37
  620. package/src/Local/Sidecar.ts +10 -1
  621. package/src/Nuke.ts +66 -43
  622. package/src/Output.ts +120 -7
  623. package/src/Plan.ts +140 -52
  624. package/src/Platform.ts +47 -18
  625. package/src/Provider.ts +48 -3
  626. package/src/Report.ts +77 -275
  627. package/src/Runtime/ManagedHttpShutdown.ts +21 -4
  628. package/src/RuntimeContext.ts +1 -1
  629. package/src/Stack.ts +113 -135
  630. package/src/State/BucketState.ts +53 -21
  631. package/src/State/LocalState.ts +7 -9
  632. package/src/State/Provisioning.ts +8 -1
  633. package/src/State/ResourceState.ts +2 -0
  634. package/src/State/State.ts +30 -0
  635. package/src/State/StateEncoding.ts +22 -0
  636. package/src/State/index.ts +2 -2
  637. package/src/Telemetry/Layer.ts +3 -24
  638. package/src/Telemetry/Metrics.ts +1 -1
  639. package/src/TelemetryRelay.ts +1 -1
  640. package/src/TelemetryRuntime.ts +8 -8
  641. package/src/Util/ConsoleSink.ts +76 -13
  642. package/src/Util/LogAnnotation.ts +18 -0
  643. package/src/Util/LogRecord.ts +386 -0
  644. package/src/Util/Node.ts +20 -6
  645. package/src/Util/PlatformServices.ts +17 -4
  646. package/src/Util/ResourceOutput.ts +26 -25
  647. package/src/Util/Shutdown.ts +52 -0
  648. package/src/Util/Terminal.ts +3 -20
  649. package/src/Util/TraceParent.ts +70 -0
  650. package/src/Util/base64.ts +22 -0
  651. package/src/Util/cached-function.ts +30 -19
  652. package/src/Util/data.ts +2 -2
  653. package/src/Util/equal.ts +3 -2
  654. package/src/Util/extraFiles.ts +9 -8
  655. package/src/Util/interactive.ts +1 -1
  656. package/src/Website/AstroOutput.ts +83 -0
  657. package/src/Workflows.ts +11 -0
  658. package/src/index.ts +1 -0
  659. package/lib/Alchemist/Progress.d.ts +0 -16
  660. package/lib/Alchemist/Progress.d.ts.map +0 -1
  661. package/lib/Alchemist/Progress.js +0 -123
  662. package/lib/Alchemist/Progress.js.map +0 -1
  663. package/lib/Alchemist/Session.d.ts +0 -116
  664. package/lib/Alchemist/Session.d.ts.map +0 -1
  665. package/lib/Alchemist/Session.js +0 -212
  666. package/lib/Alchemist/Session.js.map +0 -1
  667. package/lib/Alchemist/routes/drift.d.ts +0 -55
  668. package/lib/Alchemist/routes/drift.d.ts.map +0 -1
  669. package/lib/Alchemist/routes/drift.js +0 -52
  670. package/lib/Alchemist/routes/drift.js.map +0 -1
  671. package/lib/Alchemist/routes/logs.d.ts +0 -41
  672. package/lib/Alchemist/routes/logs.d.ts.map +0 -1
  673. package/lib/Alchemist/routes/logs.js.map +0 -1
  674. package/lib/Alchemist/routes/nuke.d.ts +0 -46
  675. package/lib/Alchemist/routes/nuke.d.ts.map +0 -1
  676. package/lib/Alchemist/routes/nuke.js +0 -80
  677. package/lib/Alchemist/routes/nuke.js.map +0 -1
  678. package/lib/Alchemist/routes/profile.d.ts +0 -133
  679. package/lib/Alchemist/routes/profile.d.ts.map +0 -1
  680. package/lib/Alchemist/routes/profile.js.map +0 -1
  681. package/lib/Alchemist/routes/provider.d.ts.map +0 -1
  682. package/lib/Alchemist/routes/provider.js.map +0 -1
  683. package/lib/Alchemist/routes/stack.d.ts +0 -95
  684. package/lib/Alchemist/routes/stack.d.ts.map +0 -1
  685. package/lib/Alchemist/routes/stack.js +0 -73
  686. package/lib/Alchemist/routes/stack.js.map +0 -1
  687. package/lib/Alchemist/routes/state.d.ts.map +0 -1
  688. package/lib/Alchemist/routes/state.js.map +0 -1
  689. package/lib/Cli/CliKit/CliKit.d.ts +0 -92
  690. package/lib/Cli/CliKit/CliKit.d.ts.map +0 -1
  691. package/lib/Cli/CliKit/CliKit.js +0 -27
  692. package/lib/Cli/CliKit/CliKit.js.map +0 -1
  693. package/lib/Cli/CliKit/index.d.ts +0 -9
  694. package/lib/Cli/CliKit/index.d.ts.map +0 -1
  695. package/lib/Cli/CliKit/index.js +0 -9
  696. package/lib/Cli/CliKit/index.js.map +0 -1
  697. package/lib/Cli/CliKit/interaction.d.ts +0 -13
  698. package/lib/Cli/CliKit/interaction.d.ts.map +0 -1
  699. package/lib/Cli/CliKit/interaction.js +0 -17
  700. package/lib/Cli/CliKit/interaction.js.map +0 -1
  701. package/lib/Cli/CliKit/layer.d.ts +0 -7
  702. package/lib/Cli/CliKit/layer.d.ts.map +0 -1
  703. package/lib/Cli/CliKit/layer.js +0 -33
  704. package/lib/Cli/CliKit/layer.js.map +0 -1
  705. package/lib/Local/DevLog.d.ts +0 -32
  706. package/lib/Local/DevLog.d.ts.map +0 -1
  707. package/lib/Local/DevLog.js +0 -112
  708. package/lib/Local/DevLog.js.map +0 -1
  709. package/lib/Test/Alchemy.d.ts +0 -79
  710. package/lib/Test/Alchemy.d.ts.map +0 -1
  711. package/lib/Test/Alchemy.js +0 -193
  712. package/lib/Test/Alchemy.js.map +0 -1
  713. package/lib/Test/Bun.d.ts +0 -69
  714. package/lib/Test/Bun.d.ts.map +0 -1
  715. package/lib/Test/Bun.js +0 -126
  716. package/lib/Test/Bun.js.map +0 -1
  717. package/lib/Test/Core.d.ts +0 -277
  718. package/lib/Test/Core.d.ts.map +0 -1
  719. package/lib/Test/Core.js +0 -362
  720. package/lib/Test/Core.js.map +0 -1
  721. package/lib/Test/Http.d.ts +0 -109
  722. package/lib/Test/Http.d.ts.map +0 -1
  723. package/lib/Test/Http.js +0 -123
  724. package/lib/Test/Http.js.map +0 -1
  725. package/lib/Test/TestState.d.ts +0 -12
  726. package/lib/Test/TestState.d.ts.map +0 -1
  727. package/lib/Test/TestState.js +0 -15
  728. package/lib/Test/TestState.js.map +0 -1
  729. package/lib/Test/Vitest.d.ts +0 -60
  730. package/lib/Test/Vitest.d.ts.map +0 -1
  731. package/lib/Test/Vitest.js +0 -132
  732. package/lib/Test/Vitest.js.map +0 -1
  733. package/lib/Test/index.d.ts +0 -3
  734. package/lib/Test/index.d.ts.map +0 -1
  735. package/lib/Test/index.js +0 -3
  736. package/lib/Test/index.js.map +0 -1
  737. package/lib/Util/FileLogger.d.ts +0 -7
  738. package/lib/Util/FileLogger.d.ts.map +0 -1
  739. package/lib/Util/FileLogger.js +0 -16
  740. package/lib/Util/FileLogger.js.map +0 -1
  741. package/src/Alchemist/Progress.ts +0 -167
  742. package/src/Alchemist/Session.ts +0 -415
  743. package/src/Alchemist/routes/drift.ts +0 -87
  744. package/src/Alchemist/routes/nuke.ts +0 -131
  745. package/src/Alchemist/routes/stack.ts +0 -173
  746. package/src/Cli/CliKit/CliKit.ts +0 -159
  747. package/src/Cli/CliKit/index.ts +0 -41
  748. package/src/Cli/CliKit/interaction.ts +0 -19
  749. package/src/Cli/CliKit/layer.ts +0 -44
  750. package/src/Local/DevLog.ts +0 -122
  751. package/src/Test/Alchemy.ts +0 -334
  752. package/src/Test/Bun.ts +0 -230
  753. package/src/Test/Core.ts +0 -785
  754. package/src/Test/Http.ts +0 -201
  755. package/src/Test/TestState.ts +0 -35
  756. package/src/Test/Vitest.ts +0 -239
  757. package/src/Test/index.ts +0 -2
  758. package/src/Util/FileLogger.ts +0 -20
package/src/Apply.ts CHANGED
@@ -3,7 +3,7 @@ import type { ConfigError } from "effect/Config";
3
3
  import * as Data from "effect/Data";
4
4
  import * as Deferred from "effect/Deferred";
5
5
  import * as Effect from "effect/Effect";
6
- import * as Exit from "effect/Exit";
6
+ import * as Formatter from "effect/Formatter";
7
7
  import * as Layer from "effect/Layer";
8
8
  import * as Option from "effect/Option";
9
9
  import type { PlatformError } from "effect/PlatformError";
@@ -11,7 +11,13 @@ import * as Predicate from "effect/Predicate";
11
11
  import type { Simplify } from "effect/Types";
12
12
  import type { ActionLike } from "./Action.ts";
13
13
  import { makeResolveContext } from "./ActionRuntimeContext.ts";
14
- import { OwnedBySomeoneElse, stripUnowned, Unowned } from "./AdoptPolicy.ts";
14
+ import {
15
+ OwnedBySomeoneElse,
16
+ stripUnowned,
17
+ Unowned,
18
+ Unresolved,
19
+ UnverifiableReplacement,
20
+ } from "./AdoptPolicy.ts";
15
21
  import { AlchemyContext } from "./AlchemyContext.ts";
16
22
  import {
17
23
  Artifacts,
@@ -26,26 +32,21 @@ import {
26
32
  failCredentialsRequired,
27
33
  demandPlanCredentials,
28
34
  } from "./Auth/Demand.ts";
29
- import { havePropsChanged, stripUnresolved } from "./Diff.ts";
35
+ import { havePropsChanged, isResolved, stripEffects, stripUnresolved } from "./Diff.ts";
36
+ import { captureEmit, type ApplyEvent, type ApplyStatus } from "./Events.ts";
30
37
  import type { Input } from "./Input.ts";
31
38
  import { generateInstanceId } from "./InstanceId.ts";
32
39
  import * as Output from "./Output.ts";
33
40
  import { type ActionApply, type Apply, type Delete, type Plan } from "./Plan.ts";
34
41
  import {
35
42
  type DeleteInProgress,
43
+ type ProviderService,
36
44
  findProviderByType,
37
45
  missingProviderError,
38
46
  tryFindProviderByType,
39
47
  } from "./Provider.ts";
40
48
  import { stampedMode, type ProviderMode } from "./ProviderMode.ts";
41
- import {
42
- type PlanDisplayOptions,
43
- type PlanStatusSession,
44
- type ScopedPlanStatusSession,
45
- Cli,
46
- noopSession,
47
- } from "./Report.ts";
48
- import type { ApplyStatus } from "./Report.ts";
49
+ import { resourceSession } from "./Report.ts";
49
50
  import type { ResourceBinding } from "./Resource.ts";
50
51
  import { ResourceContext } from "./ResourceContext.ts";
51
52
  import { RuntimeContext } from "./RuntimeContext.ts";
@@ -70,19 +71,20 @@ import {
70
71
  StateStoreError,
71
72
  } from "./State/index.ts";
72
73
  import { type ResourceOp, recordResourceOp } from "./Telemetry/Metrics.ts";
74
+ import { LogAnnotation } from "./Util/LogAnnotation.ts";
73
75
  import { hashInput } from "./Util/sha256.ts";
74
76
 
75
77
  export type AppliedPlan<P extends Plan> = {
76
- [id in keyof P["resources"]]: P["resources"][id] extends Delete | undefined | never
78
+ [id in keyof P["resources"]]: P["resources"][id] extends Delete | undefined
77
79
  ? never
78
80
  : Simplify<P["resources"][id]["resource"]["attr"]>;
79
81
  };
80
82
 
81
- export interface ApplyOptions {
82
- planDisplay?: PlanDisplayOptions;
83
- /** Structured event sink for non-CLI callers. */
84
- session?: PlanStatusSession;
85
- }
83
+ /**
84
+ * Where the engine reports apply progress. Every event goes out as a log
85
+ * record; renderers observe them with `onEvent`.
86
+ */
87
+ type Reporter = (event: ApplyEvent) => Effect.Effect<void>;
86
88
 
87
89
  interface ResourceTracker {
88
90
  output: any;
@@ -107,6 +109,26 @@ const track = (
107
109
  outputs[fqn] = entry.output;
108
110
  };
109
111
 
112
+ /**
113
+ * Whether an attr-less checkpoint lost props to `stripUnresolved`. Its stored
114
+ * props no longer identify the physical resource it was creating (e.g. a
115
+ * stripped namespace makes a name match a different resource), so recovery
116
+ * must not look the resource up from them.
117
+ *
118
+ * Effect-valued props don't count: `Output.evaluate` passes them through
119
+ * untouched, so even fully resolved props carry them (a Function's runtime
120
+ * wiring). They never name a physical resource, and treating them as holes
121
+ * would mark every create of such a resource and orphan it on interruption.
122
+ */
123
+ const propsIncomplete = (value: {
124
+ attr?: unknown;
125
+ props?: unknown;
126
+ propsIncomplete?: true;
127
+ }): true | undefined =>
128
+ value.attr === undefined && (value.propsIncomplete || !isResolved(stripEffects(value.props)))
129
+ ? true
130
+ : undefined;
131
+
110
132
  const provideLifecycleScope =
111
133
  (resource: ResourceContext["Service"]) =>
112
134
  <A, E, R>(effect: Effect.Effect<A, E, R>) =>
@@ -138,6 +160,8 @@ const instrumentLifecycle =
138
160
  <A, E, R>(effect: Effect.Effect<A, E, R>) =>
139
161
  effect.pipe(
140
162
  provideLifecycleScope({ logicalId, fqn, instanceId, type: resourceType }),
163
+ // Every log a provider writes during the op carries its resource.
164
+ Effect.annotateLogs(LogAnnotation.fqn, fqn),
141
165
  recordResourceOp(resourceType, op),
142
166
  Effect.withSpan(`provider.${op}`, {
143
167
  attributes: {
@@ -150,9 +174,92 @@ const instrumentLifecycle =
150
174
  }),
151
175
  );
152
176
 
177
+ type AdmissionNode = {
178
+ provider: Pick<ProviderService<any>, "observe" | "read">;
179
+ props: any;
180
+ deferredAdoption?: { adopt: boolean };
181
+ resource: { Type: string };
182
+ };
183
+
184
+ /**
185
+ * A dependency cycle precreates on raw props, before `read` can check
186
+ * ownership. Ask the provider's `observe` what exists at the identity
187
+ * precreate would claim, and refuse a foreign resource unless adoption is
188
+ * allowed. A provider without `observe` precreates `unchecked`; one whose
189
+ * identity has not resolved yet reports it `unresolved`, so the engine must
190
+ * check the resolved identity before reconcile claims it.
191
+ */
192
+ const observeBeforePrecreate = Effect.fn(function* (
193
+ node: AdmissionNode,
194
+ news: any,
195
+ fqn: string,
196
+ logicalId: string,
197
+ instanceId: string,
198
+ previous?: any,
199
+ ) {
200
+ if (node.provider.observe === undefined || node.deferredAdoption === undefined) {
201
+ return "unchecked" as const;
202
+ }
203
+ const observed = yield* node.provider
204
+ .observe({ id: logicalId, fqn, instanceId, news, previous })
205
+ .pipe(instrumentLifecycle("observe", fqn, node.resource.Type, logicalId, instanceId));
206
+ if (observed === Unresolved) return "unresolved" as const;
207
+ if (observed !== undefined && Unowned.is(observed) && !node.deferredAdoption.adopt) {
208
+ return yield* new OwnedBySomeoneElse({
209
+ message:
210
+ `Cannot pre-create resource '${fqn}' (${node.resource.Type}): ` +
211
+ "it exists in the cloud but is not owned by this " +
212
+ "stack/stage/logical-id. Re-run with `--adopt` (or " +
213
+ "wrap the effect in `adopt(true)`) to take it over.",
214
+ resourceType: node.resource.Type,
215
+ logicalId,
216
+ });
217
+ }
218
+ return "admitted" as const;
219
+ });
220
+
221
+ /** A provider's `observe` reported `Unresolved` for fully resolved props. */
222
+ class UnresolvedObservation extends Data.TaggedError("UnresolvedObservation")<{
223
+ message: string;
224
+ }> {}
225
+
226
+ /**
227
+ * Reports what exists at the resolved identity reconcile will claim: `read`
228
+ * when the provider implements it, `observe` otherwise. A replacement passes
229
+ * its `previous` generation's attributes, so the provider can recognize it.
230
+ */
231
+ const observeResolved = Effect.fn(function* (
232
+ node: AdmissionNode,
233
+ news: Record<string, any>,
234
+ fqn: string,
235
+ logicalId: string,
236
+ instanceId: string,
237
+ previous?: any,
238
+ ) {
239
+ if (node.provider.read) {
240
+ return yield* node.provider
241
+ .read({ id: logicalId, fqn, instanceId, olds: news, output: undefined, previous })
242
+ .pipe(instrumentLifecycle("read", fqn, node.resource.Type, logicalId, instanceId));
243
+ }
244
+ const observed = yield* node.provider.observe!({
245
+ id: logicalId,
246
+ fqn,
247
+ instanceId,
248
+ news,
249
+ previous,
250
+ }).pipe(instrumentLifecycle("observe", fqn, node.resource.Type, logicalId, instanceId));
251
+ if (observed === Unresolved) {
252
+ return yield* Effect.die(
253
+ new UnresolvedObservation({
254
+ message: `The provider for '${fqn}' (${node.resource.Type}) reported its identity as Unresolved, but its props are resolved.`,
255
+ }),
256
+ );
257
+ }
258
+ return observed;
259
+ });
260
+
153
261
  export const apply = <P extends Plan>(
154
262
  plan: P,
155
- options: ApplyOptions = {},
156
263
  ): Effect.Effect<
157
264
  Input.Resolve<P["output"]>,
158
265
  | Output.InvalidReferenceError
@@ -181,144 +288,146 @@ export const apply = <P extends Plan>(
181
288
  yield* demandPlanCredentials(plan);
182
289
  }
183
290
 
184
- // Renderer resolution: an explicit session wins, then the ambient Cli
185
- // renderer service (the bundled CLI, LoggingCli in tests, or a custom
186
- // implementation), else events are dropped.
187
- const session =
188
- options.session ??
189
- (yield* Effect.serviceOption(Cli).pipe(
190
- Effect.flatMap(
191
- Option.match({
192
- onNone: () => Effect.succeed(noopSession),
193
- onSome: (cli) => cli.startApplySession(plan, options.planDisplay),
194
- }),
195
- ),
196
- ));
197
- // The nested gen exists so `onExit` can settle the session on every
198
- // exit path without introducing a scope: local dev providers start
199
- // long-running processes in the AMBIENT scope during reconcile, so
200
- // wrapping this body in Effect.scoped would kill them when apply
201
- // returns.
202
- return yield* Effect.gen(function* () {
203
- const state = yield* yield* State;
204
- const stack = yield* Stack;
205
- const stage = yield* Stage;
206
- const stackName = stack.name;
207
-
208
- const tracker: Record<string, ResourceTracker> = {};
209
- const outputs: Record<string, any> = {};
210
- const terminalStatuses = new Map<
211
- string,
212
- {
213
- fqn: string;
214
- id: string;
215
- type: string;
216
- status: Extract<ApplyStatus, "created" | "updated" | "adopted" | "ran" | "skipped">;
217
- providerMode?: ProviderMode;
218
- }
219
- >();
220
-
221
- // ── FQN migrations (renamedFrom) ──
222
- // Persist renames before any lifecycle operation runs: a node whose row
223
- // was found under a former FQN carries that row pre-remapped in
224
- // `node.state` (see Plan's rename resolution). Commit it at the current
225
- // FQN FIRST, then drop the former row — in that order, so an
226
- // interruption leaves rows at both FQNs with the same instanceId, which
227
- // the next plan recognizes as an in-flight migration (and never as an
228
- // orphan to delete).
229
- //
230
- // In a same-deploy shift (A→B while B→C), C's former FQN `B` is
231
- // simultaneously B's migration TARGET. C must NOT delete it: B's own
232
- // `state.set` supersedes the stale copy, and the migrations run
233
- // concurrently — the delete could land after B's write and destroy the
234
- // freshly migrated row.
235
- const migrationTargets = new Set(
236
- Object.values(plan.resources)
237
- .filter((node) => node.renamedFrom?.length && node.state !== undefined)
238
- .map((node) => node.resource.FQN),
239
- );
240
- yield* Effect.forEach(
241
- Object.values(plan.resources),
242
- (node) => {
243
- const { renamedFrom, state: row } = node;
244
- return renamedFrom === undefined || renamedFrom.length === 0 || row === undefined
245
- ? Effect.void
246
- : Effect.gen(function* () {
247
- yield* state.set({ stack: stackName, stage, fqn: node.resource.FQN, value: row });
248
- yield* Effect.forEach(
249
- renamedFrom.filter((formerFqn) => !migrationTargets.has(formerFqn)),
250
- (formerFqn) => state.delete({ stack: stackName, stage, fqn: formerFqn }),
251
- { concurrency: "unbounded" },
252
- );
253
- });
254
- },
255
- { concurrency: "unbounded" },
256
- );
291
+ const emitEvent = yield* captureEmit;
292
+ // The last status each resource announced, so the post-convergence
293
+ // flush below re-emits only what is still unannounced (cycle members).
294
+ const announced = new Map<string, ApplyStatus>();
295
+ const reportEvent: Reporter = (event) => {
296
+ if (event.type === "apply.resource.status") announced.set(event.fqn, event.status);
297
+ return emitEvent(event);
298
+ };
299
+ // No Effect.scoped around apply: local dev providers start long-running
300
+ // processes in the AMBIENT scope during reconcile, which a scope here
301
+ // would kill when apply returns.
302
+ const state = yield* yield* State;
303
+ const stack = yield* Stack;
304
+ const stage = yield* Stage;
305
+ const stackName = stack.name;
306
+
307
+ const tracker: Record<string, ResourceTracker> = {};
308
+ const outputs: Record<string, any> = {};
309
+ const terminalStatuses = new Map<
310
+ string,
311
+ {
312
+ fqn: string;
313
+ id: string;
314
+ type: string;
315
+ status: Extract<ApplyStatus, "created" | "updated" | "adopted" | "ran" | "skipped">;
316
+ providerMode?: ProviderMode;
317
+ }
318
+ >();
319
+
320
+ // ── FQN migrations (renamedFrom) ──
321
+ // Persist renames before any lifecycle operation runs: a node whose row
322
+ // was found under a former FQN carries that row pre-remapped in
323
+ // `node.state` (see Plan's rename resolution). Commit it at the current
324
+ // FQN FIRST, then drop the former row — in that order, so an
325
+ // interruption leaves rows at both FQNs with the same instanceId, which
326
+ // the next plan recognizes as an in-flight migration (and never as an
327
+ // orphan to delete).
328
+ //
329
+ // In a same-deploy shift (A→B while B→C), C's former FQN `B` is
330
+ // simultaneously B's migration TARGET. C must NOT delete it: B's own
331
+ // `state.set` supersedes the stale copy, and the migrations run
332
+ // concurrently — the delete could land after B's write and destroy the
333
+ // freshly migrated row.
334
+ const migrationTargets = new Set(
335
+ Object.values(plan.resources)
336
+ .filter((node) => node.renamedFrom?.length && node.state !== undefined)
337
+ .map((node) => node.resource.FQN),
338
+ );
339
+ yield* Effect.forEach(
340
+ Object.values(plan.resources),
341
+ (node) => {
342
+ const { renamedFrom, state: row } = node;
343
+ return renamedFrom === undefined || renamedFrom.length === 0 || row === undefined
344
+ ? Effect.void
345
+ : Effect.gen(function* () {
346
+ yield* state.set({ stack: stackName, stage, fqn: node.resource.FQN, value: row });
347
+ yield* Effect.forEach(
348
+ renamedFrom.filter((formerFqn) => !migrationTargets.has(formerFqn)),
349
+ (formerFqn) => state.delete({ stack: stackName, stage, fqn: formerFqn }),
350
+ { concurrency: "unbounded" },
351
+ );
352
+ });
353
+ },
354
+ { concurrency: "unbounded" },
355
+ );
257
356
 
258
- yield* executePlan(
259
- plan,
260
- tracker,
261
- outputs,
262
- terminalStatuses,
263
- session,
264
- state,
265
- stackName,
266
- stage,
267
- );
357
+ yield* executePlan(
358
+ plan,
359
+ tracker,
360
+ outputs,
361
+ terminalStatuses,
362
+ reportEvent,
363
+ state,
364
+ stackName,
365
+ stage,
366
+ );
268
367
 
269
- // TODO(sam): support roll back to previous state if errors occur during expansion
270
- // -> RISK: some UPDATEs may not be reversible (i.e. trigger replacements)
271
- // TODO(sam): should pivot be done separately? E.g shift traffic?
368
+ // TODO(sam): support roll back to previous state if errors occur during expansion
369
+ // -> RISK: some UPDATEs may not be reversible (i.e. trigger replacements)
370
+ // TODO(sam): should pivot be done separately? E.g shift traffic?
272
371
 
273
- yield* collectGarbage(plan, session);
372
+ yield* collectGarbage(plan, reportEvent);
274
373
 
275
- yield* converge(plan, tracker, outputs, terminalStatuses, session, state, stackName, stage);
374
+ yield* converge(plan, tracker, outputs, terminalStatuses, reportEvent, state, stackName, stage);
276
375
 
277
- yield* Effect.forEach(
278
- Array.from(terminalStatuses.values()),
279
- ({ fqn, id, type, status, providerMode }) =>
280
- session.emit({ _tag: "apply.resource.status", fqn, id, type, status, providerMode }),
281
- { concurrency: "unbounded" },
282
- );
376
+ // Cycle members hold their terminal status until `converge` settles
377
+ // it; everything else announced it as it finished.
378
+ yield* Effect.forEach(
379
+ Array.from(terminalStatuses.values()).filter(
380
+ ({ fqn, status }) => announced.get(fqn) !== status,
381
+ ),
382
+ ({ fqn, id, type, status, providerMode }) =>
383
+ reportEvent({
384
+ type: "apply.resource.status",
385
+ fqn,
386
+ id,
387
+ resourceType: type,
388
+ status,
389
+ providerMode,
390
+ }),
391
+ { concurrency: "unbounded" },
392
+ );
283
393
 
284
- if (plan.destroy) {
285
- // The destroy converged: every resource row was deleted above. Drop
286
- // the rest of the stage's persisted state — notably the stack output
287
- // record written by the last deploy — so `getOutput` returns
288
- // undefined and `listStages` no longer reports the stage.
289
- // https://github.com/alchemy-run/alchemy/issues/961
290
- yield* state.deleteStack({ stack: stackName, stage });
291
- // Invariant: a successful destroy leaves the stage EMPTY. If rows
292
- // survive, this destroy session could not actually see (or delete)
293
- // the stack's state — e.g. its plan listed an empty store while
294
- // committed rows existed — and reporting success here would silently
295
- // leak every cloud resource those rows track. Fail loudly instead so
296
- // the leak surfaces in the run that caused it.
297
- const remaining = yield* state.list({ stack: stackName, stage });
298
- if (remaining.length > 0) {
299
- return yield* new StateStoreError({
300
- message:
301
- `destroy of ${stackName}/${stage} reported success but ${remaining.length} ` +
302
- `state row(s) remain (${remaining.join(", ")}) — the destroy session could ` +
303
- `not see the stack's persisted state, so its cloud resources were NOT deleted`,
304
- });
305
- }
306
- return undefined;
394
+ if (plan.destroy) {
395
+ // The destroy converged: every resource row was deleted above. Drop
396
+ // the rest of the stage's persisted state — notably the stack output
397
+ // record written by the last deploy — so `getOutput` returns
398
+ // undefined and `listStages` no longer reports the stage.
399
+ // https://github.com/alchemy-run/alchemy/issues/961
400
+ yield* state.deleteStack({ stack: stackName, stage });
401
+ // Invariant: a successful destroy leaves the stage EMPTY. If rows
402
+ // survive, this destroy session could not actually see (or delete)
403
+ // the stack's state — e.g. its plan listed an empty store while
404
+ // committed rows existed — and reporting success here would silently
405
+ // leak every cloud resource those rows track. Fail loudly instead so
406
+ // the leak surfaces in the run that caused it.
407
+ const remaining = yield* state.list({ stack: stackName, stage });
408
+ if (remaining.length > 0) {
409
+ return yield* new StateStoreError({
410
+ message:
411
+ `destroy of ${stackName}/${stage} reported success but ${remaining.length} ` +
412
+ `state row(s) remain (${remaining.join(", ")}) — the destroy session could ` +
413
+ `not see the stack's persisted state, so its cloud resources were NOT deleted`,
414
+ });
307
415
  }
416
+ return undefined;
417
+ }
308
418
 
309
- if (plan.selectedFqns !== undefined || !plan.output) {
310
- return undefined;
311
- }
419
+ if (plan.selectedFqns !== undefined || !plan.output) {
420
+ return undefined;
421
+ }
312
422
 
313
- const resolved = yield* Output.evaluate(plan.output, outputs);
423
+ const resolved = yield* Output.evaluate(plan.output, outputs);
314
424
 
315
- // Persist the stack's evaluated outputs so cross-stack references
316
- // (`yield* OtherStack` / `OtherStack.stage.<name>` / `Output.stackRef`)
317
- // can read them back out of the state store.
318
- yield* state.setOutput({ stack: stackName, stage, value: resolved });
425
+ // Persist the stack's evaluated outputs so cross-stack references
426
+ // (`yield* OtherStack` / `OtherStack.stage.<name>` / `Output.stackRef`)
427
+ // can read them back out of the state store.
428
+ yield* state.setOutput({ stack: stackName, stage, value: resolved });
319
429
 
320
- return resolved;
321
- }).pipe(Effect.onExit((exit) => session.done(Exit.isSuccess(exit) ? "success" : "failure")));
430
+ return resolved;
322
431
  }).pipe(
323
432
  ensureArtifactStore,
324
433
  Effect.withSpan("apply", {
@@ -350,7 +459,7 @@ const executePlan = Effect.fn(function* (
350
459
  providerMode?: ProviderMode;
351
460
  }
352
461
  >,
353
- session: PlanStatusSession,
462
+ reportEvent: Reporter,
354
463
  state: {
355
464
  set: <V extends PersistedState>(req: {
356
465
  stack: string;
@@ -368,10 +477,8 @@ const executePlan = Effect.fn(function* (
368
477
  const allNodes: Record<string, Apply | ActionApply> = { ...plan.resources, ...plan.actions };
369
478
 
370
479
  const ready = Object.fromEntries(
371
- yield* Effect.all(
372
- Object.keys(allNodes).map((fqn) =>
373
- Effect.map(Deferred.make<void>(), (d) => [fqn, d] as const),
374
- ),
480
+ yield* Effect.forEach(Object.keys(allNodes), (fqn) =>
481
+ Effect.map(Deferred.make<void>(), (d) => [fqn, d] as const),
375
482
  ),
376
483
  ) as Record<string, Deferred.Deferred<void>>;
377
484
 
@@ -380,50 +487,48 @@ const executePlan = Effect.fn(function* (
380
487
  // precreate stubs do NOT signal `readyStable`, so any consumer that
381
488
  // requires stable inputs (e.g. Tasks) waits past the precreate phase.
382
489
  const readyStable = Object.fromEntries(
383
- yield* Effect.all(
384
- Object.keys(allNodes).map((fqn) =>
385
- Effect.map(Deferred.make<void>(), (d) => [fqn, d] as const),
386
- ),
490
+ yield* Effect.forEach(Object.keys(allNodes), (fqn) =>
491
+ Effect.map(Deferred.make<void>(), (d) => [fqn, d] as const),
387
492
  ),
388
493
  ) as Record<string, Deferred.Deferred<void>>;
389
494
 
390
495
  const waitForDeps = (downstreamFqn: string, fqns: string[]) =>
391
- Effect.all(
392
- fqns
393
- .filter((fqn) => fqn in ready)
394
- .map((fqn) =>
395
- // Non-cycle upstreams must be observed at their TERMINAL output
396
- // (`readyStable`), not their early precreate signal (`ready`). This
397
- // is what makes a failed upstream actually interrupt its downstream:
398
- // a resource with `precreate` resolves `ready` before its real
399
- // `reconcile` runs, so a downstream waiting on `ready` would proceed
400
- // (and even finish) even though the upstream's reconcile later
401
- // failed. Waiting on `readyStable` means the downstream's
402
- // `waitForDeps` short-circuits with the upstream's failure cause.
403
- //
404
- // Cycle members are the exception: peers in an SCC depend on each
405
- // other, so they must rendezvous on the early `ready`/precreate
406
- // signal to break the deadlock. Phase 3 (`converge`) re-runs them
407
- // against final outputs once the cycle settles. A downstream
408
- // outside the cycle must still wait for reconcile: e.g. a queue
409
- // consumer cannot attach to a Worker's fetch-only precreate stub.
410
- plan.cycleMembers.has(downstreamFqn) && plan.cycleMembers.has(fqn)
411
- ? Deferred.await(ready[fqn])
412
- : Deferred.await(readyStable[fqn]),
413
- ),
496
+ Effect.forEach(
497
+ fqns.filter((fqn) => fqn in ready),
498
+ (fqn) =>
499
+ // Non-cycle upstreams must be observed at their TERMINAL output
500
+ // (`readyStable`), not their early precreate signal (`ready`). This
501
+ // is what makes a failed upstream actually interrupt its downstream:
502
+ // a resource with `precreate` resolves `ready` before its real
503
+ // `reconcile` runs, so a downstream waiting on `ready` would proceed
504
+ // (and even finish) even though the upstream's reconcile later
505
+ // failed. Waiting on `readyStable` means the downstream's
506
+ // `waitForDeps` short-circuits with the upstream's failure cause.
507
+ //
508
+ // Cycle members are the exception: peers in an SCC depend on each
509
+ // other, so they must rendezvous on the early `ready`/precreate
510
+ // signal to break the deadlock. Phase 3 (`converge`) re-runs them
511
+ // against final outputs once the cycle settles. A downstream
512
+ // outside the cycle must still wait for reconcile: e.g. a queue
513
+ // consumer cannot attach to a Worker's fetch-only precreate stub.
514
+ plan.cycleMembers.has(downstreamFqn) && plan.cycleMembers.has(fqn)
515
+ ? Deferred.await(ready[fqn])
516
+ : Deferred.await(readyStable[fqn]),
414
517
  { concurrency: "unbounded" },
415
518
  );
416
519
 
417
520
  const waitForStableDeps = (fqns: string[]) =>
418
- Effect.all(
419
- fqns.filter((fqn) => fqn in readyStable).map((fqn) => Deferred.await(readyStable[fqn])),
521
+ Effect.forEach(
522
+ fqns.filter((fqn) => fqn in readyStable),
523
+ (fqn) => Deferred.await(readyStable[fqn]),
420
524
  { concurrency: "unbounded" },
421
525
  );
422
526
 
423
527
  const failures: LifecycleFailure[] = [];
424
528
 
425
- yield* Effect.all(
426
- Object.entries(allNodes).map(([fqn, node]) =>
529
+ yield* Effect.forEach(
530
+ Object.entries(allNodes),
531
+ ([fqn, node]) =>
427
532
  (node as ActionApply).kind === "action"
428
533
  ? executeActionNode(
429
534
  fqn,
@@ -433,7 +538,7 @@ const executePlan = Effect.fn(function* (
433
538
  ready,
434
539
  readyStable,
435
540
  terminalStatuses,
436
- session,
541
+ reportEvent,
437
542
  state,
438
543
  stackName,
439
544
  stage,
@@ -448,15 +553,14 @@ const executePlan = Effect.fn(function* (
448
553
  ready,
449
554
  readyStable,
450
555
  terminalStatuses as any,
451
- session,
556
+ reportEvent,
452
557
  state,
453
558
  stackName,
454
559
  stage,
455
560
  (fqns) => waitForDeps(fqn, fqns),
456
561
  failures,
457
- plan.cycleMembers.has(fqn),
562
+ plan.cycleMembers,
458
563
  ),
459
- ),
460
564
  { concurrency: "unbounded" },
461
565
  );
462
566
 
@@ -498,7 +602,9 @@ const failureMessage = (cause: Cause.Cause<unknown>): string | undefined => {
498
602
  const message =
499
603
  Predicate.hasProperty(error, "message") && typeof error.message === "string"
500
604
  ? error.message
501
- : String(error);
605
+ : typeof error === "string"
606
+ ? error
607
+ : Formatter.format(error);
502
608
  const line = message.split("\n", 1)[0]!;
503
609
  return tag !== undefined && !line.includes(tag) ? `${tag}: ${line}` : line;
504
610
  }
@@ -522,7 +628,7 @@ const executeNode = (
522
628
  providerMode?: ProviderMode;
523
629
  }
524
630
  >,
525
- session: PlanStatusSession,
631
+ reportEvent: Reporter,
526
632
  state: {
527
633
  set: <V extends ResourceState>(req: {
528
634
  stack: string;
@@ -535,9 +641,10 @@ const executeNode = (
535
641
  stage: string,
536
642
  waitForDeps: (fqns: string[]) => Effect.Effect<void[], never, never>,
537
643
  failures: LifecycleFailure[],
538
- inCycle: boolean,
644
+ cycleMembers: ReadonlySet<string>,
539
645
  ): Effect.Effect<void, never, never> =>
540
646
  Effect.gen(function* () {
647
+ const inCycle = cycleMembers.has(fqn);
541
648
  const logicalId = node.resource.LogicalId;
542
649
  const namespace = node.resource.Namespace;
543
650
 
@@ -562,23 +669,14 @@ const executeNode = (
562
669
  value: {
563
670
  ...value,
564
671
  adoptionBlocked: value.adoptionBlocked ?? node.adoptionBlocked,
672
+ propsIncomplete: propsIncomplete(value),
565
673
  props: stripUnresolved(value.props),
566
674
  bindings: stripUnresolved(value.bindings),
567
675
  namespace,
568
676
  } as S,
569
677
  });
570
678
 
571
- const scopedSession = {
572
- ...session,
573
- note: (note, options?) =>
574
- session.emit({
575
- fqn,
576
- id: logicalId,
577
- _tag: "apply.resource.note",
578
- message: note,
579
- kind: options?.kind,
580
- }),
581
- } satisfies ScopedPlanStatusSession;
679
+ const scopedSession = resourceSession(reportEvent, fqn, logicalId);
582
680
 
583
681
  // On a mode-switch replacement (local ⇄ live) surface the transition:
584
682
  // the old generation's stamped mode → the mode resolved for this run.
@@ -591,11 +689,11 @@ const executeNode = (
591
689
  : undefined;
592
690
 
593
691
  const report = (status: ApplyStatus) =>
594
- session.emit({
595
- _tag: "apply.resource.status",
692
+ reportEvent({
693
+ type: "apply.resource.status",
596
694
  fqn,
597
695
  id: logicalId,
598
- type: node.resource.Type,
696
+ resourceType: node.resource.Type,
599
697
  status,
600
698
  providerMode: node.mode,
601
699
  fromProviderMode,
@@ -633,11 +731,11 @@ const executeNode = (
633
731
  // terminal status is known. Their final status is flushed from
634
732
  // `terminalStatuses` after `converge` completes.
635
733
  if (inCycle) return;
636
- yield* session.emit({
637
- _tag: "apply.resource.status",
734
+ yield* reportEvent({
735
+ type: "apply.resource.status",
638
736
  fqn,
639
737
  id: logicalId,
640
- type: node.resource.Type,
738
+ resourceType: node.resource.Type,
641
739
  status,
642
740
  providerMode: node.mode,
643
741
  });
@@ -712,6 +810,23 @@ const executeNode = (
712
810
  return [...new Set([...propDeps, ...bindingDeps])];
713
811
  };
714
812
 
813
+ // A cycle precreates before its peers reconcile. An upstream outside the
814
+ // cycle cannot depend on it, so wait for those upstreams and resolve the
815
+ // props they determine: only values derived from cycle peers stay
816
+ // unresolved when precreate and `observe` run.
817
+ const resolvePrecreateProps = Effect.gen(function* () {
818
+ const outside = allUpstreamFqns().filter((upstream) => !cycleMembers.has(upstream));
819
+ yield* waitForDeps(outside);
820
+ return yield* Output.evaluateAvailable(
821
+ node.props,
822
+ Object.fromEntries(
823
+ outside
824
+ .filter((upstream) => Object.hasOwn(outputs, upstream))
825
+ .map((upstream) => [upstream, outputs[upstream]]),
826
+ ),
827
+ );
828
+ });
829
+
715
830
  // ── instance ID ──
716
831
 
717
832
  const resolveInstanceId = Effect.gen(function* () {
@@ -793,6 +908,8 @@ const executeNode = (
793
908
  }
794
909
 
795
910
  let attr: any = node.state?.attr;
911
+ // Whether the identity reconcile claims has passed the ownership check.
912
+ let admitted = node.deferredAdoption === undefined;
796
913
 
797
914
  if (attr !== undefined) {
798
915
  // Precreate/read may already have produced a usable output snapshot. Publish
@@ -806,6 +923,10 @@ const executeNode = (
806
923
  // Durable Object classes are empty) can serve traffic while the real
807
924
  // version propagates.
808
925
  if (inCycle && node.provider.precreate && attr === undefined) {
926
+ const props = yield* resolvePrecreateProps;
927
+ // Without `observe`, precreate and reconcile claim the identity unchecked.
928
+ admitted =
929
+ (yield* observeBeforePrecreate(node, props, fqn, logicalId, instanceId)) !== "unresolved";
809
930
  // Some resources need a placeholder physical resource before their real
810
931
  // create can finish. Persist that stub so downstream evaluation can proceed.
811
932
  yield* report("pre-creating");
@@ -813,7 +934,7 @@ const executeNode = (
813
934
  .precreate({
814
935
  id: logicalId,
815
936
  fqn,
816
- news: node.props,
937
+ news: props,
817
938
  session: scopedSession,
818
939
  instanceId,
819
940
  bindings: excludeDeletedBindings(node.bindings),
@@ -826,7 +947,9 @@ const executeNode = (
826
947
  instanceId,
827
948
  resourceType: node.resource.Type,
828
949
  props: node.props,
829
- attr,
950
+ // A stub for an unresolved identity claims nothing. Leave the
951
+ // checkpoint without it, so a retry checks the identity again.
952
+ attr: admitted ? attr : undefined,
830
953
  providerVersion: node.provider.version ?? 0,
831
954
  bindings: excludeDeletedBindings(node.bindings),
832
955
  downstream: node.downstream,
@@ -852,8 +975,8 @@ const executeNode = (
852
975
 
853
976
  const bindingOutputs = excludeDeletedBindings(yield* Output.evaluate(node.bindings, outputs));
854
977
 
855
- if (attr === undefined && node.deferredAdoption && node.provider.read) {
856
- const checkpoint = () =>
978
+ if (!admitted) {
979
+ const checkpoint = (attr: any) =>
857
980
  commit<CreatingResourceState>({
858
981
  status: "creating",
859
982
  fqn,
@@ -869,13 +992,12 @@ const executeNode = (
869
992
  providerMode: node.mode,
870
993
  adoptionBlocked: node.adoptionBlocked,
871
994
  });
872
- // Refusal or interruption must retain identity, never foreign attributes.
873
- yield* checkpoint();
874
- const observed = yield* node.provider
875
- .read({ id: logicalId, fqn, instanceId, olds: news, output: undefined })
876
- .pipe(instrumentLifecycle("read", fqn, node.resource.Type, logicalId, instanceId));
995
+ // Refusal or interruption must retain identity, never foreign
996
+ // attributes, nor a stub for an identity not yet checked.
997
+ yield* checkpoint(undefined);
998
+ const observed = yield* observeResolved(node, news, fqn, logicalId, instanceId);
877
999
  if (observed !== undefined) {
878
- if (Unowned.is(observed) && !node.deferredAdoption.adopt) {
1000
+ if (Unowned.is(observed) && !node.deferredAdoption?.adopt) {
879
1001
  return yield* new OwnedBySomeoneElse({
880
1002
  message:
881
1003
  `Cannot adopt resource '${fqn}' (${node.resource.Type}): ` +
@@ -886,9 +1008,10 @@ const executeNode = (
886
1008
  logicalId,
887
1009
  });
888
1010
  }
889
- attr = stripUnowned(observed);
1011
+ // Reconcile keeps a precreated stub as its output.
1012
+ attr ??= stripUnowned(observed);
890
1013
  // A creating checkpoint retains olds: undefined on retry.
891
- yield* checkpoint();
1014
+ yield* checkpoint(attr);
892
1015
  }
893
1016
  }
894
1017
 
@@ -1173,15 +1296,99 @@ const executeNode = (
1173
1296
  }
1174
1297
  });
1175
1298
 
1176
- if (node.deleteFirst) {
1299
+ const deleteFirst = Effect.fn(function* () {
1177
1300
  yield* scopedSession.note(
1178
1301
  "Deleting previous resource before creating its replacement (deleteFirst)...",
1179
1302
  );
1180
1303
  yield* deleteOldGenerations(replState.old);
1181
- }
1304
+ });
1182
1305
 
1183
1306
  let attr: any = replState.attr;
1184
1307
 
1308
+ // ── replacement admission ──
1309
+ //
1310
+ // The replacement may resolve to a physical identity that already
1311
+ // exists and belongs to someone else (e.g. a renamed Worker pointing at
1312
+ // a foreign script). Read it before anything is mutated — before
1313
+ // precreate, reconcile, and delete-first cleanup of the previous
1314
+ // generation — and refuse an unowned target unless adoption is allowed,
1315
+ // exactly like a fresh create.
1316
+ let admitted = attr !== undefined || node.deferredAdoption === undefined;
1317
+ const admit = Effect.fn(function* (props: Record<string, any>) {
1318
+ admitted = true;
1319
+ const observed = yield* observeResolved(
1320
+ node,
1321
+ props,
1322
+ fqn,
1323
+ logicalId,
1324
+ instanceId,
1325
+ replState.old?.attr,
1326
+ );
1327
+ if (observed === undefined) return;
1328
+ if (Unowned.is(observed) && !node.deferredAdoption?.adopt) {
1329
+ return yield* new OwnedBySomeoneElse({
1330
+ message:
1331
+ `Cannot replace resource '${fqn}' (${node.resource.Type}): ` +
1332
+ "its replacement exists in the cloud but is not owned by this " +
1333
+ "stack/stage/logical-id. Re-run with `--adopt` (or " +
1334
+ "wrap the effect in `adopt(true)`) to take it over.",
1335
+ resourceType: node.resource.Type,
1336
+ logicalId,
1337
+ });
1338
+ }
1339
+ // A delete-first target may be the previous generation itself, which
1340
+ // is about to be deleted — never hand its attributes to reconcile.
1341
+ // Reconcile keeps a precreated stub as its output.
1342
+ if (!node.deleteFirst) attr ??= stripUnowned(observed);
1343
+ });
1344
+
1345
+ // A cycle precreates on the props its upstreams outside the cycle
1346
+ // determine; anything else waits for every upstream.
1347
+ const precreateProps = inCycle ? yield* resolvePrecreateProps : node.props;
1348
+
1349
+ if (!admitted && isResolved(precreateProps)) {
1350
+ yield* admit(precreateProps);
1351
+ }
1352
+
1353
+ // A cycle precreates before its props resolve, so `observe` admits the
1354
+ // identity precreate will claim — before delete-first, too. Without
1355
+ // `observe`, precreate and reconcile claim it unchecked. An unresolved
1356
+ // identity is admitted once it resolves, before reconcile.
1357
+ if (!admitted && inCycle) {
1358
+ const observation = yield* observeBeforePrecreate(
1359
+ node,
1360
+ precreateProps,
1361
+ fqn,
1362
+ logicalId,
1363
+ instanceId,
1364
+ replState.old?.attr,
1365
+ );
1366
+ admitted = observation !== "unresolved";
1367
+ if (!admitted && node.deleteFirst && !node.deferredAdoption?.adopt) {
1368
+ return yield* new UnverifiableReplacement({
1369
+ message:
1370
+ `Cannot replace resource '${fqn}' (${node.resource.Type}): ` +
1371
+ "it must be deleted before its replacement is pre-created, but " +
1372
+ "the replacement's identity depends on outputs that are not " +
1373
+ "resolved yet, so its ownership cannot be checked first. Re-run " +
1374
+ "with `--adopt` (or wrap the effect in `adopt(true)`) to replace it anyway.",
1375
+ resourceType: node.resource.Type,
1376
+ logicalId,
1377
+ });
1378
+ }
1379
+ }
1380
+
1381
+ // A cycle must delete before precreate claims the identity. Plan has
1382
+ // already refused one whose identity could not be admitted first
1383
+ // without `observe`; the check above refuses an unresolved one.
1384
+ // Otherwise the previous generation survives until reconcile is
1385
+ // about to run, so a failed upstream never leaves the resource missing.
1386
+ let deletedFirst = false;
1387
+ if (node.deleteFirst && inCycle) {
1388
+ yield* deleteFirst();
1389
+ deletedFirst = true;
1390
+ }
1391
+
1185
1392
  if (attr !== undefined) {
1186
1393
  // If precreate already ran, expose that intermediate output immediately so
1187
1394
  // downstream resources can resolve against the same in-flight replacement.
@@ -1194,7 +1401,7 @@ const executeNode = (
1194
1401
  .precreate({
1195
1402
  id: logicalId,
1196
1403
  fqn,
1197
- news: node.props,
1404
+ news: precreateProps,
1198
1405
  session: scopedSession,
1199
1406
  instanceId,
1200
1407
  bindings: excludeDeletedBindings(node.bindings),
@@ -1207,7 +1414,9 @@ const executeNode = (
1207
1414
  instanceId,
1208
1415
  resourceType: node.resource.Type,
1209
1416
  props: node.props,
1210
- attr,
1417
+ // A stub for an unresolved identity claims nothing. Leave the
1418
+ // checkpoint without it, so a retry checks the identity again.
1419
+ attr: admitted ? attr : undefined,
1211
1420
  providerVersion: node.provider.version ?? 0,
1212
1421
  bindings: excludeDeletedBindings(node.bindings),
1213
1422
  downstream: node.downstream,
@@ -1233,6 +1442,13 @@ const executeNode = (
1233
1442
 
1234
1443
  const bindingOutputs = excludeDeletedBindings(yield* Output.evaluate(node.bindings, outputs));
1235
1444
 
1445
+ if (!admitted) {
1446
+ yield* admit(news);
1447
+ }
1448
+ if (node.deleteFirst && !deletedFirst) {
1449
+ yield* deleteFirst();
1450
+ }
1451
+
1236
1452
  attr = yield* node.provider
1237
1453
  .reconcile({
1238
1454
  id: logicalId,
@@ -1304,23 +1520,23 @@ const executeNode = (
1304
1520
  return;
1305
1521
  }
1306
1522
 
1307
- return yield* Effect.die(`Unknown action: ${node.action}`);
1523
+ return yield* Effect.die(`Unknown action: ${(node as { action: string }).action}`);
1308
1524
  }).pipe(
1309
1525
  Effect.catchCause((cause) =>
1310
1526
  // Record the failure, propagate it to any downstream resources waiting on
1311
1527
  // our Deferred (so their waitForDeps short-circuits instead of deadlocking),
1312
- // emit a "fail" status to the session, and resolve to void so Effect.all
1528
+ // emit a "fail" status, and resolve to void so Effect.all
1313
1529
  // does not interrupt sibling fibers. The aggregated cause is raised at
1314
1530
  // the end of executePlan.
1315
1531
  Effect.gen(function* () {
1316
1532
  failures.push({ fqn, logicalId: node.resource.LogicalId, type: node.resource.Type, cause });
1317
1533
  yield* Deferred.failCause(ready[fqn], cause as Cause.Cause<never>);
1318
1534
  yield* Deferred.failCause(readyStable[fqn], cause as Cause.Cause<never>);
1319
- yield* session.emit({
1320
- _tag: "apply.resource.status",
1535
+ yield* reportEvent({
1536
+ type: "apply.resource.status",
1321
1537
  fqn,
1322
1538
  id: node.resource.LogicalId,
1323
- type: node.resource.Type,
1539
+ resourceType: node.resource.Type,
1324
1540
  status: "fail",
1325
1541
  message: failureMessage(cause),
1326
1542
  providerMode: node.mode,
@@ -1380,7 +1596,7 @@ const executeActionNode = (
1380
1596
  providerMode?: ProviderMode;
1381
1597
  }
1382
1598
  >,
1383
- session: PlanStatusSession,
1599
+ reportEvent: Reporter,
1384
1600
  state: {
1385
1601
  set: <V extends PersistedState>(req: {
1386
1602
  stack: string;
@@ -1403,7 +1619,13 @@ const executeActionNode = (
1403
1619
  state.set({ stack: stackName, stage, fqn, value: { ...value, namespace } as S });
1404
1620
 
1405
1621
  const report = (status: ApplyStatus) =>
1406
- session.emit({ _tag: "apply.resource.status", fqn, id: logicalId, type: task.Type, status });
1622
+ reportEvent({
1623
+ type: "apply.resource.status",
1624
+ fqn,
1625
+ id: logicalId,
1626
+ resourceType: task.Type,
1627
+ status,
1628
+ });
1407
1629
 
1408
1630
  const signalReady = Deferred.succeed(ready[fqn], void 0);
1409
1631
  const signalReadyStable = Deferred.succeed(readyStable[fqn], void 0);
@@ -1494,11 +1716,11 @@ const executeActionNode = (
1494
1716
  failures.push({ fqn, logicalId: node.def.LogicalId, type: node.def.Type, cause });
1495
1717
  yield* Deferred.failCause(ready[fqn], cause as Cause.Cause<never>);
1496
1718
  yield* Deferred.failCause(readyStable[fqn], cause as Cause.Cause<never>);
1497
- yield* session.emit({
1498
- _tag: "apply.resource.status",
1719
+ yield* reportEvent({
1720
+ type: "apply.resource.status",
1499
1721
  fqn,
1500
1722
  id: node.def.LogicalId,
1501
- type: node.def.Type,
1723
+ resourceType: node.def.Type,
1502
1724
  status: "fail",
1503
1725
  message: failureMessage(cause),
1504
1726
  });
@@ -1537,7 +1759,7 @@ const converge = Effect.fn(function* (
1537
1759
  providerMode?: ProviderMode;
1538
1760
  }
1539
1761
  >,
1540
- session: PlanStatusSession,
1762
+ reportEvent: Reporter,
1541
1763
  state: {
1542
1764
  set: <V extends PersistedState>(req: {
1543
1765
  stack: string;
@@ -1574,17 +1796,33 @@ const converge = Effect.fn(function* (
1574
1796
  const namespace = node.resource.Namespace;
1575
1797
  const instanceId = tracker[fqn].instanceId;
1576
1798
 
1577
- const scopedSession = {
1578
- ...session,
1579
- note: (note, options?) =>
1580
- session.emit({
1581
- fqn,
1582
- id: logicalId,
1583
- _tag: "apply.resource.note",
1584
- message: note,
1585
- kind: options?.kind,
1586
- }),
1587
- } satisfies ScopedPlanStatusSession;
1799
+ const scopedSession = resourceSession(reportEvent, fqn, logicalId);
1800
+
1801
+ // A cycle peer resolves against its peers' first outputs, so an
1802
+ // identity checked then may resolve differently now. Check the identity
1803
+ // these props resolve to before reconcile claims it.
1804
+ const deferredAdoption = "deferredAdoption" in node ? node.deferredAdoption : undefined;
1805
+ if (propsChanged && deferredAdoption !== undefined) {
1806
+ const observed = yield* observeResolved(
1807
+ node,
1808
+ newProps,
1809
+ fqn,
1810
+ logicalId,
1811
+ instanceId,
1812
+ tracker[fqn].output,
1813
+ );
1814
+ if (observed !== undefined && Unowned.is(observed) && !deferredAdoption.adopt) {
1815
+ return yield* new OwnedBySomeoneElse({
1816
+ message:
1817
+ `Cannot converge resource '${fqn}' (${node.resource.Type}): ` +
1818
+ "its final identity exists in the cloud but is not owned by this " +
1819
+ "stack/stage/logical-id. Re-run with `--adopt` (or " +
1820
+ "wrap the effect in `adopt(true)`) to take it over.",
1821
+ resourceType: node.resource.Type,
1822
+ logicalId,
1823
+ });
1824
+ }
1825
+ }
1588
1826
 
1589
1827
  const attr = yield* node.provider
1590
1828
  .reconcile({
@@ -1764,7 +2002,7 @@ export class DestroyError extends Data.TaggedError("DestroyError")<{
1764
2002
  }
1765
2003
  }
1766
2004
 
1767
- const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSession) {
2005
+ const collectGarbage = Effect.fn(function* (plan: Plan, reportEvent: Reporter) {
1768
2006
  const state = yield* yield* State;
1769
2007
  const stack = yield* Stack;
1770
2008
  const stackName = stack.name;
@@ -1773,28 +2011,28 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
1773
2011
  // Task deletions are pure state drops — no body is invoked. Run them in
1774
2012
  // parallel before resource GC; tasks never have provider-side dependencies
1775
2013
  // to wait on.
1776
- yield* Effect.all(
1777
- Object.entries(plan.actionDeletions ?? {}).map(([fqn, node]) =>
2014
+ yield* Effect.forEach(
2015
+ Object.entries(plan.actionDeletions ?? {}),
2016
+ ([fqn, node]) =>
1778
2017
  node === undefined
1779
2018
  ? Effect.void
1780
2019
  : Effect.gen(function* () {
1781
- yield* session.emit({
1782
- _tag: "apply.resource.status",
2020
+ yield* reportEvent({
2021
+ type: "apply.resource.status",
1783
2022
  fqn,
1784
2023
  id: node.def.LogicalId,
1785
- type: node.def.Type,
2024
+ resourceType: node.def.Type,
1786
2025
  status: "deleting",
1787
2026
  });
1788
2027
  yield* state.delete({ stack: stackName, stage, fqn });
1789
- yield* session.emit({
1790
- _tag: "apply.resource.status",
2028
+ yield* reportEvent({
2029
+ type: "apply.resource.status",
1791
2030
  fqn,
1792
2031
  id: node.def.LogicalId,
1793
- type: node.def.Type,
2032
+ resourceType: node.def.Type,
1794
2033
  status: "deleted",
1795
2034
  });
1796
2035
  }),
1797
- ),
1798
2036
  { concurrency: "unbounded" },
1799
2037
  );
1800
2038
 
@@ -1897,6 +2135,9 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
1897
2135
  const adoptionBlocked = isDeleteNode(node)
1898
2136
  ? node.state.adoptionBlocked
1899
2137
  : generation.adoptionBlocked;
2138
+ const incompleteProps = isDeleteNode(node)
2139
+ ? node.state.propsIncomplete
2140
+ : generation.propsIncomplete;
1900
2141
  // Mutable: an attr-less row (interrupted create) may recover its
1901
2142
  // attributes from `provider.read` below, right before deletion.
1902
2143
  let attr = persistedAttr;
@@ -1922,26 +2163,16 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
1922
2163
  });
1923
2164
 
1924
2165
  const report = (status: ApplyStatus) =>
1925
- session.emit({
1926
- _tag: "apply.resource.status",
2166
+ reportEvent({
2167
+ type: "apply.resource.status",
1927
2168
  fqn,
1928
2169
  id: logicalId,
1929
- type: resourceType,
2170
+ resourceType,
1930
2171
  status,
1931
2172
  providerMode,
1932
2173
  });
1933
2174
 
1934
- const scopedSession = {
1935
- ...session,
1936
- note: (note, options?) =>
1937
- session.emit({
1938
- fqn,
1939
- id: logicalId,
1940
- _tag: "apply.resource.note",
1941
- message: note,
1942
- kind: options?.kind,
1943
- }),
1944
- } satisfies ScopedPlanStatusSession;
2175
+ const scopedSession = resourceSession(reportEvent, fqn, logicalId);
1945
2176
 
1946
2177
  return yield* (deletions[fqn] ??= yield* Effect.cached(
1947
2178
  Effect.gen(function* () {
@@ -1950,8 +2181,9 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
1950
2181
  // this resource legitimately undeletable (dependency violation),
1951
2182
  // so it is skipped with a "blocked by" note instead of surfacing
1952
2183
  // a spurious second error.
1953
- const dependents = yield* Effect.all(
1954
- downstream.map((dep) =>
2184
+ const dependents = yield* Effect.forEach(
2185
+ downstream,
2186
+ (dep) =>
1955
2187
  dep !== fqn && !ancestors.has(dep)
1956
2188
  ? dep in deletionGraph
1957
2189
  ? deleteResource(
@@ -1965,7 +2197,6 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
1965
2197
  outcome: unresolved.has(dep) ? ("failed" as const) : ("deleted" as const),
1966
2198
  }))
1967
2199
  : Effect.succeed({ dep, outcome: "deleted" as const }),
1968
- ),
1969
2200
  { concurrency: "unbounded" },
1970
2201
  );
1971
2202
 
@@ -2050,6 +2281,13 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
2050
2281
  "migrated predecessor. Any interrupted new physical " +
2051
2282
  "resource must be identified and cleaned up manually.",
2052
2283
  );
2284
+ } else if (incompleteProps) {
2285
+ yield* scopedSession.note(
2286
+ "Skipping recovery: unresolved properties were omitted from " +
2287
+ "this interrupted create's state, so they cannot identify it. " +
2288
+ "Any interrupted physical resource must be identified and " +
2289
+ "cleaned up manually.",
2290
+ );
2053
2291
  } else if (provider.read) {
2054
2292
  const recovered = yield* provider
2055
2293
  .read({ id: logicalId, fqn, instanceId, olds: props as never, output: undefined })
@@ -2111,6 +2349,7 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
2111
2349
  removalPolicy: node.resource.RemovalPolicy,
2112
2350
  providerMode,
2113
2351
  adoptionBlocked,
2352
+ propsIncomplete: incompleteProps,
2114
2353
  });
2115
2354
  }
2116
2355
 
@@ -2181,6 +2420,7 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
2181
2420
  bindings: excludeDeletedBindings(node.bindings),
2182
2421
  removalPolicy: node.removalPolicy,
2183
2422
  providerMode: node.providerMode,
2423
+ propsIncomplete: node.propsIncomplete,
2184
2424
  });
2185
2425
  }
2186
2426
  yield* scopedSession.note(
@@ -2206,10 +2446,9 @@ const collectGarbage = Effect.fn(function* (plan: Plan, session: PlanStatusSessi
2206
2446
  // retained) inside each node's delete effect — the effects resolve to
2207
2447
  // outcomes and never fail, so one bad resource never interrupts sibling
2208
2448
  // deletions mid-flight.
2209
- yield* Effect.all(
2210
- Object.values(deletionGraph)
2211
- .filter((node) => node !== undefined)
2212
- .map((node) => deleteResource(node)),
2449
+ yield* Effect.forEach(
2450
+ Object.values(deletionGraph).filter((node) => node !== undefined),
2451
+ (node) => deleteResource(node),
2213
2452
  { concurrency: "unbounded" },
2214
2453
  );
2215
2454
  });