@quadnix/octo 0.0.30 → 0.1.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 (362) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +25 -3
  3. package/dist/app.type.d.ts +143 -4
  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 +1 -1
  18. package/dist/decorators/model.decorator.js +1 -1
  19. package/dist/decorators/module.decorator.d.ts +16 -10
  20. package/dist/decorators/module.decorator.js +16 -10
  21. package/dist/decorators/module.decorator.js.map +1 -1
  22. package/dist/decorators/on-event.decorator.d.ts +5 -0
  23. package/dist/decorators/on-event.decorator.js +5 -0
  24. package/dist/decorators/on-event.decorator.js.map +1 -1
  25. package/dist/decorators/validate.decorator.d.ts +15 -1
  26. package/dist/decorators/validate.decorator.js +15 -1
  27. package/dist/decorators/validate.decorator.js.map +1 -1
  28. package/dist/errors/container.error.d.ts +18 -0
  29. package/dist/errors/container.error.js +18 -0
  30. package/dist/errors/container.error.js.map +1 -1
  31. package/dist/errors/index.d.ts +1 -0
  32. package/dist/errors/index.js +1 -0
  33. package/dist/errors/index.js.map +1 -1
  34. package/dist/errors/module.error.d.ts +6 -0
  35. package/dist/errors/module.error.js +6 -0
  36. package/dist/errors/module.error.js.map +1 -1
  37. package/dist/errors/node.error.d.ts +56 -0
  38. package/dist/errors/node.error.js +56 -0
  39. package/dist/errors/node.error.js.map +1 -1
  40. package/dist/errors/schema.error.d.ts +6 -0
  41. package/dist/errors/schema.error.js +6 -0
  42. package/dist/errors/schema.error.js.map +1 -1
  43. package/dist/errors/terraform.error.d.ts +19 -0
  44. package/dist/errors/terraform.error.js +23 -0
  45. package/dist/errors/terraform.error.js.map +1 -0
  46. package/dist/errors/transaction.error.d.ts +61 -0
  47. package/dist/errors/transaction.error.js +61 -0
  48. package/dist/errors/transaction.error.js.map +1 -1
  49. package/dist/events/action.event.d.ts +0 -2
  50. package/dist/events/action.event.js +0 -2
  51. package/dist/events/action.event.js.map +1 -1
  52. package/dist/events/event.model.d.ts +21 -5
  53. package/dist/events/event.model.js +11 -5
  54. package/dist/events/event.model.js.map +1 -1
  55. package/dist/events/hook/commit.hook.event.d.ts +0 -6
  56. package/dist/events/hook/commit.hook.event.js +0 -6
  57. package/dist/events/hook/commit.hook.event.js.map +1 -1
  58. package/dist/events/hook/hook.event.d.ts +0 -2
  59. package/dist/events/hook/hook.event.js +0 -2
  60. package/dist/events/hook/hook.event.js.map +1 -1
  61. package/dist/events/hook/model.hook.event.d.ts +0 -6
  62. package/dist/events/hook/model.hook.event.js +0 -6
  63. package/dist/events/hook/model.hook.event.js.map +1 -1
  64. package/dist/events/hook/resource.hook.event.d.ts +0 -6
  65. package/dist/events/hook/resource.hook.event.js +0 -6
  66. package/dist/events/hook/resource.hook.event.js.map +1 -1
  67. package/dist/events/index.d.ts +3 -0
  68. package/dist/events/index.js +3 -0
  69. package/dist/events/index.js.map +1 -1
  70. package/dist/events/mode-result.event.d.ts +57 -0
  71. package/dist/events/mode-result.event.js +24 -0
  72. package/dist/events/mode-result.event.js.map +1 -0
  73. package/dist/events/mode.event.d.ts +57 -0
  74. package/dist/events/mode.event.js +32 -0
  75. package/dist/events/mode.event.js.map +1 -0
  76. package/dist/events/module.event.d.ts +0 -2
  77. package/dist/events/module.event.js +0 -2
  78. package/dist/events/module.event.js.map +1 -1
  79. package/dist/events/registration.event.d.ts +18 -14
  80. package/dist/events/registration.event.js +18 -14
  81. package/dist/events/registration.event.js.map +1 -1
  82. package/dist/events/serialization.event.d.ts +15 -12
  83. package/dist/events/serialization.event.js +15 -12
  84. package/dist/events/serialization.event.js.map +1 -1
  85. package/dist/events/terraform.event.d.ts +42 -0
  86. package/dist/events/terraform.event.js +31 -0
  87. package/dist/events/terraform.event.js.map +1 -0
  88. package/dist/events/transaction.event.d.ts +0 -37
  89. package/dist/events/transaction.event.js +0 -28
  90. package/dist/events/transaction.event.js.map +1 -1
  91. package/dist/functions/container/container.d.ts +54 -13
  92. package/dist/functions/container/container.js +63 -18
  93. package/dist/functions/container/container.js.map +1 -1
  94. package/dist/functions/container/test-container.d.ts +43 -29
  95. package/dist/functions/container/test-container.js +71 -43
  96. package/dist/functions/container/test-container.js.map +1 -1
  97. package/dist/functions/dependency/dependency.d.ts +82 -8
  98. package/dist/functions/dependency/dependency.js +80 -14
  99. package/dist/functions/dependency/dependency.js.map +1 -1
  100. package/dist/functions/diff/aggregate-resource-actions.d.ts +19 -0
  101. package/dist/functions/diff/aggregate-resource-actions.js +41 -0
  102. package/dist/functions/diff/aggregate-resource-actions.js.map +1 -0
  103. package/dist/functions/diff/diff-metadata.d.ts +21 -3
  104. package/dist/functions/diff/diff-metadata.js +18 -0
  105. package/dist/functions/diff/diff-metadata.js.map +1 -1
  106. package/dist/functions/diff/diff.d.ts +55 -1
  107. package/dist/functions/diff/diff.js +44 -3
  108. package/dist/functions/diff/diff.js.map +1 -1
  109. package/dist/functions/diff/diff.utility.d.ts +17 -2
  110. package/dist/functions/diff/diff.utility.js +53 -38
  111. package/dist/functions/diff/diff.utility.js.map +1 -1
  112. package/dist/functions/hook/commit.hook.d.ts +16 -1
  113. package/dist/functions/hook/commit.hook.js +21 -6
  114. package/dist/functions/hook/commit.hook.js.map +1 -1
  115. package/dist/functions/hook/model-action.hook.d.ts +16 -1
  116. package/dist/functions/hook/model-action.hook.js +21 -6
  117. package/dist/functions/hook/model-action.hook.js.map +1 -1
  118. package/dist/functions/hook/resource-action.hook.d.ts +16 -1
  119. package/dist/functions/hook/resource-action.hook.js +21 -6
  120. package/dist/functions/hook/resource-action.hook.js.map +1 -1
  121. package/dist/functions/node/node-action.abstract.d.ts +23 -0
  122. package/dist/functions/node/node-action.abstract.js +20 -0
  123. package/dist/functions/node/node-action.abstract.js.map +1 -1
  124. package/dist/functions/node/node.abstract.d.ts +56 -5
  125. package/dist/functions/node/node.abstract.js +85 -12
  126. package/dist/functions/node/node.abstract.js.map +1 -1
  127. package/dist/functions/node/node.interface.d.ts +1 -0
  128. package/dist/functions/schema/schema.d.ts +7 -0
  129. package/dist/functions/schema/schema.js +9 -0
  130. package/dist/functions/schema/schema.js.map +1 -1
  131. package/dist/index.d.ts +5 -1
  132. package/dist/index.js +4 -1
  133. package/dist/index.js.map +1 -1
  134. package/dist/main.d.ts +244 -14
  135. package/dist/main.js +361 -72
  136. package/dist/main.js.map +1 -1
  137. package/dist/models/account/account.model.d.ts +37 -7
  138. package/dist/models/account/account.model.js +40 -8
  139. package/dist/models/account/account.model.js.map +1 -1
  140. package/dist/models/account/account.schema.d.ts +13 -1
  141. package/dist/models/account/account.schema.js +12 -0
  142. package/dist/models/account/account.schema.js.map +1 -1
  143. package/dist/models/app/app.model.d.ts +16 -1
  144. package/dist/models/app/app.model.js +19 -4
  145. package/dist/models/app/app.model.js.map +1 -1
  146. package/dist/models/app/app.schema.d.ts +6 -0
  147. package/dist/models/app/app.schema.js +6 -0
  148. package/dist/models/app/app.schema.js.map +1 -1
  149. package/dist/models/deployment/deployment.model.d.ts +13 -1
  150. package/dist/models/deployment/deployment.model.js +16 -4
  151. package/dist/models/deployment/deployment.model.js.map +1 -1
  152. package/dist/models/deployment/deployment.schema.d.ts +2 -0
  153. package/dist/models/deployment/deployment.schema.js +2 -0
  154. package/dist/models/deployment/deployment.schema.js.map +1 -1
  155. package/dist/models/environment/environment.model.d.ts +13 -1
  156. package/dist/models/environment/environment.model.js +20 -8
  157. package/dist/models/environment/environment.model.js.map +1 -1
  158. package/dist/models/environment/environment.schema.d.ts +2 -0
  159. package/dist/models/environment/environment.schema.js +2 -0
  160. package/dist/models/environment/environment.schema.js.map +1 -1
  161. package/dist/models/execution/execution.model.d.ts +20 -2
  162. package/dist/models/execution/execution.model.js +46 -28
  163. package/dist/models/execution/execution.model.js.map +1 -1
  164. package/dist/models/execution/execution.schema.d.ts +11 -0
  165. package/dist/models/execution/execution.schema.js +11 -0
  166. package/dist/models/execution/execution.schema.js.map +1 -1
  167. package/dist/models/filesystem/filesystem.model.d.ts +27 -1
  168. package/dist/models/filesystem/filesystem.model.js +30 -4
  169. package/dist/models/filesystem/filesystem.model.js.map +1 -1
  170. package/dist/models/filesystem/filesystem.schema.d.ts +5 -0
  171. package/dist/models/filesystem/filesystem.schema.js +5 -0
  172. package/dist/models/filesystem/filesystem.schema.js.map +1 -1
  173. package/dist/models/image/image.model.d.ts +17 -4
  174. package/dist/models/image/image.model.js +20 -7
  175. package/dist/models/image/image.model.js.map +1 -1
  176. package/dist/models/image/image.schema.d.ts +8 -0
  177. package/dist/models/image/image.schema.js +8 -0
  178. package/dist/models/image/image.schema.js.map +1 -1
  179. package/dist/models/model-action.interface.d.ts +17 -4
  180. package/dist/models/model.abstract.d.ts +96 -1
  181. package/dist/models/model.abstract.js +106 -7
  182. package/dist/models/model.abstract.js.map +1 -1
  183. package/dist/models/model.interface.d.ts +3 -0
  184. package/dist/models/pipeline/pipeline.model.d.ts +13 -1
  185. package/dist/models/pipeline/pipeline.model.js +18 -6
  186. package/dist/models/pipeline/pipeline.model.js.map +1 -1
  187. package/dist/models/pipeline/pipeline.schema.d.ts +8 -0
  188. package/dist/models/pipeline/pipeline.schema.js +8 -0
  189. package/dist/models/pipeline/pipeline.schema.js.map +1 -1
  190. package/dist/models/region/region.model.d.ts +16 -1
  191. package/dist/models/region/region.model.js +19 -4
  192. package/dist/models/region/region.model.js.map +1 -1
  193. package/dist/models/region/region.schema.d.ts +6 -0
  194. package/dist/models/region/region.schema.js +6 -0
  195. package/dist/models/region/region.schema.js.map +1 -1
  196. package/dist/models/server/server.model.d.ts +13 -1
  197. package/dist/models/server/server.model.js +16 -4
  198. package/dist/models/server/server.model.js.map +1 -1
  199. package/dist/models/server/server.schema.d.ts +3 -1
  200. package/dist/models/server/server.schema.js +3 -1
  201. package/dist/models/server/server.schema.js.map +1 -1
  202. package/dist/models/service/service.model.d.ts +15 -1
  203. package/dist/models/service/service.model.js +15 -1
  204. package/dist/models/service/service.model.js.map +1 -1
  205. package/dist/models/service/service.schema.d.ts +4 -1
  206. package/dist/models/service/service.schema.js +4 -1
  207. package/dist/models/service/service.schema.js.map +1 -1
  208. package/dist/models/subnet/subnet.model.d.ts +27 -3
  209. package/dist/models/subnet/subnet.model.js +40 -16
  210. package/dist/models/subnet/subnet.model.js.map +1 -1
  211. package/dist/models/subnet/subnet.schema.d.ts +9 -0
  212. package/dist/models/subnet/subnet.schema.js +9 -0
  213. package/dist/models/subnet/subnet.schema.js.map +1 -1
  214. package/dist/modes/apply-transaction.d.ts +23 -0
  215. package/dist/modes/apply-transaction.js +25 -0
  216. package/dist/modes/apply-transaction.js.map +1 -0
  217. package/dist/modes/commit.mode.d.ts +54 -0
  218. package/dist/modes/commit.mode.js +235 -0
  219. package/dist/modes/commit.mode.js.map +1 -0
  220. package/dist/modes/generate.mode.d.ts +29 -0
  221. package/dist/modes/generate.mode.js +49 -0
  222. package/dist/modes/generate.mode.js.map +1 -0
  223. package/dist/modes/run-action.mode.d.ts +30 -0
  224. package/dist/modes/run-action.mode.js +140 -0
  225. package/dist/modes/run-action.mode.js.map +1 -0
  226. package/dist/modes/validate.mode.d.ts +162 -0
  227. package/dist/modes/validate.mode.js +480 -0
  228. package/dist/modes/validate.mode.js.map +1 -0
  229. package/dist/modules/module.abstract.d.ts +51 -0
  230. package/dist/modules/module.abstract.js +36 -0
  231. package/dist/modules/module.abstract.js.map +1 -1
  232. package/dist/modules/module.container.d.ts +36 -0
  233. package/dist/modules/module.container.js +36 -0
  234. package/dist/modules/module.container.js.map +1 -1
  235. package/dist/modules/test-module.container.d.ts +139 -25
  236. package/dist/modules/test-module.container.js +410 -178
  237. package/dist/modules/test-module.container.js.map +1 -1
  238. package/dist/overlays/anchor.abstract.d.ts +32 -1
  239. package/dist/overlays/anchor.abstract.js +42 -11
  240. package/dist/overlays/anchor.abstract.js.map +1 -1
  241. package/dist/overlays/anchor.schema.d.ts +21 -0
  242. package/dist/overlays/anchor.schema.js +21 -0
  243. package/dist/overlays/anchor.schema.js.map +1 -1
  244. package/dist/overlays/overlay-data.repository.d.ts +18 -0
  245. package/dist/overlays/overlay-data.repository.js +18 -0
  246. package/dist/overlays/overlay-data.repository.js.map +1 -1
  247. package/dist/overlays/overlay.abstract.d.ts +56 -1
  248. package/dist/overlays/overlay.abstract.js +79 -20
  249. package/dist/overlays/overlay.abstract.js.map +1 -1
  250. package/dist/overlays/overlay.schema.d.ts +20 -0
  251. package/dist/overlays/overlay.schema.js +20 -0
  252. package/dist/overlays/overlay.schema.js.map +1 -1
  253. package/dist/resources/resource-action.interface.d.ts +26 -2
  254. package/dist/resources/resource-data.repository.d.ts +63 -1
  255. package/dist/resources/resource-data.repository.js +94 -4
  256. package/dist/resources/resource-data.repository.js.map +1 -1
  257. package/dist/resources/resource.abstract.d.ts +118 -3
  258. package/dist/resources/resource.abstract.js +166 -33
  259. package/dist/resources/resource.abstract.js.map +1 -1
  260. package/dist/resources/resource.schema.d.ts +29 -1
  261. package/dist/resources/resource.schema.js +28 -0
  262. package/dist/resources/resource.schema.js.map +1 -1
  263. package/dist/resources/terraform-resource.abstract.d.ts +44 -0
  264. package/dist/resources/terraform-resource.abstract.js +45 -0
  265. package/dist/resources/terraform-resource.abstract.js.map +1 -0
  266. package/dist/services/event/event.service.d.ts +30 -3
  267. package/dist/services/event/event.service.js +58 -16
  268. package/dist/services/event/event.service.js.map +1 -1
  269. package/dist/services/input/input.service.d.ts +52 -3
  270. package/dist/services/input/input.service.js +72 -8
  271. package/dist/services/input/input.service.js.map +1 -1
  272. package/dist/services/schema-translation/schema-translation.service.d.ts +9 -0
  273. package/dist/services/schema-translation/schema-translation.service.js +9 -0
  274. package/dist/services/schema-translation/schema-translation.service.js.map +1 -1
  275. package/dist/services/serialization/model/model-serialization.service.d.ts +26 -2
  276. package/dist/services/serialization/model/model-serialization.service.js +110 -62
  277. package/dist/services/serialization/model/model-serialization.service.js.map +1 -1
  278. package/dist/services/serialization/resource/resource-serialization.service.d.ts +33 -4
  279. package/dist/services/serialization/resource/resource-serialization.service.js +64 -28
  280. package/dist/services/serialization/resource/resource-serialization.service.js.map +1 -1
  281. package/dist/services/state-management/file-app-lock.utility.d.ts +43 -0
  282. package/dist/services/state-management/file-app-lock.utility.js +124 -0
  283. package/dist/services/state-management/file-app-lock.utility.js.map +1 -0
  284. package/dist/services/state-management/local-encryption.state-provider.d.ts +53 -2
  285. package/dist/services/state-management/local-encryption.state-provider.js +75 -49
  286. package/dist/services/state-management/local-encryption.state-provider.js.map +1 -1
  287. package/dist/services/state-management/local.state-provider.d.ts +49 -2
  288. package/dist/services/state-management/local.state-provider.js +70 -49
  289. package/dist/services/state-management/local.state-provider.js.map +1 -1
  290. package/dist/services/state-management/state-management.service.d.ts +141 -6
  291. package/dist/services/state-management/state-management.service.js +149 -4
  292. package/dist/services/state-management/state-management.service.js.map +1 -1
  293. package/dist/services/state-management/state-provider.interface.d.ts +55 -1
  294. package/dist/services/state-management/terraform-state.service.d.ts +76 -0
  295. package/dist/services/state-management/terraform-state.service.js +154 -0
  296. package/dist/services/state-management/terraform-state.service.js.map +1 -0
  297. package/dist/services/state-management/test.state-provider.d.ts +38 -1
  298. package/dist/services/state-management/test.state-provider.js +52 -21
  299. package/dist/services/state-management/test.state-provider.js.map +1 -1
  300. package/dist/services/terraform/terraform.service.d.ts +426 -0
  301. package/dist/services/terraform/terraform.service.js +995 -0
  302. package/dist/services/terraform/terraform.service.js.map +1 -0
  303. package/dist/services/terraform/terraform.type.d.ts +387 -0
  304. package/dist/services/terraform/terraform.type.js +579 -0
  305. package/dist/services/terraform/terraform.type.js.map +1 -0
  306. package/dist/services/transaction/transaction.service.d.ts +86 -10
  307. package/dist/services/transaction/transaction.service.js +387 -232
  308. package/dist/services/transaction/transaction.service.js.map +1 -1
  309. package/dist/services/validation/validation.service.d.ts +13 -1
  310. package/dist/services/validation/validation.service.js +12 -0
  311. package/dist/services/validation/validation.service.js.map +1 -1
  312. package/dist/utilities/array/array.utility.d.ts +3 -0
  313. package/dist/utilities/array/array.utility.js +3 -0
  314. package/dist/utilities/array/array.utility.js.map +1 -1
  315. package/dist/utilities/file/file.utility.d.ts +15 -0
  316. package/dist/utilities/file/file.utility.js +18 -1
  317. package/dist/utilities/file/file.utility.js.map +1 -1
  318. package/dist/utilities/hcl/hcl.utility.d.ts +61 -0
  319. package/dist/utilities/hcl/hcl.utility.js +229 -0
  320. package/dist/utilities/hcl/hcl.utility.js.map +1 -0
  321. package/dist/utilities/node/node.utility.d.ts +3 -0
  322. package/dist/utilities/node/node.utility.js +3 -0
  323. package/dist/utilities/node/node.utility.js.map +1 -1
  324. package/dist/utilities/object/object.utility.d.ts +12 -0
  325. package/dist/utilities/object/object.utility.js +12 -0
  326. package/dist/utilities/object/object.utility.js.map +1 -1
  327. package/dist/utilities/project/project.utility.d.ts +28 -0
  328. package/dist/utilities/project/project.utility.js +35 -0
  329. package/dist/utilities/project/project.utility.js.map +1 -0
  330. package/dist/utilities/string/string.utility.d.ts +21 -0
  331. package/dist/utilities/string/string.utility.js +39 -0
  332. package/dist/utilities/string/string.utility.js.map +1 -0
  333. package/dist/utilities/terraform/terraform.utility.d.ts +227 -0
  334. package/dist/utilities/terraform/terraform.utility.js +434 -0
  335. package/dist/utilities/terraform/terraform.utility.js.map +1 -0
  336. package/dist/utilities/test-helpers/test-classes.d.ts +18 -31
  337. package/dist/utilities/test-helpers/test-classes.js +18 -41
  338. package/dist/utilities/test-helpers/test-classes.js.map +1 -1
  339. package/dist/utilities/test-helpers/test-models.js +12 -0
  340. package/dist/utilities/test-helpers/test-models.js.map +1 -1
  341. package/dist/utilities/test-helpers/test-modes.d.ts +315 -0
  342. package/dist/utilities/test-helpers/test-modes.js +463 -0
  343. package/dist/utilities/test-helpers/test-modes.js.map +1 -0
  344. package/dist/utilities/test-helpers/test-modules.d.ts +41 -0
  345. package/dist/utilities/test-helpers/test-modules.js +79 -0
  346. package/dist/utilities/test-helpers/test-modules.js.map +1 -0
  347. package/dist/utilities/test-helpers/test-overlays.d.ts +17 -1
  348. package/dist/utilities/test-helpers/test-overlays.js +49 -5
  349. package/dist/utilities/test-helpers/test-overlays.js.map +1 -1
  350. package/dist/utilities/test-helpers/test-resources.d.ts +19 -1
  351. package/dist/utilities/test-helpers/test-resources.js +61 -3
  352. package/dist/utilities/test-helpers/test-resources.js.map +1 -1
  353. package/dist/utilities/validation/validation.utility.d.ts +24 -0
  354. package/dist/utilities/validation/validation.utility.js +24 -0
  355. package/dist/utilities/validation/validation.utility.js.map +1 -1
  356. package/package.json +6 -5
  357. package/dist/services/capture/capture.service.d.ts +0 -19
  358. package/dist/services/capture/capture.service.js +0 -43
  359. package/dist/services/capture/capture.service.js.map +0 -1
  360. package/dist/utilities/cidr/cidr.utility.d.ts +0 -10
  361. package/dist/utilities/cidr/cidr.utility.js +0 -51
  362. package/dist/utilities/cidr/cidr.utility.js.map +0 -1
@@ -0,0 +1,124 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { readFile, rm, writeFile } from 'node:fs/promises';
3
+ import { TransactionError } from '../../errors/index.js';
4
+ /**
5
+ * The app lock, kept as a file on disk. Shared by the state providers that keep state in a directory.
6
+ *
7
+ * The lock is taken with an exclusive create, which the filesystem resolves atomically: of two
8
+ * processes racing for the same path, exactly one succeeds. Reading first and writing second would
9
+ * let both believe they hold it.
10
+ *
11
+ * The lock never expires, so a run that died holding one leaves it held until a person releases it
12
+ * with `octo unlock --force`. That decision turns on whether the holder is still working, so the
13
+ * record carries the time it was taken and a blocked run is told how long it has been held.
14
+ *
15
+ * @internal
16
+ */
17
+ export class FileAppLockUtility {
18
+ /**
19
+ * @internal
20
+ */
21
+ static async getAppLock(lockFilePath) {
22
+ return (await this.readLock(lockFilePath))?.lockId;
23
+ }
24
+ /**
25
+ * @internal
26
+ */
27
+ static async isAppLocked(lockFilePath, lockId) {
28
+ const existingLockId = await this.getAppLock(lockFilePath);
29
+ if (!existingLockId) {
30
+ return false;
31
+ }
32
+ if (existingLockId !== lockId) {
33
+ throw new TransactionError('Invalid lock ID!');
34
+ }
35
+ return true;
36
+ }
37
+ /**
38
+ * @internal
39
+ */
40
+ static async lockApp(lockFilePath) {
41
+ const lockId = randomUUID();
42
+ const record = { lockId, startedAt: new Date().toISOString() };
43
+ try {
44
+ await writeFile(lockFilePath, JSON.stringify(record), { flag: 'wx' });
45
+ }
46
+ catch (error) {
47
+ if (error.code === 'EEXIST') {
48
+ // The holder is read back and reported, so a blocked run can be told what to break without a
49
+ // separate command to ask, and how long it has been held without one either.
50
+ const holder = await this.readLock(lockFilePath);
51
+ const heldFor = holder?.startedAt ? this.describeAge(holder.startedAt) : undefined;
52
+ throw new TransactionError(`App already locked with lock ID "${holder?.lockId}"${heldFor ? `, held for ${heldFor}` : ''}!`);
53
+ }
54
+ throw error;
55
+ }
56
+ return { lockId };
57
+ }
58
+ /**
59
+ * @internal
60
+ */
61
+ static async unlockApp(lockFilePath, lockId) {
62
+ const existingLockId = await this.getAppLock(lockFilePath);
63
+ if (!existingLockId) {
64
+ return;
65
+ }
66
+ if (existingLockId !== lockId) {
67
+ throw new TransactionError('Invalid lock ID!');
68
+ }
69
+ await rm(lockFilePath, { force: true });
70
+ }
71
+ /**
72
+ * How long the lock has been held, as a short readable span. Undefined when the recorded time
73
+ * cannot be read as one, so a broken value is left out rather than reported as a negative age.
74
+ */
75
+ static describeAge(startedAt) {
76
+ const heldForMs = Date.now() - Date.parse(startedAt);
77
+ if (!Number.isFinite(heldForMs) || heldForMs < 0) {
78
+ return undefined;
79
+ }
80
+ const seconds = Math.floor(heldForMs / 1000);
81
+ if (seconds < 60) {
82
+ return `${seconds}s`;
83
+ }
84
+ const minutes = Math.floor(seconds / 60);
85
+ if (minutes < 60) {
86
+ return `${minutes}m`;
87
+ }
88
+ const hours = Math.floor(minutes / 60);
89
+ if (hours < 24) {
90
+ return `${hours}h ${minutes % 60}m`;
91
+ }
92
+ return `${Math.floor(hours / 24)}d ${hours % 24}h`;
93
+ }
94
+ /**
95
+ * The lock file's record, or undefined when no lock is held. A file holding an id and nothing else
96
+ * is a lock taken before the record carried a time, and reads as that id with no age.
97
+ */
98
+ static async readLock(lockFilePath) {
99
+ let contents;
100
+ try {
101
+ contents = (await readFile(lockFilePath, 'utf-8')).trim();
102
+ }
103
+ catch (error) {
104
+ if (error.code === 'ENOENT') {
105
+ return undefined;
106
+ }
107
+ throw error;
108
+ }
109
+ if (!contents) {
110
+ return undefined;
111
+ }
112
+ if (!contents.startsWith('{')) {
113
+ return { lockId: contents };
114
+ }
115
+ try {
116
+ const record = JSON.parse(contents);
117
+ return typeof record.lockId === 'string' ? record : { lockId: contents };
118
+ }
119
+ catch (error) {
120
+ return { lockId: contents };
121
+ }
122
+ }
123
+ }
124
+ //# sourceMappingURL=file-app-lock.utility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-app-lock.utility.js","sourceRoot":"","sources":["../../../src/services/state-management/file-app-lock.utility.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,71 @@
1
1
  import type { IStateProvider } from './state-provider.interface.js';
2
2
  /**
3
+ * Keeps state in a local directory, encrypted, with an `.enc` suffix.
4
+ *
5
+ * The point is that the resulting files are safe to commit to version control, which gives a small
6
+ * team shared state without any infrastructure to run.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * await octo.initialize(new LocalEncryptionStateProvider('./infrastructure', process.env.OCTO_KEY!));
11
+ * ```
12
+ *
3
13
  * @group Services/State Management
14
+ *
15
+ * @see Techniques for [State Providers](/docs/techniques/state-providers).
4
16
  */
5
17
  export declare class LocalEncryptionStateProvider implements IStateProvider {
6
18
  private readonly encryptionKey;
7
19
  private readonly localStateDirectoryPath;
8
20
  private readonly lockFilePath;
21
+ /**
22
+ * @param localStateDirectoryPath The directory state files are written into.
23
+ * @param encryptionKey The key state is encrypted with. It must be at least 3 characters.
24
+ * @throws {@link TransactionError} If the key is too weak.
25
+ */
9
26
  constructor(localStateDirectoryPath: string, encryptionKey: string);
10
- private addOrUpdateAppLock;
27
+ /**
28
+ * Deletes a state file. Deleting one that is not there is not an error.
29
+ */
30
+ deleteState(stateFileName: string): Promise<void>;
31
+ /**
32
+ * The id of the lock currently held, or `undefined` when the app is unlocked. The lock file is not
33
+ * encrypted - a lock id identifies a run, and reveals nothing about the state it guards.
34
+ */
11
35
  getAppLock(): Promise<string | undefined>;
36
+ /**
37
+ * Reads a state file.
38
+ *
39
+ * @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
40
+ */
12
41
  getState(stateFileName: string): Promise<Buffer>;
42
+ /**
43
+ * Whether `lockId` is the lock currently held.
44
+ *
45
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
46
+ */
13
47
  isAppLocked(lockId: string): Promise<boolean>;
48
+ /**
49
+ * The names of the state files whose name starts with `prefix`, with the `.enc` suffix removed so
50
+ * a caller can read them back by the name it knows.
51
+ */
52
+ listStates(prefix: string): Promise<string[]>;
53
+ /**
54
+ * Takes the app lock, writing its id into `local-state.lock` beside the state files.
55
+ *
56
+ * @throws {@link TransactionError} When a lock is held, naming the id that holds it.
57
+ */
14
58
  lockApp(): Promise<{
15
59
  lockId: string;
16
60
  }>;
61
+ /**
62
+ * Writes a state file, overwriting whatever was there.
63
+ */
17
64
  saveState(stateFileName: string, data: Buffer): Promise<void>;
65
+ /**
66
+ * Releases the app lock by deleting the lock file.
67
+ *
68
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
69
+ */
18
70
  unlockApp(lockId: string): Promise<void>;
19
- updateAppLockTransaction(lockId: string): Promise<void>;
20
71
  }
@@ -1,40 +1,55 @@
1
- import { readFile, writeFile } from 'fs/promises';
1
+ import { readdir, rm } from 'fs/promises';
2
2
  import { join, resolve } from 'path';
3
3
  import { TransactionError } from '../../errors/index.js';
4
4
  import { FileUtility } from '../../utilities/file/file.utility.js';
5
+ import { FileAppLockUtility } from './file-app-lock.utility.js';
5
6
  /**
7
+ * Keeps state in a local directory, encrypted, with an `.enc` suffix.
8
+ *
9
+ * The point is that the resulting files are safe to commit to version control, which gives a small
10
+ * team shared state without any infrastructure to run.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * await octo.initialize(new LocalEncryptionStateProvider('./infrastructure', process.env.OCTO_KEY!));
15
+ * ```
16
+ *
6
17
  * @group Services/State Management
18
+ *
19
+ * @see Techniques for [State Providers](/docs/techniques/state-providers).
7
20
  */
8
21
  export class LocalEncryptionStateProvider {
22
+ /**
23
+ * @param localStateDirectoryPath The directory state files are written into.
24
+ * @param encryptionKey The key state is encrypted with. It must be at least 3 characters.
25
+ * @throws {@link TransactionError} If the key is too weak.
26
+ */
9
27
  constructor(localStateDirectoryPath, encryptionKey) {
10
28
  if (encryptionKey.length < 3) {
11
29
  throw new TransactionError('Selected encryption key is too weak!');
12
30
  }
13
31
  this.encryptionKey = encryptionKey;
14
32
  this.localStateDirectoryPath = resolve(localStateDirectoryPath);
15
- this.lockFilePath = resolve(join(localStateDirectoryPath, 'local-state.lock'));
33
+ this.lockFilePath = join(this.localStateDirectoryPath, 'local-state.lock');
16
34
  }
17
- async addOrUpdateAppLock(lockId) {
18
- await writeFile(this.lockFilePath, lockId);
35
+ /**
36
+ * Deletes a state file. Deleting one that is not there is not an error.
37
+ */
38
+ async deleteState(stateFileName) {
39
+ await rm(join(this.localStateDirectoryPath, stateFileName + '.enc'), { force: true });
19
40
  }
41
+ /**
42
+ * The id of the lock currently held, or `undefined` when the app is unlocked. The lock file is not
43
+ * encrypted - a lock id identifies a run, and reveals nothing about the state it guards.
44
+ */
20
45
  async getAppLock() {
21
- try {
22
- const contents = await readFile(this.lockFilePath, 'utf-8');
23
- const appLock = contents.replace(/\s/g, '');
24
- if (!appLock) {
25
- return undefined;
26
- }
27
- return appLock;
28
- }
29
- catch (error) {
30
- if (error.code === 'ENOENT') {
31
- return undefined;
32
- }
33
- else {
34
- throw error;
35
- }
36
- }
46
+ return FileAppLockUtility.getAppLock(this.lockFilePath);
37
47
  }
48
+ /**
49
+ * Reads a state file.
50
+ *
51
+ * @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
52
+ */
38
53
  async getState(stateFileName) {
39
54
  try {
40
55
  return await FileUtility.decryptFileToBuffer(join(this.localStateDirectoryPath, stateFileName + '.enc'), this.encryptionKey);
@@ -46,45 +61,56 @@ export class LocalEncryptionStateProvider {
46
61
  throw error;
47
62
  }
48
63
  }
64
+ /**
65
+ * Whether `lockId` is the lock currently held.
66
+ *
67
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
68
+ */
49
69
  async isAppLocked(lockId) {
50
- const existingLockId = await this.getAppLock();
51
- if (!existingLockId) {
52
- return false;
53
- }
54
- if (lockId !== existingLockId) {
55
- throw new TransactionError('Invalid lock ID!');
70
+ return FileAppLockUtility.isAppLocked(this.lockFilePath, lockId);
71
+ }
72
+ /**
73
+ * The names of the state files whose name starts with `prefix`, with the `.enc` suffix removed so
74
+ * a caller can read them back by the name it knows.
75
+ */
76
+ async listStates(prefix) {
77
+ let entries;
78
+ try {
79
+ entries = await readdir(this.localStateDirectoryPath);
56
80
  }
57
- else {
58
- return true;
81
+ catch (error) {
82
+ if (error.code === 'ENOENT') {
83
+ return [];
84
+ }
85
+ throw error;
59
86
  }
87
+ return entries
88
+ .filter((entry) => entry.endsWith('.enc') && entry.startsWith(prefix))
89
+ .map((entry) => entry.slice(0, -'.enc'.length));
60
90
  }
91
+ /**
92
+ * Takes the app lock, writing its id into `local-state.lock` beside the state files.
93
+ *
94
+ * @throws {@link TransactionError} When a lock is held, naming the id that holds it.
95
+ */
61
96
  async lockApp() {
62
- const existingLockId = await this.getAppLock();
63
- if (existingLockId) {
64
- throw new TransactionError('App already locked!');
65
- }
66
- const lockId = crypto.randomUUID();
67
- await this.addOrUpdateAppLock(lockId);
68
- return { lockId };
97
+ await FileUtility.ensureDirectory(this.localStateDirectoryPath);
98
+ return FileAppLockUtility.lockApp(this.lockFilePath);
69
99
  }
100
+ /**
101
+ * Writes a state file, overwriting whatever was there.
102
+ */
70
103
  async saveState(stateFileName, data) {
104
+ await FileUtility.ensureDirectory(this.localStateDirectoryPath);
71
105
  await FileUtility.encryptBufferToFile(data, join(this.localStateDirectoryPath, stateFileName + '.enc'), this.encryptionKey);
72
106
  }
107
+ /**
108
+ * Releases the app lock by deleting the lock file.
109
+ *
110
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
111
+ */
73
112
  async unlockApp(lockId) {
74
- const existingLockId = await this.getAppLock();
75
- if (!existingLockId) {
76
- return;
77
- }
78
- if (lockId !== existingLockId) {
79
- throw new TransactionError('Invalid lock ID!');
80
- }
81
- await this.addOrUpdateAppLock('');
82
- }
83
- async updateAppLockTransaction(lockId) {
84
- const isAppLocked = await this.isAppLocked(lockId);
85
- if (!isAppLocked) {
86
- throw new TransactionError('App is unlocked!');
87
- }
113
+ return FileAppLockUtility.unlockApp(this.lockFilePath, lockId);
88
114
  }
89
115
  }
90
116
  //# sourceMappingURL=local-encryption.state-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-encryption.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/local-encryption.state-provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"local-encryption.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/local-encryption.state-provider.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,66 @@
1
1
  import type { IStateProvider } from './state-provider.interface.js';
2
2
  /**
3
+ * Keeps state in a directory on the local filesystem.
4
+ *
5
+ * Good for experimenting on your own machine. It is not shared, so a team running Octo against the
6
+ * same infrastructure needs a provider that persists somewhere they all reach.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * await octo.initialize(new LocalStateProvider('./infrastructure'));
11
+ * ```
12
+ *
3
13
  * @group Services/State Management
14
+ *
15
+ * @see Techniques for [State Providers](/docs/techniques/state-providers).
4
16
  */
5
17
  export declare class LocalStateProvider implements IStateProvider {
6
18
  private readonly localStateDirectoryPath;
7
19
  private readonly lockFilePath;
20
+ /**
21
+ * @param localStateDirectoryPath The directory state files are written into.
22
+ */
8
23
  constructor(localStateDirectoryPath: string);
9
- private addOrUpdateAppLock;
24
+ /**
25
+ * Deletes a state file. Deleting one that is not there is not an error.
26
+ */
27
+ deleteState(stateFileName: string): Promise<void>;
28
+ /**
29
+ * The id of the lock currently held, or `undefined` when the app is unlocked.
30
+ */
10
31
  getAppLock(): Promise<string | undefined>;
32
+ /**
33
+ * Reads a state file.
34
+ *
35
+ * @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
36
+ */
11
37
  getState(stateFileName: string): Promise<Buffer>;
38
+ /**
39
+ * Whether `lockId` is the lock currently held.
40
+ *
41
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
42
+ */
12
43
  isAppLocked(lockId: string): Promise<boolean>;
44
+ /**
45
+ * The names of the state files whose name starts with `prefix`.
46
+ */
47
+ listStates(prefix: string): Promise<string[]>;
48
+ /**
49
+ * Takes the app lock, writing its id into `local-state.lock` beside the state files.
50
+ *
51
+ * @throws {@link TransactionError} When a lock is held, naming the id that holds it.
52
+ */
13
53
  lockApp(): Promise<{
14
54
  lockId: string;
15
55
  }>;
56
+ /**
57
+ * Writes a state file, overwriting whatever was there.
58
+ */
16
59
  saveState(stateFileName: string, data: Buffer): Promise<void>;
60
+ /**
61
+ * Releases the app lock by deleting the lock file.
62
+ *
63
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
64
+ */
17
65
  unlockApp(lockId: string): Promise<void>;
18
- updateAppLockTransaction(lockId: string): Promise<void>;
19
66
  }
@@ -1,35 +1,48 @@
1
- import { readFile, writeFile } from 'fs/promises';
1
+ import { readFile, readdir, rm, writeFile } from 'fs/promises';
2
2
  import { join, resolve } from 'path';
3
3
  import { TransactionError } from '../../errors/index.js';
4
+ import { FileUtility } from '../../utilities/file/file.utility.js';
5
+ import { FileAppLockUtility } from './file-app-lock.utility.js';
4
6
  /**
7
+ * Keeps state in a directory on the local filesystem.
8
+ *
9
+ * Good for experimenting on your own machine. It is not shared, so a team running Octo against the
10
+ * same infrastructure needs a provider that persists somewhere they all reach.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * await octo.initialize(new LocalStateProvider('./infrastructure'));
15
+ * ```
16
+ *
5
17
  * @group Services/State Management
18
+ *
19
+ * @see Techniques for [State Providers](/docs/techniques/state-providers).
6
20
  */
7
21
  export class LocalStateProvider {
22
+ /**
23
+ * @param localStateDirectoryPath The directory state files are written into.
24
+ */
8
25
  constructor(localStateDirectoryPath) {
9
26
  this.localStateDirectoryPath = resolve(localStateDirectoryPath);
10
- this.lockFilePath = resolve(join(localStateDirectoryPath, 'local-state.lock'));
27
+ this.lockFilePath = join(this.localStateDirectoryPath, 'local-state.lock');
11
28
  }
12
- async addOrUpdateAppLock(lockId) {
13
- await writeFile(this.lockFilePath, lockId);
29
+ /**
30
+ * Deletes a state file. Deleting one that is not there is not an error.
31
+ */
32
+ async deleteState(stateFileName) {
33
+ await rm(join(this.localStateDirectoryPath, stateFileName), { force: true });
14
34
  }
35
+ /**
36
+ * The id of the lock currently held, or `undefined` when the app is unlocked.
37
+ */
15
38
  async getAppLock() {
16
- try {
17
- const contents = await readFile(this.lockFilePath, 'utf-8');
18
- const appLock = contents.replace(/\s/g, '');
19
- if (!appLock) {
20
- return undefined;
21
- }
22
- return appLock;
23
- }
24
- catch (error) {
25
- if (error.code === 'ENOENT') {
26
- return undefined;
27
- }
28
- else {
29
- throw error;
30
- }
31
- }
39
+ return FileAppLockUtility.getAppLock(this.lockFilePath);
32
40
  }
41
+ /**
42
+ * Reads a state file.
43
+ *
44
+ * @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
45
+ */
33
46
  async getState(stateFileName) {
34
47
  try {
35
48
  return await readFile(join(this.localStateDirectoryPath, stateFileName));
@@ -41,45 +54,53 @@ export class LocalStateProvider {
41
54
  throw error;
42
55
  }
43
56
  }
57
+ /**
58
+ * Whether `lockId` is the lock currently held.
59
+ *
60
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
61
+ */
44
62
  async isAppLocked(lockId) {
45
- const existingLockId = await this.getAppLock();
46
- if (!existingLockId) {
47
- return false;
48
- }
49
- if (lockId !== existingLockId) {
50
- throw new TransactionError('Invalid lock ID!');
63
+ return FileAppLockUtility.isAppLocked(this.lockFilePath, lockId);
64
+ }
65
+ /**
66
+ * The names of the state files whose name starts with `prefix`.
67
+ */
68
+ async listStates(prefix) {
69
+ let entries;
70
+ try {
71
+ entries = await readdir(this.localStateDirectoryPath);
51
72
  }
52
- else {
53
- return true;
73
+ catch (error) {
74
+ if (error.code === 'ENOENT') {
75
+ return [];
76
+ }
77
+ throw error;
54
78
  }
79
+ return entries.filter((entry) => entry.startsWith(prefix));
55
80
  }
81
+ /**
82
+ * Takes the app lock, writing its id into `local-state.lock` beside the state files.
83
+ *
84
+ * @throws {@link TransactionError} When a lock is held, naming the id that holds it.
85
+ */
56
86
  async lockApp() {
57
- const existingLockId = await this.getAppLock();
58
- if (existingLockId) {
59
- throw new TransactionError('App already locked!');
60
- }
61
- const lockId = crypto.randomUUID();
62
- await this.addOrUpdateAppLock(lockId);
63
- return { lockId };
87
+ await FileUtility.ensureDirectory(this.localStateDirectoryPath);
88
+ return FileAppLockUtility.lockApp(this.lockFilePath);
64
89
  }
90
+ /**
91
+ * Writes a state file, overwriting whatever was there.
92
+ */
65
93
  async saveState(stateFileName, data) {
94
+ await FileUtility.ensureDirectory(this.localStateDirectoryPath);
66
95
  await writeFile(join(this.localStateDirectoryPath, stateFileName), data);
67
96
  }
97
+ /**
98
+ * Releases the app lock by deleting the lock file.
99
+ *
100
+ * @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
101
+ */
68
102
  async unlockApp(lockId) {
69
- const existingLockId = await this.getAppLock();
70
- if (!existingLockId) {
71
- return;
72
- }
73
- if (lockId !== existingLockId) {
74
- throw new TransactionError('Invalid lock ID!');
75
- }
76
- await this.addOrUpdateAppLock('');
77
- }
78
- async updateAppLockTransaction(lockId) {
79
- const isAppLocked = await this.isAppLocked(lockId);
80
- if (!isAppLocked) {
81
- throw new TransactionError('App is unlocked!');
82
- }
103
+ return FileAppLockUtility.unlockApp(this.lockFilePath, lockId);
83
104
  }
84
105
  }
85
106
  //# sourceMappingURL=local.state-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/local.state-provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"local.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/local.state-provider.ts"],"names":[],"mappings":"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"}