@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.
- package/LICENSE +661 -0
- package/README.md +117 -8
- package/dist/app.type.d.ts +277 -19
- package/dist/app.type.js +80 -9
- package/dist/app.type.js.map +1 -1
- package/dist/decorators/action.decorator.d.ts +10 -6
- package/dist/decorators/action.decorator.js +19 -6
- package/dist/decorators/action.decorator.js.map +1 -1
- package/dist/decorators/anchor.decorator.d.ts +12 -5
- package/dist/decorators/anchor.decorator.js +12 -5
- package/dist/decorators/anchor.decorator.js.map +1 -1
- package/dist/decorators/enable-hook.decorator.d.ts +1 -1
- package/dist/decorators/enable-hook.decorator.js +1 -1
- package/dist/decorators/factory.decorator.d.ts +18 -34
- package/dist/decorators/factory.decorator.js +18 -34
- package/dist/decorators/factory.decorator.js.map +1 -1
- package/dist/decorators/model.decorator.d.ts +4 -6
- package/dist/decorators/model.decorator.js +2 -7
- package/dist/decorators/model.decorator.js.map +1 -1
- package/dist/decorators/module.decorator.d.ts +16 -10
- package/dist/decorators/module.decorator.js +16 -10
- package/dist/decorators/module.decorator.js.map +1 -1
- package/dist/decorators/on-event.decorator.d.ts +7 -2
- package/dist/decorators/on-event.decorator.js +5 -0
- package/dist/decorators/on-event.decorator.js.map +1 -1
- package/dist/decorators/resource.decorator.d.ts +50 -1
- package/dist/decorators/resource.decorator.js +38 -1
- package/dist/decorators/resource.decorator.js.map +1 -1
- package/dist/decorators/validate.decorator.d.ts +15 -1
- package/dist/decorators/validate.decorator.js +15 -1
- package/dist/decorators/validate.decorator.js.map +1 -1
- package/dist/errors/container.error.d.ts +18 -0
- package/dist/errors/container.error.js +18 -0
- package/dist/errors/container.error.js.map +1 -1
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/module.error.d.ts +6 -0
- package/dist/errors/module.error.js +6 -0
- package/dist/errors/module.error.js.map +1 -1
- package/dist/errors/node.error.d.ts +56 -0
- package/dist/errors/node.error.js +56 -0
- package/dist/errors/node.error.js.map +1 -1
- package/dist/errors/schema.error.d.ts +14 -1
- package/dist/errors/schema.error.js +11 -1
- package/dist/errors/schema.error.js.map +1 -1
- package/dist/errors/terraform.error.d.ts +20 -0
- package/dist/errors/terraform.error.js +24 -0
- package/dist/errors/terraform.error.js.map +1 -0
- package/dist/errors/transaction.error.d.ts +93 -2
- package/dist/errors/transaction.error.js +83 -0
- package/dist/errors/transaction.error.js.map +1 -1
- package/dist/events/action.event.d.ts +8 -4
- package/dist/events/action.event.js +2 -4
- package/dist/events/action.event.js.map +1 -1
- package/dist/events/command.event.d.ts +43 -0
- package/dist/events/command.event.js +33 -0
- package/dist/events/command.event.js.map +1 -0
- package/dist/events/event.model.d.ts +26 -8
- package/dist/events/event.model.js +15 -7
- package/dist/events/event.model.js.map +1 -1
- package/dist/events/hook/commit.hook.event.d.ts +1 -7
- package/dist/events/hook/commit.hook.event.js +0 -6
- package/dist/events/hook/commit.hook.event.js.map +1 -1
- package/dist/events/hook/hook.event.d.ts +1 -3
- package/dist/events/hook/hook.event.js +0 -2
- package/dist/events/hook/hook.event.js.map +1 -1
- package/dist/events/hook/model.hook.event.d.ts +1 -7
- package/dist/events/hook/model.hook.event.js +0 -6
- package/dist/events/hook/model.hook.event.js.map +1 -1
- package/dist/events/hook/resource.hook.event.d.ts +1 -7
- package/dist/events/hook/resource.hook.event.js +0 -6
- package/dist/events/hook/resource.hook.event.js.map +1 -1
- package/dist/events/index.d.ts +5 -0
- package/dist/events/index.js +5 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/mode-result.event.d.ts +57 -0
- package/dist/events/mode-result.event.js +24 -0
- package/dist/events/mode-result.event.js.map +1 -0
- package/dist/events/mode.event.d.ts +61 -0
- package/dist/events/mode.event.js +32 -0
- package/dist/events/mode.event.js.map +1 -0
- package/dist/events/module.event.d.ts +7 -5
- package/dist/events/module.event.js +3 -4
- package/dist/events/module.event.js.map +1 -1
- package/dist/events/registration.event.d.ts +19 -15
- package/dist/events/registration.event.js +18 -14
- package/dist/events/registration.event.js.map +1 -1
- package/dist/events/serialization.event.d.ts +16 -13
- package/dist/events/serialization.event.js +15 -12
- package/dist/events/serialization.event.js.map +1 -1
- package/dist/events/state.event.d.ts +102 -0
- package/dist/events/state.event.js +69 -0
- package/dist/events/state.event.js.map +1 -0
- package/dist/events/terraform.event.d.ts +78 -0
- package/dist/events/terraform.event.js +55 -0
- package/dist/events/terraform.event.js.map +1 -0
- package/dist/events/transaction.event.d.ts +3 -40
- package/dist/events/transaction.event.js +1 -29
- package/dist/events/transaction.event.js.map +1 -1
- package/dist/functions/container/container.d.ts +54 -13
- package/dist/functions/container/container.js +64 -19
- package/dist/functions/container/container.js.map +1 -1
- package/dist/functions/container/test-container.d.ts +43 -29
- package/dist/functions/container/test-container.js +71 -43
- package/dist/functions/container/test-container.js.map +1 -1
- package/dist/functions/dependency/dependency.d.ts +84 -23
- package/dist/functions/dependency/dependency.js +84 -14
- package/dist/functions/dependency/dependency.js.map +1 -1
- package/dist/functions/diff/aggregate-resource-actions.d.ts +19 -0
- package/dist/functions/diff/aggregate-resource-actions.js +41 -0
- package/dist/functions/diff/aggregate-resource-actions.js.map +1 -0
- package/dist/functions/diff/diff-metadata.d.ts +21 -3
- package/dist/functions/diff/diff-metadata.js +18 -0
- package/dist/functions/diff/diff-metadata.js.map +1 -1
- package/dist/functions/diff/diff.d.ts +68 -7
- package/dist/functions/diff/diff.js +44 -3
- package/dist/functions/diff/diff.js.map +1 -1
- package/dist/functions/hook/commit.hook.d.ts +16 -1
- package/dist/functions/hook/commit.hook.js +21 -6
- package/dist/functions/hook/commit.hook.js.map +1 -1
- package/dist/functions/hook/model-action.hook.d.ts +16 -1
- package/dist/functions/hook/model-action.hook.js +21 -6
- package/dist/functions/hook/model-action.hook.js.map +1 -1
- package/dist/functions/hook/resource-action.hook.d.ts +16 -1
- package/dist/functions/hook/resource-action.hook.js +21 -6
- package/dist/functions/hook/resource-action.hook.js.map +1 -1
- package/dist/functions/node/node-action.abstract.d.ts +23 -2
- package/dist/functions/node/node-action.abstract.js +22 -8
- package/dist/functions/node/node-action.abstract.js.map +1 -1
- package/dist/functions/node/node.abstract.d.ts +56 -5
- package/dist/functions/node/node.abstract.js +106 -22
- package/dist/functions/node/node.abstract.js.map +1 -1
- package/dist/functions/node/node.interface.d.ts +3 -1
- package/dist/functions/schema/schema.d.ts +7 -0
- package/dist/functions/schema/schema.js +10 -1
- package/dist/functions/schema/schema.js.map +1 -1
- package/dist/index.d.ts +12 -6
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/index.type.d.ts +5 -0
- package/dist/index.type.js +2 -0
- package/dist/index.type.js.map +1 -0
- package/dist/main.d.ts +245 -14
- package/dist/main.js +377 -72
- package/dist/main.js.map +1 -1
- package/dist/models/account/account.model.d.ts +43 -7
- package/dist/models/account/account.model.js +56 -8
- package/dist/models/account/account.model.js.map +1 -1
- package/dist/models/account/account.schema.d.ts +13 -1
- package/dist/models/account/account.schema.js +12 -0
- package/dist/models/account/account.schema.js.map +1 -1
- package/dist/models/app/app.model.d.ts +13 -8
- package/dist/models/app/app.model.js +17 -32
- package/dist/models/app/app.model.js.map +1 -1
- package/dist/models/app/app.schema.d.ts +6 -0
- package/dist/models/app/app.schema.js +6 -0
- package/dist/models/app/app.schema.js.map +1 -1
- package/dist/models/deployment/deployment.model.d.ts +13 -1
- package/dist/models/deployment/deployment.model.js +16 -4
- package/dist/models/deployment/deployment.model.js.map +1 -1
- package/dist/models/deployment/deployment.schema.d.ts +6 -0
- package/dist/models/deployment/deployment.schema.js +6 -0
- package/dist/models/deployment/deployment.schema.js.map +1 -1
- package/dist/models/environment/environment.model.d.ts +15 -3
- package/dist/models/environment/environment.model.js +22 -10
- package/dist/models/environment/environment.model.js.map +1 -1
- package/dist/models/environment/environment.schema.d.ts +2 -0
- package/dist/models/environment/environment.schema.js +2 -0
- package/dist/models/environment/environment.schema.js.map +1 -1
- package/dist/models/execution/execution.model.d.ts +21 -3
- package/dist/models/execution/execution.model.js +47 -29
- package/dist/models/execution/execution.model.js.map +1 -1
- package/dist/models/execution/execution.schema.d.ts +11 -0
- package/dist/models/execution/execution.schema.js +11 -0
- package/dist/models/execution/execution.schema.js.map +1 -1
- package/dist/models/filesystem/filesystem.model.d.ts +27 -1
- package/dist/models/filesystem/filesystem.model.js +30 -4
- package/dist/models/filesystem/filesystem.model.js.map +1 -1
- package/dist/models/filesystem/filesystem.schema.d.ts +5 -0
- package/dist/models/filesystem/filesystem.schema.js +5 -0
- package/dist/models/filesystem/filesystem.schema.js.map +1 -1
- package/dist/models/image/image.model.d.ts +19 -5
- package/dist/models/image/image.model.js +25 -11
- package/dist/models/image/image.model.js.map +1 -1
- package/dist/models/image/image.schema.d.ts +8 -0
- package/dist/models/image/image.schema.js +8 -0
- package/dist/models/image/image.schema.js.map +1 -1
- package/dist/models/model-action.interface.d.ts +17 -4
- package/dist/models/model.abstract.d.ts +96 -1
- package/dist/models/model.abstract.js +107 -8
- package/dist/models/model.abstract.js.map +1 -1
- package/dist/models/model.interface.d.ts +3 -0
- package/dist/models/pipeline/pipeline.model.d.ts +14 -2
- package/dist/models/pipeline/pipeline.model.js +19 -7
- package/dist/models/pipeline/pipeline.model.js.map +1 -1
- package/dist/models/pipeline/pipeline.schema.d.ts +8 -0
- package/dist/models/pipeline/pipeline.schema.js +8 -0
- package/dist/models/pipeline/pipeline.schema.js.map +1 -1
- package/dist/models/region/region.model.d.ts +16 -1
- package/dist/models/region/region.model.js +19 -4
- package/dist/models/region/region.model.js.map +1 -1
- package/dist/models/region/region.schema.d.ts +6 -0
- package/dist/models/region/region.schema.js +6 -0
- package/dist/models/region/region.schema.js.map +1 -1
- package/dist/models/server/server.model.d.ts +15 -3
- package/dist/models/server/server.model.js +18 -6
- package/dist/models/server/server.model.js.map +1 -1
- package/dist/models/server/server.schema.d.ts +3 -1
- package/dist/models/server/server.schema.js +3 -1
- package/dist/models/server/server.schema.js.map +1 -1
- package/dist/models/service/service.model.d.ts +37 -6
- package/dist/models/service/service.model.js +65 -11
- package/dist/models/service/service.model.js.map +1 -1
- package/dist/models/service/service.schema.d.ts +48 -1
- package/dist/models/service/service.schema.js +56 -1
- package/dist/models/service/service.schema.js.map +1 -1
- package/dist/models/subnet/subnet.model.d.ts +27 -3
- package/dist/models/subnet/subnet.model.js +40 -16
- package/dist/models/subnet/subnet.model.js.map +1 -1
- package/dist/models/subnet/subnet.schema.d.ts +9 -0
- package/dist/models/subnet/subnet.schema.js +9 -0
- package/dist/models/subnet/subnet.schema.js.map +1 -1
- package/dist/modes/apply-transaction.d.ts +23 -0
- package/dist/modes/apply-transaction.js +25 -0
- package/dist/modes/apply-transaction.js.map +1 -0
- package/dist/modes/commit.mode.d.ts +54 -0
- package/dist/modes/commit.mode.js +235 -0
- package/dist/modes/commit.mode.js.map +1 -0
- package/dist/modes/generate.mode.d.ts +30 -0
- package/dist/modes/generate.mode.js +50 -0
- package/dist/modes/generate.mode.js.map +1 -0
- package/dist/modes/run-action.mode.d.ts +30 -0
- package/dist/modes/run-action.mode.js +140 -0
- package/dist/modes/run-action.mode.js.map +1 -0
- package/dist/modes/validate.mode.d.ts +186 -0
- package/dist/modes/validate.mode.js +558 -0
- package/dist/modes/validate.mode.js.map +1 -0
- package/dist/modules/module.abstract.d.ts +51 -0
- package/dist/modules/module.abstract.js +36 -0
- package/dist/modules/module.abstract.js.map +1 -1
- package/dist/modules/module.container.d.ts +43 -1
- package/dist/modules/module.container.js +77 -5
- package/dist/modules/module.container.js.map +1 -1
- package/dist/modules/test-module.container.d.ts +139 -25
- package/dist/modules/test-module.container.js +383 -199
- package/dist/modules/test-module.container.js.map +1 -1
- package/dist/overlays/anchor.abstract.d.ts +32 -1
- package/dist/overlays/anchor.abstract.js +42 -11
- package/dist/overlays/anchor.abstract.js.map +1 -1
- package/dist/overlays/anchor.schema.d.ts +21 -0
- package/dist/overlays/anchor.schema.js +21 -0
- package/dist/overlays/anchor.schema.js.map +1 -1
- package/dist/overlays/overlay-data.repository.d.ts +18 -0
- package/dist/overlays/overlay-data.repository.js +18 -0
- package/dist/overlays/overlay-data.repository.js.map +1 -1
- package/dist/overlays/overlay.abstract.d.ts +56 -1
- package/dist/overlays/overlay.abstract.js +79 -20
- package/dist/overlays/overlay.abstract.js.map +1 -1
- package/dist/overlays/overlay.schema.d.ts +20 -0
- package/dist/overlays/overlay.schema.js +20 -0
- package/dist/overlays/overlay.schema.js.map +1 -1
- package/dist/resources/resource-action.interface.d.ts +29 -3
- package/dist/resources/resource-data.repository.d.ts +63 -1
- package/dist/resources/resource-data.repository.js +94 -4
- package/dist/resources/resource-data.repository.js.map +1 -1
- package/dist/resources/resource.abstract.d.ts +163 -6
- package/dist/resources/resource.abstract.js +223 -59
- package/dist/resources/resource.abstract.js.map +1 -1
- package/dist/resources/resource.interface.d.ts +0 -2
- package/dist/resources/resource.schema.d.ts +39 -1
- package/dist/resources/resource.schema.js +38 -0
- package/dist/resources/resource.schema.js.map +1 -1
- package/dist/resources/terraform-resource.abstract.d.ts +44 -0
- package/dist/resources/terraform-resource.abstract.js +45 -0
- package/dist/resources/terraform-resource.abstract.js.map +1 -0
- package/dist/services/event/event.service.d.ts +32 -5
- package/dist/services/event/event.service.js +58 -16
- package/dist/services/event/event.service.js.map +1 -1
- package/dist/services/input/input.service.d.ts +82 -5
- package/dist/services/input/input.service.js +143 -12
- package/dist/services/input/input.service.js.map +1 -1
- package/dist/services/schema-translation/schema-translation.service.d.ts +9 -0
- package/dist/services/schema-translation/schema-translation.service.js +9 -0
- package/dist/services/schema-translation/schema-translation.service.js.map +1 -1
- package/dist/services/serialization/model/model-serialization.service.d.ts +25 -3
- package/dist/services/serialization/model/model-serialization.service.js +113 -62
- package/dist/services/serialization/model/model-serialization.service.js.map +1 -1
- package/dist/services/serialization/resource/resource-serialization.service.d.ts +36 -6
- package/dist/services/serialization/resource/resource-serialization.service.js +77 -28
- package/dist/services/serialization/resource/resource-serialization.service.js.map +1 -1
- package/dist/services/state-management/local.state-provider.d.ts +67 -4
- package/dist/services/state-management/local.state-provider.js +168 -41
- package/dist/services/state-management/local.state-provider.js.map +1 -1
- package/dist/services/state-management/remote.state-provider.d.ts +216 -0
- package/dist/services/state-management/remote.state-provider.js +645 -0
- package/dist/services/state-management/remote.state-provider.js.map +1 -0
- package/dist/services/state-management/state-management.service.d.ts +195 -17
- package/dist/services/state-management/state-management.service.js +259 -10
- package/dist/services/state-management/state-management.service.js.map +1 -1
- package/dist/services/state-management/state-provider.interface.d.ts +98 -3
- package/dist/services/state-management/state-provider.interface.js +14 -1
- package/dist/services/state-management/state-provider.interface.js.map +1 -1
- package/dist/services/state-management/terraform-state.service.d.ts +99 -0
- package/dist/services/state-management/terraform-state.service.js +197 -0
- package/dist/services/state-management/terraform-state.service.js.map +1 -0
- package/dist/services/state-management/test.state-provider.d.ts +42 -4
- package/dist/services/state-management/test.state-provider.js +77 -25
- package/dist/services/state-management/test.state-provider.js.map +1 -1
- package/dist/services/terraform/terraform.service.d.ts +480 -0
- package/dist/services/terraform/terraform.service.js +1082 -0
- package/dist/services/terraform/terraform.service.js.map +1 -0
- package/dist/services/terraform/terraform.type.d.ts +387 -0
- package/dist/services/terraform/terraform.type.js +579 -0
- package/dist/services/terraform/terraform.type.js.map +1 -0
- package/dist/services/transaction/transaction.service.d.ts +110 -10
- package/dist/services/transaction/transaction.service.js +570 -251
- package/dist/services/transaction/transaction.service.js.map +1 -1
- package/dist/services/validation/validation.service.d.ts +15 -3
- package/dist/services/validation/validation.service.js +12 -0
- package/dist/services/validation/validation.service.js.map +1 -1
- package/dist/utilities/array/array.utility.d.ts +3 -0
- package/dist/utilities/array/array.utility.js +3 -0
- package/dist/utilities/array/array.utility.js.map +1 -1
- package/dist/{functions → utilities}/diff/diff.utility.d.ts +19 -3
- package/dist/{functions → utilities}/diff/diff.utility.js +57 -41
- package/dist/utilities/diff/diff.utility.js.map +1 -0
- package/dist/utilities/file/file.utility.d.ts +16 -2
- package/dist/utilities/file/file.utility.js +23 -61
- package/dist/utilities/file/file.utility.js.map +1 -1
- package/dist/utilities/hcl/hcl.utility.d.ts +128 -0
- package/dist/utilities/hcl/hcl.utility.js +402 -0
- package/dist/utilities/hcl/hcl.utility.js.map +1 -0
- package/dist/utilities/http/http.utility.d.ts +57 -0
- package/dist/utilities/http/http.utility.js +98 -0
- package/dist/utilities/http/http.utility.js.map +1 -0
- package/dist/utilities/node/node.utility.d.ts +3 -0
- package/dist/utilities/node/node.utility.js +3 -0
- package/dist/utilities/node/node.utility.js.map +1 -1
- package/dist/utilities/object/object.utility.d.ts +12 -0
- package/dist/utilities/object/object.utility.js +12 -0
- package/dist/utilities/object/object.utility.js.map +1 -1
- package/dist/utilities/project/project.utility.d.ts +28 -0
- package/dist/utilities/project/project.utility.js +35 -0
- package/dist/utilities/project/project.utility.js.map +1 -0
- package/dist/utilities/string/string.utility.d.ts +41 -0
- package/dist/utilities/string/string.utility.js +65 -0
- package/dist/utilities/string/string.utility.js.map +1 -0
- package/dist/utilities/terraform/terraform.utility.d.ts +276 -0
- package/dist/utilities/terraform/terraform.utility.js +623 -0
- package/dist/utilities/terraform/terraform.utility.js.map +1 -0
- package/dist/utilities/test-helpers/test-classes.d.ts +36 -30
- package/dist/utilities/test-helpers/test-classes.js +38 -39
- package/dist/utilities/test-helpers/test-classes.js.map +1 -1
- package/dist/utilities/test-helpers/test-models.d.ts +8 -1
- package/dist/utilities/test-helpers/test-models.js +37 -12
- package/dist/utilities/test-helpers/test-models.js.map +1 -1
- package/dist/utilities/test-helpers/test-modes.d.ts +315 -0
- package/dist/utilities/test-helpers/test-modes.js +486 -0
- package/dist/utilities/test-helpers/test-modes.js.map +1 -0
- package/dist/utilities/test-helpers/test-modules.d.ts +47 -0
- package/dist/utilities/test-helpers/test-modules.js +85 -0
- package/dist/utilities/test-helpers/test-modules.js.map +1 -0
- package/dist/utilities/test-helpers/test-overlays.d.ts +20 -2
- package/dist/utilities/test-helpers/test-overlays.js +56 -6
- package/dist/utilities/test-helpers/test-overlays.js.map +1 -1
- package/dist/utilities/test-helpers/test-resources.d.ts +23 -3
- package/dist/utilities/test-helpers/test-resources.js +83 -23
- package/dist/utilities/test-helpers/test-resources.js.map +1 -1
- package/dist/utilities/validation/validation.utility.d.ts +24 -0
- package/dist/utilities/validation/validation.utility.js +24 -0
- package/dist/utilities/validation/validation.utility.js.map +1 -1
- package/package.json +12 -6
- package/dist/functions/diff/diff.utility.js.map +0 -1
- package/dist/services/capture/capture.service.d.ts +0 -19
- package/dist/services/capture/capture.service.js +0 -43
- package/dist/services/capture/capture.service.js.map +0 -1
- package/dist/services/state-management/local-encryption.state-provider.d.ts +0 -20
- package/dist/services/state-management/local-encryption.state-provider.js +0 -90
- package/dist/services/state-management/local-encryption.state-provider.js.map +0 -1
- package/dist/utilities/cidr/cidr.utility.d.ts +0 -10
- package/dist/utilities/cidr/cidr.utility.js +0 -51
- package/dist/utilities/cidr/cidr.utility.js.map +0 -1
|
@@ -1,14 +1,109 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* The prefix of the state files the journal writes. A remote state provider uploads them while the
|
|
3
|
+
* lock is held, and never replaces them when it refreshes.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare const JOURNAL_STATE_FILE_NAME_PREFIX = "journal.";
|
|
8
|
+
/**
|
|
9
|
+
* The commands that run before a lock. Every other command runs under one, and its journal files
|
|
10
|
+
* belong to the lock held.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare const JOURNAL_COMMANDS_BEFORE_LOCK: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Where Octo's state files live.
|
|
17
|
+
*
|
|
18
|
+
* Octo has no database - it records what it built in state files, and reads them back on the next run
|
|
19
|
+
* to work out the diff. A state provider is only asked to put a named blob somewhere and hand it back
|
|
20
|
+
* later, so implementing this interface is all it takes to keep state in S3, a database, or anywhere
|
|
21
|
+
* else your team already trusts.
|
|
22
|
+
*
|
|
23
|
+
* Pass one to {@link Octo.initialize}.
|
|
24
|
+
*
|
|
2
25
|
* @group Services/State Management
|
|
26
|
+
*
|
|
27
|
+
* @see Techniques for [State Providers](/docs/techniques/state-providers).
|
|
3
28
|
*/
|
|
4
29
|
export interface IStateProvider {
|
|
30
|
+
/**
|
|
31
|
+
* The id of the lock currently held, or `undefined` when the app is unlocked.
|
|
32
|
+
*/
|
|
5
33
|
getAppLock(): Promise<string | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Reads a state file.
|
|
36
|
+
*
|
|
37
|
+
* @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
|
|
38
|
+
* Octo treats that as a first run rather than an error.
|
|
39
|
+
*/
|
|
6
40
|
getState(stateFileName: string): Promise<Buffer>;
|
|
41
|
+
/**
|
|
42
|
+
* Whether `lockId` is the lock currently held.
|
|
43
|
+
*
|
|
44
|
+
* @throws {@link TransactionError} With the message `Invalid lock ID!` when a *different* lock is
|
|
45
|
+
* held, so a caller holding a stale id is told it is stale rather than told the app is free.
|
|
46
|
+
*/
|
|
7
47
|
isAppLocked(lockId: string): Promise<boolean>;
|
|
8
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The names of the state files whose name starts with `prefix`, named as
|
|
50
|
+
* {@link IStateProvider.getState} would be given them.
|
|
51
|
+
*
|
|
52
|
+
* Octo reads state by name everywhere else, so this is the only way it can discover a file it was
|
|
53
|
+
* not told about - a record an interrupted run left behind. Returns an empty list when the store
|
|
54
|
+
* holds nothing matching, including when it does not exist yet.
|
|
55
|
+
*/
|
|
56
|
+
listStates(prefix: string): Promise<string[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Takes the app lock and returns its id, which `apply` and `commit` must then present.
|
|
59
|
+
*
|
|
60
|
+
* The lock is taken atomically, so of two callers racing for it exactly one wins. With `lockId`,
|
|
61
|
+
* resumes the run already holding that lock instead, which is how a run that died is finished.
|
|
62
|
+
* `commitId` names the record the run writes into, where the provider keeps one.
|
|
63
|
+
*
|
|
64
|
+
* A provider sharing state names where a resume took the state directory from in `resumedFrom`:
|
|
65
|
+
* `directory`, the directory the lock was taken in, left as it was; `run`, what the run uploaded so
|
|
66
|
+
* far; `sealed`, the newest sealed state, because the run uploaded nothing.
|
|
67
|
+
*
|
|
68
|
+
* @throws {@link AppLockError} When a lock is held, naming the id that holds it. When `lockId` is
|
|
69
|
+
* given and is not the lock held.
|
|
70
|
+
*/
|
|
71
|
+
lockApp(lockId?: string): Promise<{
|
|
72
|
+
commitId?: string;
|
|
9
73
|
lockId: string;
|
|
74
|
+
resumedFrom?: 'directory' | 'run' | 'sealed';
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Brings the state up to the newest a run may plan against. `generate` calls it before reading any.
|
|
78
|
+
*
|
|
79
|
+
* A provider whose state is always the newest does nothing here, and returns `replaced: false`.
|
|
80
|
+
* One that replaced the state files names the commit it replaced them with, and the one before.
|
|
81
|
+
*/
|
|
82
|
+
refreshState(): Promise<{
|
|
83
|
+
commitId?: string;
|
|
84
|
+
previousCommitId?: string;
|
|
85
|
+
replaced: boolean;
|
|
10
86
|
}>;
|
|
11
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Writes state files as one change, overwriting whatever was there. A file comes from `data`, or is
|
|
89
|
+
* copied from the file at `filePath` without being read into memory; one given `data: undefined` is
|
|
90
|
+
* deleted. Deleting one that is not there is not an error. A name holding `/` is the machine's own:
|
|
91
|
+
* a provider sharing state keeps it on the machine.
|
|
92
|
+
*
|
|
93
|
+
* A provider that pays per write makes one write of the whole change rather than one per file.
|
|
94
|
+
*/
|
|
95
|
+
saveStates(stateFiles: ({
|
|
96
|
+
data: Buffer | undefined;
|
|
97
|
+
stateFileName: string;
|
|
98
|
+
} | {
|
|
99
|
+
filePath: string;
|
|
100
|
+
stateFileName: string;
|
|
101
|
+
})[]): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Releases the app lock. Unlocking an app that is not locked is not an error.
|
|
104
|
+
*
|
|
105
|
+
* @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is
|
|
106
|
+
* held, so one run can never release another's.
|
|
107
|
+
*/
|
|
12
108
|
unlockApp(lockId: string): Promise<void>;
|
|
13
|
-
updateAppLockTransaction(lockId: string): Promise<void>;
|
|
14
109
|
}
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The prefix of the state files the journal writes. A remote state provider uploads them while the
|
|
3
|
+
* lock is held, and never replaces them when it refreshes.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export const JOURNAL_STATE_FILE_NAME_PREFIX = 'journal.';
|
|
8
|
+
/**
|
|
9
|
+
* The commands that run before a lock. Every other command runs under one, and its journal files
|
|
10
|
+
* belong to the lock held.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export const JOURNAL_COMMANDS_BEFORE_LOCK = ['generate', 'lock', 'validate'];
|
|
2
15
|
//# sourceMappingURL=state-provider.interface.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-provider.interface.js","sourceRoot":"","sources":["../../../src/services/state-management/state-provider.interface.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"state-provider.interface.js","sourceRoot":"","sources":["../../../src/services/state-management/state-provider.interface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,UAAU,CAAC;AAEzD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { StateManagementService } from './state-management.service.js';
|
|
2
|
+
/**
|
|
3
|
+
* Moves each module folder's `terraform.tfstate` in and out of Octo's {@link IStateProvider}.
|
|
4
|
+
*
|
|
5
|
+
* Terraform's record of what exists is the one thing Octo cannot rebuild, and a local backend leaves
|
|
6
|
+
* it in the module folder where only the machine that ran the apply can see it. Checking it out
|
|
7
|
+
* before a terraform command and back in after puts it wherever Octo state already lives, so a team
|
|
8
|
+
* sharing Octo state shares terraform state with it.
|
|
9
|
+
*
|
|
10
|
+
* Check-in is frequent rather than atomic: it runs on every terraform command's return, success or
|
|
11
|
+
* failure, and on a timer through a long apply. A partial record of what exists beats none.
|
|
12
|
+
*
|
|
13
|
+
* {@link TerraformUtility} drives this around every command it runs, so nothing calls it directly.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare class TerraformStateService {
|
|
18
|
+
private checkInQueue;
|
|
19
|
+
private isPeriodicCheckInRunning;
|
|
20
|
+
private periodicCheckIn;
|
|
21
|
+
private readonly stateManagementService;
|
|
22
|
+
/**
|
|
23
|
+
* @param stateManagementService Where terraform state is read from and written to.
|
|
24
|
+
*/
|
|
25
|
+
constructor(stateManagementService: StateManagementService);
|
|
26
|
+
/**
|
|
27
|
+
* Writes every module folder's terraform state to the state provider, as one change.
|
|
28
|
+
*
|
|
29
|
+
* A folder holding no state file, or one recording no resources, has its state **deleted** rather
|
|
30
|
+
* than written - that is a module terraform has destroyed, and a file recording nothing is a file
|
|
31
|
+
* worth nobody's history. A file that does not parse is left out, keeping the provider's copy:
|
|
32
|
+
* terraform rewrites the file in place, so a check-in during a command can read it empty or half
|
|
33
|
+
* written.
|
|
34
|
+
*
|
|
35
|
+
* Check-ins are serialized, so the one on a command's return never races the one on the timer.
|
|
36
|
+
*/
|
|
37
|
+
checkIn(terragruntDir: string, moduleIds: string[]): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Writes the state provider's terraform state into every module folder.
|
|
40
|
+
*
|
|
41
|
+
* A module the provider holds nothing for keeps whatever its folder already has, which is what
|
|
42
|
+
* adopts the state of a stack that ran with a local backend until now. A folder whose state is
|
|
43
|
+
* ahead of the provider's keeps it too, which is what a run killed before its last check-in
|
|
44
|
+
* leaves behind. The check-in that follows hands either to the provider.
|
|
45
|
+
*/
|
|
46
|
+
checkOut(terragruntDir: string, moduleIds: string[]): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* The state moves the last generate recorded, each from one module folder into another.
|
|
49
|
+
*/
|
|
50
|
+
getRecordedMoves(): Promise<{
|
|
51
|
+
addresses: {
|
|
52
|
+
from: string;
|
|
53
|
+
to: string;
|
|
54
|
+
}[];
|
|
55
|
+
fromModuleId: string;
|
|
56
|
+
moduleId: string;
|
|
57
|
+
outputs: {
|
|
58
|
+
from: string;
|
|
59
|
+
to: string;
|
|
60
|
+
}[];
|
|
61
|
+
}[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Starts checking state in every `intervalInMs`, bounding what a killed runner loses to one interval.
|
|
64
|
+
*/
|
|
65
|
+
startPeriodicCheckIn(terragruntDir: string, moduleIds: string[], intervalInMs: number): void;
|
|
66
|
+
/**
|
|
67
|
+
* Stops the timer {@link TerraformStateService.startPeriodicCheckIn} started.
|
|
68
|
+
*/
|
|
69
|
+
stopPeriodicCheckIn(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Whether the folder's terraform state is a later write of the same state the provider holds: the
|
|
72
|
+
* same `lineage`, and a higher `serial`. State that cannot be read or parsed is never ahead.
|
|
73
|
+
*/
|
|
74
|
+
private isFolderStateAhead;
|
|
75
|
+
/**
|
|
76
|
+
* A terraform state file's contents, or `undefined` when it does not parse.
|
|
77
|
+
*/
|
|
78
|
+
private parseState;
|
|
79
|
+
/**
|
|
80
|
+
* The name one module's terraform state is stored under, alongside Octo's own state files.
|
|
81
|
+
*/
|
|
82
|
+
private stateFileName;
|
|
83
|
+
/**
|
|
84
|
+
* The body of a check-in, run one at a time through {@link TerraformStateService.checkIn}.
|
|
85
|
+
*/
|
|
86
|
+
private writeStates;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
export declare class TerraformStateServiceFactory {
|
|
92
|
+
/**
|
|
93
|
+
* Never cached: {@link Octo.initialize} builds a new {@link StateManagementService} around the
|
|
94
|
+
* provider it is given, and a cached instance would go on writing to the previous one.
|
|
95
|
+
*
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
static create(): Promise<TerraformStateService>;
|
|
99
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { Factory } from '../../decorators/factory.decorator.js';
|
|
11
|
+
import { Container } from '../../functions/container/container.js';
|
|
12
|
+
import { StateManagementService } from './state-management.service.js';
|
|
13
|
+
const TERRAFORM_STATE_FILE_NAME = 'terraform.tfstate';
|
|
14
|
+
/**
|
|
15
|
+
* Moves each module folder's `terraform.tfstate` in and out of Octo's {@link IStateProvider}.
|
|
16
|
+
*
|
|
17
|
+
* Terraform's record of what exists is the one thing Octo cannot rebuild, and a local backend leaves
|
|
18
|
+
* it in the module folder where only the machine that ran the apply can see it. Checking it out
|
|
19
|
+
* before a terraform command and back in after puts it wherever Octo state already lives, so a team
|
|
20
|
+
* sharing Octo state shares terraform state with it.
|
|
21
|
+
*
|
|
22
|
+
* Check-in is frequent rather than atomic: it runs on every terraform command's return, success or
|
|
23
|
+
* failure, and on a timer through a long apply. A partial record of what exists beats none.
|
|
24
|
+
*
|
|
25
|
+
* {@link TerraformUtility} drives this around every command it runs, so nothing calls it directly.
|
|
26
|
+
*
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
export class TerraformStateService {
|
|
30
|
+
/**
|
|
31
|
+
* @param stateManagementService Where terraform state is read from and written to.
|
|
32
|
+
*/
|
|
33
|
+
constructor(stateManagementService) {
|
|
34
|
+
this.checkInQueue = Promise.resolve();
|
|
35
|
+
this.isPeriodicCheckInRunning = false;
|
|
36
|
+
this.stateManagementService = stateManagementService;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Writes every module folder's terraform state to the state provider, as one change.
|
|
40
|
+
*
|
|
41
|
+
* A folder holding no state file, or one recording no resources, has its state **deleted** rather
|
|
42
|
+
* than written - that is a module terraform has destroyed, and a file recording nothing is a file
|
|
43
|
+
* worth nobody's history. A file that does not parse is left out, keeping the provider's copy:
|
|
44
|
+
* terraform rewrites the file in place, so a check-in during a command can read it empty or half
|
|
45
|
+
* written.
|
|
46
|
+
*
|
|
47
|
+
* Check-ins are serialized, so the one on a command's return never races the one on the timer.
|
|
48
|
+
*/
|
|
49
|
+
async checkIn(terragruntDir, moduleIds) {
|
|
50
|
+
this.checkInQueue = this.checkInQueue.then(() => this.writeStates(terragruntDir, moduleIds), () => this.writeStates(terragruntDir, moduleIds));
|
|
51
|
+
return this.checkInQueue;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Writes the state provider's terraform state into every module folder.
|
|
55
|
+
*
|
|
56
|
+
* A module the provider holds nothing for keeps whatever its folder already has, which is what
|
|
57
|
+
* adopts the state of a stack that ran with a local backend until now. A folder whose state is
|
|
58
|
+
* ahead of the provider's keeps it too, which is what a run killed before its last check-in
|
|
59
|
+
* leaves behind. The check-in that follows hands either to the provider.
|
|
60
|
+
*/
|
|
61
|
+
async checkOut(terragruntDir, moduleIds) {
|
|
62
|
+
for (const moduleId of moduleIds) {
|
|
63
|
+
let data;
|
|
64
|
+
try {
|
|
65
|
+
data = await this.stateManagementService.getState(this.stateFileName(moduleId));
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.message === 'No state found!') {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
const stateFilePath = join(terragruntDir, moduleId, TERRAFORM_STATE_FILE_NAME);
|
|
74
|
+
if (await this.isFolderStateAhead(stateFilePath, data)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
await writeFile(stateFilePath, data);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The state moves the last generate recorded, each from one module folder into another.
|
|
82
|
+
*/
|
|
83
|
+
async getRecordedMoves() {
|
|
84
|
+
const { userData } = await this.stateManagementService.getModelState(this.stateManagementService.modelStateFileName);
|
|
85
|
+
return (userData.terraformFolders ?? []).flatMap(({ moduleId, moves = [] }) => moves.map(({ addresses, fromModuleId, outputs }) => ({ addresses, fromModuleId, moduleId, outputs })));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Starts checking state in every `intervalInMs`, bounding what a killed runner loses to one interval.
|
|
89
|
+
*/
|
|
90
|
+
startPeriodicCheckIn(terragruntDir, moduleIds, intervalInMs) {
|
|
91
|
+
if (this.periodicCheckIn) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.periodicCheckIn = setInterval(() => {
|
|
95
|
+
// Skip the tick while the last one is still checking in, rather than waiting behind it.
|
|
96
|
+
if (this.isPeriodicCheckInRunning) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
this.isPeriodicCheckInRunning = true;
|
|
100
|
+
// A tick that fails is not worth aborting the terraform command that is still running - the
|
|
101
|
+
// check-in on its return reports the failure instead.
|
|
102
|
+
void this.checkIn(terragruntDir, moduleIds)
|
|
103
|
+
.catch(() => { })
|
|
104
|
+
.finally(() => {
|
|
105
|
+
this.isPeriodicCheckInRunning = false;
|
|
106
|
+
});
|
|
107
|
+
}, intervalInMs);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Stops the timer {@link TerraformStateService.startPeriodicCheckIn} started.
|
|
111
|
+
*/
|
|
112
|
+
stopPeriodicCheckIn() {
|
|
113
|
+
if (this.periodicCheckIn) {
|
|
114
|
+
clearInterval(this.periodicCheckIn);
|
|
115
|
+
this.periodicCheckIn = undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Whether the folder's terraform state is a later write of the same state the provider holds: the
|
|
120
|
+
* same `lineage`, and a higher `serial`. State that cannot be read or parsed is never ahead.
|
|
121
|
+
*/
|
|
122
|
+
async isFolderStateAhead(stateFilePath, providerData) {
|
|
123
|
+
try {
|
|
124
|
+
const folderState = JSON.parse(await readFile(stateFilePath, 'utf-8'));
|
|
125
|
+
const providerState = JSON.parse(providerData.toString());
|
|
126
|
+
return (typeof folderState.serial === 'number' &&
|
|
127
|
+
typeof providerState.serial === 'number' &&
|
|
128
|
+
folderState.lineage === providerState.lineage &&
|
|
129
|
+
folderState.serial > providerState.serial);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A terraform state file's contents, or `undefined` when it does not parse.
|
|
137
|
+
*/
|
|
138
|
+
parseState(data) {
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(data.toString());
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The name one module's terraform state is stored under, alongside Octo's own state files.
|
|
148
|
+
*/
|
|
149
|
+
stateFileName(moduleId) {
|
|
150
|
+
return `${moduleId}.tfstate`;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The body of a check-in, run one at a time through {@link TerraformStateService.checkIn}.
|
|
154
|
+
*/
|
|
155
|
+
async writeStates(terragruntDir, moduleIds) {
|
|
156
|
+
const stateFiles = [];
|
|
157
|
+
for (const moduleId of moduleIds) {
|
|
158
|
+
const stateFilePath = join(terragruntDir, moduleId, TERRAFORM_STATE_FILE_NAME);
|
|
159
|
+
const stateFileName = this.stateFileName(moduleId);
|
|
160
|
+
// Delete the state of a module with no state file.
|
|
161
|
+
if (!existsSync(stateFilePath)) {
|
|
162
|
+
stateFiles.push({ data: undefined, stateFileName });
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Skip a file terraform is still writing.
|
|
166
|
+
const data = await readFile(stateFilePath);
|
|
167
|
+
const state = this.parseState(data);
|
|
168
|
+
if (!state) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
// Delete the state of a module recording no resources, and write every other.
|
|
172
|
+
const holdsNoResources = Array.isArray(state.resources) && state.resources.length === 0;
|
|
173
|
+
stateFiles.push({ data: holdsNoResources ? undefined : data, stateFileName });
|
|
174
|
+
}
|
|
175
|
+
await this.stateManagementService.saveStates(stateFiles);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* @internal
|
|
180
|
+
*/
|
|
181
|
+
let TerraformStateServiceFactory = class TerraformStateServiceFactory {
|
|
182
|
+
/**
|
|
183
|
+
* Never cached: {@link Octo.initialize} builds a new {@link StateManagementService} around the
|
|
184
|
+
* provider it is given, and a cached instance would go on writing to the previous one.
|
|
185
|
+
*
|
|
186
|
+
* @internal
|
|
187
|
+
*/
|
|
188
|
+
static async create() {
|
|
189
|
+
const stateManagementService = await Container.getInstance().get(StateManagementService);
|
|
190
|
+
return new TerraformStateService(stateManagementService);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
TerraformStateServiceFactory = __decorate([
|
|
194
|
+
Factory(TerraformStateService)
|
|
195
|
+
], TerraformStateServiceFactory);
|
|
196
|
+
export { TerraformStateServiceFactory };
|
|
197
|
+
//# sourceMappingURL=terraform-state.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terraform-state.service.js","sourceRoot":"","sources":["../../../src/services/state-management/terraform-state.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +1,55 @@
|
|
|
1
1
|
import type { IStateProvider } from './state-provider.interface.js';
|
|
2
2
|
/**
|
|
3
|
+
* Keeps state in memory, and discards it when the process ends. For tests.
|
|
4
|
+
*
|
|
3
5
|
* @group Services/State Management
|
|
6
|
+
*
|
|
7
|
+
* @see Techniques for [State Providers](/docs/techniques/state-providers).
|
|
4
8
|
*/
|
|
5
9
|
export declare class TestStateProvider implements IStateProvider {
|
|
6
10
|
private readonly localState;
|
|
7
11
|
private lockId;
|
|
12
|
+
/**
|
|
13
|
+
* The id of the lock currently held, or `undefined` when the app is unlocked.
|
|
14
|
+
*/
|
|
8
15
|
getAppLock(): Promise<string | undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* Reads a state file.
|
|
18
|
+
*
|
|
19
|
+
* @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
|
|
20
|
+
*/
|
|
9
21
|
getState(stateFileName: string): Promise<Buffer>;
|
|
22
|
+
/**
|
|
23
|
+
* Whether `lockId` is the lock currently held.
|
|
24
|
+
*
|
|
25
|
+
* @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
|
|
26
|
+
*/
|
|
10
27
|
isAppLocked(lockId: string): Promise<boolean>;
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
/**
|
|
29
|
+
* The names of the state files whose name starts with `prefix`.
|
|
30
|
+
*/
|
|
31
|
+
listStates(prefix: string): Promise<string[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Takes the app lock. With `lockId`, resumes the run already holding it.
|
|
34
|
+
*
|
|
35
|
+
* @throws {@link TransactionError} When a lock is held, naming the id that holds it. When `lockId`
|
|
36
|
+
* is given and is not the lock held.
|
|
37
|
+
*/
|
|
38
|
+
lockApp(lockId?: string): ReturnType<IStateProvider['lockApp']>;
|
|
39
|
+
/**
|
|
40
|
+
* Does nothing: the state lives in this process alone, so it is always the newest.
|
|
41
|
+
*/
|
|
42
|
+
refreshState(): Promise<{
|
|
43
|
+
replaced: boolean;
|
|
13
44
|
}>;
|
|
14
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Writes state files, overwriting whatever was there and deleting each one given no `data`.
|
|
47
|
+
*/
|
|
48
|
+
saveStates(stateFiles: Parameters<IStateProvider['saveStates']>[0]): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Releases the app lock.
|
|
51
|
+
*
|
|
52
|
+
* @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
|
|
53
|
+
*/
|
|
15
54
|
unlockApp(lockId: string): Promise<void>;
|
|
16
|
-
updateAppLockTransaction(lockId: string): Promise<void>;
|
|
17
55
|
}
|
|
@@ -1,60 +1,112 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { AppLockError, TransactionError } from '../../errors/index.js';
|
|
2
4
|
/**
|
|
5
|
+
* Keeps state in memory, and discards it when the process ends. For tests.
|
|
6
|
+
*
|
|
3
7
|
* @group Services/State Management
|
|
8
|
+
*
|
|
9
|
+
* @see Techniques for [State Providers](/docs/techniques/state-providers).
|
|
4
10
|
*/
|
|
5
11
|
export class TestStateProvider {
|
|
6
12
|
constructor() {
|
|
7
13
|
this.localState = {};
|
|
8
14
|
this.lockId = undefined;
|
|
9
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* The id of the lock currently held, or `undefined` when the app is unlocked.
|
|
18
|
+
*/
|
|
10
19
|
async getAppLock() {
|
|
11
20
|
return this.lockId;
|
|
12
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Reads a state file.
|
|
24
|
+
*
|
|
25
|
+
* @throws {@link TransactionError} With the message `No state found!` when the file does not exist.
|
|
26
|
+
*/
|
|
13
27
|
async getState(stateFileName) {
|
|
14
28
|
if (!(stateFileName in this.localState)) {
|
|
15
29
|
throw new TransactionError('No state found!');
|
|
16
30
|
}
|
|
17
31
|
return this.localState[stateFileName];
|
|
18
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether `lockId` is the lock currently held.
|
|
35
|
+
*
|
|
36
|
+
* @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
|
|
37
|
+
*/
|
|
19
38
|
async isAppLocked(lockId) {
|
|
20
|
-
|
|
21
|
-
if (!existingLockId) {
|
|
39
|
+
if (!this.lockId) {
|
|
22
40
|
return false;
|
|
23
41
|
}
|
|
24
|
-
if (lockId !==
|
|
42
|
+
if (this.lockId !== lockId) {
|
|
25
43
|
throw new TransactionError('Invalid lock ID!');
|
|
26
44
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The names of the state files whose name starts with `prefix`.
|
|
49
|
+
*/
|
|
50
|
+
async listStates(prefix) {
|
|
51
|
+
return Object.keys(this.localState).filter((stateFileName) => stateFileName.startsWith(prefix));
|
|
30
52
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Takes the app lock. With `lockId`, resumes the run already holding it.
|
|
55
|
+
*
|
|
56
|
+
* @throws {@link TransactionError} When a lock is held, naming the id that holds it. When `lockId`
|
|
57
|
+
* is given and is not the lock held.
|
|
58
|
+
*/
|
|
59
|
+
async lockApp(lockId) {
|
|
60
|
+
if (lockId) {
|
|
61
|
+
if (this.lockId !== lockId) {
|
|
62
|
+
throw new AppLockError(`App is not locked with lock ID "${lockId}"!`, { reason: 'not-held' });
|
|
63
|
+
}
|
|
64
|
+
return { lockId };
|
|
35
65
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
66
|
+
if (this.lockId) {
|
|
67
|
+
throw new AppLockError(`App already locked with lock ID "${this.lockId}"!`, {
|
|
68
|
+
holder: { lockId: this.lockId },
|
|
69
|
+
reason: 'held',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
this.lockId = randomUUID();
|
|
73
|
+
return { lockId: this.lockId };
|
|
39
74
|
}
|
|
40
|
-
|
|
41
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Does nothing: the state lives in this process alone, so it is always the newest.
|
|
77
|
+
*/
|
|
78
|
+
async refreshState() {
|
|
79
|
+
return { replaced: false };
|
|
42
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Writes state files, overwriting whatever was there and deleting each one given no `data`.
|
|
83
|
+
*/
|
|
84
|
+
async saveStates(stateFiles) {
|
|
85
|
+
for (const stateFile of stateFiles) {
|
|
86
|
+
if ('filePath' in stateFile) {
|
|
87
|
+
this.localState[stateFile.stateFileName] = await readFile(stateFile.filePath);
|
|
88
|
+
}
|
|
89
|
+
else if (stateFile.data === undefined) {
|
|
90
|
+
delete this.localState[stateFile.stateFileName];
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.localState[stateFile.stateFileName] = stateFile.data;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Releases the app lock.
|
|
99
|
+
*
|
|
100
|
+
* @throws {@link TransactionError} With the message `Invalid lock ID!` when a different lock is held.
|
|
101
|
+
*/
|
|
43
102
|
async unlockApp(lockId) {
|
|
44
|
-
|
|
45
|
-
if (!existingLockId) {
|
|
103
|
+
if (!this.lockId) {
|
|
46
104
|
return;
|
|
47
105
|
}
|
|
48
|
-
if (lockId !==
|
|
106
|
+
if (this.lockId !== lockId) {
|
|
49
107
|
throw new TransactionError('Invalid lock ID!');
|
|
50
108
|
}
|
|
51
109
|
this.lockId = undefined;
|
|
52
110
|
}
|
|
53
|
-
async updateAppLockTransaction(lockId) {
|
|
54
|
-
const isAppLocked = await this.isAppLocked(lockId);
|
|
55
|
-
if (!isAppLocked) {
|
|
56
|
-
throw new TransactionError('App is unlocked!');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
111
|
}
|
|
60
112
|
//# sourceMappingURL=test.state-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/test.state-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"test.state-provider.js","sourceRoot":"","sources":["../../../src/services/state-management/test.state-provider.ts"],"names":[],"mappings":"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"}
|