@reventlessdev/reventless-aws 3.0.0-alpha.346 → 3.0.0-alpha.348
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/CHANGELOG.md +34 -0
- package/package.json +17 -13
- package/rescript.json +2 -1
- package/run-bake-manifest.mjs +3 -0
- package/run-deploy-app.mjs +3 -0
- package/scripts/BakeManifest.res +395 -0
- package/scripts/BakeManifest.res.mjs +487 -0
- package/scripts/DeployApp.res +708 -0
- package/scripts/DeployApp.res.mjs +1015 -0
- package/scripts/DeployManifest.res +84 -0
- package/scripts/DeployManifest.res.mjs +112 -0
- package/scripts/ProvisionAccounts.res +60 -46
- package/scripts/ProvisionAccounts.res.mjs +51 -37
- package/scripts/PulumiCli.res +43 -0
- package/scripts/PulumiCli.res.mjs +106 -0
- package/src/Platform.res +19 -2
- package/src/Platform.res.mjs +12 -4
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +1 -5
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +1 -1
- package/src/adapter/Api/Platform_UIFragments_Lambda.res +1 -5
- package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -5
- package/src/adapter/Auth/Auth_ActiveRoleStore.res.mjs +1 -2
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res +1 -5
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +1 -2
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +52 -31
- package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +75 -44
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +1 -5
- package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +1 -2
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +1 -5
- package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res.mjs +1 -2
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +5 -4
- package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res.mjs +1 -1
- package/src/adapter/Postgres/PgMigration_Builder.res +1 -1
- package/src/adapter/Postgres/PgMigration_Builder.res.mjs +1 -2
- package/src/adapter/Runtime/CommandGeneratorEntryPoint_Ops.res +2 -0
- package/src/adapter/Runtime/CommandGeneratorEntryPoint_Ops.res.mjs +2 -2
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +15 -6
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +51 -30
- package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +31 -14
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +1 -5
- package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +1 -1
- package/src/adapter/StateTopic/StateTopic_AppSync.res +1 -5
- package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +1 -1
- package/src/adapter/Task/TaskBucket_S3.res +1 -3
- package/src/adapter/Task/TaskBucket_S3.res.mjs +1 -1
- package/src/adapter/Upload/Upload_Claim_S3.res +1 -5
- package/src/adapter/Upload/Upload_Claim_S3.res.mjs +1 -1
- package/src/adapter/Upload/Upload_Presign_S3.res +1 -5
- package/src/adapter/Upload/Upload_Presign_S3.res.mjs +1 -2
- package/src/capability/Capability_Geocoding_AwsLocation.res +5 -1
- package/src/capability/Capability_Geocoding_AwsLocation.res.mjs +7 -1
- package/src/components/Api/AppSync_SdlDecorate.res +4 -2
- package/src/components/Api/AppSync_SdlDecorate.res.mjs +1 -1
- package/src/plugin/cloner/ClonerRunner_Fargate.res +1 -5
- package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +1 -1
- package/src/plugin/stack/Plugin_Stack.res +4 -0
- package/src/plugin/stack/Plugin_Stack.res.mjs +2 -0
- package/src/util/Util_DeadLetterQueue.res +1 -5
- package/src/util/Util_DeadLetterQueue.res.mjs +1 -2
- package/src/util/Util_StoreLayout.res +15 -2
- package/src/util/Util_StoreLayout.res.mjs +11 -3
- package/tests/BakeManifestTest.res +204 -0
- package/tests/BakeManifestTest.res.mjs +259 -0
- package/tests/DcbColdStartPartitionTest.res +32 -0
- package/tests/DcbColdStartPartitionTest.res.mjs +33 -0
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +88 -0
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res.mjs +112 -0
- package/tests/DcbUnresolvedPartitionSlice.res +28 -0
- package/tests/DcbUnresolvedPartitionSlice.res.mjs +38 -0
- package/tests/DeployAppTest.res +90 -0
- package/tests/DeployAppTest.res.mjs +133 -0
- package/tests/LambdaLayerLookupTest.res +104 -0
- package/tests/LambdaLayerLookupTest.res.mjs +117 -0
- package/tests/ProvisionAccountsTest.res +26 -0
- package/tests/ProvisionAccountsTest.res.mjs +31 -0
- package/tests/Util_StoreLayoutTest.res +6 -0
- package/tests/Util_StoreLayoutTest.res.mjs +7 -4
- package/tests/dcbColdStartPartition.mjs +66 -0
- package/tests/setup/layerArn.cjs +5 -0
|
@@ -0,0 +1,1015 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Yaml from "yaml";
|
|
4
|
+
import * as Nodefs from "node:fs";
|
|
5
|
+
import * as Nodeurl from "node:url";
|
|
6
|
+
import * as Nodepath from "node:path";
|
|
7
|
+
import * as SSM$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/SSM.res.mjs";
|
|
8
|
+
import * as STS$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/STS.res.mjs";
|
|
9
|
+
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
10
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
11
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
12
|
+
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
13
|
+
import * as Lambda$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/Lambda.res.mjs";
|
|
14
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
15
|
+
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
16
|
+
import * as Lambda$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/Lambda/Lambda.res.mjs";
|
|
17
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
18
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
19
|
+
import * as ClientSsm from "@aws-sdk/client-ssm";
|
|
20
|
+
import * as ClientSts from "@aws-sdk/client-sts";
|
|
21
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
22
|
+
import * as ClientLambda from "@aws-sdk/client-lambda";
|
|
23
|
+
import * as BakeManifest$ReventlessAws from "./BakeManifest.res.mjs";
|
|
24
|
+
import * as AccountsManifest$Reventless from "@reventlessdev/reventless-spec/src/types/AccountsManifest.res.mjs";
|
|
25
|
+
import * as Util_AwsError$ReventlessAws from "../src/util/Util_AwsError.res.mjs";
|
|
26
|
+
import * as DeployManifest$ReventlessAws from "./DeployManifest.res.mjs";
|
|
27
|
+
import * as ProvisionAccounts$ReventlessAws from "./ProvisionAccounts.res.mjs";
|
|
28
|
+
import * as IndexJs from "@pulumi/pulumi/automation/index.js";
|
|
29
|
+
|
|
30
|
+
let defaultStack = "dev";
|
|
31
|
+
|
|
32
|
+
function parseArgs(argv) {
|
|
33
|
+
let acc = {
|
|
34
|
+
TAG: "Ok",
|
|
35
|
+
_0: {
|
|
36
|
+
command: undefined,
|
|
37
|
+
manifest: undefined,
|
|
38
|
+
stack: defaultStack,
|
|
39
|
+
help: false
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
let i = 0;
|
|
43
|
+
let count = argv.length;
|
|
44
|
+
while (i < count) {
|
|
45
|
+
let flag = argv[i];
|
|
46
|
+
let value = argv[i + 1 | 0];
|
|
47
|
+
let match = acc;
|
|
48
|
+
let exit = 0;
|
|
49
|
+
if (match.TAG === "Ok") {
|
|
50
|
+
let a = match._0;
|
|
51
|
+
let exit$1 = 0;
|
|
52
|
+
switch (flag) {
|
|
53
|
+
case "--manifest" :
|
|
54
|
+
if (value !== undefined) {
|
|
55
|
+
acc = {
|
|
56
|
+
TAG: "Ok",
|
|
57
|
+
_0: {
|
|
58
|
+
command: a.command,
|
|
59
|
+
manifest: value,
|
|
60
|
+
stack: a.stack,
|
|
61
|
+
help: a.help
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
i = i + 2 | 0;
|
|
65
|
+
} else {
|
|
66
|
+
exit = 1;
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
case "--stack" :
|
|
70
|
+
if (value !== undefined) {
|
|
71
|
+
acc = {
|
|
72
|
+
TAG: "Ok",
|
|
73
|
+
_0: {
|
|
74
|
+
command: a.command,
|
|
75
|
+
manifest: a.manifest,
|
|
76
|
+
stack: value,
|
|
77
|
+
help: a.help
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
i = i + 2 | 0;
|
|
81
|
+
} else {
|
|
82
|
+
exit = 1;
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
case "--help" :
|
|
86
|
+
case "-h" :
|
|
87
|
+
exit$1 = 2;
|
|
88
|
+
break;
|
|
89
|
+
case "down" :
|
|
90
|
+
if (a.command === undefined) {
|
|
91
|
+
acc = {
|
|
92
|
+
TAG: "Ok",
|
|
93
|
+
_0: {
|
|
94
|
+
command: "Down",
|
|
95
|
+
manifest: a.manifest,
|
|
96
|
+
stack: a.stack,
|
|
97
|
+
help: a.help
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
i = i + 1 | 0;
|
|
101
|
+
} else {
|
|
102
|
+
exit$1 = 3;
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case "up" :
|
|
106
|
+
if (a.command === undefined) {
|
|
107
|
+
acc = {
|
|
108
|
+
TAG: "Ok",
|
|
109
|
+
_0: {
|
|
110
|
+
command: "Up",
|
|
111
|
+
manifest: a.manifest,
|
|
112
|
+
stack: a.stack,
|
|
113
|
+
help: a.help
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
i = i + 1 | 0;
|
|
117
|
+
} else {
|
|
118
|
+
exit$1 = 3;
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
default:
|
|
122
|
+
exit$1 = 3;
|
|
123
|
+
}
|
|
124
|
+
switch (exit$1) {
|
|
125
|
+
case 2 :
|
|
126
|
+
acc = {
|
|
127
|
+
TAG: "Ok",
|
|
128
|
+
_0: {
|
|
129
|
+
command: a.command,
|
|
130
|
+
manifest: a.manifest,
|
|
131
|
+
stack: a.stack,
|
|
132
|
+
help: true
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
i = i + 1 | 0;
|
|
136
|
+
break;
|
|
137
|
+
case 3 :
|
|
138
|
+
acc = {
|
|
139
|
+
TAG: "Error",
|
|
140
|
+
_0: `unknown argument "` + flag + `"`
|
|
141
|
+
};
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
i = count;
|
|
146
|
+
}
|
|
147
|
+
if (exit === 1) {
|
|
148
|
+
acc = {
|
|
149
|
+
TAG: "Error",
|
|
150
|
+
_0: flag + ` needs a value`
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
return acc;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let usage = `
|
|
158
|
+
Deploy an app to AWS, or remove it again.
|
|
159
|
+
|
|
160
|
+
deploy-app up Deploy the platform and every plugin, bake the component
|
|
161
|
+
manifest, create the accounts in .reventless/users.<stack>.yaml,
|
|
162
|
+
and print the web address and the sign-ins.
|
|
163
|
+
deploy-app down Remove every stack, and the Lambda layer and SSM parameter
|
|
164
|
+
\`up\` created.
|
|
165
|
+
|
|
166
|
+
--manifest <path> The deploy manifest. Defaults to ` + DeployManifest$ReventlessAws.defaultFile + `
|
|
167
|
+
in the working directory.
|
|
168
|
+
--stack <name> The try-out stack. Defaults to "` + defaultStack + `".
|
|
169
|
+
|
|
170
|
+
Region and credentials come from the environment, as for any AWS call. Only
|
|
171
|
+
stacks declaring reventless:disposable: "true" are touched; \`up\` sets it on
|
|
172
|
+
every stack it creates.
|
|
173
|
+
`;
|
|
174
|
+
|
|
175
|
+
function projectOf(p) {
|
|
176
|
+
let file = Nodepath.join(p.dir, "Pulumi.yaml");
|
|
177
|
+
let json;
|
|
178
|
+
try {
|
|
179
|
+
json = Yaml.parse(Nodefs.readFileSync(file, "utf8"));
|
|
180
|
+
} catch (exn) {
|
|
181
|
+
json = undefined;
|
|
182
|
+
}
|
|
183
|
+
if (json === undefined) {
|
|
184
|
+
return {
|
|
185
|
+
TAG: "Error",
|
|
186
|
+
_0: file + ` cannot be read — is ` + p.dir + ` a Pulumi project?`
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
let field = name => Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(json), o => o[name]), Stdlib_JSON.Decode.string);
|
|
190
|
+
let projectName = field("name");
|
|
191
|
+
if (projectName !== undefined) {
|
|
192
|
+
return {
|
|
193
|
+
TAG: "Ok",
|
|
194
|
+
_0: {
|
|
195
|
+
label: p.name,
|
|
196
|
+
dir: p.dir,
|
|
197
|
+
projectName: projectName,
|
|
198
|
+
program: Nodepath.join(p.dir, Stdlib_Option.getOr(field("main"), "index.js")),
|
|
199
|
+
stackDefaults: p.stackDefaults
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
} else {
|
|
203
|
+
return {
|
|
204
|
+
TAG: "Error",
|
|
205
|
+
_0: file + ` names no project`
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function projectsOf(manifest) {
|
|
211
|
+
let e = projectOf(manifest.platform);
|
|
212
|
+
if (e.TAG !== "Ok") {
|
|
213
|
+
return e;
|
|
214
|
+
}
|
|
215
|
+
let plugins = manifest.plugins.map(projectOf);
|
|
216
|
+
let match = plugins.find(Stdlib_Result.isError);
|
|
217
|
+
if (match !== undefined && match.TAG !== "Ok") {
|
|
218
|
+
return {
|
|
219
|
+
TAG: "Error",
|
|
220
|
+
_0: match._0
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
TAG: "Ok",
|
|
225
|
+
_0: [
|
|
226
|
+
e._0,
|
|
227
|
+
Stdlib_Array.filterMap(plugins, r => Stdlib_Result.mapOr(r, undefined, p => p))
|
|
228
|
+
]
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function checkNode(version) {
|
|
233
|
+
let major = Stdlib_Option.flatMap(version.split(".")[0], v => Stdlib_Int.fromString(v, undefined));
|
|
234
|
+
if (major !== undefined && major >= 22) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
return `Reventless needs Node ` + (22).toString() + ` or later, and this is Node ` + version + `. Switch to the version in .node-version (for example \`fnm use\` or \`nvm use\`).`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function backendNeedsPassphrase(url, env) {
|
|
241
|
+
if (url !== undefined && !url.startsWith("https://") && env["PULUMI_CONFIG_PASSPHRASE"] === undefined) {
|
|
242
|
+
return env["PULUMI_CONFIG_PASSPHRASE_FILE"] === undefined;
|
|
243
|
+
} else {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function unbuilt(projects) {
|
|
249
|
+
return projects.filter(p => !Nodefs.existsSync(p.program));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function check(projects) {
|
|
253
|
+
let problems = [];
|
|
254
|
+
Stdlib_Option.forEach(checkNode(Stdlib_Option.getOr(process.versions["node"], "0")), p => {
|
|
255
|
+
problems.push(p);
|
|
256
|
+
});
|
|
257
|
+
let sts = STS$AwsSdk.client(undefined, undefined);
|
|
258
|
+
let region;
|
|
259
|
+
let exit = 0;
|
|
260
|
+
let region$1;
|
|
261
|
+
try {
|
|
262
|
+
region$1 = await sts.config.region();
|
|
263
|
+
exit = 1;
|
|
264
|
+
} catch (exn) {
|
|
265
|
+
problems.push("No AWS region is set. Set AWS_REGION (for example `export AWS_REGION=eu-west-1`) or give your AWS profile a region.");
|
|
266
|
+
region = undefined;
|
|
267
|
+
}
|
|
268
|
+
if (exit === 1) {
|
|
269
|
+
region = region$1;
|
|
270
|
+
}
|
|
271
|
+
let account;
|
|
272
|
+
if (region !== undefined) {
|
|
273
|
+
let exit$1 = 0;
|
|
274
|
+
let identity;
|
|
275
|
+
try {
|
|
276
|
+
identity = await STS$AwsSdk.client(region, undefined).send(new ClientSts.GetCallerIdentityCommand({}));
|
|
277
|
+
exit$1 = 1;
|
|
278
|
+
} catch (raw_exn) {
|
|
279
|
+
let exn$1 = Primitive_exceptions.internalToException(raw_exn);
|
|
280
|
+
problems.push(`The AWS credentials do not work (` + Util_AwsError$ReventlessAws.describe(exn$1) + `). Sign in — \`aws sso login\`, or set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY — and try again.`);
|
|
281
|
+
account = undefined;
|
|
282
|
+
}
|
|
283
|
+
if (exit$1 === 1) {
|
|
284
|
+
account = identity.Account;
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
account = undefined;
|
|
288
|
+
}
|
|
289
|
+
let platform = projects[0];
|
|
290
|
+
if (platform !== undefined) {
|
|
291
|
+
let exit$2 = 0;
|
|
292
|
+
let workspace;
|
|
293
|
+
try {
|
|
294
|
+
workspace = await IndexJs.LocalWorkspace.create({
|
|
295
|
+
workDir: platform.dir
|
|
296
|
+
});
|
|
297
|
+
exit$2 = 1;
|
|
298
|
+
} catch (exn$2) {
|
|
299
|
+
problems.push("The Pulumi CLI could not be run. Install it — https://www.pulumi.com/docs/iac/download-install/ — and try again.");
|
|
300
|
+
}
|
|
301
|
+
if (exit$2 === 1) {
|
|
302
|
+
let exit$3 = 0;
|
|
303
|
+
let who;
|
|
304
|
+
try {
|
|
305
|
+
who = await workspace.whoAmI();
|
|
306
|
+
exit$3 = 2;
|
|
307
|
+
} catch (exn$3) {
|
|
308
|
+
problems.push("Pulumi is not logged in. Run `pulumi login` (Pulumi Cloud) or `pulumi login --local`, and try again.");
|
|
309
|
+
}
|
|
310
|
+
if (exit$3 === 2) {
|
|
311
|
+
if (backendNeedsPassphrase(who.url, process.env)) {
|
|
312
|
+
problems.push(`Pulumi is logged in to ` + Stdlib_Option.getOr(who.url, "a self-managed backend") + `, which protects stack secrets with a passphrase. Set PULUMI_CONFIG_PASSPHRASE (an empty value is allowed) and try again.`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
unbuilt(projects).forEach(p => {
|
|
318
|
+
problems.push(p.label + ` is not built: ` + p.program + ` is missing. Run \`pnpm run build\` and try again.`);
|
|
319
|
+
});
|
|
320
|
+
if (problems.length !== 0) {
|
|
321
|
+
return {
|
|
322
|
+
TAG: "Error",
|
|
323
|
+
_0: problems
|
|
324
|
+
};
|
|
325
|
+
} else if (region !== undefined) {
|
|
326
|
+
if (account !== undefined) {
|
|
327
|
+
return {
|
|
328
|
+
TAG: "Ok",
|
|
329
|
+
_0: {
|
|
330
|
+
region: region,
|
|
331
|
+
account: account
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
} else {
|
|
335
|
+
return {
|
|
336
|
+
TAG: "Error",
|
|
337
|
+
_0: ["The AWS account could not be identified."]
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
return {
|
|
342
|
+
TAG: "Error",
|
|
343
|
+
_0: ["The AWS account could not be identified."]
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function layerName(stack) {
|
|
349
|
+
return `reventless-aws-` + stack;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
let layerDescriptionPrefix = "reventless-aws@";
|
|
353
|
+
|
|
354
|
+
function layerDescription(version) {
|
|
355
|
+
return layerDescriptionPrefix + version;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function releaseUrl(version) {
|
|
359
|
+
return `https://github.com/ReventlessDev/reventless-core/releases/download/` + encodeURIComponent("@reventlessdev/reventless-aws@" + version) + `/reventless-layer.zip`;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function installedVersion() {
|
|
363
|
+
return Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(JSON.parse(Nodefs.readFileSync(Nodepath.join(Nodepath.dirname(Nodeurl.fileURLToPath(import.meta.url)), "..", "package.json"), "utf8"))), o => o["version"]), Stdlib_JSON.Decode.string), "unknown");
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function errorName(exn) {
|
|
367
|
+
return Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), e => Stdlib_JsExn.name(e));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function storedLayerArn(ssm, parameter) {
|
|
371
|
+
let output;
|
|
372
|
+
try {
|
|
373
|
+
output = await ssm.send(new ClientSsm.GetParameterCommand({
|
|
374
|
+
Name: parameter
|
|
375
|
+
}));
|
|
376
|
+
} catch (raw_exn) {
|
|
377
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
378
|
+
if (Primitive_object.equal(errorName(exn), SSM$AwsSdk.parameterNotFound)) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
throw exn;
|
|
382
|
+
}
|
|
383
|
+
return Stdlib_Option.flatMap(output.Parameter, p => p.Value);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async function layerVersionDescription(lambda, arn) {
|
|
387
|
+
let output;
|
|
388
|
+
try {
|
|
389
|
+
output = await lambda.send(new ClientLambda.GetLayerVersionByArnCommand({
|
|
390
|
+
Arn: arn
|
|
391
|
+
}));
|
|
392
|
+
} catch (exn) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
return output.Description;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async function ensureLayer(stack, region, version) {
|
|
399
|
+
let arn = process.env["REVENTLESS_LAYER_ARN"];
|
|
400
|
+
let exit = 0;
|
|
401
|
+
if (arn !== undefined) {
|
|
402
|
+
if (arn.trim() !== "") {
|
|
403
|
+
console.log(`layer ` + arn + ` (from REVENTLESS_LAYER_ARN)`);
|
|
404
|
+
return {
|
|
405
|
+
TAG: "Ok",
|
|
406
|
+
_0: arn.trim()
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
exit = 1;
|
|
410
|
+
} else {
|
|
411
|
+
exit = 1;
|
|
412
|
+
}
|
|
413
|
+
if (exit === 1) {
|
|
414
|
+
let ssm = SSM$AwsSdk.client(region, undefined);
|
|
415
|
+
let lambda = Lambda$AwsSdk.client(region, undefined);
|
|
416
|
+
let parameter = Lambda$PulumiAws.layerParameter(stack);
|
|
417
|
+
let stored = await storedLayerArn(ssm, parameter);
|
|
418
|
+
let current = stored !== undefined && Primitive_object.equal(await layerVersionDescription(lambda, stored), layerDescriptionPrefix + version) ? stored : undefined;
|
|
419
|
+
if (current !== undefined) {
|
|
420
|
+
console.log(`layer ` + current + ` (already published for ` + version + `)`);
|
|
421
|
+
return {
|
|
422
|
+
TAG: "Ok",
|
|
423
|
+
_0: current
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
let url = releaseUrl(version);
|
|
427
|
+
console.log(`layer downloading ` + url);
|
|
428
|
+
let exit$1 = 0;
|
|
429
|
+
let response;
|
|
430
|
+
try {
|
|
431
|
+
response = await fetch(url, {});
|
|
432
|
+
exit$1 = 2;
|
|
433
|
+
} catch (raw_exn) {
|
|
434
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
435
|
+
return {
|
|
436
|
+
TAG: "Error",
|
|
437
|
+
_0: `downloading ` + url + ` failed: ` + Util_AwsError$ReventlessAws.describe(exn)
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (exit$1 === 2) {
|
|
441
|
+
if (response.status === 404) {
|
|
442
|
+
return {
|
|
443
|
+
TAG: "Error",
|
|
444
|
+
_0: `No Lambda layer was released for reventless-aws@` + version + ` — this checkout sits between two releases. Build one with \`REVENTLESS_AWS_VERSION=` + version + ` pnpm run build\` in reventless/layer-builder/, publish it, and set REVENTLESS_LAYER_ARN.`
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (!response.ok) {
|
|
448
|
+
return {
|
|
449
|
+
TAG: "Error",
|
|
450
|
+
_0: `downloading ` + url + ` failed with HTTP ` + response.status.toString()
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
let zip = new Uint8Array(await response.arrayBuffer());
|
|
454
|
+
let published = await lambda.send(new ClientLambda.PublishLayerVersionCommand({
|
|
455
|
+
LayerName: layerName(stack),
|
|
456
|
+
Description: layerDescriptionPrefix + version,
|
|
457
|
+
Content: {
|
|
458
|
+
ZipFile: zip
|
|
459
|
+
},
|
|
460
|
+
CompatibleRuntimes: [
|
|
461
|
+
"nodejs20.x",
|
|
462
|
+
"nodejs22.x"
|
|
463
|
+
]
|
|
464
|
+
}));
|
|
465
|
+
let arn$1 = published.LayerVersionArn;
|
|
466
|
+
if (arn$1 !== undefined) {
|
|
467
|
+
await ssm.send(new ClientSsm.PutParameterCommand({
|
|
468
|
+
Name: parameter,
|
|
469
|
+
Value: arn$1,
|
|
470
|
+
Type: "String",
|
|
471
|
+
Overwrite: true
|
|
472
|
+
}));
|
|
473
|
+
console.log(`layer ` + arn$1 + ` (published, stored in ` + parameter + `)`);
|
|
474
|
+
return {
|
|
475
|
+
TAG: "Ok",
|
|
476
|
+
_0: arn$1
|
|
477
|
+
};
|
|
478
|
+
} else {
|
|
479
|
+
return {
|
|
480
|
+
TAG: "Error",
|
|
481
|
+
_0: `publishing the layer ` + layerName(stack) + ` returned no ARN`
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async function removeLayer(stack, region) {
|
|
489
|
+
let lambda = Lambda$AwsSdk.client(region, undefined);
|
|
490
|
+
let ssm = SSM$AwsSdk.client(region, undefined);
|
|
491
|
+
let name = layerName(stack);
|
|
492
|
+
let versions = [];
|
|
493
|
+
let marker;
|
|
494
|
+
let more = true;
|
|
495
|
+
while (more) {
|
|
496
|
+
let exit = 0;
|
|
497
|
+
let page;
|
|
498
|
+
try {
|
|
499
|
+
page = await lambda.send(new ClientLambda.ListLayerVersionsCommand({
|
|
500
|
+
LayerName: name,
|
|
501
|
+
Marker: marker
|
|
502
|
+
}));
|
|
503
|
+
exit = 1;
|
|
504
|
+
} catch (raw_exn) {
|
|
505
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
506
|
+
if (Primitive_object.equal(errorName(exn), "ResourceNotFoundException")) {
|
|
507
|
+
more = false;
|
|
508
|
+
} else {
|
|
509
|
+
throw exn;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (exit === 1) {
|
|
513
|
+
Stdlib_Option.forEach(page.LayerVersions, page => {
|
|
514
|
+
versions.push(...page);
|
|
515
|
+
});
|
|
516
|
+
marker = page.NextMarker;
|
|
517
|
+
more = page.NextMarker !== undefined;
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
for (let index = 0, index_finish = versions.length; index < index_finish; ++index) {
|
|
521
|
+
let v = versions[index];
|
|
522
|
+
let match = v.Version;
|
|
523
|
+
let match$1 = v.Description;
|
|
524
|
+
if (match !== undefined && match$1 !== undefined && match$1.startsWith(layerDescriptionPrefix)) {
|
|
525
|
+
await lambda.send(new ClientLambda.DeleteLayerVersionCommand({
|
|
526
|
+
LayerName: name,
|
|
527
|
+
VersionNumber: match
|
|
528
|
+
}));
|
|
529
|
+
console.log(`layer removed ` + name + `:` + match.toString());
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
let parameter = Lambda$PulumiAws.layerParameter(stack);
|
|
533
|
+
let arn = await storedLayerArn(ssm, parameter);
|
|
534
|
+
if (arn !== undefined && arn.includes(`:layer:` + name + `:`)) {
|
|
535
|
+
await ssm.send(new ClientSsm.DeleteParameterCommand({
|
|
536
|
+
Name: parameter
|
|
537
|
+
}));
|
|
538
|
+
console.log(`layer removed ` + parameter);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
let disposableKey = "reventless:disposable";
|
|
544
|
+
|
|
545
|
+
async function isDisposable(stack) {
|
|
546
|
+
let val;
|
|
547
|
+
try {
|
|
548
|
+
val = await stack.getConfig(disposableKey);
|
|
549
|
+
} catch (exn) {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
return val.value === "true";
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async function existingStack(project, stack, envVars) {
|
|
556
|
+
let found;
|
|
557
|
+
try {
|
|
558
|
+
found = await IndexJs.LocalWorkspace.selectStack({
|
|
559
|
+
stackName: stack,
|
|
560
|
+
workDir: project.dir
|
|
561
|
+
}, {
|
|
562
|
+
envVars: envVars
|
|
563
|
+
});
|
|
564
|
+
} catch (exn) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
return Primitive_option.some(found);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function newStackConfig(project, region) {
|
|
571
|
+
return Object.entries(project.stackDefaults).concat([
|
|
572
|
+
[
|
|
573
|
+
"aws:region",
|
|
574
|
+
region
|
|
575
|
+
],
|
|
576
|
+
[
|
|
577
|
+
"aws-native:region",
|
|
578
|
+
region
|
|
579
|
+
],
|
|
580
|
+
[
|
|
581
|
+
disposableKey,
|
|
582
|
+
"true"
|
|
583
|
+
]
|
|
584
|
+
]);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
async function openForUp(project, stack, region, envVars, extra) {
|
|
588
|
+
let setAll = async (s, settings) => {
|
|
589
|
+
for (let index = 0, index_finish = settings.length; index < index_finish; ++index) {
|
|
590
|
+
let match = settings[index];
|
|
591
|
+
await s.setConfig(match[0], {
|
|
592
|
+
value: match[1]
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
let existing = await existingStack(project, stack, envVars);
|
|
597
|
+
if (existing !== undefined) {
|
|
598
|
+
let existing$1 = Primitive_option.valFromOption(existing);
|
|
599
|
+
if (await isDisposable(existing$1)) {
|
|
600
|
+
await setAll(existing$1, extra);
|
|
601
|
+
return {
|
|
602
|
+
TAG: "Ok",
|
|
603
|
+
_0: existing$1
|
|
604
|
+
};
|
|
605
|
+
} else {
|
|
606
|
+
return {
|
|
607
|
+
TAG: "Error",
|
|
608
|
+
_0: project.projectName + `/` + stack + ` already exists and does not declare ` + disposableKey + `: "true". deploy-app only deploys try-out stacks it created; pick another --stack.`
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
let created = await IndexJs.LocalWorkspace.createOrSelectStack({
|
|
613
|
+
stackName: stack,
|
|
614
|
+
workDir: project.dir
|
|
615
|
+
}, {
|
|
616
|
+
envVars: envVars
|
|
617
|
+
});
|
|
618
|
+
await setAll(created, newStackConfig(project, region).concat(extra));
|
|
619
|
+
console.log(`stack ` + project.projectName + `/` + stack + ` (created)`);
|
|
620
|
+
return {
|
|
621
|
+
TAG: "Ok",
|
|
622
|
+
_0: created
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function stream(text) {
|
|
627
|
+
process.stdout.write(text);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function failureDetail(exn) {
|
|
631
|
+
let message = Util_AwsError$ReventlessAws.describe(exn);
|
|
632
|
+
let errors = [];
|
|
633
|
+
message.split("\n").map(prim => prim.trim()).forEach(line => {
|
|
634
|
+
if (line.startsWith("error:") && !errors.includes(line)) {
|
|
635
|
+
errors.push(line);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
if (errors.length !== 0) {
|
|
640
|
+
return errors.join("\n");
|
|
641
|
+
} else {
|
|
642
|
+
return message;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
async function deploy(project, stack, name) {
|
|
647
|
+
console.log(`\n── Deploying ` + project.label + ` (` + project.projectName + `/` + name + `) ──\n`);
|
|
648
|
+
try {
|
|
649
|
+
await stack.up({
|
|
650
|
+
onOutput: stream
|
|
651
|
+
});
|
|
652
|
+
return {
|
|
653
|
+
TAG: "Ok",
|
|
654
|
+
_0: undefined
|
|
655
|
+
};
|
|
656
|
+
} catch (raw_exn) {
|
|
657
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
658
|
+
return {
|
|
659
|
+
TAG: "Error",
|
|
660
|
+
_0: `deploying ` + project.projectName + `/` + name + ` failed. Fix the cause and run up again; what was created is kept and reused.\n` + failureDetail(exn)
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function outputString(outputs, name) {
|
|
666
|
+
return Stdlib_Option.flatMap(outputs[name], o => Stdlib_JSON.Decode.string(o.value));
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function accountsFileName(stack) {
|
|
670
|
+
return `users.` + stack + `.yaml`;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function accountsFile(platformDir, stack) {
|
|
674
|
+
let file = Nodepath.join(platformDir, ".reventless", accountsFileName(stack));
|
|
675
|
+
let template = Nodepath.join(platformDir, AccountsManifest$Reventless.templateName);
|
|
676
|
+
let match = Nodefs.existsSync(file);
|
|
677
|
+
let match$1 = Nodefs.existsSync(template);
|
|
678
|
+
if (match) {
|
|
679
|
+
return file;
|
|
680
|
+
} else if (match$1) {
|
|
681
|
+
Nodefs.mkdirSync(Nodepath.dirname(file), {
|
|
682
|
+
recursive: true
|
|
683
|
+
});
|
|
684
|
+
Nodefs.cpSync(template, file, {});
|
|
685
|
+
console.log(`manifest ` + file + ` (new, copied from ` + template + `)`);
|
|
686
|
+
return file;
|
|
687
|
+
} else {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function signInLines(entries) {
|
|
693
|
+
let width = Stdlib_Array.reduce(entries, 0, (w, e) => Math.max(w, e.username.length));
|
|
694
|
+
return entries.map(e => ` ` + e.username.padEnd(width, " ") + ` [` + e.groups.join(", ") + `]`);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
async function up(manifest, stack) {
|
|
698
|
+
let e = projectsOf(manifest);
|
|
699
|
+
if (e.TAG !== "Ok") {
|
|
700
|
+
return e;
|
|
701
|
+
}
|
|
702
|
+
let match = e._0;
|
|
703
|
+
let plugins = match[1];
|
|
704
|
+
let platform = match[0];
|
|
705
|
+
let problems = await check([platform].concat(plugins));
|
|
706
|
+
if (problems.TAG !== "Ok") {
|
|
707
|
+
return {
|
|
708
|
+
TAG: "Error",
|
|
709
|
+
_0: `not ready to deploy:\n` + problems._0.map(p => ` - ` + p).join("\n")
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
let match$1 = problems._0;
|
|
713
|
+
let region = match$1.region;
|
|
714
|
+
console.log(`account ` + match$1.account + `, region ` + region + `, stack ` + stack);
|
|
715
|
+
let startedAt = new Date().toISOString();
|
|
716
|
+
let e$1 = await ensureLayer(stack, region, installedVersion());
|
|
717
|
+
if (e$1.TAG !== "Ok") {
|
|
718
|
+
return e$1;
|
|
719
|
+
}
|
|
720
|
+
let envVars = Object.fromEntries([[
|
|
721
|
+
"REVENTLESS_LAYER_ARN",
|
|
722
|
+
e$1._0
|
|
723
|
+
]]);
|
|
724
|
+
let e$2 = await openForUp(platform, stack, region, envVars, []);
|
|
725
|
+
if (e$2.TAG !== "Ok") {
|
|
726
|
+
return e$2;
|
|
727
|
+
}
|
|
728
|
+
let platformStack = e$2._0;
|
|
729
|
+
let e$3 = await deploy(platform, platformStack, stack);
|
|
730
|
+
if (e$3.TAG !== "Ok") {
|
|
731
|
+
return e$3;
|
|
732
|
+
}
|
|
733
|
+
let platformOutputs = await platformStack.outputs();
|
|
734
|
+
let platformRef = outputString(platformOutputs, "platformStack");
|
|
735
|
+
if (platformRef === undefined) {
|
|
736
|
+
return {
|
|
737
|
+
TAG: "Error",
|
|
738
|
+
_0: `the platform stack exports no platformStack — its reventless-aws is older than this command`
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
let deployPlugins = async index => {
|
|
742
|
+
let plugin = plugins[index];
|
|
743
|
+
if (plugin === undefined) {
|
|
744
|
+
return {
|
|
745
|
+
TAG: "Ok",
|
|
746
|
+
_0: undefined
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
let e = await openForUp(plugin, stack, region, envVars, [[
|
|
750
|
+
"platform:stack",
|
|
751
|
+
platformRef
|
|
752
|
+
]]);
|
|
753
|
+
if (e.TAG !== "Ok") {
|
|
754
|
+
return e;
|
|
755
|
+
}
|
|
756
|
+
let e$1 = await deploy(plugin, e._0, stack);
|
|
757
|
+
if (e$1.TAG === "Ok") {
|
|
758
|
+
return await deployPlugins(index + 1 | 0);
|
|
759
|
+
} else {
|
|
760
|
+
return e$1;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
let e$4 = await deployPlugins(0);
|
|
764
|
+
if (e$4.TAG !== "Ok") {
|
|
765
|
+
return e$4;
|
|
766
|
+
}
|
|
767
|
+
console.log("\n── Baking the component manifest ──\n");
|
|
768
|
+
let e$5 = await BakeManifest$ReventlessAws.bake(manifest, stack, startedAt);
|
|
769
|
+
if (e$5.TAG !== "Ok") {
|
|
770
|
+
return e$5;
|
|
771
|
+
}
|
|
772
|
+
let match$2 = accountsFile(platform.dir, stack);
|
|
773
|
+
let match$3 = outputString(platformOutputs, "identityProviderId");
|
|
774
|
+
let accounts;
|
|
775
|
+
if (match$2 !== undefined) {
|
|
776
|
+
if (match$3 !== undefined) {
|
|
777
|
+
console.log("\n── Creating the accounts ──\n");
|
|
778
|
+
let e$6 = await ProvisionAccounts$ReventlessAws.provision(match$2, match$3, undefined);
|
|
779
|
+
accounts = e$6.TAG === "Ok" ? ({
|
|
780
|
+
TAG: "Ok",
|
|
781
|
+
_0: match$2
|
|
782
|
+
}) : e$6;
|
|
783
|
+
} else {
|
|
784
|
+
accounts = {
|
|
785
|
+
TAG: "Error",
|
|
786
|
+
_0: "the platform stack exports no identityProviderId to create accounts in"
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
} else {
|
|
790
|
+
accounts = {
|
|
791
|
+
TAG: "Ok",
|
|
792
|
+
_0: undefined
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
if (accounts.TAG !== "Ok") {
|
|
796
|
+
return accounts;
|
|
797
|
+
}
|
|
798
|
+
console.log("\n── Ready ──\n");
|
|
799
|
+
let url = outputString(platformOutputs, "hostShellUrl");
|
|
800
|
+
if (url !== undefined) {
|
|
801
|
+
console.log(` Open: ` + url);
|
|
802
|
+
} else {
|
|
803
|
+
console.log(" This platform deploys no web app.");
|
|
804
|
+
}
|
|
805
|
+
Stdlib_Option.forEach(accounts._0, file => {
|
|
806
|
+
let entries = AccountsManifest$Reventless.parseFile(file);
|
|
807
|
+
if (entries.TAG !== "Ok") {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
let entries$1 = entries._0;
|
|
811
|
+
if (entries$1.length !== 0) {
|
|
812
|
+
console.log(" Sign in:");
|
|
813
|
+
signInLines(entries$1).forEach(line => {
|
|
814
|
+
console.log(line);
|
|
815
|
+
});
|
|
816
|
+
console.log(` The passwords are in ` + file + `.`);
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
console.log(` Remove it all again: deploy-app down --stack ` + stack);
|
|
821
|
+
return {
|
|
822
|
+
TAG: "Ok",
|
|
823
|
+
_0: undefined
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
async function down(manifest, stack) {
|
|
828
|
+
let e = projectsOf(manifest);
|
|
829
|
+
if (e.TAG !== "Ok") {
|
|
830
|
+
return e;
|
|
831
|
+
}
|
|
832
|
+
let match = e._0;
|
|
833
|
+
let sts = STS$AwsSdk.client(undefined, undefined);
|
|
834
|
+
let region;
|
|
835
|
+
try {
|
|
836
|
+
region = await sts.config.region();
|
|
837
|
+
} catch (exn) {
|
|
838
|
+
return {
|
|
839
|
+
TAG: "Error",
|
|
840
|
+
_0: "No AWS region is set. Set AWS_REGION and try again."
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
let envVars = {};
|
|
844
|
+
let ordered = match[1].toReversed().concat([match[0]]);
|
|
845
|
+
let found = [];
|
|
846
|
+
let refused = [];
|
|
847
|
+
for (let index = 0, index_finish = ordered.length; index < index_finish; ++index) {
|
|
848
|
+
let project = ordered[index];
|
|
849
|
+
let s = await existingStack(project, stack, envVars);
|
|
850
|
+
if (s !== undefined) {
|
|
851
|
+
let s$1 = Primitive_option.valFromOption(s);
|
|
852
|
+
if (await isDisposable(s$1)) {
|
|
853
|
+
found.push([
|
|
854
|
+
project,
|
|
855
|
+
s$1
|
|
856
|
+
]);
|
|
857
|
+
} else {
|
|
858
|
+
refused.push(project.projectName + `/` + stack);
|
|
859
|
+
}
|
|
860
|
+
} else {
|
|
861
|
+
console.log(`stack ` + project.projectName + `/` + stack + ` (not deployed)`);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (refused.length !== 0) {
|
|
865
|
+
return {
|
|
866
|
+
TAG: "Error",
|
|
867
|
+
_0: `nothing was removed: ` + refused.join(", ") + ` ` + (
|
|
868
|
+
refused.length === 1 ? "does" : "do"
|
|
869
|
+
) + ` not declare ` + disposableKey + `: "true", and deploy-app only removes try-out stacks it created.`
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
let removeStacks = async index => {
|
|
873
|
+
let match = found[index];
|
|
874
|
+
if (match === undefined) {
|
|
875
|
+
return {
|
|
876
|
+
TAG: "Ok",
|
|
877
|
+
_0: undefined
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
let s = match[1];
|
|
881
|
+
let project = match[0];
|
|
882
|
+
console.log(`\n── Removing ` + project.label + ` (` + project.projectName + `/` + stack + `) ──\n`);
|
|
883
|
+
let val;
|
|
884
|
+
try {
|
|
885
|
+
val = await s.destroy({
|
|
886
|
+
onOutput: stream
|
|
887
|
+
});
|
|
888
|
+
} catch (raw_exn) {
|
|
889
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
890
|
+
return {
|
|
891
|
+
TAG: "Error",
|
|
892
|
+
_0: `removing ` + project.projectName + `/` + stack + ` failed. Fix the cause and run down again.\n` + failureDetail(exn)
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
await s.workspace.removeStack(stack);
|
|
896
|
+
return await removeStacks(index + 1 | 0);
|
|
897
|
+
};
|
|
898
|
+
let e$1 = await removeStacks(0);
|
|
899
|
+
if (e$1.TAG !== "Ok") {
|
|
900
|
+
return e$1;
|
|
901
|
+
}
|
|
902
|
+
await removeLayer(stack, region);
|
|
903
|
+
console.log(found.length === 0 ? `\nNo stack was deployed as ` + stack + `.` : `\nRemoved ` + stack + `.`);
|
|
904
|
+
return {
|
|
905
|
+
TAG: "Ok",
|
|
906
|
+
_0: undefined
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
async function run() {
|
|
911
|
+
let e = parseArgs(process.argv.slice(2, process.argv.length));
|
|
912
|
+
if (e.TAG !== "Ok") {
|
|
913
|
+
return e;
|
|
914
|
+
}
|
|
915
|
+
let args = e._0;
|
|
916
|
+
let command = args.command;
|
|
917
|
+
if (args.help) {
|
|
918
|
+
console.log(usage);
|
|
919
|
+
return {
|
|
920
|
+
TAG: "Ok",
|
|
921
|
+
_0: undefined
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
if (command === undefined) {
|
|
925
|
+
return {
|
|
926
|
+
TAG: "Error",
|
|
927
|
+
_0: "say `up` or `down` (--help for more)"
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
let stack = args.stack;
|
|
931
|
+
let e$1 = DeployManifest$ReventlessAws.load(Stdlib_Option.getOr(args.manifest, DeployManifest$ReventlessAws.defaultFile));
|
|
932
|
+
if (e$1.TAG !== "Ok") {
|
|
933
|
+
return e$1;
|
|
934
|
+
}
|
|
935
|
+
let manifest = e$1._0;
|
|
936
|
+
if (command === "Up") {
|
|
937
|
+
return await up(manifest, stack);
|
|
938
|
+
} else {
|
|
939
|
+
return await down(manifest, stack);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
async function main() {
|
|
944
|
+
let message;
|
|
945
|
+
try {
|
|
946
|
+
message = await run();
|
|
947
|
+
} catch (raw_exn) {
|
|
948
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
949
|
+
console.error(`deploy-app: ` + Util_AwsError$ReventlessAws.describe(exn));
|
|
950
|
+
process.exit(1);
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
if (message.TAG === "Ok") {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
console.error(`deploy-app: ` + message._0);
|
|
957
|
+
process.exit(1);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
let Automation;
|
|
961
|
+
|
|
962
|
+
let Lambda;
|
|
963
|
+
|
|
964
|
+
let Ssm;
|
|
965
|
+
|
|
966
|
+
let Sts;
|
|
967
|
+
|
|
968
|
+
let Manifest;
|
|
969
|
+
|
|
970
|
+
let requiredNodeMajor = 22;
|
|
971
|
+
|
|
972
|
+
export {
|
|
973
|
+
Automation,
|
|
974
|
+
Lambda,
|
|
975
|
+
Ssm,
|
|
976
|
+
Sts,
|
|
977
|
+
Manifest,
|
|
978
|
+
defaultStack,
|
|
979
|
+
parseArgs,
|
|
980
|
+
usage,
|
|
981
|
+
projectOf,
|
|
982
|
+
projectsOf,
|
|
983
|
+
requiredNodeMajor,
|
|
984
|
+
checkNode,
|
|
985
|
+
backendNeedsPassphrase,
|
|
986
|
+
unbuilt,
|
|
987
|
+
check,
|
|
988
|
+
layerName,
|
|
989
|
+
layerDescriptionPrefix,
|
|
990
|
+
layerDescription,
|
|
991
|
+
releaseUrl,
|
|
992
|
+
installedVersion,
|
|
993
|
+
errorName,
|
|
994
|
+
storedLayerArn,
|
|
995
|
+
layerVersionDescription,
|
|
996
|
+
ensureLayer,
|
|
997
|
+
removeLayer,
|
|
998
|
+
disposableKey,
|
|
999
|
+
isDisposable,
|
|
1000
|
+
existingStack,
|
|
1001
|
+
newStackConfig,
|
|
1002
|
+
openForUp,
|
|
1003
|
+
stream,
|
|
1004
|
+
failureDetail,
|
|
1005
|
+
deploy,
|
|
1006
|
+
outputString,
|
|
1007
|
+
accountsFileName,
|
|
1008
|
+
accountsFile,
|
|
1009
|
+
signInLines,
|
|
1010
|
+
up,
|
|
1011
|
+
down,
|
|
1012
|
+
run,
|
|
1013
|
+
main,
|
|
1014
|
+
}
|
|
1015
|
+
/* yaml Not a pure module */
|