@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
@@ -1,14 +1,25 @@
1
- import { Container } from '../functions/container/container.js';
1
+ import { mkdtemp } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import {} from '../functions/container/container.js';
5
+ import { DiffAction } from '../functions/diff/diff.js';
6
+ import { ANodeAction } from '../functions/node/node-action.abstract.js';
2
7
  import { Octo } from '../main.js';
3
8
  import { AModel } from '../models/model.abstract.js';
9
+ import { applyModelTransaction } from '../modes/apply-transaction.js';
4
10
  import { OverlayDataRepository } from '../overlays/overlay-data.repository.js';
5
11
  import { AOverlay } from '../overlays/overlay.abstract.js';
12
+ import { ResourceDataRepository } from '../resources/resource-data.repository.js';
6
13
  import { AResource } from '../resources/resource.abstract.js';
7
14
  import { InputService } from '../services/input/input.service.js';
8
- import { LocalEncryptionStateProvider } from '../services/state-management/local-encryption.state-provider.js';
9
15
  import { LocalStateProvider } from '../services/state-management/local.state-provider.js';
16
+ import { StateManagementService } from '../services/state-management/state-management.service.js';
10
17
  import { TestStateProvider } from '../services/state-management/test.state-provider.js';
18
+ import { TerraformService } from '../services/terraform/terraform.service.js';
11
19
  import { TransactionService } from '../services/transaction/transaction.service.js';
20
+ import { DiffUtility } from '../utilities/diff/diff.utility.js';
21
+ import { HclUtility } from '../utilities/hcl/hcl.utility.js';
22
+ import { TerraformUtility } from '../utilities/terraform/terraform.utility.js';
12
23
  import { TestAnchor } from '../utilities/test-helpers/test-classes.js';
13
24
  import { create } from '../utilities/test-helpers/test-models.js';
14
25
  import { createTestOverlays } from '../utilities/test-helpers/test-overlays.js';
@@ -16,127 +27,115 @@ import { createResources, createTestResources } from '../utilities/test-helpers/
16
27
  import { AModule } from './module.abstract.js';
17
28
  import { ModuleContainer } from './module.container.js';
18
29
  // Universal Test Module and Actions.
30
+ /**
31
+ * @internal
32
+ */
19
33
  class UniversalTestModuleSchema {
20
34
  }
35
+ /**
36
+ * @internal
37
+ */
21
38
  class UniversalTestModule extends AModule {
22
39
  static { this.MODULE_PACKAGE = '@octo'; }
23
40
  static { this.MODULE_SCHEMA = UniversalTestModuleSchema; }
41
+ /**
42
+ * @internal
43
+ */
24
44
  async onInit() {
25
45
  return;
26
46
  }
27
47
  }
48
+ /**
49
+ * @internal
50
+ */
28
51
  class UniversalModelAction {
52
+ /**
53
+ * @internal
54
+ */
29
55
  filter() {
30
56
  return true;
31
57
  }
58
+ /**
59
+ * @internal
60
+ */
32
61
  async handle() {
33
62
  return {};
34
63
  }
35
64
  }
36
- class UniversalResourceAction {
65
+ /**
66
+ * @internal
67
+ */
68
+ class UniversalResourceAction extends ANodeAction {
69
+ /**
70
+ * @internal
71
+ */
72
+ constructor() {
73
+ super();
74
+ }
75
+ /**
76
+ * @internal
77
+ */
37
78
  filter() {
38
79
  return true;
39
80
  }
81
+ /**
82
+ * @internal
83
+ */
40
84
  async handle() { }
41
- async mock() { }
42
85
  }
43
86
  /**
87
+ * The harness for testing a module.
88
+ *
89
+ * It runs your module through the real Octo lifecycle against an in-memory state provider, and hands
90
+ * back everything a test needs to assert on: the model and resource transactions, the generated HCL,
91
+ * and the resource responses. Create it inside a {@link TestContainer} so each test file is isolated.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const container = await TestContainer.create({ mocks: [] }, { factoryTimeoutInMs: 500 });
96
+ * const testModuleContainer = new TestModuleContainer(container);
97
+ * await testModuleContainer.initialize();
98
+ *
99
+ * const generator = testModuleContainer.runModules([
100
+ * { inputs: { name: 'test-app' }, moduleId: 'app', type: SimpleAppModule },
101
+ * ]);
102
+ * const { modelTransaction } = (await generator.next()).value;
103
+ * ```
104
+ *
44
105
  * @group Modules
45
106
  */
46
107
  export class TestModuleContainer {
47
- constructor() {
108
+ /**
109
+ * @param container The {@link TestContainer} this run resolves its services from.
110
+ */
111
+ constructor(container) {
112
+ this.container = container;
48
113
  this.octo = new Octo();
49
114
  }
50
- async commit(app, { appLockId, enableResourceCapture = false, filterByModuleIds = [], skipResourceTransaction = false, } = {}) {
51
- if (!appLockId) {
52
- const { lockId } = await this.stateProvider.lockApp();
53
- appLockId = lockId;
54
- }
55
- const generator = this.octo.beginTransaction(app, {
56
- appLockId: skipResourceTransaction ? undefined : appLockId,
57
- enableResourceCapture,
58
- yieldModelDiffs: true,
59
- yieldModelTransaction: true,
60
- yieldResourceDiffs: true,
61
- yieldResourceTransaction: true,
62
- });
63
- const response = {};
64
- try {
65
- response.modelDiffs = (await generator.next()).value;
66
- response.modelTransaction = (await generator.next()).value;
67
- response.resourceDiffs = (await generator.next()).value;
68
- response.resourceTransaction = (await generator.next()).value;
69
- await generator.next();
70
- }
71
- catch (error) {
72
- if (!skipResourceTransaction || error.message !== 'App is not in lock state!') {
73
- await this.reset();
74
- throw error;
75
- }
76
- }
77
- finally {
78
- await this.stateProvider.unlockApp(appLockId);
79
- }
80
- const container = Container.getInstance();
81
- const inputService = await container.get(InputService);
82
- for (const moduleId of filterByModuleIds) {
83
- response.modelDiffs = response.modelDiffs
84
- .map((i) => i.filter((j) => {
85
- if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
86
- return inputService.getModuleIdFromModel(j.node) === moduleId;
87
- }
88
- else if (j.node instanceof AOverlay) {
89
- return inputService.getModuleIdFromOverlay(j.node) === moduleId;
90
- }
91
- else {
92
- return false;
93
- }
94
- }))
95
- .filter((i) => i.length);
96
- response.modelTransaction = response.modelTransaction
97
- .map((i) => i.filter((j) => {
98
- if (j.node instanceof AModel && !(j.node instanceof AOverlay)) {
99
- return inputService.getModuleIdFromModel(j.node) === moduleId;
100
- }
101
- else if (j.node instanceof AOverlay) {
102
- return inputService.getModuleIdFromOverlay(j.node) === moduleId;
103
- }
104
- else {
105
- return false;
106
- }
107
- }))
108
- .filter((i) => i.length);
109
- response.resourceDiffs = response.resourceDiffs
110
- .map((i) => i.filter((j) => {
111
- if (j.node instanceof AResource) {
112
- return inputService.getModuleIdFromResource(j.node) === moduleId;
113
- }
114
- else {
115
- return false;
116
- }
117
- }))
118
- .filter((i) => i.length);
119
- if (!skipResourceTransaction) {
120
- response.resourceTransaction = response.resourceTransaction
121
- .map((i) => i.filter((j) => {
122
- if (j.node instanceof AResource) {
123
- return inputService.getModuleIdFromResource(j.node) === moduleId;
124
- }
125
- else {
126
- return false;
127
- }
128
- }))
129
- .filter((i) => i.length);
130
- }
131
- }
132
- await this.reset();
133
- return response;
115
+ /**
116
+ * To seed resources that already exist, as though the given module had produced them.
117
+ * Use it to stand up the prerequisites a module under test expects to find.
118
+ */
119
+ async createResources(moduleId, args, options) {
120
+ const moduleContainer = await this.container.get(ModuleContainer);
121
+ // Register new moduleId as instance of the universal module.
122
+ moduleContainer.load(UniversalTestModule, moduleId, {});
123
+ // Immediately unload the universal module to ensure it does not run in apply().
124
+ moduleContainer.unload(UniversalTestModule);
125
+ return createResources(args, { ...options, moduleId });
134
126
  }
127
+ /**
128
+ * To build a throwaway anchor for a test double, without declaring an anchor class.
129
+ */
135
130
  createTestAnchor(anchorId, properties, parent) {
136
131
  return new TestAnchor(anchorId, properties, parent);
137
132
  }
133
+ /**
134
+ * To seed models, as though the given module had produced them.
135
+ * Each model gets a no-op action, so the models appear in a transaction without doing any work.
136
+ */
138
137
  async createTestModels(moduleId, args) {
139
- const container = Container.getInstance();
138
+ const container = this.container;
140
139
  const [inputService, moduleContainer, transactionService] = await Promise.all([
141
140
  container.get(InputService),
142
141
  container.get(ModuleContainer),
@@ -148,16 +147,11 @@ export class TestModuleContainer {
148
147
  moduleContainer.unload(UniversalTestModule);
149
148
  const result = create(args);
150
149
  for (const models of Object.values(result)) {
151
- // Check if the model has already been registered.
152
- // If no error thrown, the model has already been registered.
153
150
  for (const model of models) {
154
- try {
155
- inputService.getModuleIdFromModel(model);
151
+ // Skip models that are already registered (a defined moduleId means it is known).
152
+ if (inputService.getModuleIdFromModel(model) !== undefined) {
156
153
  continue;
157
154
  }
158
- catch (error) {
159
- /* do nothing. */
160
- }
161
155
  inputService.registerModel(moduleId, model);
162
156
  const universalAction = new UniversalModelAction();
163
157
  Object.assign(universalAction, {
@@ -177,126 +171,186 @@ export class TestModuleContainer {
177
171
  }
178
172
  return result;
179
173
  }
174
+ /**
175
+ * To seed overlays, as though the given module had produced them.
176
+ * An overlay given no actions gets a no-op one.
177
+ */
180
178
  async createTestOverlays(moduleId, args) {
181
- const container = Container.getInstance();
182
- const [inputService, moduleContainer, transactionService] = await Promise.all([
183
- container.get(InputService),
184
- container.get(ModuleContainer),
185
- container.get(TransactionService),
186
- ]);
179
+ const moduleContainer = await this.container.get(ModuleContainer);
187
180
  // Register new moduleId as instance of the universal module.
188
181
  moduleContainer.load(UniversalTestModule, moduleId, {});
189
182
  // Immediately unload the universal module to ensure it does not run in apply().
190
183
  moduleContainer.unload(UniversalTestModule);
191
- const result = await createTestOverlays(args);
192
- for (const overlay of Object.values(result)) {
193
- inputService.registerOverlay(moduleId, overlay);
194
- const universalAction = new UniversalModelAction();
195
- Object.assign(universalAction, {
196
- constructor: { name: `${UniversalModelAction.name}For${overlay.constructor.name}` },
197
- });
198
- try {
199
- transactionService.unregisterOverlayActions(overlay.constructor);
200
- transactionService.registerOverlayActions(overlay.constructor, [
201
- universalAction,
202
- ]);
203
- }
204
- catch (error) {
205
- if (error.message !==
206
- `Action "${universalAction.constructor.name}" already registered for overlay "${overlay.constructor.name}"!`) {
207
- throw error;
208
- }
184
+ // Default any overlay without explicit actions to a universal no-op action, named after the
185
+ // overlay so it reads clearly in a transaction snapshot. createTestOverlays registers them.
186
+ for (const arg of args) {
187
+ if (!arg.overlayActions || arg.overlayActions.length === 0) {
188
+ const [, nodeName] = arg.context.split('=')[0].split('/');
189
+ const universalAction = new UniversalModelAction();
190
+ Object.assign(universalAction, {
191
+ constructor: { name: `${UniversalModelAction.name}For${nodeName}` },
192
+ });
193
+ arg.overlayActions = [universalAction];
209
194
  }
210
195
  }
211
- return result;
196
+ return createTestOverlays(args, { moduleId });
212
197
  }
213
- async createResources(moduleId, args, options) {
214
- const container = Container.getInstance();
215
- const [inputService, moduleContainer] = await Promise.all([
216
- container.get(InputService),
217
- container.get(ModuleContainer),
218
- ]);
198
+ /**
199
+ * To seed resources, as though the given module had produced them.
200
+ * A resource given no actions gets a no-op one, unless terraform owns it.
201
+ */
202
+ async createTestResources(moduleId, args, options) {
203
+ const moduleContainer = await this.container.get(ModuleContainer);
219
204
  // Register new moduleId as instance of the universal module.
220
205
  moduleContainer.load(UniversalTestModule, moduleId, {});
221
206
  // Immediately unload the universal module to ensure it does not run in apply().
222
207
  moduleContainer.unload(UniversalTestModule);
223
- const result = await createResources(args, options);
224
- for (const resource of Object.values(result)) {
225
- inputService.registerResource(moduleId, resource);
208
+ // Default any resource without explicit actions to a universal no-op action, named after the
209
+ // resource so it reads clearly in a transaction snapshot. createTestResources registers them,
210
+ // and skips terraform resources (which terraform owns and cannot have actions).
211
+ for (const arg of args) {
212
+ if (!arg.resourceActions || arg.resourceActions.length === 0) {
213
+ const [, nodeName] = arg.resourceContext.split('=')[0].split('/');
214
+ const universalAction = new UniversalResourceAction();
215
+ Object.assign(universalAction, {
216
+ constructor: { name: `${UniversalResourceAction.name}For${nodeName}` },
217
+ });
218
+ arg.resourceActions = [universalAction];
219
+ }
226
220
  }
227
- return result;
221
+ return createTestResources(args, { ...options, moduleId });
228
222
  }
229
- async createTestResources(moduleId, args, options) {
230
- const container = Container.getInstance();
231
- const [inputService, moduleContainer, transactionService] = await Promise.all([
232
- container.get(InputService),
233
- container.get(ModuleContainer),
234
- container.get(TransactionService),
235
- ]);
236
- // Register new moduleId as instance of the universal module.
237
- moduleContainer.load(UniversalTestModule, moduleId, {});
238
- // Immediately unload the universal module to ensure it does not run in apply().
239
- moduleContainer.unload(UniversalTestModule);
240
- const result = await createTestResources(args, options);
241
- for (const resource of Object.values(result)) {
242
- inputService.registerResource(moduleId, resource);
243
- try {
244
- transactionService.registerResourceActions(resource.constructor, [
245
- new UniversalResourceAction(),
246
- ]);
223
+ /**
224
+ * Reduces a transaction's diffs, model or resource, to a stable digest you can snapshot:
225
+ * `+ <context>` (create), `- <context>` (delete), `^ <context>` (replace), `* <context>` (update).
226
+ *
227
+ * A diff is classified exactly as {@link Octo.validate} aggregates it, so a digest and a validate
228
+ * report of the same transaction never disagree. Only an add/delete of a `resourceId` creates or
229
+ * destroys a resource; an add/delete on any other field changes a resource that stays -
230
+ * re-pointing a `parent`, most commonly - and reads as an update.
231
+ *
232
+ * The digest has one entry per diff, not per resource, so a resource may appear more than once.
233
+ */
234
+ digestDiffs(diffs) {
235
+ const changes = [];
236
+ for (const d of diffs.flat()) {
237
+ if (d.action === DiffAction.ADD && d.field === 'resourceId') {
238
+ changes.push(`+ ${d.node.getContext()}`);
247
239
  }
248
- catch (error) {
249
- if (error.message !==
250
- `Action "${UniversalResourceAction.name}" already registered for resource "${resource.constructor.name}"!`) {
251
- throw error;
252
- }
240
+ else if (d.action === DiffAction.DELETE && d.field === 'resourceId') {
241
+ changes.push(`- ${d.node.getContext()}`);
242
+ }
243
+ else if (d.action === DiffAction.REPLACE) {
244
+ changes.push(`^ ${d.node.getContext()}`);
245
+ }
246
+ else if (d.action === DiffAction.VALIDATE) {
247
+ // Not a change: validation runs as its own transaction, one diff per surviving resource.
248
+ }
249
+ else {
250
+ changes.push(`* ${d.node.getContext()}`);
253
251
  }
254
252
  }
255
- return result;
256
- }
257
- mapTransactionActions(transaction) {
258
- return transaction.map((i) => i.map((j) => j.actions.map((a) => a.constructor.name)).flat());
253
+ return changes;
259
254
  }
255
+ /**
256
+ * Boots Octo for the test. Call it once, before running any module.
257
+ *
258
+ * @param stateProvider Defaults to an in-memory {@link TestStateProvider}. Only the local and test
259
+ * providers are accepted - a test must never write to shared state.
260
+ * @param initializeInContainer Factories to resolve at boot. See {@link Octo.initialize}.
261
+ * @param excludeInContainer Factories to unregister at boot. See {@link Octo.initialize}.
262
+ */
260
263
  async initialize(stateProvider, initializeInContainer, excludeInContainer) {
261
- if (stateProvider &&
262
- !(stateProvider instanceof LocalEncryptionStateProvider ||
263
- stateProvider instanceof LocalStateProvider ||
264
- stateProvider instanceof TestStateProvider)) {
265
- throw new Error('TestModuleContainer is only meant to work with LocalEncryption, Local, or Test state provider!');
264
+ if (stateProvider && !(stateProvider instanceof LocalStateProvider || stateProvider instanceof TestStateProvider)) {
265
+ throw new Error('TestModuleContainer is only meant to work with Local or Test state provider!');
266
266
  }
267
267
  this.stateProvider = stateProvider ?? new TestStateProvider();
268
268
  await this.octo.initialize(this.stateProvider, initializeInContainer, excludeInContainer);
269
269
  // Always register the UniversalTestModule to allow users to create test prerequisites.
270
- const moduleContainer = await Container.getInstance().get(ModuleContainer);
270
+ const moduleContainer = await this.container.get(ModuleContainer);
271
271
  moduleContainer.register(UniversalTestModule, { packageName: '@octo' });
272
272
  }
273
- async orderModules(modules) {
274
- const moduleContainer = await Container.getInstance().get(ModuleContainer);
275
- moduleContainer.order(modules);
273
+ /**
274
+ * Whether the committed resource state matches the previous one, i.e. whether the last run
275
+ * settled without leaving a pending change.
276
+ */
277
+ async isResourceStateEqual() {
278
+ const container = this.container;
279
+ const stateManagementService = await container.get(StateManagementService);
280
+ const resourcesActual = await stateManagementService.getResourceState('resources-actual.json');
281
+ const resourcesOld = await stateManagementService.getResourceState('resources-old.json');
282
+ return DiffUtility.isObjectDeepEquals(resourcesActual.data, resourcesOld.data);
276
283
  }
277
- registerCapture(resourceContext, response) {
278
- this.octo.registerCapture(resourceContext, response);
284
+ /**
285
+ * Reduces a transaction to the names of the actions it ran, in order. Snapshot it to assert that
286
+ * a change triggered the actions you expected.
287
+ */
288
+ mapTransactionActions(transaction) {
289
+ return transaction.map((i) => i.map((j) => j.actions.map((a) => a.constructor.name)).flat());
279
290
  }
280
- async runModule(module) {
281
- const moduleContainer = await Container.getInstance().get(ModuleContainer);
282
- const moduleMetadataIndex = moduleContainer.getMetadataIndex(module.type);
283
- if (moduleMetadataIndex === -1) {
284
- moduleContainer.register(module.type, { packageName: module.type.MODULE_PACKAGE });
285
- }
286
- const moduleMetadata = moduleContainer.getMetadata(module.type);
287
- if (module.hidden === true) {
288
- moduleContainer.unload(moduleMetadata.module);
289
- }
290
- else {
291
- moduleContainer.load(moduleMetadata.module, module.moduleId, module.inputs);
292
- }
293
- return (await this.octo.compose());
291
+ /**
292
+ * See {@link Octo.registerHooks}.
293
+ */
294
+ registerHooks(...args) {
295
+ return this.octo.registerHooks(...args);
296
+ }
297
+ /**
298
+ * See {@link Octo.registerTags}.
299
+ */
300
+ registerTags(...args) {
301
+ return this.octo.registerTags(...args);
302
+ }
303
+ /**
304
+ * See {@link Octo.registerTerraformConfig}. Required before a run that generates terraform.
305
+ */
306
+ registerTerraformConfig(...args) {
307
+ return this.octo.registerTerraformConfig(...args);
294
308
  }
295
- async runModules(modules) {
296
- const moduleContainer = await Container.getInstance().get(ModuleContainer);
297
- for (const module of modules) {
298
- const moduleMetadataIndex = moduleContainer.getMetadataIndex(module.type);
299
- if (moduleMetadataIndex === -1) {
309
+ /**
310
+ * See {@link Octo.registerTerraformProvider}. Required before a run that generates terraform.
311
+ */
312
+ registerTerraformProvider(...args) {
313
+ return this.octo.registerTerraformProvider(...args);
314
+ }
315
+ /**
316
+ * Tears down the composed graph - models, overlays, inputs, and modules - so the next
317
+ * {@link TestModuleContainer.runModules} composes fresh. Call it in your test teardown.
318
+ */
319
+ async reset() {
320
+ const container = this.container;
321
+ // Reset ModuleContainer constructor injections.
322
+ await container.get(InputService, { args: [true] });
323
+ await container.get(OverlayDataRepository, {
324
+ args: [true, []],
325
+ });
326
+ // Reset module container.
327
+ const moduleContainer = await container.get(ModuleContainer);
328
+ moduleContainer.reset();
329
+ }
330
+ /**
331
+ * Runs the given modules through Octo's lifecycle, and yields the result once.
332
+ *
333
+ * How far the lifecycle goes is set by `terraformTarget`, and this is the choice that decides what
334
+ * the test costs:
335
+ * - `'skip'` - composes and commits in memory. No terraform, no cloud. This is a unit test.
336
+ * - `'plan'` - generates the module folders and runs `terraform plan` against them.
337
+ * - `'apply'` - generates, plans, applies, and commits. **This creates real infrastructure.**
338
+ *
339
+ * @param modules The modules to load, in order.
340
+ * @param options `filterByModuleIds` narrows the run to those modules; `outputDir` is where the
341
+ * terraform folders are written, defaulting to a temporary directory.
342
+ */
343
+ async *runModules(modules, { filterByModuleIds = [], outputDir, terraformTarget = 'skip', } = {}) {
344
+ const [moduleContainer, resourceDataRepository, terraformService, terraformUtility] = await Promise.all([
345
+ this.container.get(ModuleContainer),
346
+ this.container.get(ResourceDataRepository),
347
+ this.container.get(TerraformService),
348
+ this.container.get(TerraformUtility),
349
+ ]);
350
+ // Load modules.
351
+ const moduleList = Array.isArray(modules) ? modules : [modules];
352
+ for (const module of moduleList) {
353
+ if (moduleContainer.getMetadataIndex(module.type) === -1) {
300
354
  moduleContainer.register(module.type, {
301
355
  packageName: module.type.MODULE_PACKAGE,
302
356
  });
@@ -309,18 +363,148 @@ export class TestModuleContainer {
309
363
  moduleContainer.load(moduleMetadata.module, module.moduleId, module.inputs);
310
364
  }
311
365
  }
312
- return (await this.octo.compose());
366
+ // Compose modules.
367
+ moduleContainer.order(moduleList.map((m) => m.type));
368
+ await this.octo.compose();
369
+ const app = this.octo.getRootModel();
370
+ const collectResponses = () => Object.fromEntries(resourceDataRepository.getActualResourcesByProperties().map((r) => [r.getContext(), r.response]));
371
+ if (terraformTarget === 'skip') {
372
+ // this.commit() applies the model graph exactly once and, before its internal reset, stores the
373
+ // rendered desired state in `previousHcl`. Derive the render and block diff from that single
374
+ // apply rather than a separate preview render — a preview would re-run model actions, and
375
+ // non-idempotent ones (e.g. sibling associations) would then apply twice.
376
+ const priorHcl = this.previousHcl ?? '';
377
+ const transaction = await this.commit(app, { filterByModuleIds });
378
+ const currentHcl = this.previousHcl ?? '';
379
+ yield {
380
+ hclDiff: HclUtility.diffBlocks(priorHcl, currentHcl),
381
+ hclRender: currentHcl,
382
+ modelTransaction: transaction.modelTransaction,
383
+ resourceDiffs: transaction.resourceDiffs,
384
+ resourceTransaction: transaction.resourceTransaction,
385
+ responses: collectResponses(),
386
+ validateReport: undefined,
387
+ warnings: [],
388
+ };
389
+ return;
390
+ }
391
+ // In production octo runs generate/validate/commit as three separate processes, each of which
392
+ // derives the resource graph once from intent. runModules drives all three in one process, so it
393
+ // builds the model transaction once and hands the same result to each mode. The previous run's
394
+ // sweep is cleared first, as a new process would start without it.
395
+ terraformService.resetTransactionState();
396
+ const transaction = await applyModelTransaction(app);
397
+ // Generate.
398
+ const dir = outputDir ?? (await mkdtemp(join(tmpdir(), 'octo-hcl-')));
399
+ const resourceDiffs = await this.octo.generate(app, { outputDir: dir }, transaction);
400
+ // Render the full HCL and the block diff from the sweep the transaction produced.
401
+ const currentHcl = HclUtility.serialize(terraformService.renderAllModules());
402
+ const diffHcl = HclUtility.diffBlocks(this.previousHcl ?? '', currentHcl);
403
+ this.previousHcl = currentHcl;
404
+ // Validate.
405
+ const validateReport = await this.octo.validate(app, await terraformUtility.plan(dir, { json: true }), transaction);
406
+ if (validateReport.failures.length > 0) {
407
+ throw new Error(`runModules(): terraform could not plan:\n${validateReport.failures
408
+ .map((failure) => `${failure.moduleId ? `[${failure.moduleId}] ` : ''}${failure.message}`)
409
+ .join('\n')}`);
410
+ }
411
+ const result = {
412
+ hclDiff: diffHcl,
413
+ hclRender: currentHcl,
414
+ modelTransaction: [],
415
+ resourceDiffs,
416
+ resourceTransaction: [],
417
+ responses: collectResponses(),
418
+ validateReport,
419
+ warnings: [],
420
+ };
421
+ if (terraformTarget === 'plan') {
422
+ yield result;
423
+ return;
424
+ }
425
+ // Apply.
426
+ await terraformUtility.apply(dir);
427
+ // Commit. The lock is taken and released here, the way the CLI does it around octo.commit().
428
+ const { lockId } = await this.stateProvider.lockApp();
429
+ let warnings;
430
+ try {
431
+ ({ warnings } = await this.octo.commit(app, { lockId, outputs: await terraformUtility.output(dir, { json: true }) }, transaction));
432
+ }
433
+ finally {
434
+ await this.stateProvider.unlockApp(lockId);
435
+ }
436
+ // Re-collect responses after the commit: it is commit that maps terraform outputs onto the
437
+ // actual resource graph, so a snapshot taken before it (as `response` holds) would miss them.
438
+ yield { ...result, responses: collectResponses(), warnings };
313
439
  }
314
- async reset() {
315
- const container = Container.getInstance();
316
- // Reset ModuleContainer constructor injections.
317
- await container.get(InputService, { args: [true] });
318
- await container.get(OverlayDataRepository, {
319
- args: [true, []],
440
+ /**
441
+ * Persists the run's state, so a later run in the same test diffs against it.
442
+ */
443
+ async commit(app, { filterByModuleIds = [], skipResourceTransaction = false, } = {}) {
444
+ const [terraformService, transactionService] = await Promise.all([
445
+ this.container.get(TerraformService),
446
+ this.container.get(TransactionService),
447
+ ]);
448
+ // Each transaction sweeps the full resource graph into the terraform service, so the previous
449
+ // call's sweep must be cleared first. Config and providers survive, as they would in a real
450
+ // process — tests register them once (in beforeEach), not per transaction.
451
+ terraformService.resetTransactionState();
452
+ const diffs = await app.diff();
453
+ const generator = transactionService.beginTransaction(diffs, {
454
+ generateTerraform: true,
455
+ yieldModelDiffs: true,
456
+ yieldModelTransaction: true,
457
+ yieldResourceDiffs: true,
458
+ yieldResourceTransaction: true,
320
459
  });
321
- // Reset module container.
322
- const moduleContainer = await container.get(ModuleContainer);
323
- moduleContainer.reset();
460
+ const response = {};
461
+ try {
462
+ response.modelDiffs = (await generator.next()).value;
463
+ response.modelTransaction = (await generator.next()).value;
464
+ response.resourceDiffs = (await generator.next()).value;
465
+ if (!skipResourceTransaction) {
466
+ response.resourceTransaction = (await generator.next()).value;
467
+ await generator.next();
468
+ }
469
+ else {
470
+ response.resourceTransaction = [];
471
+ }
472
+ }
473
+ catch (error) {
474
+ await this.reset();
475
+ throw error;
476
+ }
477
+ if (!skipResourceTransaction) {
478
+ await this.octo['commitTransaction'](app, response.modelTransaction, response.resourceTransaction);
479
+ }
480
+ // Establish the HCL diff baseline from the same transaction that just applied the models, so the
481
+ // next runModules() render reports its `diff` against the committed state. Captured before
482
+ // reset(), which wipes the model attribution renderAllModules() depends on.
483
+ this.previousHcl = HclUtility.serialize(terraformService.renderAllModules());
484
+ const inputService = await this.container.get(InputService);
485
+ if (filterByModuleIds.length > 0) {
486
+ const isFromModule = (node) => {
487
+ if (node instanceof AResource) {
488
+ return filterByModuleIds.includes(inputService.getModuleIdFromResource(node));
489
+ }
490
+ else if (node instanceof AOverlay) {
491
+ return filterByModuleIds.includes(inputService.getModuleIdFromOverlay(node));
492
+ }
493
+ else if (node instanceof AModel) {
494
+ return filterByModuleIds.includes(inputService.getModuleIdFromModel(node));
495
+ }
496
+ return false;
497
+ };
498
+ const keep = (diffs) => diffs.map((i) => i.filter((j) => isFromModule(j.node))).filter((i) => i.length);
499
+ response.modelDiffs = keep(response.modelDiffs);
500
+ response.modelTransaction = keep(response.modelTransaction);
501
+ response.resourceDiffs = keep(response.resourceDiffs);
502
+ if (!skipResourceTransaction) {
503
+ response.resourceTransaction = keep(response.resourceTransaction);
504
+ }
505
+ }
506
+ await this.reset();
507
+ return response;
324
508
  }
325
509
  }
326
510
  //# sourceMappingURL=test-module.container.js.map