alchemy-effect 0.2.0 → 0.4.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 (494) hide show
  1. package/bin/alchemy-effect.js +55354 -8
  2. package/bin/alchemy-effect.js.map +1 -1
  3. package/bin/alchemy-effect.ts +266 -10
  4. package/lib/$.d.ts +5 -0
  5. package/lib/$.d.ts.map +1 -0
  6. package/lib/$.js +9 -0
  7. package/lib/$.js.map +1 -0
  8. package/lib/app.d.ts +4 -17
  9. package/lib/app.d.ts.map +1 -1
  10. package/lib/app.js +0 -20
  11. package/lib/app.js.map +1 -1
  12. package/lib/apply.d.ts +15 -75
  13. package/lib/apply.d.ts.map +1 -1
  14. package/lib/apply.js +439 -154
  15. package/lib/apply.js.map +1 -1
  16. package/lib/assert-never.d.ts +12 -0
  17. package/lib/assert-never.d.ts.map +1 -0
  18. package/lib/assert-never.js +11 -0
  19. package/lib/assert-never.js.map +1 -0
  20. package/lib/aws/account.d.ts +10 -1
  21. package/lib/aws/account.d.ts.map +1 -1
  22. package/lib/aws/account.js +18 -3
  23. package/lib/aws/account.js.map +1 -1
  24. package/lib/aws/client.d.ts.map +1 -1
  25. package/lib/aws/client.js +0 -1
  26. package/lib/aws/client.js.map +1 -1
  27. package/lib/aws/config.d.ts +15 -0
  28. package/lib/aws/config.d.ts.map +1 -0
  29. package/lib/aws/config.js +1 -0
  30. package/lib/aws/config.js.map +1 -0
  31. package/lib/aws/credentials.d.ts +10 -0
  32. package/lib/aws/credentials.d.ts.map +1 -1
  33. package/lib/aws/credentials.js +73 -47
  34. package/lib/aws/credentials.js.map +1 -1
  35. package/lib/aws/dynamodb/client.d.ts +1 -1
  36. package/lib/aws/dynamodb/client.d.ts.map +1 -1
  37. package/lib/aws/dynamodb/index.d.ts +2 -1
  38. package/lib/aws/dynamodb/index.d.ts.map +1 -1
  39. package/lib/aws/dynamodb/index.js +1 -2
  40. package/lib/aws/dynamodb/index.js.map +1 -1
  41. package/lib/aws/dynamodb/secondary-index.d.ts +5 -4
  42. package/lib/aws/dynamodb/secondary-index.d.ts.map +1 -1
  43. package/lib/aws/dynamodb/table.d.ts +23 -20
  44. package/lib/aws/dynamodb/table.d.ts.map +1 -1
  45. package/lib/aws/dynamodb/table.get-item.d.ts +8 -6
  46. package/lib/aws/dynamodb/table.get-item.d.ts.map +1 -1
  47. package/lib/aws/dynamodb/table.get-item.js +4 -2
  48. package/lib/aws/dynamodb/table.get-item.js.map +1 -1
  49. package/lib/aws/dynamodb/table.js.map +1 -1
  50. package/lib/aws/dynamodb/table.provider.d.ts +3 -4
  51. package/lib/aws/dynamodb/table.provider.d.ts.map +1 -1
  52. package/lib/aws/dynamodb/table.provider.js +18 -29
  53. package/lib/aws/dynamodb/table.provider.js.map +1 -1
  54. package/lib/aws/ec2/client.d.ts +1 -1
  55. package/lib/aws/ec2/client.d.ts.map +1 -1
  56. package/lib/aws/ec2/index.d.ts +11 -0
  57. package/lib/aws/ec2/index.d.ts.map +1 -1
  58. package/lib/aws/ec2/index.js +11 -0
  59. package/lib/aws/ec2/index.js.map +1 -1
  60. package/lib/aws/ec2/internet-gateway.d.ts +65 -0
  61. package/lib/aws/ec2/internet-gateway.d.ts.map +1 -0
  62. package/lib/aws/ec2/internet-gateway.js +4 -0
  63. package/lib/aws/ec2/internet-gateway.js.map +1 -0
  64. package/lib/aws/ec2/internet-gateway.provider.d.ts +6 -0
  65. package/lib/aws/ec2/internet-gateway.provider.d.ts.map +1 -0
  66. package/lib/aws/ec2/internet-gateway.provider.js +193 -0
  67. package/lib/aws/ec2/internet-gateway.provider.js.map +1 -0
  68. package/lib/aws/ec2/route-table-association.d.ts +63 -0
  69. package/lib/aws/ec2/route-table-association.d.ts.map +1 -0
  70. package/lib/aws/ec2/route-table-association.js +4 -0
  71. package/lib/aws/ec2/route-table-association.js.map +1 -0
  72. package/lib/aws/ec2/route-table-association.provider.d.ts +4 -0
  73. package/lib/aws/ec2/route-table-association.provider.d.ts.map +1 -0
  74. package/lib/aws/ec2/route-table-association.provider.js +121 -0
  75. package/lib/aws/ec2/route-table-association.provider.js.map +1 -0
  76. package/lib/aws/ec2/route-table.d.ts +159 -0
  77. package/lib/aws/ec2/route-table.d.ts.map +1 -0
  78. package/lib/aws/ec2/route-table.js +4 -0
  79. package/lib/aws/ec2/route-table.js.map +1 -0
  80. package/lib/aws/ec2/route-table.provider.d.ts +6 -0
  81. package/lib/aws/ec2/route-table.provider.d.ts.map +1 -0
  82. package/lib/aws/ec2/route-table.provider.js +213 -0
  83. package/lib/aws/ec2/route-table.provider.js.map +1 -0
  84. package/lib/aws/ec2/route.d.ts +155 -0
  85. package/lib/aws/ec2/route.d.ts.map +1 -0
  86. package/lib/aws/ec2/route.js +3 -0
  87. package/lib/aws/ec2/route.js.map +1 -0
  88. package/lib/aws/ec2/route.provider.d.ts +4 -0
  89. package/lib/aws/ec2/route.provider.d.ts.map +1 -0
  90. package/lib/aws/ec2/route.provider.js +166 -0
  91. package/lib/aws/ec2/route.provider.js.map +1 -0
  92. package/lib/aws/ec2/subnet.d.ts +175 -0
  93. package/lib/aws/ec2/subnet.d.ts.map +1 -0
  94. package/lib/aws/ec2/subnet.js +4 -0
  95. package/lib/aws/ec2/subnet.js.map +1 -0
  96. package/lib/aws/ec2/subnet.provider.d.ts +4 -0
  97. package/lib/aws/ec2/subnet.provider.d.ts.map +1 -0
  98. package/lib/aws/ec2/subnet.provider.js +250 -0
  99. package/lib/aws/ec2/subnet.provider.js.map +1 -0
  100. package/lib/aws/ec2/vpc.d.ts +13 -8
  101. package/lib/aws/ec2/vpc.d.ts.map +1 -1
  102. package/lib/aws/ec2/vpc.js +1 -0
  103. package/lib/aws/ec2/vpc.js.map +1 -1
  104. package/lib/aws/ec2/vpc.provider.d.ts +1 -2
  105. package/lib/aws/ec2/vpc.provider.d.ts.map +1 -1
  106. package/lib/aws/ec2/vpc.provider.js +45 -37
  107. package/lib/aws/ec2/vpc.provider.js.map +1 -1
  108. package/lib/aws/index.d.ts +15 -19
  109. package/lib/aws/index.d.ts.map +1 -1
  110. package/lib/aws/index.js +8 -10
  111. package/lib/aws/index.js.map +1 -1
  112. package/lib/aws/lambda/consume.d.ts +10 -11
  113. package/lib/aws/lambda/consume.d.ts.map +1 -1
  114. package/lib/aws/lambda/consume.js +3 -3
  115. package/lib/aws/lambda/consume.js.map +1 -1
  116. package/lib/aws/lambda/function.d.ts +7 -7
  117. package/lib/aws/lambda/function.d.ts.map +1 -1
  118. package/lib/aws/lambda/function.handler.d.ts +1 -1
  119. package/lib/aws/lambda/function.handler.d.ts.map +1 -1
  120. package/lib/aws/lambda/function.handler.js.map +1 -1
  121. package/lib/aws/lambda/function.invoke.d.ts +6 -4
  122. package/lib/aws/lambda/function.invoke.d.ts.map +1 -1
  123. package/lib/aws/lambda/function.invoke.js +3 -1
  124. package/lib/aws/lambda/function.invoke.js.map +1 -1
  125. package/lib/aws/lambda/function.js +1 -1
  126. package/lib/aws/lambda/function.js.map +1 -1
  127. package/lib/aws/lambda/function.provider.d.ts +3 -2
  128. package/lib/aws/lambda/function.provider.d.ts.map +1 -1
  129. package/lib/aws/lambda/function.provider.js +28 -25
  130. package/lib/aws/lambda/function.provider.js.map +1 -1
  131. package/lib/aws/lambda/index.d.ts +1 -0
  132. package/lib/aws/lambda/index.d.ts.map +1 -1
  133. package/lib/aws/lambda/index.js +1 -0
  134. package/lib/aws/lambda/index.js.map +1 -1
  135. package/lib/aws/lambda/serve.d.ts +2 -4
  136. package/lib/aws/lambda/serve.d.ts.map +1 -1
  137. package/lib/aws/profile.d.ts +2 -2
  138. package/lib/aws/profile.d.ts.map +1 -1
  139. package/lib/aws/profile.js +1 -1
  140. package/lib/aws/profile.js.map +1 -1
  141. package/lib/aws/region.d.ts +14 -2
  142. package/lib/aws/region.d.ts.map +1 -1
  143. package/lib/aws/region.js +26 -1
  144. package/lib/aws/region.js.map +1 -1
  145. package/lib/aws/sqs/client.d.ts +1 -1
  146. package/lib/aws/sqs/client.d.ts.map +1 -1
  147. package/lib/aws/sqs/index.d.ts +1 -0
  148. package/lib/aws/sqs/index.d.ts.map +1 -1
  149. package/lib/aws/sqs/index.js +1 -0
  150. package/lib/aws/sqs/index.js.map +1 -1
  151. package/lib/aws/sqs/queue.consume.d.ts +1 -1
  152. package/lib/aws/sqs/queue.consume.d.ts.map +1 -1
  153. package/lib/aws/sqs/queue.consume.js +0 -1
  154. package/lib/aws/sqs/queue.consume.js.map +1 -1
  155. package/lib/aws/sqs/queue.d.ts +6 -4
  156. package/lib/aws/sqs/queue.d.ts.map +1 -1
  157. package/lib/aws/sqs/queue.event-source.d.ts +8 -6
  158. package/lib/aws/sqs/queue.event-source.d.ts.map +1 -1
  159. package/lib/aws/sqs/queue.event-source.js +26 -44
  160. package/lib/aws/sqs/queue.event-source.js.map +1 -1
  161. package/lib/aws/sqs/queue.js +1 -1
  162. package/lib/aws/sqs/queue.js.map +1 -1
  163. package/lib/aws/sqs/queue.provider.d.ts +2 -2
  164. package/lib/aws/sqs/queue.provider.d.ts.map +1 -1
  165. package/lib/aws/sqs/queue.provider.js +2 -1
  166. package/lib/aws/sqs/queue.provider.js.map +1 -1
  167. package/lib/aws/sqs/queue.send-message.d.ts +7 -5
  168. package/lib/aws/sqs/queue.send-message.d.ts.map +1 -1
  169. package/lib/aws/sqs/queue.send-message.js +4 -2
  170. package/lib/aws/sqs/queue.send-message.js.map +1 -1
  171. package/lib/binding.d.ts +12 -12
  172. package/lib/binding.d.ts.map +1 -1
  173. package/lib/binding.js.map +1 -1
  174. package/lib/cli/components/ApprovePlan.d.ts +2 -2
  175. package/lib/cli/components/ApprovePlan.d.ts.map +1 -1
  176. package/lib/cli/components/ApprovePlan.js.map +1 -1
  177. package/lib/cli/components/Plan.d.ts +2 -2
  178. package/lib/cli/components/Plan.d.ts.map +1 -1
  179. package/lib/cli/components/Plan.js.map +1 -1
  180. package/lib/cli/components/PlanProgress.d.ts +8 -4
  181. package/lib/cli/components/PlanProgress.d.ts.map +1 -1
  182. package/lib/cli/components/PlanProgress.js +11 -1
  183. package/lib/cli/components/PlanProgress.js.map +1 -1
  184. package/lib/cli/index.d.ts +384 -264
  185. package/lib/cli/index.d.ts.map +1 -1
  186. package/lib/cli/index.js +57 -65
  187. package/lib/cli/index.js.map +1 -1
  188. package/lib/cli/ink-service.d.ts +4 -0
  189. package/lib/cli/ink-service.d.ts.map +1 -0
  190. package/lib/cli/ink-service.js +43 -0
  191. package/lib/cli/ink-service.js.map +1 -0
  192. package/lib/cli/service.d.ts +21 -0
  193. package/lib/cli/service.d.ts.map +1 -0
  194. package/lib/cli/service.js +5 -0
  195. package/lib/cli/service.js.map +1 -0
  196. package/lib/cloudflare/account.d.ts +10 -0
  197. package/lib/cloudflare/account.d.ts.map +1 -0
  198. package/lib/cloudflare/account.js +24 -0
  199. package/lib/cloudflare/account.js.map +1 -0
  200. package/lib/cloudflare/api.d.ts +7 -7
  201. package/lib/cloudflare/api.d.ts.map +1 -1
  202. package/lib/cloudflare/api.js +18 -17
  203. package/lib/cloudflare/api.js.map +1 -1
  204. package/lib/cloudflare/config.d.ts +9 -0
  205. package/lib/cloudflare/config.d.ts.map +1 -0
  206. package/lib/cloudflare/config.js +1 -0
  207. package/lib/cloudflare/config.js.map +1 -0
  208. package/lib/cloudflare/index.d.ts +3 -1
  209. package/lib/cloudflare/index.d.ts.map +1 -1
  210. package/lib/cloudflare/index.js +3 -0
  211. package/lib/cloudflare/index.js.map +1 -1
  212. package/lib/cloudflare/kv/namespace.binding.d.ts +5 -3
  213. package/lib/cloudflare/kv/namespace.binding.d.ts.map +1 -1
  214. package/lib/cloudflare/kv/namespace.binding.js +1 -1
  215. package/lib/cloudflare/kv/namespace.binding.js.map +1 -1
  216. package/lib/cloudflare/kv/namespace.client.d.ts +1 -1
  217. package/lib/cloudflare/kv/namespace.d.ts +3 -2
  218. package/lib/cloudflare/kv/namespace.d.ts.map +1 -1
  219. package/lib/cloudflare/kv/namespace.js.map +1 -1
  220. package/lib/cloudflare/kv/namespace.provider.d.ts +3 -2
  221. package/lib/cloudflare/kv/namespace.provider.d.ts.map +1 -1
  222. package/lib/cloudflare/kv/namespace.provider.js +9 -7
  223. package/lib/cloudflare/kv/namespace.provider.js.map +1 -1
  224. package/lib/cloudflare/live.d.ts +5 -5
  225. package/lib/cloudflare/live.d.ts.map +1 -1
  226. package/lib/cloudflare/live.js +5 -8
  227. package/lib/cloudflare/live.js.map +1 -1
  228. package/lib/cloudflare/r2/bucket.binding.d.ts +5 -3
  229. package/lib/cloudflare/r2/bucket.binding.d.ts.map +1 -1
  230. package/lib/cloudflare/r2/bucket.binding.js +1 -1
  231. package/lib/cloudflare/r2/bucket.binding.js.map +1 -1
  232. package/lib/cloudflare/r2/bucket.d.ts +3 -2
  233. package/lib/cloudflare/r2/bucket.d.ts.map +1 -1
  234. package/lib/cloudflare/r2/bucket.js.map +1 -1
  235. package/lib/cloudflare/r2/bucket.provider.d.ts +3 -2
  236. package/lib/cloudflare/r2/bucket.provider.d.ts.map +1 -1
  237. package/lib/cloudflare/r2/bucket.provider.js +14 -8
  238. package/lib/cloudflare/r2/bucket.provider.js.map +1 -1
  239. package/lib/cloudflare/worker/assets.fetch.d.ts +3 -2
  240. package/lib/cloudflare/worker/assets.fetch.d.ts.map +1 -1
  241. package/lib/cloudflare/worker/assets.fetch.js +2 -1
  242. package/lib/cloudflare/worker/assets.fetch.js.map +1 -1
  243. package/lib/cloudflare/worker/assets.provider.d.ts +1 -1
  244. package/lib/cloudflare/worker/assets.provider.d.ts.map +1 -1
  245. package/lib/cloudflare/worker/index.d.ts +0 -1
  246. package/lib/cloudflare/worker/index.d.ts.map +1 -1
  247. package/lib/cloudflare/worker/worker.d.ts +5 -6
  248. package/lib/cloudflare/worker/worker.d.ts.map +1 -1
  249. package/lib/cloudflare/worker/worker.handler.d.ts +1 -1
  250. package/lib/cloudflare/worker/worker.handler.d.ts.map +1 -1
  251. package/lib/cloudflare/worker/worker.handler.js.map +1 -1
  252. package/lib/cloudflare/worker/worker.js.map +1 -1
  253. package/lib/cloudflare/worker/worker.provider.d.ts +3 -2
  254. package/lib/cloudflare/worker/worker.provider.d.ts.map +1 -1
  255. package/lib/cloudflare/worker/worker.provider.js +12 -7
  256. package/lib/cloudflare/worker/worker.provider.js.map +1 -1
  257. package/lib/cloudflare/worker/worker.serve.d.ts +7 -7
  258. package/lib/cloudflare/worker/worker.serve.d.ts.map +1 -1
  259. package/lib/cloudflare/worker/worker.serve.js.map +1 -1
  260. package/lib/data.d.ts +3 -0
  261. package/lib/data.d.ts.map +1 -0
  262. package/lib/data.js +8 -0
  263. package/lib/data.js.map +1 -0
  264. package/lib/destroy.d.ts +1 -1
  265. package/lib/destroy.d.ts.map +1 -1
  266. package/lib/destroy.js +1 -4
  267. package/lib/destroy.js.map +1 -1
  268. package/lib/diff.d.ts +18 -0
  269. package/lib/diff.d.ts.map +1 -0
  270. package/lib/diff.js +22 -0
  271. package/lib/diff.js.map +1 -0
  272. package/lib/env.d.ts +5 -0
  273. package/lib/env.d.ts.map +1 -1
  274. package/lib/env.js +15 -29
  275. package/lib/env.js.map +1 -1
  276. package/lib/event.d.ts +1 -1
  277. package/lib/event.d.ts.map +1 -1
  278. package/lib/exports.d.ts +9 -0
  279. package/lib/exports.d.ts.map +1 -0
  280. package/lib/exports.js +13 -0
  281. package/lib/exports.js.map +1 -0
  282. package/lib/index.d.ts +10 -2
  283. package/lib/index.d.ts.map +1 -1
  284. package/lib/index.js +10 -5
  285. package/lib/index.js.map +1 -1
  286. package/lib/input.d.ts +32 -0
  287. package/lib/input.d.ts.map +1 -0
  288. package/lib/input.js +1 -0
  289. package/lib/input.js.map +1 -0
  290. package/lib/instance-id.d.ts +8 -0
  291. package/lib/instance-id.d.ts.map +1 -0
  292. package/lib/instance-id.js +12 -0
  293. package/lib/instance-id.js.map +1 -0
  294. package/lib/output.d.ts +145 -0
  295. package/lib/output.d.ts.map +1 -0
  296. package/lib/output.js +283 -0
  297. package/lib/output.js.map +1 -0
  298. package/lib/physical-name.d.ts +14 -1
  299. package/lib/physical-name.d.ts.map +1 -1
  300. package/lib/physical-name.js +41 -2
  301. package/lib/physical-name.js.map +1 -1
  302. package/lib/plan.d.ts +84 -58
  303. package/lib/plan.d.ts.map +1 -1
  304. package/lib/plan.js +504 -166
  305. package/lib/plan.js.map +1 -1
  306. package/lib/policy.d.ts +3 -4
  307. package/lib/policy.d.ts.map +1 -1
  308. package/lib/policy.js +0 -1
  309. package/lib/policy.js.map +1 -1
  310. package/lib/provider.d.ts +39 -24
  311. package/lib/provider.d.ts.map +1 -1
  312. package/lib/provider.js +9 -0
  313. package/lib/provider.js.map +1 -1
  314. package/lib/ref.d.ts +14 -0
  315. package/lib/ref.d.ts.map +1 -0
  316. package/lib/ref.js +21 -0
  317. package/lib/ref.js.map +1 -0
  318. package/lib/resource.d.ts +13 -8
  319. package/lib/resource.d.ts.map +1 -1
  320. package/lib/resource.js.map +1 -1
  321. package/lib/runtime.d.ts +7 -6
  322. package/lib/runtime.d.ts.map +1 -1
  323. package/lib/runtime.js.map +1 -1
  324. package/lib/service.d.ts +9 -6
  325. package/lib/service.d.ts.map +1 -1
  326. package/lib/service.js.map +1 -1
  327. package/lib/stack.d.ts +60 -0
  328. package/lib/stack.d.ts.map +1 -0
  329. package/lib/stack.js +11 -0
  330. package/lib/stack.js.map +1 -0
  331. package/lib/stage.d.ts +39 -0
  332. package/lib/stage.d.ts.map +1 -0
  333. package/lib/stage.js +32 -0
  334. package/lib/stage.js.map +1 -0
  335. package/lib/state.d.ts +135 -17
  336. package/lib/state.d.ts.map +1 -1
  337. package/lib/state.js +34 -30
  338. package/lib/state.js.map +1 -1
  339. package/lib/tags.d.ts +15 -0
  340. package/lib/tags.d.ts.map +1 -1
  341. package/lib/tags.js +27 -0
  342. package/lib/tags.js.map +1 -1
  343. package/lib/test.d.ts +25 -4
  344. package/lib/test.d.ts.map +1 -1
  345. package/lib/test.js +54 -14
  346. package/lib/test.js.map +1 -1
  347. package/lib/todo.d.ts +3 -0
  348. package/lib/todo.d.ts.map +1 -0
  349. package/lib/todo.js +3 -0
  350. package/lib/todo.js.map +1 -0
  351. package/lib/tsconfig.test.tsbuildinfo +1 -1
  352. package/lib/type.d.ts +3 -0
  353. package/lib/type.d.ts.map +1 -1
  354. package/lib/unknown.d.ts +4 -0
  355. package/lib/unknown.d.ts.map +1 -0
  356. package/lib/unknown.js +4 -0
  357. package/lib/unknown.js.map +1 -0
  358. package/lib/user.d.ts +3 -0
  359. package/lib/user.d.ts.map +1 -0
  360. package/lib/user.js +3 -0
  361. package/lib/user.js.map +1 -0
  362. package/lib/util.d.ts +6 -0
  363. package/lib/util.d.ts.map +1 -0
  364. package/lib/util.js +9 -0
  365. package/lib/util.js.map +1 -0
  366. package/package.json +18 -12
  367. package/src/$.ts +17 -0
  368. package/src/app.ts +3 -32
  369. package/src/apply.ts +824 -452
  370. package/src/assert-never.ts +18 -0
  371. package/src/aws/account.ts +23 -3
  372. package/src/aws/client.ts +0 -1
  373. package/src/aws/config.ts +16 -0
  374. package/src/aws/credentials.ts +212 -177
  375. package/src/aws/dynamodb/index.ts +3 -3
  376. package/src/aws/dynamodb/table.get-item.ts +5 -9
  377. package/src/aws/dynamodb/table.provider.ts +36 -39
  378. package/src/aws/dynamodb/table.ts +29 -84
  379. package/src/aws/ec2/index.ts +12 -0
  380. package/src/aws/ec2/internet-gateway.provider.ts +316 -0
  381. package/src/aws/ec2/internet-gateway.ts +79 -0
  382. package/src/aws/ec2/route-table-association.provider.ts +214 -0
  383. package/src/aws/ec2/route-table-association.ts +82 -0
  384. package/src/aws/ec2/route-table.provider.ts +306 -0
  385. package/src/aws/ec2/route-table.ts +175 -0
  386. package/src/aws/ec2/route.provider.ts +213 -0
  387. package/src/aws/ec2/route.ts +192 -0
  388. package/src/aws/ec2/subnet.provider.ts +358 -0
  389. package/src/aws/ec2/subnet.ts +213 -0
  390. package/src/aws/ec2/vpc.provider.ts +58 -50
  391. package/src/aws/ec2/vpc.ts +21 -8
  392. package/src/aws/index.ts +49 -40
  393. package/src/aws/lambda/consume.ts +8 -7
  394. package/src/aws/lambda/function.handler.ts +1 -1
  395. package/src/aws/lambda/function.invoke.ts +6 -2
  396. package/src/aws/lambda/function.provider.ts +41 -32
  397. package/src/aws/lambda/function.ts +7 -4
  398. package/src/aws/lambda/index.ts +2 -0
  399. package/src/aws/profile.ts +1 -4
  400. package/src/aws/region.ts +42 -3
  401. package/src/aws/sqs/index.ts +2 -0
  402. package/src/aws/sqs/queue.consume.ts +1 -1
  403. package/src/aws/sqs/queue.event-source.ts +29 -55
  404. package/src/aws/sqs/queue.provider.ts +10 -2
  405. package/src/aws/sqs/queue.send-message.ts +5 -8
  406. package/src/aws/sqs/queue.ts +9 -4
  407. package/src/binding.ts +19 -19
  408. package/src/cli/components/ApprovePlan.tsx +2 -2
  409. package/src/cli/components/Plan.tsx +3 -2
  410. package/src/cli/components/PlanProgress.tsx +32 -14
  411. package/src/cli/index.ts +2 -6
  412. package/src/cli/ink-service.tsx +61 -0
  413. package/src/cli/service.ts +23 -0
  414. package/src/cloudflare/account.ts +37 -0
  415. package/src/cloudflare/api.ts +33 -29
  416. package/src/cloudflare/config.ts +7 -0
  417. package/src/cloudflare/index.ts +3 -1
  418. package/src/cloudflare/kv/namespace.binding.ts +3 -1
  419. package/src/cloudflare/kv/namespace.provider.ts +10 -8
  420. package/src/cloudflare/kv/namespace.ts +3 -2
  421. package/src/cloudflare/live.ts +11 -17
  422. package/src/cloudflare/r2/bucket.binding.ts +3 -1
  423. package/src/cloudflare/r2/bucket.provider.ts +16 -9
  424. package/src/cloudflare/r2/bucket.ts +8 -2
  425. package/src/cloudflare/worker/assets.fetch.ts +3 -1
  426. package/src/cloudflare/worker/assets.provider.ts +1 -1
  427. package/src/cloudflare/worker/index.ts +0 -2
  428. package/src/cloudflare/worker/worker.handler.ts +1 -1
  429. package/src/cloudflare/worker/worker.provider.ts +21 -14
  430. package/src/cloudflare/worker/worker.serve.ts +5 -2
  431. package/src/cloudflare/worker/worker.ts +4 -3
  432. package/src/data.ts +18 -0
  433. package/src/destroy.ts +1 -5
  434. package/src/diff.ts +48 -0
  435. package/src/env.ts +20 -32
  436. package/src/event.ts +6 -0
  437. package/src/exports.ts +21 -0
  438. package/src/index.ts +10 -5
  439. package/src/input.ts +81 -0
  440. package/src/instance-id.ts +16 -0
  441. package/src/output.ts +542 -0
  442. package/src/physical-name.ts +57 -2
  443. package/src/plan.ts +757 -278
  444. package/src/policy.ts +3 -5
  445. package/src/provider.ts +70 -31
  446. package/src/ref.ts +48 -0
  447. package/src/resource.ts +70 -10
  448. package/src/runtime.ts +15 -8
  449. package/src/service.ts +11 -7
  450. package/src/stack.ts +116 -0
  451. package/src/stage.ts +85 -0
  452. package/src/state.ts +269 -76
  453. package/src/tags.ts +31 -0
  454. package/src/test.ts +118 -17
  455. package/src/todo.ts +4 -0
  456. package/src/type.ts +4 -0
  457. package/src/unknown.ts +6 -0
  458. package/src/user.ts +4 -0
  459. package/src/util.ts +21 -0
  460. package/lib/approve.d.ts +0 -15
  461. package/lib/approve.d.ts.map +0 -1
  462. package/lib/approve.js +0 -7
  463. package/lib/approve.js.map +0 -1
  464. package/lib/cli/approve.d.ts +0 -4
  465. package/lib/cli/approve.d.ts.map +0 -1
  466. package/lib/cli/approve.js +0 -18
  467. package/lib/cli/approve.js.map +0 -1
  468. package/lib/cli/clack.d.ts +0 -14
  469. package/lib/cli/clack.d.ts.map +0 -1
  470. package/lib/cli/clack.js +0 -12
  471. package/lib/cli/clack.js.map +0 -1
  472. package/lib/cli/main.d.ts +0 -2
  473. package/lib/cli/main.d.ts.map +0 -1
  474. package/lib/cli/main.js +0 -1
  475. package/lib/cli/main.js.map +0 -1
  476. package/lib/cli/plan.d.ts +0 -13
  477. package/lib/cli/plan.d.ts.map +0 -1
  478. package/lib/cli/plan.js +0 -1
  479. package/lib/cli/plan.js.map +0 -1
  480. package/lib/cli/progress.d.ts +0 -7
  481. package/lib/cli/progress.d.ts.map +0 -1
  482. package/lib/cli/progress.js +0 -30
  483. package/lib/cli/progress.js.map +0 -1
  484. package/lib/cli/spinner.d.ts +0 -2
  485. package/lib/cli/spinner.d.ts.map +0 -1
  486. package/lib/cli/spinner.js +0 -13
  487. package/lib/cli/spinner.js.map +0 -1
  488. package/src/approve.ts +0 -13
  489. package/src/cli/approve.tsx +0 -30
  490. package/src/cli/clack.ts +0 -22
  491. package/src/cli/main.ts +0 -0
  492. package/src/cli/plan.ts +0 -16
  493. package/src/cli/progress.tsx +0 -46
  494. package/src/cli/spinner.ts +0 -14
package/lib/plan.js CHANGED
@@ -2,9 +2,12 @@ import * as Context from "effect/Context";
2
2
  import * as Data from "effect/Data";
3
3
  import * as Effect from "effect/Effect";
4
4
  import { omit } from "effect/Struct";
5
- import {} from "./provider.js";
5
+ import { App } from "./app.js";
6
+ import * as Output from "./output.js";
7
+ import { getProviderByType } from "./provider.js";
6
8
  import { isService } from "./service.js";
7
- import { State, StateStoreError } from "./state.js";
9
+ import { State, StateStoreError, } from "./state.js";
10
+ import { asEffect } from "./util.js";
8
11
  export const isBindNode = (node) => {
9
12
  return (node &&
10
13
  typeof node === "object" &&
@@ -20,187 +23,443 @@ export const isCRUD = (node) => {
20
23
  node.action === "replace" ||
21
24
  node.action === "noop"));
22
25
  };
23
- const Node = (node) => ({
24
- ...node,
25
- toString() {
26
- return `${this.action.charAt(0).toUpperCase()}${this.action.slice(1)}(${this.resource})`;
27
- },
28
- [Symbol.toStringTag]() {
29
- return this.toString();
30
- },
31
- });
32
- export const plan = ({ phase, resources, }) => {
33
- return Effect.gen(function* () {
34
- const state = yield* State;
35
- const resourceIds = yield* state.list();
36
- const resourcesState = yield* Effect.all(resourceIds.map((id) => state.get(id)));
37
- // map of resource ID -> its downstream dependencies (resources that depend on it)
38
- const downstream = resourcesState
39
- .filter((resource) => !!resource?.bindings)
40
- .flatMap((resource) => resource.bindings.flatMap(({ binding }) => [
41
- [binding.capability.resource.id, binding.capability.resource],
42
- ]))
43
- .reduce((acc, [id, resourceId]) => ({
44
- ...acc,
45
- [id]: [...(acc[id] ?? []), resourceId],
46
- }), {});
47
- const resourceGraph = phase === "update"
48
- ? Object.fromEntries((yield* Effect.all(resources
49
- .flatMap((resource) => [
50
- ...(isService(resource)
51
- ? resource.props.bindings.capabilities.map((cap) => cap.resource)
52
- : []),
53
- resource,
54
- ])
55
- .filter((node, i, arr) => arr.findIndex((n) => n.id === node.id) === i)
56
- .map(Effect.fn(function* (node) {
57
- const id = node.id;
58
- const resource = node;
59
- const news = resource.props;
60
- const oldState = yield* state.get(id);
26
+ export const plan = (..._resources) => Effect.gen(function* () {
27
+ const state = yield* State;
28
+ const findResources = (resource, visited) => {
29
+ if (visited.has(resource.id)) {
30
+ return [];
31
+ }
32
+ visited.add(resource.id);
33
+ const upstream = Object.values(Output.upstreamAny(resource.props));
34
+ return [
35
+ resource,
36
+ ...upstream,
37
+ ...upstream.flatMap((r) => findResources(r, visited)),
38
+ ];
39
+ };
40
+ const resources = _resources
41
+ .flatMap((r) => findResources(r, new Set()))
42
+ .filter((r, i, arr) => arr.findIndex((r2) => r2.id === r.id) === i);
43
+ // TODO(sam): rename terminology to Stack
44
+ const app = yield* App;
45
+ const resourceIds = yield* state.list({
46
+ stack: app.name,
47
+ stage: app.stage,
48
+ });
49
+ const oldResources = yield* Effect.all(resourceIds.map((id) => state.get({ stack: app.name, stage: app.stage, resourceId: id })));
50
+ const resolvedResources = {};
51
+ const resolveResource = (resourceExpr) => Effect.gen(function* () {
52
+ return yield* (resolvedResources[resourceExpr.src.id] ??=
53
+ yield* Effect.cached(Effect.gen(function* () {
54
+ const resource = resourceExpr.src;
61
55
  const provider = yield* resource.provider.tag;
62
- const bindings = isService(node)
63
- ? yield* diffBindings({
64
- oldState,
65
- bindings: node.props.bindings.bindings,
66
- target: {
67
- id: node.id,
68
- props: node.props,
69
- oldAttr: oldState?.output,
70
- oldProps: oldState?.props,
71
- },
72
- })
73
- : []; // TODO(sam): return undefined instead of empty array
74
- if (oldState === undefined ||
75
- oldState.status === "creating") {
76
- return Node({
77
- action: "create",
78
- news,
79
- provider,
80
- resource,
81
- bindings,
82
- // phantom
83
- attributes: undefined,
84
- });
56
+ const props = yield* resolveInput(resource.props);
57
+ const oldState = yield* state.get({
58
+ stack: app.name,
59
+ stage: app.stage,
60
+ resourceId: resource.id,
61
+ });
62
+ if (!oldState || oldState.status === "creating") {
63
+ return resourceExpr;
85
64
  }
86
- const diff = provider.diff
87
- ? yield* provider.diff({
88
- id,
89
- olds: oldState.props,
90
- news,
91
- output: oldState.output,
65
+ const oldProps = oldState.status === "created" ||
66
+ oldState.status === "updated" ||
67
+ oldState.status === "replaced"
68
+ ? // if we're in a stable state, then just use the props
69
+ oldState.props
70
+ : // if we failed to update or replace, compare with the last known stable props
71
+ oldState.status === "updating" ||
72
+ oldState.status === "replacing"
73
+ ? oldState.old.props
74
+ : // TODO(sam): it kinda doesn't make sense to diff with a "deleting" state
75
+ oldState.props;
76
+ const diff = yield* provider.diff
77
+ ? provider.diff({
78
+ id: resource.id,
79
+ olds: oldProps,
80
+ instanceId: oldState.instanceId,
81
+ news: props,
82
+ output: oldState.attr,
92
83
  })
93
- : undefined;
94
- if (!diff && arePropsChanged(oldState, resource.props)) {
95
- return Node({
96
- action: "update",
97
- olds: oldState.props,
98
- news,
99
- output: oldState.output,
100
- provider,
101
- resource,
102
- bindings,
103
- // phantom
104
- attributes: undefined,
105
- });
84
+ : Effect.succeed(undefined);
85
+ const stables = [
86
+ ...(provider.stables ?? []),
87
+ ...(diff?.stables ?? []),
88
+ ];
89
+ const withStables = (output) => stables.length > 0
90
+ ? new Output.ResourceExpr(resourceExpr.src, Object.fromEntries(stables.map((stable) => [stable, output?.[stable]])))
91
+ : // if there are no stable properties, treat every property as changed
92
+ resourceExpr;
93
+ if (diff == null) {
94
+ if (arePropsChanged(oldProps, props)) {
95
+ // the props have changed but the provider did not provide any hints as to what is stable
96
+ // so we must assume everything has changed
97
+ return withStables(oldState?.attr);
98
+ }
106
99
  }
107
- else if (diff?.action === "replace") {
108
- return Node({
109
- action: "replace",
110
- olds: oldState.props,
111
- news,
112
- output: oldState.output,
113
- provider,
114
- resource,
115
- bindings,
116
- // phantom
117
- attributes: undefined,
118
- });
100
+ else if (diff.action === "update") {
101
+ return withStables(oldState?.attr);
119
102
  }
120
- else if (diff?.action === "update") {
121
- return Node({
122
- action: "update",
123
- olds: oldState.props,
124
- news,
125
- output: oldState.output,
126
- provider,
127
- resource,
128
- bindings,
129
- // phantom
130
- attributes: undefined,
131
- });
103
+ else if (diff.action === "replace") {
104
+ return resourceExpr;
105
+ }
106
+ if (oldState.status === "created" ||
107
+ oldState.status === "updated" ||
108
+ oldState.status === "replaced") {
109
+ // we can safely return the attributes if we know they have stabilized
110
+ return oldState?.attr;
132
111
  }
133
112
  else {
134
- return Node({
135
- action: "noop",
136
- resource,
137
- bindings,
138
- // phantom
139
- attributes: undefined,
140
- });
113
+ // we must assume the resource doesn't exist if it hasn't stabilized
114
+ return resourceExpr;
141
115
  }
142
- })))).map((update) => [update.resource.id, update]))
143
- : {};
144
- const deletions = Object.fromEntries((yield* Effect.all((yield* state.list()).map(Effect.fn(function* (id) {
145
- if (id in resourceGraph) {
146
- return;
116
+ })));
117
+ });
118
+ const resolveInput = (input) => Effect.gen(function* () {
119
+ if (!input) {
120
+ return input;
121
+ }
122
+ else if (Output.isExpr(input)) {
123
+ return yield* resolveOutput(input);
124
+ }
125
+ else if (Array.isArray(input)) {
126
+ return yield* Effect.all(input.map(resolveInput));
127
+ }
128
+ else if (typeof input === "object") {
129
+ return Object.fromEntries(yield* Effect.all(Object.entries(input).map(([key, value]) => resolveInput(value).pipe(Effect.map((value) => [key, value])))));
130
+ }
131
+ return input;
132
+ });
133
+ const resolveOutput = (expr) => Effect.gen(function* () {
134
+ if (Output.isResourceExpr(expr)) {
135
+ return yield* resolveResource(expr);
136
+ }
137
+ else if (Output.isPropExpr(expr)) {
138
+ const upstream = yield* resolveOutput(expr.expr);
139
+ return upstream?.[expr.identifier];
140
+ }
141
+ else if (Output.isApplyExpr(expr)) {
142
+ const upstream = yield* resolveOutput(expr.expr);
143
+ return Output.hasOutputs(upstream) ? expr : expr.f(upstream);
144
+ }
145
+ else if (Output.isEffectExpr(expr)) {
146
+ const upstream = yield* resolveOutput(expr.expr);
147
+ return Output.hasOutputs(upstream) ? expr : yield* expr.f(upstream);
148
+ }
149
+ else if (Output.isAllExpr(expr)) {
150
+ return yield* Effect.all(expr.outs.map(resolveOutput));
151
+ }
152
+ return yield* Effect.die(new Error("Not implemented yet"));
153
+ });
154
+ // map of resource ID -> its downstream dependencies (resources that depend on it)
155
+ const oldDownstreamDependencies = Object.fromEntries(oldResources
156
+ .filter((resource) => !!resource)
157
+ .map((resource) => [resource.logicalId, resource.downstream]));
158
+ const newUpstreamDependencies = Object.fromEntries(resources.map((resource) => [
159
+ resource.id,
160
+ [
161
+ ...Object.values(Output.upstreamAny(resource.props)).map((r) => r.id),
162
+ ...(isService(resource)
163
+ ? resource.props.bindings.capabilities.map((cap) => cap.resource.id)
164
+ : []),
165
+ ],
166
+ ]));
167
+ const newDownstreamDependencies = Object.fromEntries(resources.map((resource) => [
168
+ resource.id,
169
+ Object.entries(newUpstreamDependencies)
170
+ .filter(([_, downstream]) => downstream.includes(resource.id))
171
+ .map(([id]) => id),
172
+ ]));
173
+ const resourceGraph = Object.fromEntries((yield* Effect.all(resources
174
+ .flatMap((resource) => [
175
+ ...(isService(resource)
176
+ ? resource.props.bindings.capabilities.map((cap) => cap.resource)
177
+ : []),
178
+ ...Object.values(Output.upstreamAny(resource.props)),
179
+ resource,
180
+ ])
181
+ .filter((node, i, arr) => arr.findIndex((n) => n.id === node.id) === i)
182
+ .map(Effect.fn(function* (node) {
183
+ const id = node.id;
184
+ const resource = node;
185
+ const news = yield* resolveInput(resource.props);
186
+ const oldState = yield* state.get({
187
+ stack: app.name,
188
+ stage: app.stage,
189
+ resourceId: id,
190
+ });
191
+ const provider = yield* resource.provider.tag;
192
+ const downstream = newDownstreamDependencies[id] ?? [];
193
+ const bindings = isService(node)
194
+ ? yield* diffBindings({
195
+ oldState,
196
+ bindings: node.props.bindings.bindings,
197
+ target: {
198
+ id: node.id,
199
+ props: node.props,
200
+ // TODO(sam): pick the right ones based on old status
201
+ oldAttr: oldState?.attr,
202
+ oldProps: oldState?.props,
203
+ },
204
+ })
205
+ : []; // TODO(sam): return undefined instead of empty array
206
+ const Node = (node) => ({
207
+ ...node,
208
+ provider,
209
+ resource,
210
+ bindings,
211
+ downstream,
212
+ });
213
+ // handle empty and intermediate (non-final) states:
214
+ if (oldState === undefined) {
215
+ return Node({
216
+ action: "create",
217
+ props: news,
218
+ state: oldState,
219
+ });
220
+ }
221
+ // TODO(sam): is this correct for all possible states a resource can be in?
222
+ const oldProps = oldState.props;
223
+ const diff = yield* asEffect(provider.diff
224
+ ? provider.diff({
225
+ id,
226
+ olds: oldProps,
227
+ instanceId: oldState.instanceId,
228
+ output: oldState.attr,
229
+ news,
230
+ })
231
+ : undefined).pipe(Effect.map((diff) => diff ??
232
+ {
233
+ action: arePropsChanged(oldProps, news)
234
+ ? "update"
235
+ : "noop",
236
+ }));
237
+ if (oldState.status === "creating") {
238
+ if (diff.action === "noop") {
239
+ // we're in the creating state and props are un-changed
240
+ // let's just continue where we left off
241
+ return Node({
242
+ action: "create",
243
+ props: news,
244
+ state: oldState,
245
+ });
147
246
  }
148
- const oldState = yield* state.get(id);
149
- const context = yield* Effect.context();
150
- if (oldState) {
151
- const provider = context.unsafeMap.get(oldState?.type);
152
- if (!provider) {
153
- yield* Effect.die(new Error(`Provider not found for ${oldState?.type}`));
154
- }
155
- return [
156
- id,
157
- {
158
- action: "delete",
159
- olds: oldState.props,
160
- output: oldState.output,
161
- provider,
162
- attributes: oldState?.output,
163
- // TODO(sam): Support Detach Bindings
164
- bindings: [],
165
- resource: {
166
- id: id,
167
- parent: undefined,
168
- type: oldState.type,
169
- attr: oldState.output,
170
- props: oldState.props,
171
- },
172
- downstream: downstream[id] ?? [],
247
+ else if (diff.action === "update") {
248
+ // props have changed in a way that is updatable
249
+ // again, just continue with the create
250
+ // TODO(sam): should we maybe try an update instead?
251
+ return Node({
252
+ action: "create",
253
+ props: news,
254
+ state: oldState,
255
+ });
256
+ }
257
+ else {
258
+ // props have changed in an incompatible way
259
+ // because it's possible that an un-updatable resource has already been created
260
+ // we must use a replace step to create a new one and delete the potential old one
261
+ return Node({
262
+ action: "replace",
263
+ props: news,
264
+ deleteFirst: diff.deleteFirst ?? false,
265
+ state: oldState,
266
+ });
267
+ }
268
+ }
269
+ else if (oldState.status === "updating") {
270
+ // we started to update a resource but did not complete
271
+ if (diff.action === "update" || diff.action === "noop") {
272
+ return Node({
273
+ action: "update",
274
+ props: news,
275
+ state: oldState,
276
+ });
277
+ }
278
+ else {
279
+ // we started to update a resource but now believe we should replace it
280
+ return Node({
281
+ action: "replace",
282
+ deleteFirst: diff.deleteFirst ?? false,
283
+ props: news,
284
+ // TODO(sam): can Apply handle replacements when the oldState is UpdatingResourceState?
285
+ // -> or is there we do a provider.read to try and reconcile back to UpdatedResourceState?
286
+ state: oldState,
287
+ });
288
+ }
289
+ }
290
+ else if (oldState.status === "replacing") {
291
+ // resource replacement started, but the replacement may or may not have been created
292
+ if (diff.action === "noop") {
293
+ // this is the stable case - noop means just continue with the replacement
294
+ return Node({
295
+ action: "replace",
296
+ deleteFirst: oldState.deleteFirst,
297
+ props: news,
298
+ state: oldState,
299
+ });
300
+ }
301
+ else if (diff.action === "update") {
302
+ // potential problem here - the props have changed since we tried to replace,
303
+ // but not enough to trigger another replacement. the resource provider should
304
+ // be designed as idempotent to converge to the right state when creating the new resource
305
+ // the newly generated instanceId is intended to assist with this
306
+ return Node({
307
+ action: "replace",
308
+ deleteFirst: oldState.deleteFirst,
309
+ props: news,
310
+ state: oldState,
311
+ });
312
+ }
313
+ else {
314
+ // ah shit, so we tried to replace the resource and then crashed
315
+ // now the props have changed again in such a way that the (maybe, maybe not)
316
+ // created resource should also be replaced
317
+ // TODO(sam): what should we do?
318
+ // 1. trigger a deletion of the potentially created resource
319
+ // 2. expect the resource provider to handle it idempotently?
320
+ // -> i don't think this case is fair to put on the resource provider
321
+ // because if the resource was created, it's in a state that can't be updated
322
+ return yield* Effect.fail(new CannotReplacePartiallyReplacedResource(id));
323
+ }
324
+ }
325
+ else if (oldState.status === "replaced") {
326
+ // replacement has been created but we're not done cleaning up the old state
327
+ if (diff.action === "noop") {
328
+ // this is the stable case - noop means just continue cleaning up the replacement
329
+ return Node({
330
+ action: "replace",
331
+ deleteFirst: oldState.deleteFirst,
332
+ props: news,
333
+ state: oldState,
334
+ });
335
+ }
336
+ else if (diff.action === "update") {
337
+ // the replacement has been created but now also needs to be updated
338
+ // the resource provider should:
339
+ // 1. Update the newly created replacement resource
340
+ // 2. Then proceed as normal to delete the replaced resources (after all downstream references are updated)
341
+ return Node({
342
+ action: "update",
343
+ props: news,
344
+ state: oldState,
345
+ });
346
+ }
347
+ else {
348
+ // the replacement has been created but now it needs to be replaced
349
+ // this is the worst-case scenario because downstream resources
350
+ // could have been been updated to point to the replaced resources
351
+ return yield* Effect.fail(new CannotReplacePartiallyReplacedResource(id));
352
+ }
353
+ }
354
+ else if (oldState.status === "deleting") {
355
+ if (diff.action === "noop" || diff.action === "update") {
356
+ // we're in a partially deleted state, it is unclear whether it was or was not deleted
357
+ // it should be safe to re-create it with the same instanceId?
358
+ return Node({
359
+ action: "create",
360
+ props: news,
361
+ state: {
362
+ ...oldState,
363
+ status: "creating",
364
+ props: news,
173
365
  },
174
- ];
366
+ });
175
367
  }
176
- })))).filter((v) => !!v));
177
- for (const [resourceId, deletion] of Object.entries(deletions)) {
178
- const dependencies = deletion.downstream.filter((d) => d in resourceGraph);
179
- if (dependencies.length > 0) {
180
- return yield* Effect.fail(new DeleteResourceHasDownstreamDependencies({
181
- message: `Resource ${resourceId} has downstream dependencies`,
182
- resourceId,
183
- dependencies,
184
- }));
368
+ else {
369
+ return yield* Effect.fail(new CannotReplacePartiallyReplacedResource(id));
185
370
  }
186
371
  }
187
- return {
188
- phase,
189
- resources: resourceGraph,
190
- deletions,
191
- };
192
- });
193
- };
194
- class DeleteResourceHasDownstreamDependencies extends Data.TaggedError("DeleteResourceHasDownstreamDependencies") {
372
+ else if (diff.action === "update") {
373
+ return Node({
374
+ action: "update",
375
+ props: news,
376
+ state: oldState,
377
+ });
378
+ }
379
+ else if (diff.action === "replace") {
380
+ return Node({
381
+ action: "replace",
382
+ props: news,
383
+ state: oldState,
384
+ deleteFirst: diff?.deleteFirst ?? false,
385
+ });
386
+ }
387
+ else {
388
+ return Node({
389
+ action: "noop",
390
+ state: oldState,
391
+ });
392
+ }
393
+ })))).map((update) => [update.resource.id, update]));
394
+ const deletions = Object.fromEntries((yield* Effect.all((yield* state.list({ stack: app.name, stage: app.stage })).map(Effect.fn(function* (id) {
395
+ if (id in resourceGraph) {
396
+ return;
397
+ }
398
+ const oldState = yield* state.get({
399
+ stack: app.name,
400
+ stage: app.stage,
401
+ resourceId: id,
402
+ });
403
+ if (oldState) {
404
+ const provider = yield* getProviderByType(oldState.resourceType);
405
+ return [
406
+ id,
407
+ {
408
+ action: "delete",
409
+ state: oldState,
410
+ // // TODO(sam): Support Detach Bindings
411
+ bindings: [],
412
+ provider,
413
+ resource: {
414
+ id: id,
415
+ type: oldState.resourceType,
416
+ attr: oldState.attr,
417
+ props: oldState.props,
418
+ },
419
+ // TODO(sam): is it enough to just pass through oldState?
420
+ downstream: oldDownstreamDependencies[id] ?? [],
421
+ },
422
+ ];
423
+ }
424
+ })))).filter((v) => !!v));
425
+ for (const [resourceId, deletion] of Object.entries(deletions)) {
426
+ const dependencies = deletion.state.downstream.filter((d) => d in resourceGraph);
427
+ if (dependencies.length > 0) {
428
+ return yield* Effect.fail(new DeleteResourceHasDownstreamDependencies({
429
+ message: `Resource ${resourceId} has downstream dependencies`,
430
+ resourceId,
431
+ dependencies,
432
+ }));
433
+ }
434
+ }
435
+ return {
436
+ resources: resourceGraph,
437
+ deletions,
438
+ };
439
+ });
440
+ export class CannotReplacePartiallyReplacedResource extends Data.TaggedError("CannotReplacePartiallyReplacedResource") {
441
+ constructor(logicalId) {
442
+ super({
443
+ message: `Resource '${logicalId}' did not finish being replaced in a previous deployment ` +
444
+ `and is expected to be replaced again in this deployment. ` +
445
+ `You should revert its properties and try again after a successful deployment.`,
446
+ logicalId,
447
+ });
448
+ }
195
449
  }
196
- const arePropsChanged = (oldState, newProps) => {
197
- return (JSON.stringify(omit(oldState?.props ?? {}, "bindings")) !==
198
- JSON.stringify(omit((newProps ?? {}), "bindings")));
450
+ export class DeleteResourceHasDownstreamDependencies extends Data.TaggedError("DeleteResourceHasDownstreamDependencies") {
451
+ }
452
+ const arePropsChanged = (oldProps, newProps) => {
453
+ return (Output.hasOutputs(newProps) ||
454
+ JSON.stringify(omit((oldProps ?? {}), "bindings")) !==
455
+ JSON.stringify(omit((newProps ?? {}), "bindings")));
199
456
  };
200
457
  const diffBindings = Effect.fn(function* ({ oldState, bindings, target, }) {
201
458
  // const actions: BindNode[] = [];
202
459
  const oldBindings = oldState?.bindings;
203
- const oldSids = new Set(oldBindings?.map(({ binding }) => binding.capability.sid));
460
+ // const oldSids = new Set(
461
+ // oldBindings?.map(({ binding }) => binding.capability.sid),
462
+ // );
204
463
  const diffBinding = Effect.fn(function* (binding) {
205
464
  const cap = binding.capability;
206
465
  const sid = cap.sid ?? `${cap.action}:${cap.resource.ID}`;
@@ -277,7 +536,7 @@ const isBindingDiff = Effect.fn(function* ({ target, oldBinding: { binding: oldB
277
536
  id: oldCap.resource.id,
278
537
  props: newCap.resource.props,
279
538
  oldProps: oldState?.props,
280
- oldAttr: oldState?.output,
539
+ oldAttr: oldState?.attr,
281
540
  },
282
541
  props: newBinding.props,
283
542
  attr: oldBinding.attr,
@@ -297,4 +556,83 @@ const isBindingDiff = Effect.fn(function* ({ target, oldBinding: { binding: oldB
297
556
  });
298
557
  // TODO(sam): compare props
299
558
  // oldBinding.props !== newBinding.props;
559
+ /**
560
+ * Print a plan in a human-readable format that shows the graph topology.
561
+ */
562
+ export const printPlan = (plan) => {
563
+ const lines = [];
564
+ const allNodes = { ...plan.resources, ...plan.deletions };
565
+ // Build reverse mapping: upstream -> downstream
566
+ const upstreamMap = {};
567
+ for (const [id] of Object.entries(allNodes)) {
568
+ upstreamMap[id] = [];
569
+ }
570
+ for (const [id, node] of Object.entries(allNodes)) {
571
+ if (!node)
572
+ continue;
573
+ for (const downstreamId of node.state?.downstream ?? []) {
574
+ if (upstreamMap[downstreamId]) {
575
+ upstreamMap[downstreamId].push(id);
576
+ }
577
+ }
578
+ }
579
+ // Action symbols
580
+ const actionSymbol = (action) => {
581
+ switch (action) {
582
+ case "create":
583
+ return "+";
584
+ case "update":
585
+ return "~";
586
+ case "delete":
587
+ return "-";
588
+ case "replace":
589
+ return "±";
590
+ case "noop":
591
+ return "=";
592
+ default:
593
+ return "?";
594
+ }
595
+ };
596
+ // Print header
597
+ lines.push("╔════════════════════════════════════════════════════════════════╗");
598
+ lines.push("║ PLAN ║");
599
+ lines.push("╠════════════════════════════════════════════════════════════════╣");
600
+ lines.push("║ Legend: + create, ~ update, - delete, ± replace, = noop ║");
601
+ lines.push("╚════════════════════════════════════════════════════════════════╝");
602
+ lines.push("");
603
+ // Print resources section
604
+ lines.push("┌─ Resources ────────────────────────────────────────────────────┐");
605
+ const resourceIds = Object.keys(plan.resources).sort();
606
+ for (const id of resourceIds) {
607
+ const node = plan.resources[id];
608
+ const symbol = actionSymbol(node.action);
609
+ const type = node.resource?.type ?? "unknown";
610
+ const downstream = node.state?.downstream?.length
611
+ ? ` → [${node.state?.downstream.join(", ")}]`
612
+ : "";
613
+ lines.push(`│ [${symbol}] ${id} (${type})${downstream}`);
614
+ }
615
+ if (resourceIds.length === 0) {
616
+ lines.push("│ (none)");
617
+ }
618
+ lines.push("└────────────────────────────────────────────────────────────────┘");
619
+ lines.push("");
620
+ // Print deletions section
621
+ lines.push("┌─ Deletions ────────────────────────────────────────────────────┐");
622
+ const deletionIds = Object.keys(plan.deletions).sort();
623
+ for (const id of deletionIds) {
624
+ const node = plan.deletions[id];
625
+ const type = node.resource?.type ?? "unknown";
626
+ const downstream = node.state.downstream?.length
627
+ ? ` → [${node.state.downstream.join(", ")}]`
628
+ : "";
629
+ lines.push(`│ [-] ${id} (${type})${downstream}`);
630
+ }
631
+ if (deletionIds.length === 0) {
632
+ lines.push("│ (none)");
633
+ }
634
+ lines.push("└────────────────────────────────────────────────────────────────┘");
635
+ lines.push("");
636
+ return lines.join("\n");
637
+ };
300
638
  //# sourceMappingURL=plan.js.map