declastruct 1.7.3 → 1.9.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/dist/contract/cli/apply.js +47 -13
- package/dist/contract/cli/apply.js.map +1 -1
- package/dist/contract/cli/invoke.js +45 -5
- package/dist/contract/cli/invoke.js.map +1 -1
- package/dist/contract/cli/plan.d.ts +3 -1
- package/dist/contract/cli/plan.js +56 -17
- package/dist/contract/cli/plan.js.map +1 -1
- package/dist/domain.objects/ContextDeclastructCli.d.ts +15 -0
- package/dist/domain.objects/ContextDeclastructCli.js +3 -0
- package/dist/domain.objects/ContextDeclastructCli.js.map +1 -0
- package/dist/domain.objects/DeclastructPlan.d.ts +7 -1
- package/dist/domain.objects/DeclastructPlan.js.map +1 -1
- package/dist/domain.objects/DeclastructSnapshot.d.ts +54 -0
- package/dist/domain.objects/DeclastructSnapshot.js +15 -0
- package/dist/domain.objects/DeclastructSnapshot.js.map +1 -0
- package/dist/domain.operations/apply/applyChanges.d.ts +2 -1
- package/dist/domain.operations/apply/applyChanges.js +26 -7
- package/dist/domain.operations/apply/applyChanges.js.map +1 -1
- package/dist/domain.operations/plan/planChanges.d.ts +6 -1
- package/dist/domain.operations/plan/planChanges.js +49 -9
- package/dist/domain.operations/plan/planChanges.js.map +1 -1
- package/dist/infra/asIndentedLines.d.ts +8 -0
- package/dist/infra/asIndentedLines.js +15 -0
- package/dist/infra/asIndentedLines.js.map +1 -0
- package/dist/infra/initializeProviders.d.ts +15 -0
- package/dist/infra/initializeProviders.js +20 -0
- package/dist/infra/initializeProviders.js.map +1 -0
- package/package.json +10 -5
- package/readme.md +42 -0
|
@@ -36,6 +36,7 @@ const path_1 = require("path");
|
|
|
36
36
|
const rhachet_artifact_git_1 = require("rhachet-artifact-git");
|
|
37
37
|
const DeclastructPlan_1 = require("../../domain.objects/DeclastructPlan");
|
|
38
38
|
const applyChanges_1 = require("../../domain.operations/apply/applyChanges");
|
|
39
|
+
const initializeProviders_1 = require("../../infra/initializeProviders");
|
|
39
40
|
const log = console;
|
|
40
41
|
/**
|
|
41
42
|
* .what = executes the apply command to apply infrastructure changes
|
|
@@ -50,12 +51,16 @@ const executeApplyCommand = async (input) => {
|
|
|
50
51
|
if (isYoloMode) {
|
|
51
52
|
// yolo mode requires --wish
|
|
52
53
|
if (!input.wishFilePath)
|
|
53
|
-
throw new helpful_errors_1.BadRequestError('--wish required when --plan yolo'
|
|
54
|
+
throw new helpful_errors_1.BadRequestError('--wish required when --plan yolo', {
|
|
55
|
+
hint: 'add --wish <file> to specify the wish file',
|
|
56
|
+
});
|
|
54
57
|
}
|
|
55
58
|
else {
|
|
56
59
|
// standard mode requires --plan (not "yolo")
|
|
57
60
|
if (!input.planFilePath)
|
|
58
|
-
throw new helpful_errors_1.BadRequestError('--plan required'
|
|
61
|
+
throw new helpful_errors_1.BadRequestError('--plan required', {
|
|
62
|
+
hint: 'add --plan <file> to specify the plan file',
|
|
63
|
+
});
|
|
59
64
|
}
|
|
60
65
|
// resolve plan path (null for yolo mode)
|
|
61
66
|
const resolvedPlanPath = isYoloMode
|
|
@@ -66,7 +71,10 @@ const executeApplyCommand = async (input) => {
|
|
|
66
71
|
if (!resolvedPlanPath)
|
|
67
72
|
return null;
|
|
68
73
|
if (!(0, fs_1.existsSync)(resolvedPlanPath))
|
|
69
|
-
throw new helpful_errors_1.BadRequestError(
|
|
74
|
+
throw new helpful_errors_1.BadRequestError('plan file not found', {
|
|
75
|
+
path: resolvedPlanPath,
|
|
76
|
+
hint: 'check that the --plan path points to an extant file',
|
|
77
|
+
});
|
|
70
78
|
const planJson = await (0, promises_1.readFile)(resolvedPlanPath, 'utf-8');
|
|
71
79
|
return new DeclastructPlan_1.DeclastructPlan(JSON.parse(planJson));
|
|
72
80
|
})();
|
|
@@ -76,7 +84,10 @@ const executeApplyCommand = async (input) => {
|
|
|
76
84
|
: plan.wish.uri;
|
|
77
85
|
// validate wish file exists
|
|
78
86
|
if (!(0, fs_1.existsSync)(resolvedWishPath))
|
|
79
|
-
throw new helpful_errors_1.BadRequestError(
|
|
87
|
+
throw new helpful_errors_1.BadRequestError('wish file not found', {
|
|
88
|
+
path: resolvedWishPath,
|
|
89
|
+
hint: 'check that the wish file path is correct',
|
|
90
|
+
});
|
|
80
91
|
// get git root for relative path display
|
|
81
92
|
const gitRoot = await (0, rhachet_artifact_git_1.getGitRepoRoot)({ from: process.cwd() });
|
|
82
93
|
const relativePlanPath = resolvedPlanPath
|
|
@@ -86,27 +97,49 @@ const executeApplyCommand = async (input) => {
|
|
|
86
97
|
// log header
|
|
87
98
|
log.info('');
|
|
88
99
|
log.info('🌊 declastruct apply');
|
|
89
|
-
if (relativePlanPath)
|
|
90
|
-
log.info(` plan: ${relativePlanPath}`);
|
|
91
|
-
|
|
100
|
+
if (relativePlanPath) {
|
|
101
|
+
log.info(` ├─ plan: ${relativePlanPath}`);
|
|
102
|
+
log.info(` └─ wish: ${relativeWishPath}`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
log.info(` ├─ plan: (yolo)`);
|
|
106
|
+
log.info(` └─ wish: ${relativeWishPath}`);
|
|
107
|
+
}
|
|
92
108
|
log.info('');
|
|
109
|
+
// create cli context with passthrough args from plan
|
|
110
|
+
const cliContext = {
|
|
111
|
+
passthrough: { argv: plan?.wish.argv ?? [] },
|
|
112
|
+
};
|
|
113
|
+
// inject argv from plan so wish file sees same args as plan time
|
|
114
|
+
// this ensures staleness check compares same resources
|
|
115
|
+
process.argv = [
|
|
116
|
+
process.argv[0],
|
|
117
|
+
process.argv[1],
|
|
118
|
+
...cliContext.passthrough.argv,
|
|
119
|
+
];
|
|
93
120
|
// import wish file
|
|
94
121
|
const wish = await Promise.resolve(`${resolvedWishPath}`).then(s => __importStar(require(s)));
|
|
95
122
|
// validate exports
|
|
96
123
|
if (typeof wish.getResources !== 'function')
|
|
97
|
-
throw new helpful_errors_1.BadRequestError('
|
|
124
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getResources() function', {
|
|
125
|
+
path: resolvedWishPath,
|
|
126
|
+
hint: 'add `export const getResources = () => [...]` to the wish file',
|
|
127
|
+
});
|
|
98
128
|
if (typeof wish.getProviders !== 'function')
|
|
99
|
-
throw new helpful_errors_1.BadRequestError('
|
|
129
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getProviders() function', {
|
|
130
|
+
path: resolvedWishPath,
|
|
131
|
+
hint: 'add `export const getProviders = () => [...]` to the wish file',
|
|
132
|
+
});
|
|
100
133
|
// get resources and providers
|
|
101
134
|
const resources = await wish.getResources();
|
|
102
135
|
const providers = await wish.getProviders();
|
|
103
136
|
// initialize providers
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// create context
|
|
137
|
+
await (0, initializeProviders_1.initializeProviders)({ providers });
|
|
138
|
+
// create context with passthrough args
|
|
107
139
|
const context = {
|
|
108
140
|
bottleneck: new bottleneck_1.default({ maxConcurrent: 1 }),
|
|
109
141
|
log,
|
|
142
|
+
passthrough: cliContext.passthrough,
|
|
110
143
|
};
|
|
111
144
|
// apply changes (plan=null triggers yolo mode, skipping validation)
|
|
112
145
|
const result = await (0, applyChanges_1.applyChanges)({
|
|
@@ -120,7 +153,8 @@ const executeApplyCommand = async (input) => {
|
|
|
120
153
|
await Promise.all(providers.map((p) => p.hooks.afterAll()));
|
|
121
154
|
// log summary
|
|
122
155
|
log.info('');
|
|
123
|
-
log.info(
|
|
156
|
+
log.info('🌊 declastruct apply');
|
|
157
|
+
log.info(` └─ applied: ${result.appliedChanges.length}`);
|
|
124
158
|
log.info('');
|
|
125
159
|
};
|
|
126
160
|
exports.executeApplyCommand = executeApplyCommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/contract/cli/apply.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,4DAAoC;AACpC,2BAAgC;AAChC,0CAAuC;AACvC,mDAAiD;AACjD,+BAAyC;AACzC,+DAAsD;
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/contract/cli/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,10 +5,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.invoke = void 0;
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
8
9
|
const package_json_1 = __importDefault(require("../../../package.json"));
|
|
9
10
|
const apply_1 = require("./apply");
|
|
10
11
|
const plan_1 = require("./plan");
|
|
11
12
|
const log = console;
|
|
13
|
+
/**
|
|
14
|
+
* .what = determines exit code based on error type
|
|
15
|
+
* .why = semantic exit codes let callers know if they can retry or must fix
|
|
16
|
+
*/
|
|
17
|
+
const getExitCodeForError = (error) => {
|
|
18
|
+
if (error instanceof helpful_errors_1.BadRequestError)
|
|
19
|
+
return 2;
|
|
20
|
+
return 1;
|
|
21
|
+
};
|
|
12
22
|
/**
|
|
13
23
|
* .what = invokes CLI commands based on user input
|
|
14
24
|
* .why = provides global entry point for declastruct CLI
|
|
@@ -25,16 +35,41 @@ const invoke = async ({ args }) => {
|
|
|
25
35
|
.description('Generate a change plan from a wish file')
|
|
26
36
|
.requiredOption('--wish <file>', 'Path to wish file')
|
|
27
37
|
.requiredOption('--into <file>', 'Path to output plan file')
|
|
28
|
-
.
|
|
38
|
+
.option('--snap <file>', 'Path to output snapshot file')
|
|
39
|
+
.usage('--wish <file> --into <file> [-- <wish-args>]')
|
|
40
|
+
.allowExcessArguments(true)
|
|
41
|
+
.configureOutput({
|
|
42
|
+
writeErr: (str) => {
|
|
43
|
+
// intercept unknown option errors and add hint
|
|
44
|
+
if (str.includes('unknown option')) {
|
|
45
|
+
const match = str.match(/unknown option '([^']+)'/);
|
|
46
|
+
const flag = match?.[1] ?? '';
|
|
47
|
+
log.error(str.trim());
|
|
48
|
+
log.error(`hint: to pass args to your wish file, use: -- ${flag}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
log.error(str.trim());
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
.action(async (options, command) => {
|
|
29
56
|
try {
|
|
57
|
+
// capture args after -- separator
|
|
58
|
+
const passthroughArgs = command.args;
|
|
30
59
|
await (0, plan_1.executePlanCommand)({
|
|
31
60
|
wishFilePath: options.wish,
|
|
32
61
|
planFilePath: options.into,
|
|
62
|
+
snapFilePath: options.snap ?? null,
|
|
63
|
+
passthroughArgs,
|
|
33
64
|
});
|
|
34
65
|
}
|
|
35
66
|
catch (error) {
|
|
36
|
-
|
|
37
|
-
|
|
67
|
+
// allowlist: BadRequestError (user must fix) and Error (malfunction)
|
|
68
|
+
// rethrow anything else (non-Error thrown = unexpected)
|
|
69
|
+
if (!(error instanceof Error))
|
|
70
|
+
throw error;
|
|
71
|
+
log.error('✖ plan failed:', error);
|
|
72
|
+
process.exit(getExitCodeForError(error));
|
|
38
73
|
}
|
|
39
74
|
});
|
|
40
75
|
program
|
|
@@ -42,6 +77,7 @@ const invoke = async ({ args }) => {
|
|
|
42
77
|
.description('Apply changes from a plan file')
|
|
43
78
|
.option('--plan <file>', 'Path to plan file, or "yolo" for immediate apply')
|
|
44
79
|
.option('--wish <file>', 'Path to wish file (required when --plan yolo)')
|
|
80
|
+
.allowExcessArguments(true) // ignore passthrough args - apply uses plan's captured state
|
|
45
81
|
.action(async (options) => {
|
|
46
82
|
try {
|
|
47
83
|
await (0, apply_1.executeApplyCommand)({
|
|
@@ -50,8 +86,12 @@ const invoke = async ({ args }) => {
|
|
|
50
86
|
});
|
|
51
87
|
}
|
|
52
88
|
catch (error) {
|
|
53
|
-
|
|
54
|
-
|
|
89
|
+
// allowlist: BadRequestError (user must fix) and Error (malfunction)
|
|
90
|
+
// rethrow non-Error values (unexpected)
|
|
91
|
+
if (!(error instanceof Error))
|
|
92
|
+
throw error;
|
|
93
|
+
log.error('✖ apply failed:', error);
|
|
94
|
+
process.exit(getExitCodeForError(error));
|
|
55
95
|
}
|
|
56
96
|
});
|
|
57
97
|
await program.parseAsync(args, { from: 'user' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../../src/contract/cli/invoke.ts"],"names":[],"mappings":";;;;;;AAAA,yCAAoC;
|
|
1
|
+
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../../src/contract/cli/invoke.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* .why = provides CLI interface for planning infrastructure changes
|
|
5
5
|
* .note = requires wish file with getResources() and getProviders() exports
|
|
6
6
|
*/
|
|
7
|
-
export declare const executePlanCommand: ({ wishFilePath, planFilePath, }: {
|
|
7
|
+
export declare const executePlanCommand: ({ wishFilePath, planFilePath, snapFilePath, passthroughArgs, }: {
|
|
8
8
|
wishFilePath: string;
|
|
9
9
|
planFilePath: string;
|
|
10
|
+
snapFilePath: string | null;
|
|
11
|
+
passthroughArgs?: string[];
|
|
10
12
|
}) => Promise<void>;
|
|
@@ -35,51 +35,81 @@ const helpful_errors_1 = require("helpful-errors");
|
|
|
35
35
|
const path_1 = require("path");
|
|
36
36
|
const rhachet_artifact_git_1 = require("rhachet-artifact-git");
|
|
37
37
|
const planChanges_1 = require("../../domain.operations/plan/planChanges");
|
|
38
|
+
const initializeProviders_1 = require("../../infra/initializeProviders");
|
|
38
39
|
const log = console;
|
|
39
40
|
/**
|
|
40
41
|
* .what = executes the plan command to generate an infrastructure change plan
|
|
41
42
|
* .why = provides CLI interface for planning infrastructure changes
|
|
42
43
|
* .note = requires wish file with getResources() and getProviders() exports
|
|
43
44
|
*/
|
|
44
|
-
const executePlanCommand = async ({ wishFilePath, planFilePath, }) => {
|
|
45
|
+
const executePlanCommand = async ({ wishFilePath, planFilePath, snapFilePath, passthroughArgs = [], }) => {
|
|
45
46
|
// resolve paths
|
|
46
47
|
const resolvedWishPath = (0, path_1.resolve)(process.cwd(), wishFilePath);
|
|
47
48
|
const resolvedPlanPath = (0, path_1.resolve)(process.cwd(), planFilePath);
|
|
49
|
+
const resolvedSnapPath = snapFilePath
|
|
50
|
+
? (0, path_1.resolve)(process.cwd(), snapFilePath)
|
|
51
|
+
: null;
|
|
48
52
|
// get git root for relative path display
|
|
49
53
|
const gitRoot = await (0, rhachet_artifact_git_1.getGitRepoRoot)({ from: process.cwd() });
|
|
50
54
|
const relativeWishPath = (0, path_1.relative)(gitRoot, resolvedWishPath);
|
|
51
55
|
const relativePlanPath = (0, path_1.relative)(gitRoot, resolvedPlanPath);
|
|
56
|
+
const relativeSnapPath = resolvedSnapPath
|
|
57
|
+
? (0, path_1.relative)(gitRoot, resolvedSnapPath)
|
|
58
|
+
: null;
|
|
52
59
|
// validate wish file exists
|
|
53
60
|
if (!(0, fs_1.existsSync)(resolvedWishPath)) {
|
|
54
|
-
throw new helpful_errors_1.BadRequestError(
|
|
61
|
+
throw new helpful_errors_1.BadRequestError('wish file not found', {
|
|
62
|
+
path: resolvedWishPath,
|
|
63
|
+
hint: 'check that the --wish path points to an extant file',
|
|
64
|
+
});
|
|
55
65
|
}
|
|
56
66
|
log.info('');
|
|
57
67
|
log.info('🌊 declastruct plan');
|
|
58
|
-
log.info(` wish: ${relativeWishPath}`);
|
|
59
|
-
log.info(` plan: ${relativePlanPath}`);
|
|
68
|
+
log.info(` ├─ wish: ${relativeWishPath}`);
|
|
69
|
+
log.info(` ├─ plan: ${relativePlanPath}`);
|
|
70
|
+
if (relativeSnapPath)
|
|
71
|
+
log.info(` └─ snap: ${relativeSnapPath}`);
|
|
72
|
+
else
|
|
73
|
+
log.info(` └─ snap: (none)`);
|
|
60
74
|
log.info('');
|
|
61
|
-
//
|
|
75
|
+
// create cli context with passthrough args
|
|
76
|
+
const cliContext = {
|
|
77
|
+
passthrough: { argv: passthroughArgs },
|
|
78
|
+
};
|
|
79
|
+
// inject passthrough args into process.argv before import
|
|
80
|
+
process.argv = [
|
|
81
|
+
process.argv[0],
|
|
82
|
+
process.argv[1],
|
|
83
|
+
...cliContext.passthrough.argv,
|
|
84
|
+
];
|
|
85
|
+
// import wish file (now sees passthrough.argv in process.argv)
|
|
62
86
|
const wish = await Promise.resolve(`${resolvedWishPath}`).then(s => __importStar(require(s)));
|
|
63
87
|
// validate exports
|
|
64
88
|
if (typeof wish.getResources !== 'function') {
|
|
65
|
-
throw new helpful_errors_1.BadRequestError('
|
|
89
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getResources() function', {
|
|
90
|
+
path: resolvedWishPath,
|
|
91
|
+
hint: 'add `export const getResources = () => [...]` to the wish file',
|
|
92
|
+
});
|
|
66
93
|
}
|
|
67
94
|
if (typeof wish.getProviders !== 'function') {
|
|
68
|
-
throw new helpful_errors_1.BadRequestError('
|
|
95
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getProviders() function', {
|
|
96
|
+
path: resolvedWishPath,
|
|
97
|
+
hint: 'add `export const getProviders = () => [...]` to the wish file',
|
|
98
|
+
});
|
|
69
99
|
}
|
|
70
100
|
// get resources and providers
|
|
71
101
|
const resources = await wish.getResources();
|
|
72
102
|
const providers = await wish.getProviders();
|
|
73
103
|
// initialize providers
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// create context
|
|
104
|
+
await (0, initializeProviders_1.initializeProviders)({ providers });
|
|
105
|
+
// create context with passthrough args
|
|
77
106
|
const context = {
|
|
78
107
|
bottleneck: new bottleneck_1.default({ maxConcurrent: 1 }),
|
|
79
108
|
log,
|
|
109
|
+
passthrough: cliContext.passthrough,
|
|
80
110
|
};
|
|
81
|
-
// plan changes (
|
|
82
|
-
const plan = await (0, planChanges_1.planChanges)({
|
|
111
|
+
// plan changes (outputs emitted in real-time by planChanges)
|
|
112
|
+
const { plan, snapshot } = await (0, planChanges_1.planChanges)({
|
|
83
113
|
resources,
|
|
84
114
|
providers,
|
|
85
115
|
wishFilePath: resolvedWishPath,
|
|
@@ -89,14 +119,23 @@ const executePlanCommand = async ({ wishFilePath, planFilePath, }) => {
|
|
|
89
119
|
await (0, promises_1.mkdir)(planDir, { recursive: true });
|
|
90
120
|
// write plan to file
|
|
91
121
|
await (0, promises_1.writeFile)(resolvedPlanPath, JSON.stringify(plan, null, 2), 'utf-8');
|
|
122
|
+
// write snapshot to file if requested
|
|
123
|
+
if (resolvedSnapPath) {
|
|
124
|
+
const snapDir = (0, path_1.dirname)(resolvedSnapPath);
|
|
125
|
+
await (0, promises_1.mkdir)(snapDir, { recursive: true });
|
|
126
|
+
await (0, promises_1.writeFile)(resolvedSnapPath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
127
|
+
}
|
|
92
128
|
// cleanup providers
|
|
93
|
-
|
|
94
|
-
// log.info('✨ stop providers...');
|
|
95
|
-
await Promise.all(providers.map((p) => p.hooks.afterAll()));
|
|
129
|
+
await (0, initializeProviders_1.finalizeProviders)({ providers });
|
|
96
130
|
// log summary
|
|
97
131
|
log.info('');
|
|
98
|
-
log.info(
|
|
99
|
-
log.info(`
|
|
132
|
+
log.info('🌊 declastruct plan');
|
|
133
|
+
log.info(` ├─ resources: ${plan.changes.length}`);
|
|
134
|
+
log.info(` ├─ plan: ${relativePlanPath}`);
|
|
135
|
+
if (relativeSnapPath)
|
|
136
|
+
log.info(` └─ snap: ${relativeSnapPath}`);
|
|
137
|
+
else
|
|
138
|
+
log.info(` └─ snap: (none)`);
|
|
100
139
|
log.info('');
|
|
101
140
|
};
|
|
102
141
|
exports.executePlanCommand = executePlanCommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/contract/cli/plan.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,4DAAoC;AACpC,2BAAgC;AAChC,0CAA+C;AAC/C,mDAAiD;AACjD,+BAAkD;AAClD,+DAAsD;
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/contract/cli/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = context for CLI operations with passthrough args
|
|
3
|
+
* .why = enables wish files to receive args passed via -- separator
|
|
4
|
+
*/
|
|
5
|
+
export type ContextDeclastructCli = {
|
|
6
|
+
/**
|
|
7
|
+
* args passed through from CLI via -- separator
|
|
8
|
+
*/
|
|
9
|
+
passthrough: {
|
|
10
|
+
/**
|
|
11
|
+
* argv to inject into process.argv before wish file import
|
|
12
|
+
*/
|
|
13
|
+
argv: string[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextDeclastructCli.js","sourceRoot":"","sources":["../../src/domain.objects/ContextDeclastructCli.ts"],"names":[],"mappings":""}
|
|
@@ -19,9 +19,15 @@ export interface DeclastructPlan {
|
|
|
19
19
|
*/
|
|
20
20
|
wish: {
|
|
21
21
|
/**
|
|
22
|
-
* file path URI to the wish file
|
|
22
|
+
* file path URI to the wish file
|
|
23
23
|
*/
|
|
24
24
|
uri: string;
|
|
25
|
+
/**
|
|
26
|
+
* args passed via -- separator at plan time
|
|
27
|
+
*
|
|
28
|
+
* .why = apply must replay these to get same resources for staleness check
|
|
29
|
+
*/
|
|
30
|
+
argv: string[];
|
|
25
31
|
};
|
|
26
32
|
/**
|
|
27
33
|
* all proposed changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeclastructPlan.js","sourceRoot":"","sources":["../../src/domain.objects/DeclastructPlan.ts"],"names":[],"mappings":";;;AAAA,mDAA8C;
|
|
1
|
+
{"version":3,"file":"DeclastructPlan.js","sourceRoot":"","sources":["../../src/domain.objects/DeclastructPlan.ts"],"names":[],"mappings":";;;AAAA,mDAA8C;AA2C9C,MAAa,eACX,SAAQ,6BAA6B;;AADvC,0CAOC;AAHe,uBAAO,GAAG,CAAC,MAAM,CAAU,CAAC;AAC5B,sBAAM,GAAG,CAAC,MAAM,CAAU,CAAC;AAC3B,yBAAS,GAAG,EAAW,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DomainLiteral } from 'domain-objects';
|
|
2
|
+
import type { IsoTimestamp } from './IsoTimestamp';
|
|
3
|
+
/**
|
|
4
|
+
* .what = a single entry in a snapshot, captures state for one resource
|
|
5
|
+
* .why = enables debug and audit of what declastruct observed for each resource
|
|
6
|
+
*/
|
|
7
|
+
export interface DeclastructSnapshotEntry {
|
|
8
|
+
/**
|
|
9
|
+
* which resource this entry is for
|
|
10
|
+
*/
|
|
11
|
+
forResource: {
|
|
12
|
+
/**
|
|
13
|
+
* class name of the resource
|
|
14
|
+
*/
|
|
15
|
+
class: string;
|
|
16
|
+
/**
|
|
17
|
+
* scannable identifier of this specific resource
|
|
18
|
+
*/
|
|
19
|
+
slug: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* serialized state of the resource
|
|
23
|
+
*
|
|
24
|
+
* .note = null if the resource does not exist remotely (for remote[])
|
|
25
|
+
* .note = contains _dobj stamp from serialize()
|
|
26
|
+
*/
|
|
27
|
+
state: Record<string, any> | null;
|
|
28
|
+
}
|
|
29
|
+
export declare class DeclastructSnapshotEntry extends DomainLiteral<DeclastructSnapshotEntry> implements DeclastructSnapshotEntry {
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* .what = snapshot of remote and wished state at plan time
|
|
33
|
+
* .why = enables debug and audit of what declastruct observed before diff
|
|
34
|
+
*/
|
|
35
|
+
export interface DeclastructSnapshot {
|
|
36
|
+
/**
|
|
37
|
+
* timestamp when the snapshot was taken
|
|
38
|
+
*/
|
|
39
|
+
observedAt: IsoTimestamp;
|
|
40
|
+
/**
|
|
41
|
+
* remote state for each resource (before omitReadonly)
|
|
42
|
+
*/
|
|
43
|
+
remote: DeclastructSnapshotEntry[];
|
|
44
|
+
/**
|
|
45
|
+
* wished state for each resource (what user declared)
|
|
46
|
+
*/
|
|
47
|
+
wished: DeclastructSnapshotEntry[];
|
|
48
|
+
}
|
|
49
|
+
export declare class DeclastructSnapshot extends DomainLiteral<DeclastructSnapshot> implements DeclastructSnapshot {
|
|
50
|
+
static nested: {
|
|
51
|
+
remote: typeof DeclastructSnapshotEntry;
|
|
52
|
+
wished: typeof DeclastructSnapshotEntry;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeclastructSnapshot = exports.DeclastructSnapshotEntry = void 0;
|
|
4
|
+
const domain_objects_1 = require("domain-objects");
|
|
5
|
+
class DeclastructSnapshotEntry extends domain_objects_1.DomainLiteral {
|
|
6
|
+
}
|
|
7
|
+
exports.DeclastructSnapshotEntry = DeclastructSnapshotEntry;
|
|
8
|
+
class DeclastructSnapshot extends domain_objects_1.DomainLiteral {
|
|
9
|
+
}
|
|
10
|
+
exports.DeclastructSnapshot = DeclastructSnapshot;
|
|
11
|
+
DeclastructSnapshot.nested = {
|
|
12
|
+
remote: DeclastructSnapshotEntry,
|
|
13
|
+
wished: DeclastructSnapshotEntry,
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=DeclastructSnapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeclastructSnapshot.js","sourceRoot":"","sources":["../../src/domain.objects/DeclastructSnapshot.ts"],"names":[],"mappings":";;;AAAA,mDAA+C;AAiC/C,MAAa,wBACX,SAAQ,8BAAuC;CACT;AAFxC,4DAEwC;AAuBxC,MAAa,mBACX,SAAQ,8BAAkC;;AAD5C,kDAQC;AAJe,0BAAM,GAAG;IACrB,MAAM,EAAE,wBAAwB;IAChC,MAAM,EAAE,wBAAwB;CACjC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type DomainEntity } from 'domain-objects';
|
|
2
2
|
import type { ContextLogTrail } from 'simple-log-methods';
|
|
3
3
|
import type { ContextDeclastruct } from '../../domain.objects/ContextDeclastruct';
|
|
4
|
+
import type { ContextDeclastructCli } from '../../domain.objects/ContextDeclastructCli';
|
|
4
5
|
import { type DeclastructChange } from '../../domain.objects/DeclastructChange';
|
|
5
6
|
import type { DeclastructPlan } from '../../domain.objects/DeclastructPlan';
|
|
6
7
|
import type { DeclastructProvider } from '../../domain.objects/DeclastructProvider';
|
|
@@ -15,6 +16,6 @@ export declare const applyChanges: (input: {
|
|
|
15
16
|
plan: DeclastructPlan | null;
|
|
16
17
|
resources: DomainEntity<any>[];
|
|
17
18
|
providers: DeclastructProvider<any, any>[];
|
|
18
|
-
}, context: ContextLogTrail & ContextDeclastruct) => Promise<{
|
|
19
|
+
}, context: ContextLogTrail & ContextDeclastruct & ContextDeclastructCli) => Promise<{
|
|
19
20
|
appliedChanges: DeclastructChange[];
|
|
20
21
|
}>;
|
|
@@ -9,6 +9,25 @@ const validate_1 = require("../../domain.operations/plan/validate");
|
|
|
9
9
|
const colorizeAction_1 = require("../../infra/colorizeAction");
|
|
10
10
|
const withSpinner_1 = require("../../infra/withSpinner");
|
|
11
11
|
const applyChange_1 = require("./applyChange");
|
|
12
|
+
/**
|
|
13
|
+
* .what = checks if plan has any non-KEEP changes
|
|
14
|
+
* .why = determines whether apply phase should proceed
|
|
15
|
+
*/
|
|
16
|
+
const hasChangesToApply = (input) => {
|
|
17
|
+
return input.changes.some((change) => change.action !== DeclastructChange_1.DeclastructChangeAction.KEEP);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* .what = finds resource that matches forResource identifier
|
|
21
|
+
* .why = locates the declared resource for a planned change
|
|
22
|
+
*/
|
|
23
|
+
const getOneResourceForChange = (input) => {
|
|
24
|
+
const resourceFound = input.resources.find((candidate) => candidate.constructor.name === input.forResource.class &&
|
|
25
|
+
(0, domain_objects_1.getUniqueIdentifierSlug)(candidate) === input.forResource.slug);
|
|
26
|
+
if (!resourceFound) {
|
|
27
|
+
helpful_errors_1.UnexpectedCodePathError.throw('could not find resource specified in plan. was it removed?', { forResource: input.forResource });
|
|
28
|
+
}
|
|
29
|
+
return resourceFound;
|
|
30
|
+
};
|
|
12
31
|
/**
|
|
13
32
|
* .what = applies changes to achieve desired state
|
|
14
33
|
* .why = executes infrastructure changes in a controlled, observable manner
|
|
@@ -18,18 +37,17 @@ const applyChange_1 = require("./applyChange");
|
|
|
18
37
|
*/
|
|
19
38
|
const applyChanges = async (input, context) => {
|
|
20
39
|
// replan to get current state
|
|
21
|
-
const currentPlan = await (0, planChanges_1.planChanges)({
|
|
40
|
+
const { plan: currentPlan } = await (0, planChanges_1.planChanges)({
|
|
22
41
|
resources: input.resources,
|
|
23
42
|
providers: input.providers,
|
|
24
43
|
wishFilePath: input.plan?.wish.uri ?? 'ignorable',
|
|
25
44
|
}, context);
|
|
26
45
|
// use current plan for apply (works for both modes)
|
|
27
46
|
const planToApply = currentPlan;
|
|
28
|
-
// check if there are any actionable changes (non-KEEP)
|
|
29
|
-
const hasActionableChanges = planToApply.changes.some((change) => change.action !== DeclastructChange_1.DeclastructChangeAction.KEEP);
|
|
30
47
|
// skip apply phase if everything is in sync
|
|
31
|
-
if (!
|
|
48
|
+
if (!hasChangesToApply({ changes: planToApply.changes })) {
|
|
32
49
|
return { appliedChanges: [] };
|
|
50
|
+
}
|
|
33
51
|
// validate plan matches current state (skip if no plan provided, i.e. yolo mode)
|
|
34
52
|
if (input.plan) {
|
|
35
53
|
(0, validate_1.assertPlanStillValid)({
|
|
@@ -56,9 +74,10 @@ const applyChanges = async (input, context) => {
|
|
|
56
74
|
continue;
|
|
57
75
|
}
|
|
58
76
|
// find the desired resource
|
|
59
|
-
const resourceFound =
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
const resourceFound = getOneResourceForChange({
|
|
78
|
+
resources: input.resources,
|
|
79
|
+
forResource: change.forResource,
|
|
80
|
+
});
|
|
62
81
|
// log the action line (stays fixed)
|
|
63
82
|
const actionLabel = (0, colorizeAction_1.colorizeAction)(change.action);
|
|
64
83
|
context.log.info(`○ ${actionLabel} ${change.forResource.slug}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/apply/applyChanges.ts"],"names":[],"mappings":";;;AAAA,mDAA4E;AAC5E,mDAAyD;
|
|
1
|
+
{"version":3,"file":"applyChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/apply/applyChanges.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type DomainEntity } from 'domain-objects';
|
|
2
2
|
import type { ContextLogTrail } from 'simple-log-methods';
|
|
3
3
|
import type { ContextDeclastruct } from '../../domain.objects/ContextDeclastruct';
|
|
4
|
+
import type { ContextDeclastructCli } from '../../domain.objects/ContextDeclastructCli';
|
|
4
5
|
import { DeclastructPlan } from '../../domain.objects/DeclastructPlan';
|
|
5
6
|
import type { DeclastructProvider } from '../../domain.objects/DeclastructProvider';
|
|
7
|
+
import { DeclastructSnapshot } from '../../domain.objects/DeclastructSnapshot';
|
|
6
8
|
/**
|
|
7
9
|
* .what = generates a plan of changes required to achieve desired state
|
|
8
10
|
* .why = enables users to review infrastructure changes before applying them
|
|
@@ -12,4 +14,7 @@ export declare const planChanges: (input: {
|
|
|
12
14
|
resources: DomainEntity<any>[];
|
|
13
15
|
providers: DeclastructProvider<any, any>[];
|
|
14
16
|
wishFilePath: string;
|
|
15
|
-
}, context: ContextLogTrail & ContextDeclastruct) => Promise<
|
|
17
|
+
}, context: ContextLogTrail & ContextDeclastruct & ContextDeclastructCli) => Promise<{
|
|
18
|
+
plan: DeclastructPlan;
|
|
19
|
+
snapshot: DeclastructSnapshot;
|
|
20
|
+
}>;
|
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.planChanges = void 0;
|
|
4
4
|
const domain_objects_1 = require("domain-objects");
|
|
5
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
5
6
|
const DeclastructChange_1 = require("../../domain.objects/DeclastructChange");
|
|
6
7
|
const DeclastructPlan_1 = require("../../domain.objects/DeclastructPlan");
|
|
8
|
+
const DeclastructSnapshot_1 = require("../../domain.objects/DeclastructSnapshot");
|
|
7
9
|
const del_1 = require("../../domain.operations/del/del");
|
|
10
|
+
const asIndentedLines_1 = require("../../infra/asIndentedLines");
|
|
8
11
|
const asIsoTimestamp_1 = require("../../infra/asIsoTimestamp");
|
|
9
12
|
const colorizeAction_1 = require("../../infra/colorizeAction");
|
|
10
13
|
const withSpinner_1 = require("../../infra/withSpinner");
|
|
11
14
|
const computeChange_1 = require("./computeChange");
|
|
12
15
|
const getDaoByResource_1 = require("./getDaoByResource");
|
|
13
16
|
const hashChanges_1 = require("./hashChanges");
|
|
17
|
+
/**
|
|
18
|
+
* .what = checks if all changes are KEEP (no actions required)
|
|
19
|
+
* .why = determines whether to show "all in sync" message
|
|
20
|
+
*/
|
|
21
|
+
const isAllInSync = (input) => {
|
|
22
|
+
return input.changes.every((change) => change.action === DeclastructChange_1.DeclastructChangeAction.KEEP);
|
|
23
|
+
};
|
|
14
24
|
/**
|
|
15
25
|
* .what = generates a plan of changes required to achieve desired state
|
|
16
26
|
* .why = enables users to review infrastructure changes before applying them
|
|
@@ -24,8 +34,12 @@ const planChanges = async (input, context) => {
|
|
|
24
34
|
const bottleneck = 'onPlan' in context.bottleneck
|
|
25
35
|
? context.bottleneck.onPlan
|
|
26
36
|
: context.bottleneck;
|
|
27
|
-
//
|
|
37
|
+
// capture observation timestamp (before any API calls)
|
|
38
|
+
const observedAt = (0, asIsoTimestamp_1.asIsoTimestamp)(new Date());
|
|
39
|
+
// compute change for each resource with real-time output
|
|
28
40
|
const changes = [];
|
|
41
|
+
const snapshotRemote = [];
|
|
42
|
+
const snapshotWished = [];
|
|
29
43
|
for (const resource of input.resources) {
|
|
30
44
|
const change = await bottleneck.schedule(async () => {
|
|
31
45
|
// find DAO and provider context for this resource
|
|
@@ -45,6 +59,25 @@ const planChanges = async (input, context) => {
|
|
|
45
59
|
context.log.info(` ├─ ✔ done in ${durationSec}s`);
|
|
46
60
|
// determine desired state - null if marked for deletion
|
|
47
61
|
const desiredState = (0, del_1.isMarkedForDeletion)(resource) ? null : resource;
|
|
62
|
+
// collect snapshot entry BEFORE omitReadonly (for debug and audit)
|
|
63
|
+
const forResource = {
|
|
64
|
+
class: resource.constructor.name,
|
|
65
|
+
slug: helpful_errors_1.UnexpectedCodePathError.wrap(() => (0, domain_objects_1.getUniqueIdentifierSlug)(resource), {
|
|
66
|
+
message: 'failed to getUniqueIdentifierSlug for snapshot',
|
|
67
|
+
metadata: {
|
|
68
|
+
resource,
|
|
69
|
+
ctor: resource.constructor.name,
|
|
70
|
+
},
|
|
71
|
+
})(),
|
|
72
|
+
};
|
|
73
|
+
snapshotRemote.push(new DeclastructSnapshot_1.DeclastructSnapshotEntry({
|
|
74
|
+
forResource,
|
|
75
|
+
state: remoteState ? JSON.parse((0, domain_objects_1.serialize)(remoteState)) : null,
|
|
76
|
+
}));
|
|
77
|
+
snapshotWished.push(new DeclastructSnapshot_1.DeclastructSnapshotEntry({
|
|
78
|
+
forResource,
|
|
79
|
+
state: JSON.parse((0, domain_objects_1.serialize)(resource)), // always the declared resource, not desiredState
|
|
80
|
+
}));
|
|
48
81
|
// compute change
|
|
49
82
|
const computed = (0, computeChange_1.computeChange)({
|
|
50
83
|
desired: desiredState,
|
|
@@ -60,10 +93,10 @@ const planChanges = async (input, context) => {
|
|
|
60
93
|
context.log.info(` └─ decision ${(0, colorizeAction_1.colorizeAction)(computed.action)}`);
|
|
61
94
|
// and the diff too, indented to align with tree
|
|
62
95
|
if (computed.state.difference) {
|
|
63
|
-
const indentedDiff =
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
const indentedDiff = (0, asIndentedLines_1.asIndentedLines)({
|
|
97
|
+
text: computed.state.difference,
|
|
98
|
+
indent: ' ',
|
|
99
|
+
});
|
|
67
100
|
context.log.info(indentedDiff);
|
|
68
101
|
}
|
|
69
102
|
context.log.info('');
|
|
@@ -73,20 +106,27 @@ const planChanges = async (input, context) => {
|
|
|
73
106
|
changes.push(change);
|
|
74
107
|
}
|
|
75
108
|
// log success message if everything is in sync
|
|
76
|
-
|
|
77
|
-
if (allInSync) {
|
|
109
|
+
if (isAllInSync({ changes })) {
|
|
78
110
|
context.log.info('');
|
|
79
111
|
context.log.info('🎉 everything is in sync!');
|
|
80
112
|
}
|
|
81
|
-
//
|
|
82
|
-
|
|
113
|
+
// build plan
|
|
114
|
+
const plan = new DeclastructPlan_1.DeclastructPlan({
|
|
83
115
|
hash: (0, hashChanges_1.hashChanges)(changes),
|
|
84
116
|
createdAt: (0, asIsoTimestamp_1.asIsoTimestamp)(new Date()),
|
|
85
117
|
wish: {
|
|
86
118
|
uri: input.wishFilePath,
|
|
119
|
+
argv: context.passthrough.argv,
|
|
87
120
|
},
|
|
88
121
|
changes,
|
|
89
122
|
});
|
|
123
|
+
// build snapshot
|
|
124
|
+
const snapshot = new DeclastructSnapshot_1.DeclastructSnapshot({
|
|
125
|
+
observedAt,
|
|
126
|
+
remote: snapshotRemote,
|
|
127
|
+
wished: snapshotWished,
|
|
128
|
+
});
|
|
129
|
+
return { plan, snapshot };
|
|
90
130
|
};
|
|
91
131
|
exports.planChanges = planChanges;
|
|
92
132
|
//# sourceMappingURL=planChanges.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/planChanges.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"planChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/planChanges.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asIndentedLines = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = indents each line of text with specified prefix
|
|
6
|
+
* .why = formats multi-line text to align with tree structure in logs
|
|
7
|
+
*/
|
|
8
|
+
const asIndentedLines = (input) => {
|
|
9
|
+
return input.text
|
|
10
|
+
.split('\n')
|
|
11
|
+
.map((line) => `${input.indent}${line}`)
|
|
12
|
+
.join('\n');
|
|
13
|
+
};
|
|
14
|
+
exports.asIndentedLines = asIndentedLines;
|
|
15
|
+
//# sourceMappingURL=asIndentedLines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asIndentedLines.js","sourceRoot":"","sources":["../../src/infra/asIndentedLines.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACI,MAAM,eAAe,GAAG,CAAC,KAG/B,EAAU,EAAE;IACX,OAAO,KAAK,CAAC,IAAI;SACd,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;SACvC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC,CAAC;AARW,QAAA,eAAe,mBAQ1B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DeclastructProvider } from '../domain.objects/DeclastructProvider';
|
|
2
|
+
/**
|
|
3
|
+
* .what = initializes all providers via their beforeAll hooks
|
|
4
|
+
* .why = providers may need to establish connections or state before use
|
|
5
|
+
*/
|
|
6
|
+
export declare const initializeProviders: (input: {
|
|
7
|
+
providers: DeclastructProvider<any, any>[];
|
|
8
|
+
}) => Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* .what = finalizes all providers via their afterAll hooks
|
|
11
|
+
* .why = providers may need to close connections or cleanup state after use
|
|
12
|
+
*/
|
|
13
|
+
export declare const finalizeProviders: (input: {
|
|
14
|
+
providers: DeclastructProvider<any, any>[];
|
|
15
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.finalizeProviders = exports.initializeProviders = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = initializes all providers via their beforeAll hooks
|
|
6
|
+
* .why = providers may need to establish connections or state before use
|
|
7
|
+
*/
|
|
8
|
+
const initializeProviders = async (input) => {
|
|
9
|
+
await Promise.all(input.providers.map((p) => p.hooks.beforeAll()));
|
|
10
|
+
};
|
|
11
|
+
exports.initializeProviders = initializeProviders;
|
|
12
|
+
/**
|
|
13
|
+
* .what = finalizes all providers via their afterAll hooks
|
|
14
|
+
* .why = providers may need to close connections or cleanup state after use
|
|
15
|
+
*/
|
|
16
|
+
const finalizeProviders = async (input) => {
|
|
17
|
+
await Promise.all(input.providers.map((p) => p.hooks.afterAll()));
|
|
18
|
+
};
|
|
19
|
+
exports.finalizeProviders = finalizeProviders;
|
|
20
|
+
//# sourceMappingURL=initializeProviders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initializeProviders.js","sourceRoot":"","sources":["../../src/infra/initializeProviders.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACI,MAAM,mBAAmB,GAAG,KAAK,EAAE,KAEzC,EAAiB,EAAE;IAClB,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC,CAAC;AAJW,QAAA,mBAAmB,uBAI9B;AAEF;;;GAGG;AACI,MAAM,iBAAiB,GAAG,KAAK,EAAE,KAEvC,EAAiB,EAAE;IAClB,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC;AAJW,QAAA,iBAAiB,qBAI5B"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "declastruct",
|
|
3
3
|
"author": "ehmpathy",
|
|
4
4
|
"description": "Add declarative control to any resource constructs. Declare, plan, and apply within an observable pit-of-success.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.9.0",
|
|
6
6
|
"repository": "ehmpathy/declastruct",
|
|
7
7
|
"homepage": "https://github.com/ehmpathy/declastruct",
|
|
8
8
|
"keywords": [
|
|
@@ -53,7 +53,8 @@
|
|
|
53
53
|
"preversion": "npm run prepush",
|
|
54
54
|
"postversion": "git push origin HEAD --tags --no-verify",
|
|
55
55
|
"prepare:husky": "npx husky install && chmod ug+x .husky/*",
|
|
56
|
-
"prepare": "[ -e .git ] && npm run prepare:husky || exit 0"
|
|
56
|
+
"prepare": "[ -e .git ] && npm run prepare:husky || exit 0 && npm run prepare:rhachet",
|
|
57
|
+
"prepare:rhachet": "npm run build && rhachet init --hooks --roles mechanic behaver driver reviewer librarian ergonomist architect reflector dreamer dispatcher"
|
|
57
58
|
},
|
|
58
59
|
"dependencies": {
|
|
59
60
|
"bottleneck": "2.19.5",
|
|
@@ -84,14 +85,18 @@
|
|
|
84
85
|
"cz-conventional-changelog": "3.3.0",
|
|
85
86
|
"declapract": "^0.13.1",
|
|
86
87
|
"declapract-typescript-ehmpathy": "0.45.3",
|
|
87
|
-
"declastruct": "
|
|
88
|
+
"declastruct": "link:.",
|
|
88
89
|
"declastruct-github": "1.0.7",
|
|
89
90
|
"depcheck": "1.4.3",
|
|
90
91
|
"esbuild-register": "3.6.0",
|
|
91
92
|
"husky": "8.0.3",
|
|
92
93
|
"jest": "30.2.0",
|
|
93
|
-
"rhachet": "1.
|
|
94
|
-
"rhachet-
|
|
94
|
+
"rhachet": "1.39.13",
|
|
95
|
+
"rhachet-brains-anthropic": "0.4.0",
|
|
96
|
+
"rhachet-brains-xai": "0.3.3",
|
|
97
|
+
"rhachet-roles-bhrain": "0.24.1",
|
|
98
|
+
"rhachet-roles-bhuild": "0.17.2",
|
|
99
|
+
"rhachet-roles-ehmpathy": "1.34.28",
|
|
95
100
|
"test-fns": "1.7.2",
|
|
96
101
|
"tsc-alias": "1.8.10",
|
|
97
102
|
"tsx": "4.20.6",
|
package/readme.md
CHANGED
|
@@ -120,6 +120,48 @@ planned changes:
|
|
|
120
120
|
+ metadata: { source: "app-web" }
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
+
#### pass args to your wish file
|
|
124
|
+
|
|
125
|
+
pass args to your wish file via `--` separator:
|
|
126
|
+
|
|
127
|
+
```sh
|
|
128
|
+
npx declastruct plan \
|
|
129
|
+
--wish provision/resources.ts \
|
|
130
|
+
--into provision/.temp/plan.json \
|
|
131
|
+
-- --env prod --region us-west-2
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
args after `--` are injected into `process.argv` before the wish file loads. parse them with node's `parseArgs`:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { parseArgs } from 'util';
|
|
138
|
+
|
|
139
|
+
const { values } = parseArgs({
|
|
140
|
+
args: process.argv.slice(2),
|
|
141
|
+
options: {
|
|
142
|
+
env: { type: 'string', default: 'test' },
|
|
143
|
+
region: { type: 'string', default: 'us-east-1' },
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
export const getResources = async () => {
|
|
148
|
+
// use values.env, values.region to configure resources
|
|
149
|
+
return [
|
|
150
|
+
DeclaredAwsS3Bucket.as({
|
|
151
|
+
name: `app-${values.env}-assets`,
|
|
152
|
+
region: values.region,
|
|
153
|
+
}),
|
|
154
|
+
];
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**typo safety:** unknown flags without `--` trigger an error with guidance:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
error: unknown option '--env'
|
|
162
|
+
hint: to pass args to your wish file, use: -- --env
|
|
163
|
+
```
|
|
164
|
+
|
|
123
165
|
### 3. **apply** the plan 🪄
|
|
124
166
|
|
|
125
167
|
apply the plan to make your wish come true
|