@quadnix/octo 0.1.0 → 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/README.md +108 -21
- package/dist/app.type.d.ts +141 -22
- package/dist/app.type.js.map +1 -1
- package/dist/decorators/model.decorator.d.ts +3 -5
- package/dist/decorators/model.decorator.js +1 -6
- package/dist/decorators/model.decorator.js.map +1 -1
- package/dist/decorators/on-event.decorator.d.ts +2 -2
- 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/errors/schema.error.d.ts +8 -1
- package/dist/errors/schema.error.js +5 -1
- package/dist/errors/schema.error.js.map +1 -1
- package/dist/errors/terraform.error.d.ts +4 -3
- package/dist/errors/terraform.error.js +4 -3
- package/dist/errors/terraform.error.js.map +1 -1
- package/dist/errors/transaction.error.d.ts +32 -2
- package/dist/errors/transaction.error.js +22 -0
- package/dist/errors/transaction.error.js.map +1 -1
- package/dist/events/action.event.d.ts +8 -2
- package/dist/events/action.event.js +2 -2
- 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 +7 -5
- package/dist/events/event.model.js +5 -3
- package/dist/events/event.model.js.map +1 -1
- package/dist/events/hook/commit.hook.event.d.ts +1 -1
- package/dist/events/hook/commit.hook.event.js.map +1 -1
- package/dist/events/hook/hook.event.d.ts +1 -1
- package/dist/events/hook/hook.event.js.map +1 -1
- package/dist/events/hook/model.hook.event.d.ts +1 -1
- package/dist/events/hook/model.hook.event.js.map +1 -1
- package/dist/events/hook/resource.hook.event.d.ts +1 -1
- package/dist/events/hook/resource.hook.event.js.map +1 -1
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/mode-result.event.d.ts +1 -1
- package/dist/events/mode-result.event.js.map +1 -1
- package/dist/events/mode.event.d.ts +8 -4
- package/dist/events/mode.event.js.map +1 -1
- package/dist/events/module.event.d.ts +7 -3
- package/dist/events/module.event.js +3 -2
- package/dist/events/module.event.js.map +1 -1
- package/dist/events/registration.event.d.ts +1 -1
- package/dist/events/registration.event.js.map +1 -1
- package/dist/events/serialization.event.d.ts +1 -1
- 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 +37 -1
- package/dist/events/terraform.event.js +24 -0
- package/dist/events/terraform.event.js.map +1 -1
- package/dist/events/transaction.event.d.ts +3 -3
- package/dist/events/transaction.event.js +1 -1
- package/dist/events/transaction.event.js.map +1 -1
- package/dist/functions/container/container.js +1 -1
- package/dist/functions/container/container.js.map +1 -1
- package/dist/functions/container/test-container.js +2 -2
- package/dist/functions/container/test-container.js.map +1 -1
- package/dist/functions/dependency/dependency.d.ts +9 -22
- package/dist/functions/dependency/dependency.js +5 -1
- package/dist/functions/dependency/dependency.js.map +1 -1
- package/dist/functions/diff/diff.d.ts +14 -7
- package/dist/functions/diff/diff.js.map +1 -1
- package/dist/functions/node/node-action.abstract.d.ts +8 -10
- package/dist/functions/node/node-action.abstract.js +10 -16
- package/dist/functions/node/node-action.abstract.js.map +1 -1
- package/dist/functions/node/node.abstract.js +21 -10
- package/dist/functions/node/node.abstract.js.map +1 -1
- package/dist/functions/node/node.interface.d.ts +2 -1
- package/dist/functions/schema/schema.js +1 -1
- package/dist/functions/schema/schema.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +6 -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 +4 -3
- package/dist/main.js +27 -11
- package/dist/main.js.map +1 -1
- package/dist/models/account/account.model.d.ts +6 -0
- package/dist/models/account/account.model.js +16 -0
- package/dist/models/account/account.model.js.map +1 -1
- package/dist/models/app/app.model.d.ts +0 -10
- package/dist/models/app/app.model.js +0 -30
- package/dist/models/app/app.model.js.map +1 -1
- package/dist/models/deployment/deployment.schema.d.ts +4 -0
- package/dist/models/deployment/deployment.schema.js +4 -0
- package/dist/models/deployment/deployment.schema.js.map +1 -1
- package/dist/models/environment/environment.model.d.ts +2 -2
- package/dist/models/environment/environment.model.js +2 -2
- package/dist/models/execution/execution.model.d.ts +1 -1
- package/dist/models/execution/execution.model.js +1 -1
- package/dist/models/image/image.model.d.ts +4 -3
- package/dist/models/image/image.model.js +7 -6
- package/dist/models/image/image.model.js.map +1 -1
- package/dist/models/model.abstract.js +1 -1
- package/dist/models/model.abstract.js.map +1 -1
- package/dist/models/pipeline/pipeline.model.d.ts +1 -1
- package/dist/models/pipeline/pipeline.model.js +1 -1
- package/dist/models/server/server.model.d.ts +2 -2
- package/dist/models/server/server.model.js +2 -2
- package/dist/models/service/service.model.d.ts +28 -11
- package/dist/models/service/service.model.js +56 -16
- package/dist/models/service/service.model.js.map +1 -1
- package/dist/models/service/service.schema.d.ts +46 -2
- package/dist/models/service/service.schema.js +54 -2
- package/dist/models/service/service.schema.js.map +1 -1
- package/dist/modes/commit.mode.d.ts +2 -2
- package/dist/modes/commit.mode.js +2 -2
- package/dist/modes/generate.mode.d.ts +2 -1
- package/dist/modes/generate.mode.js +3 -2
- package/dist/modes/generate.mode.js.map +1 -1
- package/dist/modes/run-action.mode.d.ts +1 -1
- package/dist/modes/run-action.mode.js +1 -1
- package/dist/modes/validate.mode.d.ts +24 -0
- package/dist/modes/validate.mode.js +89 -11
- package/dist/modes/validate.mode.js.map +1 -1
- package/dist/modules/module.container.d.ts +7 -1
- package/dist/modules/module.container.js +41 -5
- package/dist/modules/module.container.js.map +1 -1
- package/dist/modules/test-module.container.js +35 -83
- package/dist/modules/test-module.container.js.map +1 -1
- package/dist/overlays/overlay.abstract.js +1 -1
- package/dist/overlays/overlay.abstract.js.map +1 -1
- package/dist/resources/resource-action.interface.d.ts +4 -2
- package/dist/resources/resource.abstract.d.ts +50 -8
- package/dist/resources/resource.abstract.js +63 -32
- 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 +11 -1
- package/dist/resources/resource.schema.js +11 -1
- package/dist/resources/resource.schema.js.map +1 -1
- package/dist/services/event/event.service.d.ts +2 -2
- package/dist/services/event/event.service.js.map +1 -1
- package/dist/services/input/input.service.d.ts +30 -2
- package/dist/services/input/input.service.js +71 -4
- package/dist/services/input/input.service.js.map +1 -1
- package/dist/services/serialization/model/model-serialization.service.d.ts +4 -6
- package/dist/services/serialization/model/model-serialization.service.js +20 -17
- package/dist/services/serialization/model/model-serialization.service.js.map +1 -1
- package/dist/services/serialization/resource/resource-serialization.service.d.ts +7 -6
- package/dist/services/serialization/resource/resource-serialization.service.js +25 -12
- package/dist/services/serialization/resource/resource-serialization.service.js.map +1 -1
- package/dist/services/state-management/local.state-provider.d.ts +25 -9
- package/dist/services/state-management/local.state-provider.js +127 -21
- 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 +83 -40
- package/dist/services/state-management/state-management.service.js +130 -26
- package/dist/services/state-management/state-management.service.js.map +1 -1
- package/dist/services/state-management/state-provider.interface.d.ts +50 -9
- 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 +32 -9
- package/dist/services/state-management/terraform-state.service.js +64 -21
- package/dist/services/state-management/terraform-state.service.js.map +1 -1
- package/dist/services/state-management/test.state-provider.d.ts +11 -10
- package/dist/services/state-management/test.state-provider.js +35 -14
- package/dist/services/state-management/test.state-provider.js.map +1 -1
- package/dist/services/terraform/terraform.service.d.ts +57 -3
- package/dist/services/terraform/terraform.service.js +95 -8
- package/dist/services/terraform/terraform.service.js.map +1 -1
- package/dist/services/terraform/terraform.type.js +1 -1
- package/dist/services/terraform/terraform.type.js.map +1 -1
- package/dist/services/transaction/transaction.service.d.ts +29 -5
- package/dist/services/transaction/transaction.service.js +198 -34
- package/dist/services/transaction/transaction.service.js.map +1 -1
- package/dist/services/validation/validation.service.d.ts +2 -2
- package/dist/{functions → utilities}/diff/diff.utility.d.ts +2 -1
- package/dist/{functions → utilities}/diff/diff.utility.js +4 -3
- package/dist/utilities/diff/diff.utility.js.map +1 -0
- package/dist/utilities/file/file.utility.d.ts +6 -7
- package/dist/utilities/file/file.utility.js +13 -68
- package/dist/utilities/file/file.utility.js.map +1 -1
- package/dist/utilities/hcl/hcl.utility.d.ts +83 -16
- package/dist/utilities/hcl/hcl.utility.js +200 -27
- package/dist/utilities/hcl/hcl.utility.js.map +1 -1
- 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/string/string.utility.d.ts +23 -3
- package/dist/utilities/string/string.utility.js +29 -3
- package/dist/utilities/string/string.utility.js.map +1 -1
- package/dist/utilities/terraform/terraform.utility.d.ts +70 -21
- package/dist/utilities/terraform/terraform.utility.js +255 -66
- package/dist/utilities/terraform/terraform.utility.js.map +1 -1
- package/dist/utilities/test-helpers/test-classes.d.ts +19 -0
- package/dist/utilities/test-helpers/test-classes.js +22 -0
- 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 +25 -12
- package/dist/utilities/test-helpers/test-models.js.map +1 -1
- package/dist/utilities/test-helpers/test-modes.d.ts +1 -1
- package/dist/utilities/test-helpers/test-modes.js +36 -13
- package/dist/utilities/test-helpers/test-modes.js.map +1 -1
- package/dist/utilities/test-helpers/test-modules.d.ts +6 -0
- package/dist/utilities/test-helpers/test-modules.js +6 -0
- package/dist/utilities/test-helpers/test-modules.js.map +1 -1
- package/dist/utilities/test-helpers/test-overlays.d.ts +3 -1
- package/dist/utilities/test-helpers/test-overlays.js +8 -2
- package/dist/utilities/test-helpers/test-overlays.js.map +1 -1
- package/dist/utilities/test-helpers/test-resources.d.ts +4 -2
- package/dist/utilities/test-helpers/test-resources.js +22 -20
- package/dist/utilities/test-helpers/test-resources.js.map +1 -1
- package/package.json +7 -2
- package/dist/functions/diff/diff.utility.js.map +0 -1
- package/dist/services/state-management/file-app-lock.utility.d.ts +0 -43
- package/dist/services/state-management/file-app-lock.utility.js +0 -124
- package/dist/services/state-management/file-app-lock.utility.js.map +0 -1
- package/dist/services/state-management/local-encryption.state-provider.d.ts +0 -71
- package/dist/services/state-management/local-encryption.state-provider.js +0 -116
- package/dist/services/state-management/local-encryption.state-provider.js.map +0 -1
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The app lock, kept as a file on disk. Shared by the state providers that keep state in a directory.
|
|
3
|
-
*
|
|
4
|
-
* The lock is taken with an exclusive create, which the filesystem resolves atomically: of two
|
|
5
|
-
* processes racing for the same path, exactly one succeeds. Reading first and writing second would
|
|
6
|
-
* let both believe they hold it.
|
|
7
|
-
*
|
|
8
|
-
* The lock never expires, so a run that died holding one leaves it held until a person releases it
|
|
9
|
-
* with `octo unlock --force`. That decision turns on whether the holder is still working, so the
|
|
10
|
-
* record carries the time it was taken and a blocked run is told how long it has been held.
|
|
11
|
-
*
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
14
|
-
export declare class FileAppLockUtility {
|
|
15
|
-
/**
|
|
16
|
-
* @internal
|
|
17
|
-
*/
|
|
18
|
-
static getAppLock(lockFilePath: string): Promise<string | undefined>;
|
|
19
|
-
/**
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
static isAppLocked(lockFilePath: string, lockId: string): Promise<boolean>;
|
|
23
|
-
/**
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
static lockApp(lockFilePath: string): Promise<{
|
|
27
|
-
lockId: string;
|
|
28
|
-
}>;
|
|
29
|
-
/**
|
|
30
|
-
* @internal
|
|
31
|
-
*/
|
|
32
|
-
static unlockApp(lockFilePath: string, lockId: string): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* How long the lock has been held, as a short readable span. Undefined when the recorded time
|
|
35
|
-
* cannot be read as one, so a broken value is left out rather than reported as a negative age.
|
|
36
|
-
*/
|
|
37
|
-
private static describeAge;
|
|
38
|
-
/**
|
|
39
|
-
* The lock file's record, or undefined when no lock is held. A file holding an id and nothing else
|
|
40
|
-
* is a lock taken before the record carried a time, and reads as that id with no age.
|
|
41
|
-
*/
|
|
42
|
-
private static readLock;
|
|
43
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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,71 +0,0 @@
|
|
|
1
|
-
import type { IStateProvider } from './state-provider.interface.js';
|
|
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
|
-
*
|
|
13
|
-
* @group Services/State Management
|
|
14
|
-
*
|
|
15
|
-
* @see Techniques for [State Providers](/docs/techniques/state-providers).
|
|
16
|
-
*/
|
|
17
|
-
export declare class LocalEncryptionStateProvider implements IStateProvider {
|
|
18
|
-
private readonly encryptionKey;
|
|
19
|
-
private readonly localStateDirectoryPath;
|
|
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
|
-
*/
|
|
26
|
-
constructor(localStateDirectoryPath: string, encryptionKey: string);
|
|
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
|
-
*/
|
|
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
|
-
*/
|
|
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
|
-
*/
|
|
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
|
-
*/
|
|
58
|
-
lockApp(): Promise<{
|
|
59
|
-
lockId: string;
|
|
60
|
-
}>;
|
|
61
|
-
/**
|
|
62
|
-
* Writes a state file, overwriting whatever was there.
|
|
63
|
-
*/
|
|
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
|
-
*/
|
|
70
|
-
unlockApp(lockId: string): Promise<void>;
|
|
71
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { readdir, rm } from 'fs/promises';
|
|
2
|
-
import { join, resolve } from 'path';
|
|
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';
|
|
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
|
-
*
|
|
17
|
-
* @group Services/State Management
|
|
18
|
-
*
|
|
19
|
-
* @see Techniques for [State Providers](/docs/techniques/state-providers).
|
|
20
|
-
*/
|
|
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
|
-
*/
|
|
27
|
-
constructor(localStateDirectoryPath, encryptionKey) {
|
|
28
|
-
if (encryptionKey.length < 3) {
|
|
29
|
-
throw new TransactionError('Selected encryption key is too weak!');
|
|
30
|
-
}
|
|
31
|
-
this.encryptionKey = encryptionKey;
|
|
32
|
-
this.localStateDirectoryPath = resolve(localStateDirectoryPath);
|
|
33
|
-
this.lockFilePath = join(this.localStateDirectoryPath, 'local-state.lock');
|
|
34
|
-
}
|
|
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 });
|
|
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
|
-
*/
|
|
45
|
-
async getAppLock() {
|
|
46
|
-
return FileAppLockUtility.getAppLock(this.lockFilePath);
|
|
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
|
-
*/
|
|
53
|
-
async getState(stateFileName) {
|
|
54
|
-
try {
|
|
55
|
-
return await FileUtility.decryptFileToBuffer(join(this.localStateDirectoryPath, stateFileName + '.enc'), this.encryptionKey);
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
if (error.code === 'ENOENT') {
|
|
59
|
-
throw new TransactionError('No state found!');
|
|
60
|
-
}
|
|
61
|
-
throw error;
|
|
62
|
-
}
|
|
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
|
-
*/
|
|
69
|
-
async isAppLocked(lockId) {
|
|
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);
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
if (error.code === 'ENOENT') {
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
85
|
-
throw error;
|
|
86
|
-
}
|
|
87
|
-
return entries
|
|
88
|
-
.filter((entry) => entry.endsWith('.enc') && entry.startsWith(prefix))
|
|
89
|
-
.map((entry) => entry.slice(0, -'.enc'.length));
|
|
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
|
-
*/
|
|
96
|
-
async lockApp() {
|
|
97
|
-
await FileUtility.ensureDirectory(this.localStateDirectoryPath);
|
|
98
|
-
return FileAppLockUtility.lockApp(this.lockFilePath);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Writes a state file, overwriting whatever was there.
|
|
102
|
-
*/
|
|
103
|
-
async saveState(stateFileName, data) {
|
|
104
|
-
await FileUtility.ensureDirectory(this.localStateDirectoryPath);
|
|
105
|
-
await FileUtility.encryptBufferToFile(data, join(this.localStateDirectoryPath, stateFileName + '.enc'), this.encryptionKey);
|
|
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
|
-
*/
|
|
112
|
-
async unlockApp(lockId) {
|
|
113
|
-
return FileAppLockUtility.unlockApp(this.lockFilePath, lockId);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
//# sourceMappingURL=local-encryption.state-provider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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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"}
|