@quadnix/octo 0.0.30 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +117 -8
  3. package/dist/app.type.d.ts +277 -19
  4. package/dist/app.type.js +80 -9
  5. package/dist/app.type.js.map +1 -1
  6. package/dist/decorators/action.decorator.d.ts +10 -6
  7. package/dist/decorators/action.decorator.js +19 -6
  8. package/dist/decorators/action.decorator.js.map +1 -1
  9. package/dist/decorators/anchor.decorator.d.ts +12 -5
  10. package/dist/decorators/anchor.decorator.js +12 -5
  11. package/dist/decorators/anchor.decorator.js.map +1 -1
  12. package/dist/decorators/enable-hook.decorator.d.ts +1 -1
  13. package/dist/decorators/enable-hook.decorator.js +1 -1
  14. package/dist/decorators/factory.decorator.d.ts +18 -34
  15. package/dist/decorators/factory.decorator.js +18 -34
  16. package/dist/decorators/factory.decorator.js.map +1 -1
  17. package/dist/decorators/model.decorator.d.ts +4 -6
  18. package/dist/decorators/model.decorator.js +2 -7
  19. package/dist/decorators/model.decorator.js.map +1 -1
  20. package/dist/decorators/module.decorator.d.ts +16 -10
  21. package/dist/decorators/module.decorator.js +16 -10
  22. package/dist/decorators/module.decorator.js.map +1 -1
  23. package/dist/decorators/on-event.decorator.d.ts +7 -2
  24. package/dist/decorators/on-event.decorator.js +5 -0
  25. package/dist/decorators/on-event.decorator.js.map +1 -1
  26. package/dist/decorators/resource.decorator.d.ts +50 -1
  27. package/dist/decorators/resource.decorator.js +38 -1
  28. package/dist/decorators/resource.decorator.js.map +1 -1
  29. package/dist/decorators/validate.decorator.d.ts +15 -1
  30. package/dist/decorators/validate.decorator.js +15 -1
  31. package/dist/decorators/validate.decorator.js.map +1 -1
  32. package/dist/errors/container.error.d.ts +18 -0
  33. package/dist/errors/container.error.js +18 -0
  34. package/dist/errors/container.error.js.map +1 -1
  35. package/dist/errors/index.d.ts +1 -0
  36. package/dist/errors/index.js +1 -0
  37. package/dist/errors/index.js.map +1 -1
  38. package/dist/errors/module.error.d.ts +6 -0
  39. package/dist/errors/module.error.js +6 -0
  40. package/dist/errors/module.error.js.map +1 -1
  41. package/dist/errors/node.error.d.ts +56 -0
  42. package/dist/errors/node.error.js +56 -0
  43. package/dist/errors/node.error.js.map +1 -1
  44. package/dist/errors/schema.error.d.ts +14 -1
  45. package/dist/errors/schema.error.js +11 -1
  46. package/dist/errors/schema.error.js.map +1 -1
  47. package/dist/errors/terraform.error.d.ts +20 -0
  48. package/dist/errors/terraform.error.js +24 -0
  49. package/dist/errors/terraform.error.js.map +1 -0
  50. package/dist/errors/transaction.error.d.ts +93 -2
  51. package/dist/errors/transaction.error.js +83 -0
  52. package/dist/errors/transaction.error.js.map +1 -1
  53. package/dist/events/action.event.d.ts +8 -4
  54. package/dist/events/action.event.js +2 -4
  55. package/dist/events/action.event.js.map +1 -1
  56. package/dist/events/command.event.d.ts +43 -0
  57. package/dist/events/command.event.js +33 -0
  58. package/dist/events/command.event.js.map +1 -0
  59. package/dist/events/event.model.d.ts +26 -8
  60. package/dist/events/event.model.js +15 -7
  61. package/dist/events/event.model.js.map +1 -1
  62. package/dist/events/hook/commit.hook.event.d.ts +1 -7
  63. package/dist/events/hook/commit.hook.event.js +0 -6
  64. package/dist/events/hook/commit.hook.event.js.map +1 -1
  65. package/dist/events/hook/hook.event.d.ts +1 -3
  66. package/dist/events/hook/hook.event.js +0 -2
  67. package/dist/events/hook/hook.event.js.map +1 -1
  68. package/dist/events/hook/model.hook.event.d.ts +1 -7
  69. package/dist/events/hook/model.hook.event.js +0 -6
  70. package/dist/events/hook/model.hook.event.js.map +1 -1
  71. package/dist/events/hook/resource.hook.event.d.ts +1 -7
  72. package/dist/events/hook/resource.hook.event.js +0 -6
  73. package/dist/events/hook/resource.hook.event.js.map +1 -1
  74. package/dist/events/index.d.ts +5 -0
  75. package/dist/events/index.js +5 -0
  76. package/dist/events/index.js.map +1 -1
  77. package/dist/events/mode-result.event.d.ts +57 -0
  78. package/dist/events/mode-result.event.js +24 -0
  79. package/dist/events/mode-result.event.js.map +1 -0
  80. package/dist/events/mode.event.d.ts +61 -0
  81. package/dist/events/mode.event.js +32 -0
  82. package/dist/events/mode.event.js.map +1 -0
  83. package/dist/events/module.event.d.ts +7 -5
  84. package/dist/events/module.event.js +3 -4
  85. package/dist/events/module.event.js.map +1 -1
  86. package/dist/events/registration.event.d.ts +19 -15
  87. package/dist/events/registration.event.js +18 -14
  88. package/dist/events/registration.event.js.map +1 -1
  89. package/dist/events/serialization.event.d.ts +16 -13
  90. package/dist/events/serialization.event.js +15 -12
  91. package/dist/events/serialization.event.js.map +1 -1
  92. package/dist/events/state.event.d.ts +102 -0
  93. package/dist/events/state.event.js +69 -0
  94. package/dist/events/state.event.js.map +1 -0
  95. package/dist/events/terraform.event.d.ts +78 -0
  96. package/dist/events/terraform.event.js +55 -0
  97. package/dist/events/terraform.event.js.map +1 -0
  98. package/dist/events/transaction.event.d.ts +3 -40
  99. package/dist/events/transaction.event.js +1 -29
  100. package/dist/events/transaction.event.js.map +1 -1
  101. package/dist/functions/container/container.d.ts +54 -13
  102. package/dist/functions/container/container.js +64 -19
  103. package/dist/functions/container/container.js.map +1 -1
  104. package/dist/functions/container/test-container.d.ts +43 -29
  105. package/dist/functions/container/test-container.js +71 -43
  106. package/dist/functions/container/test-container.js.map +1 -1
  107. package/dist/functions/dependency/dependency.d.ts +84 -23
  108. package/dist/functions/dependency/dependency.js +84 -14
  109. package/dist/functions/dependency/dependency.js.map +1 -1
  110. package/dist/functions/diff/aggregate-resource-actions.d.ts +19 -0
  111. package/dist/functions/diff/aggregate-resource-actions.js +41 -0
  112. package/dist/functions/diff/aggregate-resource-actions.js.map +1 -0
  113. package/dist/functions/diff/diff-metadata.d.ts +21 -3
  114. package/dist/functions/diff/diff-metadata.js +18 -0
  115. package/dist/functions/diff/diff-metadata.js.map +1 -1
  116. package/dist/functions/diff/diff.d.ts +68 -7
  117. package/dist/functions/diff/diff.js +44 -3
  118. package/dist/functions/diff/diff.js.map +1 -1
  119. package/dist/functions/hook/commit.hook.d.ts +16 -1
  120. package/dist/functions/hook/commit.hook.js +21 -6
  121. package/dist/functions/hook/commit.hook.js.map +1 -1
  122. package/dist/functions/hook/model-action.hook.d.ts +16 -1
  123. package/dist/functions/hook/model-action.hook.js +21 -6
  124. package/dist/functions/hook/model-action.hook.js.map +1 -1
  125. package/dist/functions/hook/resource-action.hook.d.ts +16 -1
  126. package/dist/functions/hook/resource-action.hook.js +21 -6
  127. package/dist/functions/hook/resource-action.hook.js.map +1 -1
  128. package/dist/functions/node/node-action.abstract.d.ts +23 -2
  129. package/dist/functions/node/node-action.abstract.js +22 -8
  130. package/dist/functions/node/node-action.abstract.js.map +1 -1
  131. package/dist/functions/node/node.abstract.d.ts +56 -5
  132. package/dist/functions/node/node.abstract.js +106 -22
  133. package/dist/functions/node/node.abstract.js.map +1 -1
  134. package/dist/functions/node/node.interface.d.ts +3 -1
  135. package/dist/functions/schema/schema.d.ts +7 -0
  136. package/dist/functions/schema/schema.js +10 -1
  137. package/dist/functions/schema/schema.js.map +1 -1
  138. package/dist/index.d.ts +12 -6
  139. package/dist/index.js +9 -4
  140. package/dist/index.js.map +1 -1
  141. package/dist/index.type.d.ts +5 -0
  142. package/dist/index.type.js +2 -0
  143. package/dist/index.type.js.map +1 -0
  144. package/dist/main.d.ts +245 -14
  145. package/dist/main.js +377 -72
  146. package/dist/main.js.map +1 -1
  147. package/dist/models/account/account.model.d.ts +43 -7
  148. package/dist/models/account/account.model.js +56 -8
  149. package/dist/models/account/account.model.js.map +1 -1
  150. package/dist/models/account/account.schema.d.ts +13 -1
  151. package/dist/models/account/account.schema.js +12 -0
  152. package/dist/models/account/account.schema.js.map +1 -1
  153. package/dist/models/app/app.model.d.ts +13 -8
  154. package/dist/models/app/app.model.js +17 -32
  155. package/dist/models/app/app.model.js.map +1 -1
  156. package/dist/models/app/app.schema.d.ts +6 -0
  157. package/dist/models/app/app.schema.js +6 -0
  158. package/dist/models/app/app.schema.js.map +1 -1
  159. package/dist/models/deployment/deployment.model.d.ts +13 -1
  160. package/dist/models/deployment/deployment.model.js +16 -4
  161. package/dist/models/deployment/deployment.model.js.map +1 -1
  162. package/dist/models/deployment/deployment.schema.d.ts +6 -0
  163. package/dist/models/deployment/deployment.schema.js +6 -0
  164. package/dist/models/deployment/deployment.schema.js.map +1 -1
  165. package/dist/models/environment/environment.model.d.ts +15 -3
  166. package/dist/models/environment/environment.model.js +22 -10
  167. package/dist/models/environment/environment.model.js.map +1 -1
  168. package/dist/models/environment/environment.schema.d.ts +2 -0
  169. package/dist/models/environment/environment.schema.js +2 -0
  170. package/dist/models/environment/environment.schema.js.map +1 -1
  171. package/dist/models/execution/execution.model.d.ts +21 -3
  172. package/dist/models/execution/execution.model.js +47 -29
  173. package/dist/models/execution/execution.model.js.map +1 -1
  174. package/dist/models/execution/execution.schema.d.ts +11 -0
  175. package/dist/models/execution/execution.schema.js +11 -0
  176. package/dist/models/execution/execution.schema.js.map +1 -1
  177. package/dist/models/filesystem/filesystem.model.d.ts +27 -1
  178. package/dist/models/filesystem/filesystem.model.js +30 -4
  179. package/dist/models/filesystem/filesystem.model.js.map +1 -1
  180. package/dist/models/filesystem/filesystem.schema.d.ts +5 -0
  181. package/dist/models/filesystem/filesystem.schema.js +5 -0
  182. package/dist/models/filesystem/filesystem.schema.js.map +1 -1
  183. package/dist/models/image/image.model.d.ts +19 -5
  184. package/dist/models/image/image.model.js +25 -11
  185. package/dist/models/image/image.model.js.map +1 -1
  186. package/dist/models/image/image.schema.d.ts +8 -0
  187. package/dist/models/image/image.schema.js +8 -0
  188. package/dist/models/image/image.schema.js.map +1 -1
  189. package/dist/models/model-action.interface.d.ts +17 -4
  190. package/dist/models/model.abstract.d.ts +96 -1
  191. package/dist/models/model.abstract.js +107 -8
  192. package/dist/models/model.abstract.js.map +1 -1
  193. package/dist/models/model.interface.d.ts +3 -0
  194. package/dist/models/pipeline/pipeline.model.d.ts +14 -2
  195. package/dist/models/pipeline/pipeline.model.js +19 -7
  196. package/dist/models/pipeline/pipeline.model.js.map +1 -1
  197. package/dist/models/pipeline/pipeline.schema.d.ts +8 -0
  198. package/dist/models/pipeline/pipeline.schema.js +8 -0
  199. package/dist/models/pipeline/pipeline.schema.js.map +1 -1
  200. package/dist/models/region/region.model.d.ts +16 -1
  201. package/dist/models/region/region.model.js +19 -4
  202. package/dist/models/region/region.model.js.map +1 -1
  203. package/dist/models/region/region.schema.d.ts +6 -0
  204. package/dist/models/region/region.schema.js +6 -0
  205. package/dist/models/region/region.schema.js.map +1 -1
  206. package/dist/models/server/server.model.d.ts +15 -3
  207. package/dist/models/server/server.model.js +18 -6
  208. package/dist/models/server/server.model.js.map +1 -1
  209. package/dist/models/server/server.schema.d.ts +3 -1
  210. package/dist/models/server/server.schema.js +3 -1
  211. package/dist/models/server/server.schema.js.map +1 -1
  212. package/dist/models/service/service.model.d.ts +37 -6
  213. package/dist/models/service/service.model.js +65 -11
  214. package/dist/models/service/service.model.js.map +1 -1
  215. package/dist/models/service/service.schema.d.ts +48 -1
  216. package/dist/models/service/service.schema.js +56 -1
  217. package/dist/models/service/service.schema.js.map +1 -1
  218. package/dist/models/subnet/subnet.model.d.ts +27 -3
  219. package/dist/models/subnet/subnet.model.js +40 -16
  220. package/dist/models/subnet/subnet.model.js.map +1 -1
  221. package/dist/models/subnet/subnet.schema.d.ts +9 -0
  222. package/dist/models/subnet/subnet.schema.js +9 -0
  223. package/dist/models/subnet/subnet.schema.js.map +1 -1
  224. package/dist/modes/apply-transaction.d.ts +23 -0
  225. package/dist/modes/apply-transaction.js +25 -0
  226. package/dist/modes/apply-transaction.js.map +1 -0
  227. package/dist/modes/commit.mode.d.ts +54 -0
  228. package/dist/modes/commit.mode.js +235 -0
  229. package/dist/modes/commit.mode.js.map +1 -0
  230. package/dist/modes/generate.mode.d.ts +30 -0
  231. package/dist/modes/generate.mode.js +50 -0
  232. package/dist/modes/generate.mode.js.map +1 -0
  233. package/dist/modes/run-action.mode.d.ts +30 -0
  234. package/dist/modes/run-action.mode.js +140 -0
  235. package/dist/modes/run-action.mode.js.map +1 -0
  236. package/dist/modes/validate.mode.d.ts +186 -0
  237. package/dist/modes/validate.mode.js +558 -0
  238. package/dist/modes/validate.mode.js.map +1 -0
  239. package/dist/modules/module.abstract.d.ts +51 -0
  240. package/dist/modules/module.abstract.js +36 -0
  241. package/dist/modules/module.abstract.js.map +1 -1
  242. package/dist/modules/module.container.d.ts +43 -1
  243. package/dist/modules/module.container.js +77 -5
  244. package/dist/modules/module.container.js.map +1 -1
  245. package/dist/modules/test-module.container.d.ts +139 -25
  246. package/dist/modules/test-module.container.js +383 -199
  247. package/dist/modules/test-module.container.js.map +1 -1
  248. package/dist/overlays/anchor.abstract.d.ts +32 -1
  249. package/dist/overlays/anchor.abstract.js +42 -11
  250. package/dist/overlays/anchor.abstract.js.map +1 -1
  251. package/dist/overlays/anchor.schema.d.ts +21 -0
  252. package/dist/overlays/anchor.schema.js +21 -0
  253. package/dist/overlays/anchor.schema.js.map +1 -1
  254. package/dist/overlays/overlay-data.repository.d.ts +18 -0
  255. package/dist/overlays/overlay-data.repository.js +18 -0
  256. package/dist/overlays/overlay-data.repository.js.map +1 -1
  257. package/dist/overlays/overlay.abstract.d.ts +56 -1
  258. package/dist/overlays/overlay.abstract.js +79 -20
  259. package/dist/overlays/overlay.abstract.js.map +1 -1
  260. package/dist/overlays/overlay.schema.d.ts +20 -0
  261. package/dist/overlays/overlay.schema.js +20 -0
  262. package/dist/overlays/overlay.schema.js.map +1 -1
  263. package/dist/resources/resource-action.interface.d.ts +29 -3
  264. package/dist/resources/resource-data.repository.d.ts +63 -1
  265. package/dist/resources/resource-data.repository.js +94 -4
  266. package/dist/resources/resource-data.repository.js.map +1 -1
  267. package/dist/resources/resource.abstract.d.ts +163 -6
  268. package/dist/resources/resource.abstract.js +223 -59
  269. package/dist/resources/resource.abstract.js.map +1 -1
  270. package/dist/resources/resource.interface.d.ts +0 -2
  271. package/dist/resources/resource.schema.d.ts +39 -1
  272. package/dist/resources/resource.schema.js +38 -0
  273. package/dist/resources/resource.schema.js.map +1 -1
  274. package/dist/resources/terraform-resource.abstract.d.ts +44 -0
  275. package/dist/resources/terraform-resource.abstract.js +45 -0
  276. package/dist/resources/terraform-resource.abstract.js.map +1 -0
  277. package/dist/services/event/event.service.d.ts +32 -5
  278. package/dist/services/event/event.service.js +58 -16
  279. package/dist/services/event/event.service.js.map +1 -1
  280. package/dist/services/input/input.service.d.ts +82 -5
  281. package/dist/services/input/input.service.js +143 -12
  282. package/dist/services/input/input.service.js.map +1 -1
  283. package/dist/services/schema-translation/schema-translation.service.d.ts +9 -0
  284. package/dist/services/schema-translation/schema-translation.service.js +9 -0
  285. package/dist/services/schema-translation/schema-translation.service.js.map +1 -1
  286. package/dist/services/serialization/model/model-serialization.service.d.ts +25 -3
  287. package/dist/services/serialization/model/model-serialization.service.js +113 -62
  288. package/dist/services/serialization/model/model-serialization.service.js.map +1 -1
  289. package/dist/services/serialization/resource/resource-serialization.service.d.ts +36 -6
  290. package/dist/services/serialization/resource/resource-serialization.service.js +77 -28
  291. package/dist/services/serialization/resource/resource-serialization.service.js.map +1 -1
  292. package/dist/services/state-management/local.state-provider.d.ts +67 -4
  293. package/dist/services/state-management/local.state-provider.js +168 -41
  294. package/dist/services/state-management/local.state-provider.js.map +1 -1
  295. package/dist/services/state-management/remote.state-provider.d.ts +216 -0
  296. package/dist/services/state-management/remote.state-provider.js +645 -0
  297. package/dist/services/state-management/remote.state-provider.js.map +1 -0
  298. package/dist/services/state-management/state-management.service.d.ts +195 -17
  299. package/dist/services/state-management/state-management.service.js +259 -10
  300. package/dist/services/state-management/state-management.service.js.map +1 -1
  301. package/dist/services/state-management/state-provider.interface.d.ts +98 -3
  302. package/dist/services/state-management/state-provider.interface.js +14 -1
  303. package/dist/services/state-management/state-provider.interface.js.map +1 -1
  304. package/dist/services/state-management/terraform-state.service.d.ts +99 -0
  305. package/dist/services/state-management/terraform-state.service.js +197 -0
  306. package/dist/services/state-management/terraform-state.service.js.map +1 -0
  307. package/dist/services/state-management/test.state-provider.d.ts +42 -4
  308. package/dist/services/state-management/test.state-provider.js +77 -25
  309. package/dist/services/state-management/test.state-provider.js.map +1 -1
  310. package/dist/services/terraform/terraform.service.d.ts +480 -0
  311. package/dist/services/terraform/terraform.service.js +1082 -0
  312. package/dist/services/terraform/terraform.service.js.map +1 -0
  313. package/dist/services/terraform/terraform.type.d.ts +387 -0
  314. package/dist/services/terraform/terraform.type.js +579 -0
  315. package/dist/services/terraform/terraform.type.js.map +1 -0
  316. package/dist/services/transaction/transaction.service.d.ts +110 -10
  317. package/dist/services/transaction/transaction.service.js +570 -251
  318. package/dist/services/transaction/transaction.service.js.map +1 -1
  319. package/dist/services/validation/validation.service.d.ts +15 -3
  320. package/dist/services/validation/validation.service.js +12 -0
  321. package/dist/services/validation/validation.service.js.map +1 -1
  322. package/dist/utilities/array/array.utility.d.ts +3 -0
  323. package/dist/utilities/array/array.utility.js +3 -0
  324. package/dist/utilities/array/array.utility.js.map +1 -1
  325. package/dist/{functions → utilities}/diff/diff.utility.d.ts +19 -3
  326. package/dist/{functions → utilities}/diff/diff.utility.js +57 -41
  327. package/dist/utilities/diff/diff.utility.js.map +1 -0
  328. package/dist/utilities/file/file.utility.d.ts +16 -2
  329. package/dist/utilities/file/file.utility.js +23 -61
  330. package/dist/utilities/file/file.utility.js.map +1 -1
  331. package/dist/utilities/hcl/hcl.utility.d.ts +128 -0
  332. package/dist/utilities/hcl/hcl.utility.js +402 -0
  333. package/dist/utilities/hcl/hcl.utility.js.map +1 -0
  334. package/dist/utilities/http/http.utility.d.ts +57 -0
  335. package/dist/utilities/http/http.utility.js +98 -0
  336. package/dist/utilities/http/http.utility.js.map +1 -0
  337. package/dist/utilities/node/node.utility.d.ts +3 -0
  338. package/dist/utilities/node/node.utility.js +3 -0
  339. package/dist/utilities/node/node.utility.js.map +1 -1
  340. package/dist/utilities/object/object.utility.d.ts +12 -0
  341. package/dist/utilities/object/object.utility.js +12 -0
  342. package/dist/utilities/object/object.utility.js.map +1 -1
  343. package/dist/utilities/project/project.utility.d.ts +28 -0
  344. package/dist/utilities/project/project.utility.js +35 -0
  345. package/dist/utilities/project/project.utility.js.map +1 -0
  346. package/dist/utilities/string/string.utility.d.ts +41 -0
  347. package/dist/utilities/string/string.utility.js +65 -0
  348. package/dist/utilities/string/string.utility.js.map +1 -0
  349. package/dist/utilities/terraform/terraform.utility.d.ts +276 -0
  350. package/dist/utilities/terraform/terraform.utility.js +623 -0
  351. package/dist/utilities/terraform/terraform.utility.js.map +1 -0
  352. package/dist/utilities/test-helpers/test-classes.d.ts +36 -30
  353. package/dist/utilities/test-helpers/test-classes.js +38 -39
  354. package/dist/utilities/test-helpers/test-classes.js.map +1 -1
  355. package/dist/utilities/test-helpers/test-models.d.ts +8 -1
  356. package/dist/utilities/test-helpers/test-models.js +37 -12
  357. package/dist/utilities/test-helpers/test-models.js.map +1 -1
  358. package/dist/utilities/test-helpers/test-modes.d.ts +315 -0
  359. package/dist/utilities/test-helpers/test-modes.js +486 -0
  360. package/dist/utilities/test-helpers/test-modes.js.map +1 -0
  361. package/dist/utilities/test-helpers/test-modules.d.ts +47 -0
  362. package/dist/utilities/test-helpers/test-modules.js +85 -0
  363. package/dist/utilities/test-helpers/test-modules.js.map +1 -0
  364. package/dist/utilities/test-helpers/test-overlays.d.ts +20 -2
  365. package/dist/utilities/test-helpers/test-overlays.js +56 -6
  366. package/dist/utilities/test-helpers/test-overlays.js.map +1 -1
  367. package/dist/utilities/test-helpers/test-resources.d.ts +23 -3
  368. package/dist/utilities/test-helpers/test-resources.js +83 -23
  369. package/dist/utilities/test-helpers/test-resources.js.map +1 -1
  370. package/dist/utilities/validation/validation.utility.d.ts +24 -0
  371. package/dist/utilities/validation/validation.utility.js +24 -0
  372. package/dist/utilities/validation/validation.utility.js.map +1 -1
  373. package/package.json +12 -6
  374. package/dist/functions/diff/diff.utility.js.map +0 -1
  375. package/dist/services/capture/capture.service.d.ts +0 -19
  376. package/dist/services/capture/capture.service.js +0 -43
  377. package/dist/services/capture/capture.service.js.map +0 -1
  378. package/dist/services/state-management/local-encryption.state-provider.d.ts +0 -20
  379. package/dist/services/state-management/local-encryption.state-provider.js +0 -90
  380. package/dist/services/state-management/local-encryption.state-provider.js.map +0 -1
  381. package/dist/utilities/cidr/cidr.utility.d.ts +0 -10
  382. package/dist/utilities/cidr/cidr.utility.js +0 -51
  383. package/dist/utilities/cidr/cidr.utility.js.map +0 -1
@@ -10,35 +10,303 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  import { NodeType, ValidationType, } from '../../app.type.js';
11
11
  import { EventSource } from '../../decorators/event-source.decorator.js';
12
12
  import { Factory } from '../../decorators/factory.decorator.js';
13
- import { InputNotFoundTransactionError, InputRegistrationError, ResourceActionExceptionTransactionError, ResourceActionTimeoutTransactionError, TransactionError, ValidationTransactionError, } from '../../errors/index.js';
14
- import { ModelActionRegistrationEvent, ModelActionTransactionEvent, ModelDiffsTransactionEvent, ModelTransactionTransactionEvent, ResourceActionCompletedTransactionEvent, ResourceActionInformationTransactionEvent, ResourceActionInitiatedTransactionEvent, ResourceActionRegistrationEvent, ResourceActionSummaryTransactionEvent, ResourceDiffsTransactionEvent, ResourceTransactionTransactionEvent, } from '../../events/index.js';
13
+ import { InputNotFoundTransactionError, ResourceActionExceptionTransactionError, ResourceActionTimeoutTransactionError, TransactionError, ValidationTransactionError, } from '../../errors/index.js';
14
+ import { ModelActionRegistrationEvent, ModelActionTransactionEvent, ModelDiffsTransactionEvent, ModelTransactionTransactionEvent, ResourceActionCompletedTransactionEvent, ResourceActionInitiatedTransactionEvent, ResourceActionRegistrationEvent, ResourceActionSummaryTransactionEvent, ResourceDiffsTransactionEvent, ResourceTransactionTransactionEvent, } from '../../events/index.js';
15
15
  import { Container } from '../../functions/container/container.js';
16
16
  import { DiffMetadata } from '../../functions/diff/diff-metadata.js';
17
17
  import { DiffAction } from '../../functions/diff/diff.js';
18
- import { DiffUtility } from '../../functions/diff/diff.utility.js';
18
+ import { ANodeAction } from '../../functions/node/node-action.abstract.js';
19
19
  import { ModuleContainer } from '../../modules/module.container.js';
20
20
  import { OverlayDataRepository } from '../../overlays/overlay-data.repository.js';
21
21
  import { AOverlay } from '../../overlays/overlay.abstract.js';
22
22
  import { ResourceDataRepository } from '../../resources/resource-data.repository.js';
23
23
  import { AResource } from '../../resources/resource.abstract.js';
24
- import { CaptureService } from '../capture/capture.service.js';
24
+ import { ATerraformResource } from '../../resources/terraform-resource.abstract.js';
25
+ import { DiffUtility } from '../../utilities/diff/diff.utility.js';
25
26
  import { EventService } from '../event/event.service.js';
26
27
  import { InputService } from '../input/input.service.js';
28
+ import { ResourceSerializationService } from '../serialization/resource/resource-serialization.service.js';
29
+ import { TerraformService } from '../terraform/terraform.service.js';
30
+ /**
31
+ * No-op resource action backing terraform resource diffs. Terraform manages the resource's lifecycle;
32
+ * octo only carries the diff for review and validation.
33
+ *
34
+ * @internal
35
+ */
36
+ class TerraformNoopResourceAction extends ANodeAction {
37
+ /**
38
+ * @internal
39
+ */
40
+ constructor() {
41
+ super();
42
+ }
43
+ /**
44
+ * @internal
45
+ */
46
+ filter() {
47
+ return true;
48
+ }
49
+ /**
50
+ * @internal
51
+ */
52
+ async handle() { }
53
+ }
27
54
  /**
28
55
  * @internal
29
56
  */
30
57
  export class TransactionService {
31
- constructor(captureService, eventService, inputService, moduleContainer, overlayDataRepository, resourceDataRepository) {
32
- this.captureService = captureService;
58
+ /**
59
+ * @internal
60
+ */
61
+ constructor(eventService, inputService, moduleContainer, overlayDataRepository, resourceDataRepository, resourceSerializationService, terraformService) {
33
62
  this.eventService = eventService;
34
63
  this.inputService = inputService;
35
64
  this.moduleContainer = moduleContainer;
36
65
  this.overlayDataRepository = overlayDataRepository;
37
66
  this.resourceDataRepository = resourceDataRepository;
67
+ this.resourceSerializationService = resourceSerializationService;
68
+ this.terraformService = terraformService;
38
69
  this.modelActions = [];
39
70
  this.overlayActions = [];
40
71
  this.resourceActions = [];
41
72
  }
73
+ /**
74
+ * Runs the delete action of every **external** resource in `resourceDiffs` that is being deleted.
75
+ *
76
+ * Terraform cannot do this. Octo deletes a resource by removing its block from the configuration,
77
+ * and terraform will not run a `when = destroy` provisioner for a resource that is no longer in
78
+ * the configuration - it drops the `null_resource` from state and moves on. So the callback that
79
+ * would have told an external resource to delete itself never fires, and the real thing it created
80
+ * outlives both state files with nothing tracking it.
81
+ *
82
+ * Octo knows the resource was deleted, which is why this can be driven from its own diff instead.
83
+ * {@link commit} calls it before recording anything, so a failed delete leaves octo state untouched
84
+ * and the deletion is retried on the next run rather than being forgotten.
85
+ *
86
+ * Terraform-managed resources are excluded: terraform destroys those itself, and a resource action
87
+ * on one is rejected everywhere else in octo.
88
+ *
89
+ * @returns The diffs whose actions ran, in the order they ran.
90
+ */
91
+ async applyExternalResourceDeletes(resourceDiffs) {
92
+ const deleteDiffs = this.getExternalResourceDeletes(resourceDiffs);
93
+ if (deleteDiffs.length === 0) {
94
+ return [];
95
+ }
96
+ // Ordered among themselves: `applyOrder` is assigned across the whole resource diff set, and
97
+ // this is a subset of it, so the levels it carries can start anywhere. Re-basing them from zero
98
+ // keeps applyResources' level walk terminating.
99
+ const orders = [...new Set(deleteDiffs.map((d) => d.applyOrder))].sort((a, b) => a - b);
100
+ for (const diff of deleteDiffs) {
101
+ diff.applyOrder = orders.indexOf(diff.applyOrder);
102
+ }
103
+ // Stateless, like run-action: the actual resource graph is not touched here. `commit` syncs
104
+ // actual to new immediately afterwards, which is what records the deletion.
105
+ return this.applyResources(deleteDiffs, { skipActualResourceUpdate: true });
106
+ }
107
+ /**
108
+ * @internal
109
+ */
110
+ async *beginTransaction(diffs, { enableResourceValidation = false, filterResourceDiffsByResourceId = undefined, generateTerraform = false, skipActualResourceUpdate = false, yieldModelDiffs = false, yieldModelTransaction = false, yieldResourceDiffs = false, yieldResourceTransaction = false, } = {}) {
111
+ // Diff overlays and add to existing diffs.
112
+ const overlayDiffs = await this.overlayDataRepository.diff();
113
+ diffs.push(...overlayDiffs);
114
+ // Generate diff on models.
115
+ const modelDiffs = diffs.map((d) => {
116
+ if (d.node.constructor.NODE_TYPE === NodeType.OVERLAY) {
117
+ return new DiffMetadata(d, (this.overlayActions.find((a) => a.overlayClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d)));
118
+ }
119
+ else {
120
+ return new DiffMetadata(d, (this.modelActions.find((a) => a.modelClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d)));
121
+ }
122
+ });
123
+ // Set apply order on model diffs.
124
+ for (const diff of modelDiffs) {
125
+ this.setApplyOrder(diff, modelDiffs);
126
+ }
127
+ this.eventService.emit(new ModelDiffsTransactionEvent(undefined, [modelDiffs]));
128
+ if (yieldModelDiffs) {
129
+ yield [modelDiffs];
130
+ }
131
+ // Apply model diffs.
132
+ const modelTransaction = await this.applyModels(modelDiffs);
133
+ this.eventService.emit(new ModelTransactionTransactionEvent(undefined, modelTransaction));
134
+ if (yieldModelTransaction) {
135
+ yield modelTransaction;
136
+ }
137
+ // Generate resource diffs.
138
+ let newDiffs = await this.resourceDataRepository.diff();
139
+ let dirtyDiffs = await this.resourceDataRepository.diffDirty();
140
+ // Scope diffs to a single resource, e.g. when terraform invokes octo for one resource action.
141
+ if (filterResourceDiffsByResourceId !== undefined) {
142
+ newDiffs = newDiffs.filter((d) => d.node.resourceId === filterResourceDiffsByResourceId);
143
+ dirtyDiffs = dirtyDiffs.filter((d) => d.node.resourceId === filterResourceDiffsByResourceId);
144
+ // Prefer dirty diffs (actual-graph nodes) over equal new diffs (old-graph nodes) for
145
+ // execution: deserialized old resources are frozen and cannot receive injected inputs.
146
+ for (let i = newDiffs.length - 1; i >= 0; i--) {
147
+ const newDiff = newDiffs[i];
148
+ if (dirtyDiffs.some((d) => d.node.getContext() === newDiff.node.getContext() &&
149
+ d.action === newDiff.action &&
150
+ d.field === newDiff.field &&
151
+ DiffUtility.isObjectDeepEquals(d.value, newDiff.value))) {
152
+ newDiffs.splice(i, 1);
153
+ }
154
+ }
155
+ }
156
+ if (enableResourceValidation && (newDiffs.length > 0 || dirtyDiffs.length > 0)) {
157
+ throw new TransactionError('Cannot run resource validation with pending resource diffs!');
158
+ }
159
+ if (enableResourceValidation) {
160
+ const validationDiffs = this.resourceDataRepository.diffValidate();
161
+ newDiffs.push(...validationDiffs);
162
+ dirtyDiffs.push(...validationDiffs);
163
+ }
164
+ // new diffs = new - old | dirty diffs = new - actual
165
+ // Any new diff that is also not part of dirty diffs should be skipped, as the actual is already in desired state.
166
+ for (let i = newDiffs.length - 1; i >= 0; i--) {
167
+ const newDiff = newDiffs[i];
168
+ if (!dirtyDiffs.some((d) => d.node.getContext() === newDiff.node.getContext() &&
169
+ d.action === newDiff.action &&
170
+ d.field === newDiff.field &&
171
+ DiffUtility.isObjectDeepEquals(d.value, newDiff.value))) {
172
+ newDiffs.splice(i, 1);
173
+ }
174
+ }
175
+ // Ensure any new diffs are not operating on dirty resources.
176
+ this.resourceDataRepository.ensureDiffsNotOperatingOnDirtyResources(newDiffs);
177
+ // Skip processing dirty diffs that are already accounted for in new diffs.
178
+ for (let i = dirtyDiffs.length - 1; i >= 0; i--) {
179
+ const dirtyDiff = dirtyDiffs[i];
180
+ if (newDiffs.some((d) => d.node.getContext() === dirtyDiff.node.getContext() &&
181
+ d.action === dirtyDiff.action &&
182
+ d.field === dirtyDiff.field &&
183
+ DiffUtility.isObjectDeepEquals(d.value, dirtyDiff.value))) {
184
+ dirtyDiffs.splice(i, 1);
185
+ }
186
+ }
187
+ // Terraform resources have no resource actions - terraform owns their lifecycle. Their diffs
188
+ // remain part of the transaction as review artifacts, backed by a no-op action.
189
+ const resolveResourceActions = (d) => {
190
+ if (d.node instanceof ATerraformResource) {
191
+ return [new TerraformNoopResourceAction()];
192
+ }
193
+ return (this.resourceActions.find((a) => a.resourceClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d));
194
+ };
195
+ // Generate diff on resources.
196
+ const resourceDiffs = newDiffs.map((d) => new DiffMetadata(d, resolveResourceActions(d)));
197
+ // Set apply order on resource diffs.
198
+ for (const diff of resourceDiffs) {
199
+ this.setApplyOrder(diff, resourceDiffs);
200
+ }
201
+ // Generate diff on dirty resources.
202
+ const dirtyResourceDiffs = dirtyDiffs.map((d) => new DiffMetadata(d, resolveResourceActions(d)));
203
+ // Set apply order on dirty resource diffs.
204
+ for (const diff of dirtyResourceDiffs) {
205
+ this.setApplyOrder(diff, dirtyResourceDiffs);
206
+ }
207
+ // Contribute the full desired resource graph to terraform. Deferred until after resource diffs
208
+ // are computed and ordered, so an author refusal (a throw in diff*) or an ordering/cycle error
209
+ // aborts generation before any HCL is built — diffs gate generation.
210
+ if (generateTerraform) {
211
+ await this.generateTerraform();
212
+ }
213
+ this.eventService.emit(new ResourceDiffsTransactionEvent(undefined, [[resourceDiffs], [dirtyResourceDiffs]]));
214
+ if (yieldResourceDiffs) {
215
+ yield [resourceDiffs, dirtyResourceDiffs];
216
+ }
217
+ // Apply resource diffs.
218
+ const resourceTransaction = await this.applyResources(resourceDiffs, { skipActualResourceUpdate });
219
+ // Apply dirty resource diffs.
220
+ const dirtyResourceTransaction = await this.applyResources(dirtyResourceDiffs, { skipActualResourceUpdate });
221
+ this.eventService.emit(new ResourceTransactionTransactionEvent(undefined, [resourceTransaction, dirtyResourceTransaction]));
222
+ if (yieldResourceTransaction) {
223
+ yield [...resourceTransaction, ...dirtyResourceTransaction];
224
+ }
225
+ return modelTransaction;
226
+ }
227
+ /**
228
+ * The diffs {@link TransactionService.applyExternalResourceDeletes} runs: the deletion of every
229
+ * external resource in `resourceDiffs`. A caller that has to decide whether to run them at all
230
+ * names them through this rather than repeating the filter.
231
+ *
232
+ * @internal
233
+ */
234
+ getExternalResourceDeletes(resourceDiffs) {
235
+ return resourceDiffs
236
+ .flat()
237
+ .filter((d) => d.action === DiffAction.DELETE &&
238
+ d.field === 'resourceId' &&
239
+ !(d.node instanceof ATerraformResource) &&
240
+ !d.applied);
241
+ }
242
+ /**
243
+ * @internal
244
+ */
245
+ registerModelActions(forModel, actions) {
246
+ const modelActions = this.modelActions.find((a) => a.modelClass === forModel);
247
+ if (!modelActions) {
248
+ this.modelActions.push({ actions: actions, modelClass: forModel });
249
+ }
250
+ else {
251
+ for (const action of actions) {
252
+ if (modelActions.actions.find((a) => a.constructor.name === action.constructor.name)) {
253
+ throw new Error(`Action "${action.constructor.name}" already registered for model "${forModel.name}"!`);
254
+ }
255
+ modelActions.actions.push(action);
256
+ }
257
+ }
258
+ }
259
+ /**
260
+ * @internal
261
+ */
262
+ registerOverlayActions(forOverlay, actions) {
263
+ const overlayActions = this.overlayActions.find((a) => a.overlayClass === forOverlay);
264
+ if (!overlayActions) {
265
+ this.overlayActions.push({ actions: actions, overlayClass: forOverlay });
266
+ }
267
+ else {
268
+ for (const action of actions) {
269
+ if (overlayActions.actions.find((a) => a.constructor.name === action.constructor.name)) {
270
+ throw new Error(`Action "${action.constructor.name}" already registered for overlay "${forOverlay.name}"!`);
271
+ }
272
+ overlayActions.actions.push(action);
273
+ }
274
+ }
275
+ }
276
+ /**
277
+ * @internal
278
+ */
279
+ registerResourceActions(forResource, actions) {
280
+ if (forResource.prototype instanceof ATerraformResource) {
281
+ throw new TransactionError(`Cannot register resource actions for terraform resource "${forResource.name}"! ` +
282
+ 'Terraform resources are managed by terraform via toHCL().');
283
+ }
284
+ const resourceActions = this.resourceActions.find((a) => a.resourceClass === forResource);
285
+ if (!resourceActions) {
286
+ this.resourceActions.push({ actions: actions, resourceClass: forResource });
287
+ }
288
+ else {
289
+ for (const action of actions) {
290
+ if (resourceActions.actions.find((a) => a.constructor.name === action.constructor.name)) {
291
+ throw new Error(`Action "${action.constructor.name}" already registered for resource "${forResource.name}"!`);
292
+ }
293
+ resourceActions.actions.push(action);
294
+ }
295
+ }
296
+ }
297
+ /**
298
+ * @internal
299
+ */
300
+ unregisterModelActions(forModel) {
301
+ const modelActions = this.modelActions.find((a) => a.modelClass === forModel);
302
+ if (!modelActions) {
303
+ return;
304
+ }
305
+ modelActions.actions = [];
306
+ }
307
+ /**
308
+ * @internal
309
+ */
42
310
  async applyModels(diffs) {
43
311
  const transaction = [];
44
312
  let currentApplyOrder = 0;
@@ -56,12 +324,11 @@ export class TransactionService {
56
324
  const diffToProcess = duplicateDiffs[0].diff;
57
325
  for (const a of diff.actions) {
58
326
  // Find moduleId.
59
- let moduleId;
60
- if (diff.node instanceof AOverlay) {
61
- moduleId = this.inputService.getModuleIdFromOverlay(diff.node);
62
- }
63
- else {
64
- moduleId = this.inputService.getModuleIdFromModel(diff.node);
327
+ const moduleId = diff.node instanceof AOverlay
328
+ ? this.inputService.getModuleIdFromOverlay(diff.node)
329
+ : this.inputService.getModuleIdFromModel(diff.node);
330
+ if (moduleId === undefined) {
331
+ throw new TransactionError(`Node "${diff.node.getContext()}" is not associated with any module!`);
65
332
  }
66
333
  // Resolve all keys of the module - inputs keys and nodes generated by the module keys.
67
334
  const inputs = { inputs: {}, metadata: {}, models: {}, overlays: {}, resources: {} };
@@ -93,42 +360,39 @@ export class TransactionService {
93
360
  inputs.resources[keyValue] = inputValue;
94
361
  }
95
362
  }
96
- // Apply all actions on the diff, then update diff metadata with inputs and outputs.
97
- const outputs = await a.handle(diffToProcess, inputs, {});
363
+ // Apply all actions on the diff in the scope of the node, then update diff metadata with inputs and outputs.
364
+ const outputs = await AResource.runInScope(this.getResourceScope(diffToProcess.node), () => a.handle(diffToProcess, inputs, {}));
98
365
  for (const resource of Object.values(outputs)) {
99
- let moduleId;
100
- if (diffToProcess.node instanceof AOverlay) {
101
- moduleId = this.inputService.getModuleIdFromOverlay(diffToProcess.node);
366
+ const moduleId = diffToProcess.node instanceof AOverlay
367
+ ? this.inputService.getModuleIdFromOverlay(diffToProcess.node)
368
+ : this.inputService.getModuleIdFromModel(diffToProcess.node);
369
+ if (moduleId === undefined) {
370
+ throw new TransactionError(`Node "${diffToProcess.node.getContext()}" is not associated with any module!`);
102
371
  }
103
- else {
104
- moduleId = this.inputService.getModuleIdFromModel(diffToProcess.node);
372
+ // Record the node whose action produced the resource.
373
+ this.inputService.registerResourceModel(resource, diffToProcess.node);
374
+ // A resource already in the graph is one the action changed, not created: it keeps the module
375
+ // that created it, and that module's tags.
376
+ const existingResource = this.resourceDataRepository.getNewResourceByContext(resource.getContext());
377
+ if (existingResource && existingResource !== resource) {
378
+ throw new TransactionError(`Resource "${resource.getContext()}" already exists, and action "${a.constructor.name}" created it again!`);
379
+ }
380
+ else if (existingResource) {
381
+ continue;
105
382
  }
106
383
  // Set resource tags.
107
384
  const resourceTags = this.inputService.resolve(`${moduleId}.tag.${resource.getContext()}`);
108
385
  for (const [key, value] of Object.entries(resourceTags)) {
109
386
  resource.tags[key] = value;
110
387
  }
111
- const previousResource = this.resourceDataRepository.getNewResourceByContext(resource.getContext());
112
- if (previousResource) {
113
- resource.merge(previousResource);
114
- }
115
- else {
116
- this.resourceDataRepository.addNewResource(resource);
117
- }
118
- try {
119
- this.inputService.registerResource(moduleId, resource);
120
- }
121
- catch (error) {
122
- if (!(error instanceof InputRegistrationError)) {
123
- throw error;
124
- }
125
- }
388
+ this.resourceDataRepository.addNewResource(resource);
389
+ this.inputService.registerResource(moduleId, resource, diffToProcess.node);
126
390
  }
127
391
  duplicateDiffs.forEach((d) => {
128
392
  d.updateInputs(inputs);
129
393
  d.updateOutputs(outputs);
130
394
  });
131
- this.eventService.emit(new ModelActionTransactionEvent(a.constructor.name));
395
+ this.eventService.emit(new ModelActionTransactionEvent(a.constructor.name, duplicateDiffs[0]));
132
396
  }
133
397
  // Include the diff to process in the list of diffs processed in the same level.
134
398
  diffsProcessedInSameLevel.push(duplicateDiffs[0]);
@@ -142,34 +406,10 @@ export class TransactionService {
142
406
  }
143
407
  return transaction;
144
408
  }
145
- applyResourcesDryRun(diffs, { enableResourceCapture = false } = {}) {
146
- const captures = this.captureService.getAllCaptures();
147
- const captureContexts = Object.keys(captures);
148
- const missingCaptureContexts = [];
149
- if (enableResourceCapture) {
150
- for (const capturedContext of captureContexts) {
151
- if (!diffs.some((d) => d.node.getContext() === capturedContext)) {
152
- missingCaptureContexts.push(capturedContext);
153
- }
154
- }
155
- }
156
- if (missingCaptureContexts.length > 0) {
157
- throw new TransactionError(`Provided capture contexts do not match any resource diffs! ${missingCaptureContexts.join(', ')}`);
158
- }
159
- for (const diff of diffs) {
160
- const capture = enableResourceCapture && captureContexts.includes(diff.node.getContext())
161
- ? this.captureService.getCapture(diff.node.getContext())
162
- : undefined;
163
- for (const a of diff.actions) {
164
- this.eventService.emit(new ResourceActionInformationTransactionEvent(a.constructor.name, {
165
- action: { name: a.constructor.name },
166
- capture: a.mock ? capture : undefined,
167
- diff,
168
- }));
169
- }
170
- }
171
- }
172
- async applyResources(diffs, { enableResourceCapture = false } = {}) {
409
+ /**
410
+ * @internal
411
+ */
412
+ async applyResources(diffs, { skipActualResourceUpdate = false } = {}) {
173
413
  const transaction = [];
174
414
  const validationErrors = [];
175
415
  let currentApplyOrder = 0;
@@ -187,47 +427,66 @@ export class TransactionService {
187
427
  const diffToProcess = duplicateDiffs[0].diff;
188
428
  for (const a of diff.actions) {
189
429
  this.eventService.emit(new ResourceActionInitiatedTransactionEvent(a.constructor.name, diff));
190
- const capture = this.captureService.getCapture(diff.node.getContext());
191
- if (enableResourceCapture && capture?.response && a.mock) {
192
- const response = await a.mock(diff, capture.response);
193
- this.resourceDataRepository.getNewResourceByContext(diffToProcess.node.getContext())?.setResponse(response);
194
- }
195
- else {
196
- let actionTimeoutId;
197
- try {
198
- await Promise.race([
199
- new Promise(async (resolve, reject) => {
200
- try {
201
- const response = await a.handle(diffToProcess);
202
- this.resourceDataRepository
203
- .getNewResourceByContext(diffToProcess.node.getContext())
204
- ?.setResponse(response);
430
+ // Captured before `handle()` mutates the resource, for the summary event below.
431
+ const preHandleSynth = skipActualResourceUpdate
432
+ ? this.resourceDataRepository.getNewResourceByContext(diffToProcess.node.getContext())?.synth()
433
+ : undefined;
434
+ let actionTimeoutId;
435
+ try {
436
+ await Promise.race([
437
+ new Promise(async (resolve, reject) => {
438
+ try {
439
+ const response = await a.handle(diffToProcess);
440
+ this.resourceDataRepository
441
+ .getNewResourceByContext(diffToProcess.node.getContext())
442
+ ?.setResponse(response);
443
+ resolve();
444
+ }
445
+ catch (error) {
446
+ if (diffToProcess.action === DiffAction.VALIDATE) {
447
+ validationErrors.push(error);
205
448
  resolve();
206
449
  }
207
- catch (error) {
208
- if (diffToProcess.action === DiffAction.VALIDATE) {
209
- validationErrors.push(error);
210
- resolve();
211
- }
212
- else {
213
- reject(new ResourceActionExceptionTransactionError(error.message, error, diffToProcess, a.constructor.name));
214
- }
450
+ else {
451
+ reject(new ResourceActionExceptionTransactionError(error.message, error, diffToProcess, a.constructor.name));
215
452
  }
216
- }),
217
- new Promise((_resolve, reject) => (actionTimeoutId = setTimeout(() => {
218
- reject(new ResourceActionTimeoutTransactionError(`Resource action ${a.constructor.name} timed out after ${a.actionTimeoutInMs || 90000}ms!`, diffToProcess, a.constructor.name));
219
- }, a.actionTimeoutInMs || 90000))),
220
- ]);
221
- }
222
- finally {
223
- if (actionTimeoutId) {
224
- clearTimeout(actionTimeoutId);
225
- }
453
+ }
454
+ }),
455
+ new Promise((_resolve, reject) => (actionTimeoutId = setTimeout(() => {
456
+ reject(new ResourceActionTimeoutTransactionError(`Resource action ${a.constructor.name} timed out after ${a.actionTimeoutInMs || 90000}ms!`, diffToProcess, a.constructor.name));
457
+ }, a.actionTimeoutInMs || 90000))),
458
+ ]);
459
+ }
460
+ finally {
461
+ if (actionTimeoutId) {
462
+ clearTimeout(actionTimeoutId);
226
463
  }
227
464
  }
228
- // De-reference from actual resources.
465
+ if (skipActualResourceUpdate) {
466
+ // Stateless invocation (run-action): the actual resource graph is not maintained;
467
+ // terraform state is the source of truth until the next commit. The summary is therefore
468
+ // derived from the new-graph resource either side of `handle()`.
469
+ const postHandleSynth = diffToProcess.action === DiffAction.DELETE && diffToProcess.field === 'resourceId'
470
+ ? {}
471
+ : this.resourceDataRepository.getNewResourceByContext(diffToProcess.node.getContext())?.synth();
472
+ this.eventService.emit(new ResourceActionSummaryTransactionEvent(a.constructor.name, {
473
+ diff,
474
+ values: { current: postHandleSynth ?? {}, previous: preHandleSynth ?? {} },
475
+ }));
476
+ this.eventService.emit(new ResourceActionCompletedTransactionEvent(a.constructor.name, diff));
477
+ continue;
478
+ }
479
+ // De-reference from actual resources. The lookup can miss when a diff references a resource
480
+ // this transaction has not applied yet, so name what is missing rather than letting
481
+ // `undefined` surface as a TypeError several frames away.
229
482
  const deReferenceResource = async (context) => {
230
- return this.resourceDataRepository.getActualResourceByContext(context);
483
+ const referencedResource = this.resourceDataRepository.getActualResourceByContext(context);
484
+ if (!referencedResource) {
485
+ throw new TransactionError(`Cannot apply "${diffToProcess.action}" on field "${String(diffToProcess.field)}" of resource ` +
486
+ `"${diffToProcess.node.getContext()}": it references "${context}", which is not in the actual ` +
487
+ 'resource graph yet. The referenced resource is applied later in this transaction, or not at all.');
488
+ }
489
+ return referencedResource;
231
490
  };
232
491
  // Incrementally apply diff inverse to the respective actual resource.
233
492
  let actualResource = this.resourceDataRepository.getActualResourceByContext(diffToProcess.node.getContext());
@@ -274,20 +533,223 @@ export class TransactionService {
274
533
  }
275
534
  return transaction;
276
535
  }
536
+ /**
537
+ * Refuses two names the `uniqueProperties` of one resource class say must differ: two values of its path,
538
+ * from two resources or from one, sharing the values of its domain.
539
+ */
540
+ ensureUniqueNames(resources) {
541
+ const describeResource = (resource) => `resource "${resource.getContext()}" of module "${this.inputService.getModuleIdFromResource(resource)}"`;
542
+ const holders = new Map();
543
+ for (const resource of resources) {
544
+ for (const uniqueName of this.getUniqueNames(resource)) {
545
+ const holder = holders.get(uniqueName.key);
546
+ if (holder) {
547
+ const domainName = uniqueName.within.length > 0 ? `within ${uniqueName.within.join(', ')}` : 'across the app';
548
+ throw new TransactionError(`"${uniqueName.path}" "${uniqueName.name}" is not unique ${domainName}: ${describeResource(holder)} and ${describeResource(resource)} both use it!`);
549
+ }
550
+ holders.set(uniqueName.key, resource);
551
+ }
552
+ }
553
+ }
554
+ /**
555
+ * Contributes every resource in the new (desired) resource graph to the shared
556
+ * {@link TerraformService}: terraform resources via `toHCL()`, external resources via
557
+ * `addOctoTerraformExternalResource()`. Always processes the full desired state — terraform
558
+ * computes the actual create/update/delete against its own state.
559
+ *
560
+ * Order does not matter: terraform resources reference each other through deferred refs, and
561
+ * external resources defer their parent-input wiring — both are resolved later, once every
562
+ * resource is registered (see {@link TerraformService}'s wiring phase).
563
+ */
564
+ async generateTerraform() {
565
+ const resources = this.resourceDataRepository.getNewResourcesByProperties().filter((r) => !r.isMarkedDeleted());
566
+ this.ensureUniqueNames(resources);
567
+ for (const resource of resources) {
568
+ // Every resource is produced by a model action inside a module, so it is always module-bound.
569
+ // A missing attribution means the resource was registered out-of-band — a hard error.
570
+ const moduleId = this.inputService.getModuleIdFromResource(resource);
571
+ if (moduleId === undefined) {
572
+ throw new TransactionError(`Resource "${resource.resourceId}" is not associated with any module!`);
573
+ }
574
+ const scope = this.terraformService.scope(moduleId);
575
+ if (resource instanceof ATerraformResource) {
576
+ await resource.toHCL(scope);
577
+ }
578
+ else {
579
+ scope.addOctoTerraformExternalResource(resource);
580
+ }
581
+ }
582
+ this.moveResources(resources);
583
+ }
584
+ /**
585
+ * @internal
586
+ */
277
587
  getDiffsOfSameNode(diff, diffs, diffAction) {
278
588
  return diffs.filter((d) => d.node.getContext() === diff.node.getContext() && d.action === diffAction);
279
589
  }
590
+ /**
591
+ * @internal
592
+ */
280
593
  getDuplicateDiffs(diff, diffs) {
281
594
  return diffs.filter((d) => d.node.getContext() === diff.node.getContext() &&
282
595
  d.field === diff.field &&
283
596
  d.action === diff.action &&
284
597
  DiffUtility.isObjectDeepEquals(d.value, diff.value));
285
598
  }
599
+ /**
600
+ * @internal
601
+ */
286
602
  getMatchingDiffs(diff, diffs) {
287
603
  return diffs.filter((d) => d.node.getContext() === diff.node.getContext() &&
288
604
  d.field === diff.field &&
289
605
  DiffUtility.isObjectDeepEquals(d.value, diff.value));
290
606
  }
607
+ /**
608
+ * The scope of the resources a node's actions create: the models the node sits under. An overlay
609
+ * sits where the nodes its own module created sit; the nodes it borrows from other modules are what
610
+ * it joins, so joining one more never moves what it created. An overlay joining only borrowed nodes
611
+ * sits where all of them sit. A model another member sits under is left out, since that member's
612
+ * context already names it.
613
+ */
614
+ getResourceScope(node) {
615
+ const members = new Map();
616
+ const placedNodeContexts = new Set();
617
+ const collectMembers = (placedNode) => {
618
+ if (placedNodeContexts.has(placedNode.getContext())) {
619
+ return;
620
+ }
621
+ placedNodeContexts.add(placedNode.getContext());
622
+ if (placedNode instanceof AOverlay) {
623
+ const moduleId = this.inputService.getModuleIdFromOverlay(placedNode);
624
+ const joinedNodes = placedNode.getAnchors().map((anchor) => anchor.getParent());
625
+ const ownNodes = joinedNodes.filter((joinedNode) => moduleId !== undefined &&
626
+ (joinedNode instanceof AOverlay
627
+ ? this.inputService.getModuleIdFromOverlay(joinedNode)
628
+ : this.inputService.getModuleIdFromModel(joinedNode)) === moduleId);
629
+ for (const placingNode of ownNodes.length > 0 ? ownNodes : joinedNodes) {
630
+ collectMembers(placingNode);
631
+ }
632
+ return;
633
+ }
634
+ for (const dependency of Object.values(placedNode.getParents()).flat()) {
635
+ members.set(dependency.to.getContext(), dependency.to);
636
+ }
637
+ };
638
+ collectMembers(node);
639
+ // Find every model the members sit under.
640
+ const ancestorContexts = new Set();
641
+ const collectAncestors = (model) => {
642
+ for (const dependency of Object.values(model.getParents()).flat()) {
643
+ if (!ancestorContexts.has(dependency.to.getContext())) {
644
+ ancestorContexts.add(dependency.to.getContext());
645
+ collectAncestors(dependency.to);
646
+ }
647
+ }
648
+ };
649
+ for (const member of members.values()) {
650
+ collectAncestors(member);
651
+ }
652
+ return [...members.keys()].filter((context) => !ancestorContexts.has(context)).sort();
653
+ }
654
+ /**
655
+ * The names a resource holds that the `uniqueProperties` of its class say the provider keeps unique,
656
+ * each keyed by its class, path and domain. A path with no value holds no name.
657
+ */
658
+ getUniqueNames(resource) {
659
+ const resourceClass = resource.constructor;
660
+ const uniqueNames = [];
661
+ for (const { path, within } of resourceClass.UNIQUE_PROPERTIES ?? []) {
662
+ // Resolve every name at the path, skipping a branch with no value.
663
+ let names = [resource.properties];
664
+ for (const segment of path.split('.')) {
665
+ const isArray = segment.endsWith('[]');
666
+ const key = isArray ? segment.slice(0, -2) : segment;
667
+ names = names.flatMap((value) => {
668
+ const child = value?.[key];
669
+ if (child === undefined || child === null) {
670
+ return [];
671
+ }
672
+ return isArray ? child : [child];
673
+ });
674
+ }
675
+ if (names.length === 0) {
676
+ continue;
677
+ }
678
+ // Resolve the domain, which every named resource must have.
679
+ const domain = within.map((property) => {
680
+ const value = resource.properties[property];
681
+ if (value === undefined || value === null) {
682
+ throw new TransactionError(`resource "${resource.getContext()}" of module "${this.inputService.getModuleIdFromResource(resource)}" has no "${property}", which its "${path}" is unique within!`);
683
+ }
684
+ return value;
685
+ });
686
+ for (const name of names) {
687
+ const key = JSON.stringify([resourceClass.NODE_PACKAGE, resourceClass.NODE_NAME, path, ...domain, name]);
688
+ uniqueNames.push({ key, name, path, within });
689
+ }
690
+ }
691
+ return uniqueNames;
692
+ }
693
+ /**
694
+ * Hands each committed resource's terraform state to the resource taking it over, so the two are one
695
+ * piece of infrastructure, updated or replaced in place: a resource now rendered into another module's
696
+ * folder, and an added resource taking a name of a deleted resource of its class. Without it terraform
697
+ * creates the new one while the old one is destroyed, and the provider refuses a name still held.
698
+ * A renamed external resource is left out: octo runs its actions itself, and a move would skip them.
699
+ */
700
+ moveResources(resources) {
701
+ const actualResources = this.resourceDataRepository.getActualResourcesByProperties();
702
+ const actualContexts = new Set(actualResources.map((r) => r.getContext()));
703
+ const newContexts = new Set(resources.map((r) => r.getContext()));
704
+ // Move each resource whose folder changed.
705
+ for (const resource of resources) {
706
+ const moduleId = this.inputService.getModuleIdFromResource(resource);
707
+ const actualModuleId = this.resourceSerializationService.getActualResourceModuleId(resource);
708
+ if (actualModuleId !== undefined && actualModuleId !== moduleId) {
709
+ this.terraformService.moveResource(actualModuleId, resource.resourceId, moduleId, resource.resourceId);
710
+ }
711
+ }
712
+ // Index the names of every deleted terraform resource.
713
+ const deletedResourcesByName = new Map();
714
+ for (const resource of actualResources) {
715
+ if (!(resource instanceof ATerraformResource) || newContexts.has(resource.getContext())) {
716
+ continue;
717
+ }
718
+ for (const { key } of this.getUniqueNames(resource)) {
719
+ deletedResourcesByName.set(key, resource);
720
+ }
721
+ }
722
+ if (deletedResourcesByName.size === 0) {
723
+ return;
724
+ }
725
+ // Pair each added terraform resource with the deleted resource holding one of its names.
726
+ const takenBy = new Map();
727
+ for (const resource of resources) {
728
+ if (!(resource instanceof ATerraformResource) || actualContexts.has(resource.getContext())) {
729
+ continue;
730
+ }
731
+ const deletedResources = [
732
+ ...new Set(this.getUniqueNames(resource)
733
+ .map(({ key }) => deletedResourcesByName.get(key))
734
+ .filter((r) => r !== undefined)),
735
+ ];
736
+ if (deletedResources.length === 0) {
737
+ continue;
738
+ }
739
+ if (deletedResources.length > 1) {
740
+ throw new TransactionError(`Resource "${resource.getContext()}" takes the names of both "${deletedResources[0].getContext()}" and "${deletedResources[1].getContext()}", and can take over only one of them!`);
741
+ }
742
+ const [deletedResource] = deletedResources;
743
+ const otherResource = takenBy.get(deletedResource);
744
+ if (otherResource) {
745
+ throw new TransactionError(`Resources "${otherResource.getContext()}" and "${resource.getContext()}" both take a name of "${deletedResource.getContext()}", and only one can take it over!`);
746
+ }
747
+ takenBy.set(deletedResource, resource);
748
+ const moduleId = this.inputService.getModuleIdFromResource(resource);
749
+ const deletedModuleId = this.resourceSerializationService.getActualResourceModuleId(deletedResource) ?? moduleId;
750
+ this.terraformService.moveResource(deletedModuleId, deletedResource.resourceId, moduleId, resource.resourceId);
751
+ }
752
+ }
291
753
  /**
292
754
  * Before assigning order to a diff, all its node's parent diffs must be processed.
293
755
  * E.g. diff to add environment, depends on region to exist, thus add region diff gets processed first.
@@ -324,8 +786,9 @@ export class TransactionService {
324
786
  }
325
787
  }
326
788
  // Get diffs of same node.
327
- // Process ADD before UPDATE, and UPDATE before DELETE.
328
- if (diff.action === DiffAction.UPDATE) {
789
+ // Process ADD before UPDATE/REPLACE, and UPDATE/REPLACE before DELETE. A REPLACE recreates the
790
+ // resource in place (same context), so for ordering it behaves like an UPDATE.
791
+ if (diff.action === DiffAction.UPDATE || diff.action === DiffAction.REPLACE) {
329
792
  const diffsOfSameNodeWithAddAction = this.getDiffsOfSameNode(diff, diffs, DiffAction.ADD);
330
793
  for (const sameNodeDiffWithAddAction of diffsOfSameNodeWithAddAction) {
331
794
  this.setApplyOrder(sameNodeDiffWithAddAction, diffs, [...seen, diff]);
@@ -341,154 +804,6 @@ export class TransactionService {
341
804
  }
342
805
  diff.applyOrder = Math.max(...dependencyApplyOrders) + 1;
343
806
  }
344
- async *beginTransaction(diffs, { enableResourceCapture = false, enableResourceValidation = false, yieldModelDiffs = false, yieldModelTransaction = false, yieldResourceDiffs = false, yieldResourceTransaction = false, } = {}) {
345
- // Diff overlays and add to existing diffs.
346
- const overlayDiffs = await this.overlayDataRepository.diff();
347
- diffs.push(...overlayDiffs);
348
- // Generate diff on models.
349
- const modelDiffs = diffs.map((d) => {
350
- if (d.node.constructor.NODE_TYPE === NodeType.OVERLAY) {
351
- return new DiffMetadata(d, (this.overlayActions.find((a) => a.overlayClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d)));
352
- }
353
- else {
354
- return new DiffMetadata(d, (this.modelActions.find((a) => a.modelClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d)));
355
- }
356
- });
357
- // Set apply order on model diffs.
358
- for (const diff of modelDiffs) {
359
- this.setApplyOrder(diff, modelDiffs);
360
- }
361
- this.eventService.emit(new ModelDiffsTransactionEvent(undefined, [modelDiffs]));
362
- if (yieldModelDiffs) {
363
- yield [modelDiffs];
364
- }
365
- // Apply model diffs.
366
- const modelTransaction = await this.applyModels(modelDiffs);
367
- this.eventService.emit(new ModelTransactionTransactionEvent(undefined, modelTransaction));
368
- if (yieldModelTransaction) {
369
- yield modelTransaction;
370
- }
371
- // Generate resource diffs.
372
- const newDiffs = await this.resourceDataRepository.diff();
373
- const dirtyDiffs = await this.resourceDataRepository.diffDirty();
374
- if (enableResourceValidation && (newDiffs.length > 0 || dirtyDiffs.length > 0)) {
375
- throw new TransactionError('Cannot run resource validation with pending resource diffs!');
376
- }
377
- if (enableResourceValidation) {
378
- const validationDiffs = this.resourceDataRepository.diffValidate();
379
- newDiffs.push(...validationDiffs);
380
- dirtyDiffs.push(...validationDiffs);
381
- }
382
- // new diffs = new - old | dirty diffs = new - actual
383
- // Any new diff that is also not part of dirty diffs should be skipped, as the actual is already in desired state.
384
- for (let i = newDiffs.length - 1; i >= 0; i--) {
385
- const newDiff = newDiffs[i];
386
- if (!dirtyDiffs.some((d) => d.node.getContext() === newDiff.node.getContext() &&
387
- d.action === newDiff.action &&
388
- d.field === newDiff.field &&
389
- DiffUtility.isObjectDeepEquals(d.value, newDiff.value))) {
390
- newDiffs.splice(i, 1);
391
- }
392
- }
393
- // Ensure any new diffs are not operating on dirty resources.
394
- this.resourceDataRepository.ensureDiffsNotOperatingOnDirtyResources(newDiffs);
395
- // Skip processing dirty diffs that are already accounted for in new diffs.
396
- for (let i = dirtyDiffs.length - 1; i >= 0; i--) {
397
- const dirtyDiff = dirtyDiffs[i];
398
- if (newDiffs.some((d) => d.node.getContext() === dirtyDiff.node.getContext() &&
399
- d.action === dirtyDiff.action &&
400
- d.field === dirtyDiff.field &&
401
- DiffUtility.isObjectDeepEquals(d.value, dirtyDiff.value))) {
402
- dirtyDiffs.splice(i, 1);
403
- }
404
- }
405
- // Generate diff on resources.
406
- const resourceDiffs = newDiffs.map((d) => new DiffMetadata(d, (this.resourceActions.find((a) => a.resourceClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d))));
407
- // Set apply order on resource diffs.
408
- for (const diff of resourceDiffs) {
409
- this.setApplyOrder(diff, resourceDiffs);
410
- }
411
- // Generate diff on dirty resources.
412
- const dirtyResourceDiffs = dirtyDiffs.map((d) => new DiffMetadata(d, (this.resourceActions.find((a) => a.resourceClass === d.node.constructor)?.actions || []).filter((a) => a.filter(d))));
413
- // Set apply order on dirty resource diffs.
414
- for (const diff of dirtyResourceDiffs) {
415
- this.setApplyOrder(diff, dirtyResourceDiffs);
416
- }
417
- this.applyResourcesDryRun([...resourceDiffs, ...dirtyResourceDiffs], { enableResourceCapture });
418
- this.eventService.emit(new ResourceDiffsTransactionEvent(undefined, [[resourceDiffs], [dirtyResourceDiffs]]));
419
- if (yieldResourceDiffs) {
420
- yield [resourceDiffs, dirtyResourceDiffs];
421
- }
422
- // Apply resource diffs.
423
- const resourceTransaction = await this.applyResources(resourceDiffs, {
424
- enableResourceCapture,
425
- });
426
- // Apply dirty resource diffs.
427
- const dirtyResourceTransaction = await this.applyResources(dirtyResourceDiffs, {
428
- enableResourceCapture,
429
- });
430
- this.eventService.emit(new ResourceTransactionTransactionEvent(undefined, [resourceTransaction, dirtyResourceTransaction]));
431
- if (yieldResourceTransaction) {
432
- yield [...resourceTransaction, ...dirtyResourceTransaction];
433
- }
434
- return modelTransaction;
435
- }
436
- registerModelActions(forModel, actions) {
437
- const modelActions = this.modelActions.find((a) => a.modelClass === forModel);
438
- if (!modelActions) {
439
- this.modelActions.push({ actions: actions, modelClass: forModel });
440
- }
441
- else {
442
- for (const action of actions) {
443
- if (modelActions.actions.find((a) => a.constructor.name === action.constructor.name)) {
444
- throw new Error(`Action "${action.constructor.name}" already registered for model "${forModel.name}"!`);
445
- }
446
- modelActions.actions.push(action);
447
- }
448
- }
449
- }
450
- registerOverlayActions(forOverlay, actions) {
451
- const overlayActions = this.overlayActions.find((a) => a.overlayClass === forOverlay);
452
- if (!overlayActions) {
453
- this.overlayActions.push({ actions: actions, overlayClass: forOverlay });
454
- }
455
- else {
456
- for (const action of actions) {
457
- if (overlayActions.actions.find((a) => a.constructor.name === action.constructor.name)) {
458
- throw new Error(`Action "${action.constructor.name}" already registered for overlay "${forOverlay.name}"!`);
459
- }
460
- overlayActions.actions.push(action);
461
- }
462
- }
463
- }
464
- registerResourceActions(forResource, actions) {
465
- const resourceActions = this.resourceActions.find((a) => a.resourceClass === forResource);
466
- if (!resourceActions) {
467
- this.resourceActions.push({ actions: actions, resourceClass: forResource });
468
- }
469
- else {
470
- for (const action of actions) {
471
- if (resourceActions.actions.find((a) => a.constructor.name === action.constructor.name)) {
472
- throw new Error(`Action "${action.constructor.name}" already registered for resource "${forResource.name}"!`);
473
- }
474
- resourceActions.actions.push(action);
475
- }
476
- }
477
- }
478
- unregisterModelActions(forModel) {
479
- const modelActions = this.modelActions.find((a) => a.modelClass === forModel);
480
- if (!modelActions) {
481
- return;
482
- }
483
- modelActions.actions = [];
484
- }
485
- unregisterOverlayActions(forOverlay) {
486
- const overlayActions = this.overlayActions.find((a) => a.overlayClass === forOverlay);
487
- if (!overlayActions) {
488
- return;
489
- }
490
- overlayActions.actions = [];
491
- }
492
807
  }
493
808
  __decorate([
494
809
  EventSource(ModelActionRegistrationEvent),
@@ -512,18 +827,22 @@ __decorate([
512
827
  * @internal
513
828
  */
514
829
  let TransactionServiceFactory = class TransactionServiceFactory {
830
+ /**
831
+ * @internal
832
+ */
515
833
  static async create() {
516
834
  const container = Container.getInstance();
517
- const [captureService, eventService, inputService, moduleContainer, overlayDataRepository, resourceDataRepository] = await Promise.all([
518
- container.get(CaptureService),
835
+ const [eventService, inputService, moduleContainer, overlayDataRepository, resourceDataRepository, resourceSerializationService, terraformService,] = await Promise.all([
519
836
  container.get(EventService),
520
837
  container.get(InputService),
521
838
  container.get(ModuleContainer),
522
839
  container.get(OverlayDataRepository),
523
840
  container.get(ResourceDataRepository),
841
+ container.get(ResourceSerializationService),
842
+ container.get(TerraformService),
524
843
  ]);
525
844
  if (!this.instance) {
526
- this.instance = new TransactionService(captureService, eventService, inputService, moduleContainer, overlayDataRepository, resourceDataRepository);
845
+ this.instance = new TransactionService(eventService, inputService, moduleContainer, overlayDataRepository, resourceDataRepository, resourceSerializationService, terraformService);
527
846
  }
528
847
  return this.instance;
529
848
  }