@reventlessdev/reventless-aws 3.0.0-alpha.345 → 3.0.0-alpha.347

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/package.json +19 -12
  3. package/rescript.json +2 -1
  4. package/run-bake-manifest.mjs +3 -0
  5. package/run-deploy-app.mjs +3 -0
  6. package/run-provision-accounts.mjs +3 -0
  7. package/run-provision-admin.mjs +3 -0
  8. package/scripts/BakeManifest.res +395 -0
  9. package/scripts/BakeManifest.res.mjs +487 -0
  10. package/scripts/DeployApp.res +708 -0
  11. package/scripts/DeployApp.res.mjs +1015 -0
  12. package/scripts/DeployManifest.res +84 -0
  13. package/scripts/DeployManifest.res.mjs +112 -0
  14. package/scripts/ProvisionAccounts.res +339 -0
  15. package/scripts/ProvisionAccounts.res.mjs +351 -0
  16. package/scripts/ProvisionAdmin.res +275 -0
  17. package/scripts/ProvisionAdmin.res.mjs +289 -0
  18. package/scripts/ProvisionCognito.res +149 -0
  19. package/scripts/ProvisionCognito.res.mjs +98 -0
  20. package/scripts/ProvisionIdentity.res +76 -11
  21. package/scripts/ProvisionIdentity.res.mjs +72 -7
  22. package/scripts/ProvisionProvider.res +104 -0
  23. package/scripts/ProvisionProvider.res.mjs +123 -0
  24. package/scripts/PulumiCli.res +43 -0
  25. package/scripts/PulumiCli.res.mjs +106 -0
  26. package/src/Platform.res +51 -4
  27. package/src/Platform.res.mjs +32 -14
  28. package/src/Platform_Stack.res +119 -9
  29. package/src/Platform_Stack.res.mjs +42 -4
  30. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +1 -5
  31. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +1 -1
  32. package/src/adapter/Api/Platform_UIFragments_Lambda.res +1 -5
  33. package/src/adapter/Api/Platform_UIFragments_Lambda.res.mjs +1 -2
  34. package/src/adapter/Auth/Auth_ActiveRoleStore.res +1 -5
  35. package/src/adapter/Auth/Auth_ActiveRoleStore.res.mjs +1 -2
  36. package/src/adapter/Auth/Auth_ActiveRoleTrigger.res +1 -5
  37. package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +1 -2
  38. package/src/adapter/Auth/Auth_LoginIdentifier.res +66 -0
  39. package/src/adapter/Auth/Auth_LoginIdentifier.res.mjs +70 -0
  40. package/src/adapter/Auth/Auth_SignUpMode.res +78 -0
  41. package/src/adapter/Auth/Auth_SignUpMode.res.mjs +56 -0
  42. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +52 -31
  43. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res.mjs +75 -44
  44. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res +1 -5
  45. package/src/adapter/EventLogSubscription/EventLogSubscription_AppSync.res.mjs +1 -2
  46. package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res +1 -5
  47. package/src/adapter/Geocoder/Geocoder_AwsLocation_Resolver.res.mjs +1 -2
  48. package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +5 -4
  49. package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res.mjs +1 -1
  50. package/src/adapter/Postgres/PgMigration_Builder.res +1 -1
  51. package/src/adapter/Postgres/PgMigration_Builder.res.mjs +1 -2
  52. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +5 -0
  53. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +5 -1
  54. package/src/adapter/Runtime/CommandGeneratorEntryPoint_Ops.res +2 -0
  55. package/src/adapter/Runtime/CommandGeneratorEntryPoint_Ops.res.mjs +2 -2
  56. package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +15 -6
  57. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +51 -30
  58. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res.mjs +31 -14
  59. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +1 -5
  60. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +1 -1
  61. package/src/adapter/StateTopic/StateTopic_AppSync.res +1 -5
  62. package/src/adapter/StateTopic/StateTopic_AppSync.res.mjs +1 -1
  63. package/src/adapter/Task/TaskBucket_S3.res +1 -3
  64. package/src/adapter/Task/TaskBucket_S3.res.mjs +1 -1
  65. package/src/adapter/Upload/Upload_Claim_S3.res +1 -5
  66. package/src/adapter/Upload/Upload_Claim_S3.res.mjs +1 -1
  67. package/src/adapter/Upload/Upload_Presign_S3.res +1 -5
  68. package/src/adapter/Upload/Upload_Presign_S3.res.mjs +1 -2
  69. package/src/capability/Capability_Geocoding_AwsLocation.res +5 -1
  70. package/src/capability/Capability_Geocoding_AwsLocation.res.mjs +7 -1
  71. package/src/components/Api/AppSync_Adapter.res +56 -72
  72. package/src/components/Api/AppSync_Adapter.res.mjs +26 -60
  73. package/src/components/Api/AppSync_SdlDecorate.res +82 -1
  74. package/src/components/Api/AppSync_SdlDecorate.res.mjs +45 -0
  75. package/src/plugin/cloner/ClonerRunner_Fargate.res +1 -5
  76. package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +1 -1
  77. package/src/plugin/stack/Plugin_Stack.res +4 -0
  78. package/src/plugin/stack/Plugin_Stack.res.mjs +2 -0
  79. package/src/util/Util_DeadLetterQueue.res +1 -5
  80. package/src/util/Util_DeadLetterQueue.res.mjs +1 -2
  81. package/src/util/Util_StoreLayout.res +15 -2
  82. package/src/util/Util_StoreLayout.res.mjs +11 -3
  83. package/tests/AppSync_AdapterTest.res +83 -0
  84. package/tests/AppSync_AdapterTest.res.mjs +69 -0
  85. package/tests/Auth_LoginIdentifierTest.res +51 -0
  86. package/tests/Auth_LoginIdentifierTest.res.mjs +51 -0
  87. package/tests/Auth_SignUpModeTest.res +56 -0
  88. package/tests/Auth_SignUpModeTest.res.mjs +53 -0
  89. package/tests/BakeManifestTest.res +204 -0
  90. package/tests/BakeManifestTest.res.mjs +259 -0
  91. package/tests/DcbColdStartPartitionTest.res +32 -0
  92. package/tests/DcbColdStartPartitionTest.res.mjs +33 -0
  93. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +88 -0
  94. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res.mjs +112 -0
  95. package/tests/DcbUnresolvedPartitionSlice.res +28 -0
  96. package/tests/DcbUnresolvedPartitionSlice.res.mjs +38 -0
  97. package/tests/DeployAppTest.res +90 -0
  98. package/tests/DeployAppTest.res.mjs +133 -0
  99. package/tests/LambdaLayerLookupTest.res +104 -0
  100. package/tests/LambdaLayerLookupTest.res.mjs +117 -0
  101. package/tests/ProvisionAccountsTest.res +168 -0
  102. package/tests/ProvisionAccountsTest.res.mjs +184 -0
  103. package/tests/ProvisionAdminTest.res +55 -0
  104. package/tests/ProvisionAdminTest.res.mjs +66 -0
  105. package/tests/ProvisionIdentityTest.res +89 -3
  106. package/tests/ProvisionIdentityTest.res.mjs +66 -1
  107. package/tests/Util_OwnerScopeEnvTest.res +25 -0
  108. package/tests/Util_OwnerScopeEnvTest.res.mjs +13 -0
  109. package/tests/Util_StoreLayoutTest.res +6 -0
  110. package/tests/Util_StoreLayoutTest.res.mjs +7 -4
  111. package/tests/dcbColdStartPartition.mjs +66 -0
  112. 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 */