@awsless/awsless 0.0.44 → 0.0.45

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/bin.js CHANGED
@@ -75,13 +75,20 @@ var sub = (value, params) => {
75
75
  }
76
76
  return { "Fn::Sub": value };
77
77
  };
78
+ var split = (seperator, value) => {
79
+ return { "Fn::Split": [seperator, value] };
80
+ };
81
+ var select = (index, value) => {
82
+ return { "Fn::Select": [index, value] };
83
+ };
78
84
  var getAtt = (logicalId, attr) => {
79
85
  return { "Fn::GetAtt": [logicalId, attr] };
80
86
  };
87
+ var lazy = (cb) => {
88
+ return new Lazy(cb);
89
+ };
81
90
  var importValue = (name) => {
82
- return new Lazy((stack) => ({
83
- "Fn::ImportValue": `${stack.app.name}-${name}`
84
- }));
91
+ return { "Fn::ImportValue": name };
85
92
  };
86
93
  var formatLogicalId = (id) => {
87
94
  return pascalCase(id).replaceAll("_", "");
@@ -107,6 +114,10 @@ var Resource = class {
107
114
  tags = /* @__PURE__ */ new Map();
108
115
  deps = /* @__PURE__ */ new Set();
109
116
  stack;
117
+ addChild(...children) {
118
+ this.children.push(...children);
119
+ return this;
120
+ }
110
121
  dependsOn(...dependencies) {
111
122
  for (const dependency of dependencies) {
112
123
  this.deps.add(dependency);
@@ -175,6 +186,25 @@ var Lazy = class {
175
186
  }
176
187
  };
177
188
 
189
+ // src/formation/resource/cloud-watch/log-group.ts
190
+ var LogGroup = class extends Resource {
191
+ constructor(logicalId, props) {
192
+ super("AWS::Logs::LogGroup", logicalId);
193
+ this.props = props;
194
+ }
195
+ get arn() {
196
+ return getAtt(this.logicalId, "Arn");
197
+ }
198
+ properties() {
199
+ return {
200
+ LogGroupName: this.props.name,
201
+ ...this.attr("RetentionInDays", this.props.retention?.toDays())
202
+ // KmsKeyId: String
203
+ // DataProtectionPolicy : Json,
204
+ };
205
+ }
206
+ };
207
+
178
208
  // src/formation/resource/iam/inline-policy.ts
179
209
  var InlinePolicy = class {
180
210
  name;
@@ -202,20 +232,6 @@ var InlinePolicy = class {
202
232
  }
203
233
  };
204
234
 
205
- // src/formation/resource/iam/managed-policy.ts
206
- var ManagedPolicy = class {
207
- constructor(arn) {
208
- this.arn = arn;
209
- }
210
- static fromAwsManagedPolicyName(name) {
211
- const arn = sub("arn:${AWS::Partition}:iam::aws:policy/service-role/" + name);
212
- return new ManagedPolicy(arn);
213
- }
214
- static fromManagedPolicyArn(arn) {
215
- return new ManagedPolicy(arn);
216
- }
217
- };
218
-
219
235
  // src/formation/resource/iam/role.ts
220
236
  var Role = class extends Resource {
221
237
  constructor(logicalId, props = {}) {
@@ -259,16 +275,44 @@ var Role = class extends Resource {
259
275
  }
260
276
  };
261
277
 
278
+ // src/formation/resource/lambda/url.ts
279
+ import { constantCase } from "change-case";
280
+ var Url = class extends Resource {
281
+ constructor(logicalId, props) {
282
+ super("AWS::Lambda::Url", logicalId);
283
+ this.props = props;
284
+ }
285
+ get url() {
286
+ return getAtt(this.logicalId, "FunctionUrl");
287
+ }
288
+ properties() {
289
+ return {
290
+ AuthType: constantCase(this.props.authType ?? "none"),
291
+ InvokeMode: constantCase(this.props.invokeMode ?? "buffered"),
292
+ TargetFunctionArn: this.props.target,
293
+ ...this.attr("Qualifier", this.props.qualifier),
294
+ Cors: {
295
+ ...this.attr("AllowCredentials", this.props.cors?.allow?.credentials),
296
+ ...this.attr("AllowHeaders", this.props.cors?.allow?.headers),
297
+ ...this.attr("AllowMethods", this.props.cors?.allow?.methods),
298
+ ...this.attr("AllowOrigins", this.props.cors?.allow?.origins),
299
+ ...this.attr("ExposeHeaders", this.props.cors?.expose?.headers),
300
+ ...this.attr("MaxAge", this.props.cors?.maxAge?.toSeconds())
301
+ }
302
+ };
303
+ }
304
+ };
305
+
262
306
  // src/formation/resource/lambda/function.ts
263
307
  var Function = class extends Resource {
264
- constructor(logicalId, props) {
265
- const policy = new InlinePolicy(logicalId);
266
- const role = new Role(logicalId, {
308
+ constructor(_logicalId, props) {
309
+ const policy = new InlinePolicy(_logicalId);
310
+ const role = new Role(_logicalId, {
267
311
  assumedBy: "lambda.amazonaws.com"
268
312
  });
269
313
  role.addInlinePolicy(policy);
270
- role.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("AWSLambdaBasicExecutionRole"));
271
- super("AWS::Lambda::Function", logicalId, [role]);
314
+ super("AWS::Lambda::Function", _logicalId, [role]);
315
+ this._logicalId = _logicalId;
272
316
  this.props = props;
273
317
  if (props.code instanceof Asset) {
274
318
  this.children.push(props.code);
@@ -276,7 +320,7 @@ var Function = class extends Resource {
276
320
  this.dependsOn(role);
277
321
  this.role = role;
278
322
  this.policy = policy;
279
- this.name = formatName(this.props.name || logicalId);
323
+ this.name = formatName(this.props.name || _logicalId);
280
324
  this.environmentVariables = props.environment ? { ...props.environment } : {};
281
325
  this.tag("name", this.name);
282
326
  }
@@ -284,6 +328,29 @@ var Function = class extends Resource {
284
328
  role;
285
329
  policy;
286
330
  environmentVariables;
331
+ enableLogs(retention) {
332
+ const logGroup = new LogGroup(this._logicalId, {
333
+ name: sub("/aws/lambda/${name}", {
334
+ name: this.name
335
+ }),
336
+ retention
337
+ });
338
+ this.addChild(logGroup);
339
+ this.addPermissions({
340
+ actions: ["logs:CreateLogStream"],
341
+ resources: [logGroup.arn]
342
+ }, {
343
+ actions: ["logs:PutLogEvents"],
344
+ resources: [sub("${arn}:*", { arn: logGroup.arn })]
345
+ });
346
+ return this;
347
+ }
348
+ addUrl(props = {}) {
349
+ return new Url(this._logicalId, {
350
+ ...props,
351
+ target: this.arn
352
+ }).dependsOn(this);
353
+ }
287
354
  addPermissions(...permissions) {
288
355
  this.policy.addStatement(...permissions);
289
356
  return this;
@@ -392,7 +459,12 @@ var Stack = class {
392
459
  if (!this.exports.has(name)) {
393
460
  throw new Error(`Undefined export value: ${name}`);
394
461
  }
395
- return importValue(name);
462
+ return lazy((stack) => {
463
+ if (stack === this) {
464
+ return this.exports.get(name);
465
+ }
466
+ return importValue(`${stack.app?.name ?? "default"}-${name}`);
467
+ });
396
468
  }
397
469
  tag(name, value) {
398
470
  this.tags.set(name, value);
@@ -413,32 +485,33 @@ var Stack = class {
413
485
  toJSON() {
414
486
  const resources = {};
415
487
  const outputs = {};
416
- const walk = (object) => {
417
- for (const [key, value] of Object.entries(object)) {
418
- if (!object.hasOwnProperty(key)) {
419
- continue;
420
- }
421
- if (value instanceof Lazy) {
422
- object[key] = value.callback(this);
423
- continue;
424
- }
425
- if (typeof value === "object" && value !== null) {
426
- walk(value);
488
+ const walk = (node) => {
489
+ if (node instanceof Lazy) {
490
+ return walk(node.callback(this));
491
+ }
492
+ if (Array.isArray(node)) {
493
+ return node.map(walk);
494
+ }
495
+ if (typeof node === "object" && node !== null) {
496
+ const object = {};
497
+ for (const [key, value] of Object.entries(node)) {
498
+ object[key] = walk(value);
427
499
  }
500
+ return object;
428
501
  }
502
+ return node;
429
503
  };
430
504
  for (const resource of this.resources) {
431
- const json2 = resource.toJSON();
432
- walk(json2);
505
+ const json2 = walk(resource.toJSON());
433
506
  Object.assign(resources, json2);
434
507
  }
435
- for (const [name, value] of this.exports.entries()) {
508
+ for (let [name, value] of this.exports.entries()) {
436
509
  Object.assign(outputs, {
437
510
  [formatLogicalId(name)]: {
438
511
  Export: {
439
- Name: `${this.app?.name || "default"}-${name}`
512
+ Name: `${this.app?.name ?? "default"}-${name}`
440
513
  },
441
- Value: value
514
+ Value: walk(value)
442
515
  }
443
516
  });
444
517
  }
@@ -638,15 +711,15 @@ var durationMax = (max) => {
638
711
  };
639
712
 
640
713
  // src/schema/local-file.ts
641
- import { access, constants } from "fs/promises";
714
+ import { stat } from "fs/promises";
642
715
  import { z as z3 } from "zod";
643
716
  var LocalFileSchema = z3.string().refine(async (path) => {
644
717
  try {
645
- await access(path, constants.R_OK);
718
+ const s = await stat(path);
719
+ return s.isFile();
646
720
  } catch (error) {
647
721
  return false;
648
722
  }
649
- return true;
650
723
  }, `File doesn't exist`);
651
724
 
652
725
  // src/schema/resource-id.ts
@@ -730,49 +803,54 @@ import json from "@rollup/plugin-json";
730
803
  import commonjs from "@rollup/plugin-commonjs";
731
804
  import nodeResolve from "@rollup/plugin-node-resolve";
732
805
  import { dirname } from "path";
733
- var rollupBundle = async (input) => {
734
- const bundle = await rollup({
735
- input,
736
- external: (importee) => {
737
- return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk");
738
- },
739
- onwarn: (error) => {
740
- debugError(error.message);
741
- },
742
- treeshake: {
743
- moduleSideEffects: (id) => input === id
744
- },
745
- plugins: [
746
- commonjs({ sourceMap: true }),
747
- nodeResolve({ preferBuiltins: true }),
748
- swc({
749
- minify: true,
750
- jsc: {
751
- baseUrl: dirname(input),
752
- minify: { sourceMap: true }
753
- },
754
- sourceMaps: true
755
- }),
756
- json()
757
- ]
758
- });
759
- const result = await bundle.generate({
760
- format: "esm",
761
- sourcemap: "hidden",
762
- exports: "default"
763
- });
764
- const output = result.output[0];
765
- const code = output.code;
766
- const map = output.map?.toString();
767
- const hash = createHash("sha1").update(code).digest("hex");
768
- return {
769
- handler: "index.default",
770
- hash,
771
- files: [{
772
- name: "index.mjs",
773
- code,
774
- map
775
- }]
806
+ var rollupBundle = ({ format: format2 = "esm", minify = true, handler = "index.default" } = {}) => {
807
+ return async (input) => {
808
+ const bundle = await rollup({
809
+ input,
810
+ external: (importee) => {
811
+ return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk");
812
+ },
813
+ onwarn: (error) => {
814
+ debugError(error.message);
815
+ },
816
+ treeshake: {
817
+ moduleSideEffects: (id) => input === id
818
+ },
819
+ plugins: [
820
+ // @ts-ignore
821
+ commonjs({ sourceMap: true }),
822
+ // @ts-ignore
823
+ nodeResolve({ preferBuiltins: true }),
824
+ swc({
825
+ minify,
826
+ jsc: {
827
+ baseUrl: dirname(input),
828
+ minify: { sourceMap: true }
829
+ },
830
+ sourceMaps: true
831
+ }),
832
+ // @ts-ignore
833
+ json()
834
+ ]
835
+ });
836
+ const result = await bundle.generate({
837
+ format: format2,
838
+ sourcemap: "hidden",
839
+ exports: "auto"
840
+ });
841
+ const output = result.output[0];
842
+ const code = Buffer.from(output.code, "utf8");
843
+ const map = output.map ? Buffer.from(output.map.toString(), "utf8") : void 0;
844
+ const hash = createHash("sha1").update(code).digest("hex");
845
+ return {
846
+ handler,
847
+ hash,
848
+ files: [{
849
+ name: format2 === "esm" ? "index.mjs" : "index.js",
850
+ code,
851
+ map
852
+ }]
853
+ };
776
854
  };
777
855
  };
778
856
 
@@ -793,6 +871,8 @@ var zipFiles = (files) => {
793
871
  };
794
872
 
795
873
  // src/formation/resource/lambda/code.ts
874
+ import { fileURLToPath } from "url";
875
+ import { join } from "path";
796
876
  var Code = class {
797
877
  static fromFile(id, file, bundler) {
798
878
  return new FileCode(id, file, bundler);
@@ -800,6 +880,29 @@ var Code = class {
800
880
  static fromInline(code, handler) {
801
881
  return new InlineCode(code, handler);
802
882
  }
883
+ static fromInlineFile(id, file, bundler) {
884
+ return new InlineFileCode(id, file, bundler);
885
+ }
886
+ // static fromZipFile(id:string, file:string, hash:string, handler?:string) {
887
+ // return new ZipFileCode(id, file, hash, handler)
888
+ // }
889
+ static fromFeature(id) {
890
+ const root2 = fileURLToPath(new URL(".", import.meta.url));
891
+ const file = join(root2, `features/${id}.js`);
892
+ return new FileCode(id, file, rollupBundle({
893
+ minify: false,
894
+ handler: "index.handler"
895
+ }));
896
+ }
897
+ static fromInlineFeature(id) {
898
+ const root2 = fileURLToPath(new URL(".", import.meta.url));
899
+ const file = join(root2, `features/${id}.js`);
900
+ return new InlineFileCode(id, file, rollupBundle({
901
+ format: "cjs",
902
+ minify: false,
903
+ handler: "index.handler"
904
+ }));
905
+ }
803
906
  };
804
907
  var InlineCode = class {
805
908
  constructor(code, handler = "index.default") {
@@ -815,6 +918,36 @@ var InlineCode = class {
815
918
  };
816
919
  }
817
920
  };
921
+ var InlineFileCode = class extends Asset {
922
+ constructor(id, file, bundler) {
923
+ super("function", id);
924
+ this.file = file;
925
+ this.bundler = bundler;
926
+ }
927
+ code;
928
+ handler;
929
+ async build({ write }) {
930
+ const bundler = this.bundler ?? rollupBundle();
931
+ const { hash, files: [file], handler } = await bundler(this.file);
932
+ await Promise.all([
933
+ write("HASH", hash),
934
+ write("file.js", file.code)
935
+ ]);
936
+ this.handler = handler;
937
+ this.code = file.code.toString("utf8");
938
+ return {
939
+ size: formatByteSize(file.code.byteLength)
940
+ };
941
+ }
942
+ toCodeJson() {
943
+ return {
944
+ Handler: this.handler ?? "",
945
+ Code: {
946
+ ZipFile: this.code ?? ""
947
+ }
948
+ };
949
+ }
950
+ };
818
951
  var FileCode = class extends Asset {
819
952
  constructor(id, file, bundler) {
820
953
  super("function", id);
@@ -826,7 +959,7 @@ var FileCode = class extends Asset {
826
959
  bundle;
827
960
  s3;
828
961
  async build({ write }) {
829
- const bundler = this.bundler ?? rollupBundle;
962
+ const bundler = this.bundler ?? rollupBundle();
830
963
  const { hash, files, handler } = await bundler(this.file);
831
964
  const bundle = await zipFiles(files);
832
965
  await Promise.all([
@@ -915,24 +1048,24 @@ import { camelCase as camelCase2 } from "change-case";
915
1048
 
916
1049
  // src/util/path.ts
917
1050
  import { lstat } from "fs/promises";
918
- import { join, normalize } from "path";
1051
+ import { join as join2, normalize } from "path";
919
1052
  var root = process.cwd();
920
1053
  var directories = {
921
1054
  root,
922
1055
  get output() {
923
- return join(this.root, ".awsless");
1056
+ return join2(this.root, ".awsless");
924
1057
  },
925
1058
  get cache() {
926
- return join(this.output, "cache");
1059
+ return join2(this.output, "cache");
927
1060
  },
928
1061
  get asset() {
929
- return join(this.output, "asset");
1062
+ return join2(this.output, "asset");
930
1063
  },
931
1064
  get types() {
932
- return join(this.output, "types");
1065
+ return join2(this.output, "types");
933
1066
  },
934
1067
  get template() {
935
- return join(this.output, "template");
1068
+ return join2(this.output, "template");
936
1069
  }
937
1070
  };
938
1071
  var setRoot = (path = root) => {
@@ -942,17 +1075,17 @@ var findRootDir = async (path, configFile, level = 5) => {
942
1075
  if (!level) {
943
1076
  throw new TypeError("No awsless project found");
944
1077
  }
945
- const file = join(path, configFile);
1078
+ const file = join2(path, configFile);
946
1079
  const exists = await fileExist(file);
947
1080
  if (exists) {
948
1081
  return path;
949
1082
  }
950
- return findRootDir(normalize(join(path, "..")), configFile, level - 1);
1083
+ return findRootDir(normalize(join2(path, "..")), configFile, level - 1);
951
1084
  };
952
1085
  var fileExist = async (file) => {
953
1086
  try {
954
- const stat = await lstat(file);
955
- if (stat.isFile()) {
1087
+ const stat3 = await lstat(file);
1088
+ if (stat3.isFile()) {
956
1089
  return true;
957
1090
  }
958
1091
  } catch (error) {
@@ -965,8 +1098,8 @@ import { relative as relative2 } from "path";
965
1098
 
966
1099
  // src/util/type-gen.ts
967
1100
  import { mkdir, writeFile } from "fs/promises";
968
- import { join as join2, relative } from "path";
969
- import { camelCase, constantCase } from "change-case";
1101
+ import { join as join3, relative } from "path";
1102
+ import { camelCase, constantCase as constantCase2 } from "change-case";
970
1103
  var generateResourceTypes = async (config) => {
971
1104
  const plugins = [
972
1105
  ...defaultPlugins,
@@ -976,7 +1109,7 @@ var generateResourceTypes = async (config) => {
976
1109
  for (const plugin of plugins) {
977
1110
  const code = plugin.onTypeGen?.({ config });
978
1111
  if (code) {
979
- const file = join2(directories.types, `${plugin.name}.d.ts`);
1112
+ const file = join3(directories.types, `${plugin.name}.d.ts`);
980
1113
  files.push(relative(directories.root, file));
981
1114
  await mkdir(directories.types, { recursive: true });
982
1115
  await writeFile(file, code);
@@ -984,7 +1117,7 @@ var generateResourceTypes = async (config) => {
984
1117
  }
985
1118
  if (files.length) {
986
1119
  const code = files.map((file) => `/// <reference path='${file}' />`).join("\n");
987
- await writeFile(join2(directories.root, `awsless.d.ts`), code);
1120
+ await writeFile(join3(directories.root, `awsless.d.ts`), code);
988
1121
  }
989
1122
  };
990
1123
  var TypeGen = class {
@@ -1012,7 +1145,7 @@ var TypeGen = class {
1012
1145
  }
1013
1146
  addConst(name, type) {
1014
1147
  if (type) {
1015
- this.types.set(constantCase(name), type);
1148
+ this.types.set(constantCase2(name), type);
1016
1149
  }
1017
1150
  return this;
1018
1151
  }
@@ -1063,7 +1196,7 @@ var TypeObject = class {
1063
1196
  }
1064
1197
  addConst(name, type) {
1065
1198
  if (type) {
1066
- this.types.set(constantCase(name), type);
1199
+ this.types.set(constantCase2(name), type);
1067
1200
  }
1068
1201
  return this;
1069
1202
  }
@@ -1090,9 +1223,12 @@ var EnvironmentSchema = z6.record(z6.string(), z6.string()).optional();
1090
1223
  var ArchitectureSchema = z6.enum(["x86_64", "arm64"]);
1091
1224
  var RetryAttemptsSchema = z6.number().int().min(0).max(2);
1092
1225
  var RuntimeSchema = z6.enum([
1093
- "nodejs16.x",
1094
1226
  "nodejs18.x"
1095
1227
  ]);
1228
+ var LogSchema = z6.union([
1229
+ z6.boolean(),
1230
+ DurationSchema.refine(durationMin(Duration.days(1)), "Minimum log retention is 1 day")
1231
+ ]);
1096
1232
  var FunctionSchema = z6.union([
1097
1233
  LocalFileSchema,
1098
1234
  z6.object({
@@ -1102,6 +1238,11 @@ var FunctionSchema = z6.union([
1102
1238
  * @default false
1103
1239
  */
1104
1240
  vpc: z6.boolean().optional(),
1241
+ /** Enable logging to a CloudWatch log group.
1242
+ * Providing a duration value will set the log retention time.
1243
+ * @default false
1244
+ */
1245
+ log: LogSchema.optional(),
1105
1246
  /** The amount of time that Lambda allows a function to run before stopping it.
1106
1247
  * You can specify a size value from 1 second to 15 minutes.
1107
1248
  * @default '10 seconds'
@@ -1158,6 +1299,10 @@ var schema = z6.object({
1158
1299
  * @default false
1159
1300
  */
1160
1301
  vpc: z6.boolean().default(false),
1302
+ /** Enable logging to a CloudWatch log group.
1303
+ * @default false
1304
+ */
1305
+ log: LogSchema.default(false),
1161
1306
  /** The amount of time that Lambda allows a function to run before stopping it.
1162
1307
  * You can specify a size value from 1 second to 15 minutes.
1163
1308
  * @default '10 seconds'
@@ -1270,22 +1415,26 @@ var functionPlugin = definePlugin({
1270
1415
  var toLambdaFunction = (ctx, id, fileOrProps) => {
1271
1416
  const config = ctx.config;
1272
1417
  const stack = ctx.stack;
1418
+ const bootstrap2 = ctx.bootstrap;
1273
1419
  const props = typeof fileOrProps === "string" ? { ...config.defaults?.function, file: fileOrProps } : { ...config.defaults?.function, ...fileOrProps };
1274
1420
  const lambda = new Function(id, {
1275
- name: `${config.name}--${stack.name}--${id}`,
1421
+ name: `${config.name}-${stack.name}-${id}`,
1276
1422
  code: Code.fromFile(id, props.file),
1277
1423
  ...props,
1278
1424
  vpc: void 0
1279
1425
  });
1280
1426
  lambda.addEnvironment("APP", config.name).addEnvironment("STAGE", config.stage).addEnvironment("STACK", stack.name);
1427
+ if (props.log) {
1428
+ lambda.enableLogs(props.log instanceof Duration ? props.log : void 0);
1429
+ }
1281
1430
  if (props.vpc) {
1282
1431
  lambda.setVpc({
1283
1432
  securityGroupIds: [
1284
- ctx.bootstrap.import(`vpc-security-group-id`)
1433
+ bootstrap2.import(`vpc-security-group-id`)
1285
1434
  ],
1286
1435
  subnetIds: [
1287
- ctx.bootstrap.import(`public-subnet-1`),
1288
- ctx.bootstrap.import(`public-subnet-2`)
1436
+ bootstrap2.import(`public-subnet-1`),
1437
+ bootstrap2.import(`public-subnet-2`)
1289
1438
  ]
1290
1439
  }).addPermissions({
1291
1440
  actions: [
@@ -1298,9 +1447,6 @@ var toLambdaFunction = (ctx, id, fileOrProps) => {
1298
1447
  resources: ["*"]
1299
1448
  });
1300
1449
  }
1301
- if (props.runtime.startsWith("nodejs")) {
1302
- lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1");
1303
- }
1304
1450
  ctx.bind((other) => {
1305
1451
  other.addPermissions(lambda.permissions);
1306
1452
  });
@@ -1340,6 +1486,7 @@ var Rule = class extends Resource {
1340
1486
  };
1341
1487
 
1342
1488
  // src/formation/resource/lambda/permission.ts
1489
+ import { constantCase as constantCase3 } from "change-case";
1343
1490
  var Permission2 = class extends Resource {
1344
1491
  constructor(logicalId, props) {
1345
1492
  super("AWS::Lambda::Permission", logicalId);
@@ -1350,6 +1497,7 @@ var Permission2 = class extends Resource {
1350
1497
  FunctionName: this.props.functionArn,
1351
1498
  Action: this.props.action || "lambda:InvokeFunction",
1352
1499
  Principal: this.props.principal,
1500
+ ...this.attr("FunctionUrlAuthType", this.props.urlAuthType && constantCase3(this.props.urlAuthType)),
1353
1501
  ...this.attr("SourceArn", this.props.sourceArn)
1354
1502
  };
1355
1503
  }
@@ -1476,7 +1624,7 @@ var Queue = class extends Resource {
1476
1624
  };
1477
1625
 
1478
1626
  // src/formation/resource/lambda/event-source-mapping.ts
1479
- import { constantCase as constantCase2 } from "change-case";
1627
+ import { constantCase as constantCase4 } from "change-case";
1480
1628
  var EventSourceMapping = class extends Resource {
1481
1629
  constructor(logicalId, props) {
1482
1630
  super("AWS::Lambda::EventSourceMapping", logicalId);
@@ -1498,7 +1646,7 @@ var EventSourceMapping = class extends Resource {
1498
1646
  ...this.attr("ParallelizationFactor", this.props.parallelizationFactor),
1499
1647
  ...this.attr("TumblingWindowInSeconds", this.props.tumblingWindow?.toSeconds()),
1500
1648
  ...this.attr("BisectBatchOnFunctionError", this.props.bisectBatchOnError),
1501
- ...this.attr("StartingPosition", this.props.startingPosition && constantCase2(this.props.startingPosition)),
1649
+ ...this.attr("StartingPosition", this.props.startingPosition && constantCase4(this.props.startingPosition)),
1502
1650
  ...this.attr("StartingPositionTimestamp", this.props.startingPositionTimestamp),
1503
1651
  ...this.props.maxConcurrency ? {
1504
1652
  ScalingConfig: {
@@ -1539,7 +1687,7 @@ var SqsEventSource = class extends Group {
1539
1687
  };
1540
1688
 
1541
1689
  // src/plugins/queue.ts
1542
- import { camelCase as camelCase3, constantCase as constantCase3 } from "change-case";
1690
+ import { camelCase as camelCase3, constantCase as constantCase5 } from "change-case";
1543
1691
  import { relative as relative3 } from "path";
1544
1692
  var RetentionPeriodSchema = DurationSchema.refine(durationMin(Duration.minutes(1)), "Minimum retention period is 1 minute").refine(durationMax(Duration.days(14)), "Maximum retention period is 14 days");
1545
1693
  var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
@@ -1694,7 +1842,7 @@ var queuePlugin = definePlugin({
1694
1842
  stack.add(queue2, lambda, source);
1695
1843
  bind((lambda2) => {
1696
1844
  lambda2.addPermissions(queue2.permissions);
1697
- lambda2.addEnvironment(`QUEUE_${constantCase3(stack.name)}_${constantCase3(id)}_URL`, queue2.url);
1845
+ lambda2.addEnvironment(`QUEUE_${constantCase5(stack.name)}_${constantCase5(id)}_URL`, queue2.url);
1698
1846
  });
1699
1847
  }
1700
1848
  }
@@ -1704,7 +1852,7 @@ var queuePlugin = definePlugin({
1704
1852
  import { z as z9 } from "zod";
1705
1853
 
1706
1854
  // src/formation/resource/dynamodb/table.ts
1707
- import { constantCase as constantCase4 } from "change-case";
1855
+ import { constantCase as constantCase6 } from "change-case";
1708
1856
  var Table = class extends Resource {
1709
1857
  constructor(logicalId, props) {
1710
1858
  super("AWS::DynamoDB::Table", logicalId);
@@ -1777,7 +1925,7 @@ var Table = class extends Resource {
1777
1925
  return {
1778
1926
  TableName: this.name,
1779
1927
  BillingMode: "PAY_PER_REQUEST",
1780
- TableClass: constantCase4(this.props.class || "standard"),
1928
+ TableClass: constantCase6(this.props.class || "standard"),
1781
1929
  PointInTimeRecoverySpecification: {
1782
1930
  PointInTimeRecoveryEnabled: this.props.pointInTimeRecovery || false
1783
1931
  },
@@ -1788,7 +1936,7 @@ var Table = class extends Resource {
1788
1936
  AttributeDefinitions: this.attributeDefinitions(),
1789
1937
  ...this.props.stream ? {
1790
1938
  StreamSpecification: {
1791
- StreamViewType: constantCase4(this.props.stream)
1939
+ StreamViewType: constantCase6(this.props.stream)
1792
1940
  }
1793
1941
  } : {},
1794
1942
  ...this.props.timeToLiveAttribute ? {
@@ -1805,7 +1953,7 @@ var Table = class extends Resource {
1805
1953
  ...props.sort ? [{ KeyType: "RANGE", AttributeName: props.sort }] : []
1806
1954
  ],
1807
1955
  Projection: {
1808
- ProjectionType: constantCase4(props.projection || "all")
1956
+ ProjectionType: constantCase6(props.projection || "all")
1809
1957
  }
1810
1958
  }))
1811
1959
  } : {}
@@ -1931,21 +2079,6 @@ var tablePlugin = definePlugin({
1931
2079
  projection: z9.enum(["all", "keys-only"]).default("all")
1932
2080
  })).optional()
1933
2081
  })
1934
- // .refine(props => {
1935
- // return (
1936
- // // Check the hash key
1937
- // props.fields.hasOwnProperty(props.hash) &&
1938
- // // Check the sort key
1939
- // (!props.sort || props.fields.hasOwnProperty(props.sort)) &&
1940
- // // Check all indexes
1941
- // !Object.values(props.indexes || {}).map(index => (
1942
- // // Check the index hash key
1943
- // props.fields.hasOwnProperty(index.hash) &&
1944
- // // Check the index sort key
1945
- // (!index.sort || props.fields.hasOwnProperty(index.sort))
1946
- // )).includes(false)
1947
- // )
1948
- // }, 'Hash & Sort keys must be defined inside the table fields')
1949
2082
  ).optional()
1950
2083
  }).array()
1951
2084
  }),
@@ -2000,11 +2133,20 @@ var Bucket = class extends Resource {
2000
2133
  }
2001
2134
  name;
2002
2135
  get arn() {
2003
- return ref(this.logicalId);
2136
+ return getAtt(this.logicalId, "Arn");
2004
2137
  }
2005
2138
  get domainName() {
2006
2139
  return getAtt(this.logicalId, "DomainName");
2007
2140
  }
2141
+ get dealStackDomainName() {
2142
+ return getAtt(this.logicalId, "DualStackDomainName");
2143
+ }
2144
+ get regionalDomainName() {
2145
+ return getAtt(this.logicalId, "RegionalDomainName");
2146
+ }
2147
+ get url() {
2148
+ return getAtt(this.logicalId, "WebsiteURL");
2149
+ }
2008
2150
  get permissions() {
2009
2151
  return {
2010
2152
  actions: [
@@ -2026,15 +2168,38 @@ var Bucket = class extends Resource {
2026
2168
  return {
2027
2169
  BucketName: this.name,
2028
2170
  AccessControl: pascalCase2(this.props.accessControl ?? "private"),
2029
- ...this.props.versioned ? {
2171
+ ...this.props.versioning ? {
2030
2172
  VersioningConfiguration: {
2031
2173
  Status: "Enabled"
2032
2174
  }
2175
+ } : {},
2176
+ ...this.props.website ? {
2177
+ WebsiteConfiguration: {
2178
+ ...this.attr("IndexDocument", this.props.website.indexDocument),
2179
+ ...this.attr("ErrorDocument", this.props.website.errorDocument)
2180
+ }
2033
2181
  } : {}
2034
2182
  };
2035
2183
  }
2036
2184
  };
2037
2185
 
2186
+ // src/formation/resource/cloud-formation/custom-resource.ts
2187
+ var CustomResource = class extends Resource {
2188
+ constructor(logicalId, props) {
2189
+ super("AWS::CloudFormation::CustomResource", logicalId);
2190
+ this.props = props;
2191
+ }
2192
+ getAtt(name) {
2193
+ return getAtt(this.logicalId, name);
2194
+ }
2195
+ properties() {
2196
+ return {
2197
+ ServiceToken: this.props.serviceToken,
2198
+ ...this.props.properties
2199
+ };
2200
+ }
2201
+ };
2202
+
2038
2203
  // src/plugins/store.ts
2039
2204
  var storePlugin = definePlugin({
2040
2205
  name: "store",
@@ -2061,13 +2226,19 @@ var storePlugin = definePlugin({
2061
2226
  }
2062
2227
  return types2.toString();
2063
2228
  },
2064
- onStack({ config, stack, stackConfig, bind }) {
2229
+ onStack({ config, stack, stackConfig, bootstrap: bootstrap2, bind }) {
2065
2230
  for (const id of stackConfig.stores || []) {
2066
2231
  const bucket = new Bucket(id, {
2067
- name: `${config.name}-${stack.name}-${id}`,
2232
+ name: `store-${config.name}-${stack.name}-${id}`,
2068
2233
  accessControl: "private"
2069
2234
  });
2070
- stack.add(bucket);
2235
+ const custom = new CustomResource(id, {
2236
+ serviceToken: bootstrap2.import("feature-delete-bucket"),
2237
+ properties: {
2238
+ bucketName: bucket.name
2239
+ }
2240
+ }).dependsOn(bucket);
2241
+ stack.add(bucket, custom);
2071
2242
  bind((lambda) => {
2072
2243
  lambda.addPermissions(bucket.permissions);
2073
2244
  });
@@ -2371,7 +2542,7 @@ var toArray = (value) => {
2371
2542
  import { paramCase as paramCase4 } from "change-case";
2372
2543
 
2373
2544
  // src/formation/resource/appsync/graphql-api.ts
2374
- import { constantCase as constantCase5 } from "change-case";
2545
+ import { constantCase as constantCase7 } from "change-case";
2375
2546
  var GraphQLApi = class extends Resource {
2376
2547
  constructor(logicalId, props) {
2377
2548
  super("AWS::AppSync::GraphQLApi", logicalId);
@@ -2403,7 +2574,7 @@ var GraphQLApi = class extends Resource {
2403
2574
  properties() {
2404
2575
  return {
2405
2576
  Name: this.name,
2406
- AuthenticationType: constantCase5(this.props.authenticationType || "api-key"),
2577
+ AuthenticationType: constantCase7(this.props.authenticationType || "api-key"),
2407
2578
  AdditionalAuthenticationProviders: this.lambdaAuthProviders.map((provider) => ({
2408
2579
  AuthenticationType: "AWS_LAMBDA",
2409
2580
  LambdaAuthorizerConfig: {
@@ -2750,7 +2921,7 @@ var graphqlPlugin = definePlugin({
2750
2921
  }).array()
2751
2922
  }),
2752
2923
  onApp(ctx) {
2753
- const { config, bootstrap: bootstrap2, usEastBootstrap } = ctx;
2924
+ const { config, bootstrap: bootstrap2 } = ctx;
2754
2925
  const apis = /* @__PURE__ */ new Set();
2755
2926
  for (const stackConfig of config.stacks) {
2756
2927
  for (const id of Object.keys(stackConfig.graphql || {})) {
@@ -2783,8 +2954,9 @@ var graphqlPlugin = definePlugin({
2783
2954
  }
2784
2955
  if (props.domain) {
2785
2956
  const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
2786
- const hostedZoneId = usEastBootstrap.import(`hosted-zone-${props.domain}-id`);
2787
- const certificateArn = usEastBootstrap.import(`certificate-${props.domain}-arn`);
2957
+ const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
2958
+ const certificateArn = bootstrap2.import(`us-east-certificate-${props.domain}-arn`);
2959
+ debug("DEBUG CERT", certificateArn);
2788
2960
  const domain = new DomainName(id, {
2789
2961
  domainName,
2790
2962
  certificateArn
@@ -2900,132 +3072,31 @@ var RecordSetGroup = class extends Resource {
2900
3072
  }
2901
3073
  };
2902
3074
 
2903
- // src/custom/util.ts
2904
- var sendCode = (
2905
- /* JS */
2906
- `
2907
-
2908
- const send = async (event, id, status, data, reason = '') => {
2909
- const body = JSON.stringify({
2910
- Status: status,
2911
- Reason: reason,
2912
- PhysicalResourceId: id,
2913
- StackId: event.StackId,
2914
- RequestId: event.RequestId,
2915
- LogicalResourceId: event.LogicalResourceId,
2916
- NoEcho: false,
2917
- Data: data
2918
- })
2919
-
2920
- await fetch(event.ResponseURL, {
2921
- method: 'PUT',
2922
- port: 443,
2923
- body,
2924
- headers: {
2925
- 'content-type': '',
2926
- 'content-length': Buffer.from(body).byteLength,
2927
- },
2928
- })
2929
- }
2930
-
2931
- `
2932
- );
2933
-
2934
- // src/custom/delete-hosted-zone/handler.ts
2935
- var deleteHostedZoneRecordsHandlerCode = (
2936
- /* JS */
2937
- `
2938
-
2939
- const { Route53Client, ListResourceRecordSetsCommand, ChangeResourceRecordSetsCommand } = require('@aws-sdk/client-route-53')
2940
-
2941
- const client = new Route53Client({})
2942
-
2943
- ${sendCode}
2944
-
2945
- exports.handler = async (event) => {
2946
- const type = event.RequestType
2947
- const hostedZoneId = event.ResourceProperties.hostedZoneId
2948
-
2949
- try {
2950
- if(type === 'Delete') {
2951
- const records = await listHostedZoneRecords(hostedZoneId)
2952
- console.log(records)
2953
-
2954
- await deleteHostedZoneRecords(hostedZoneId, records)
2955
- }
2956
-
2957
- await send(event, hostedZoneId, 'SUCCESS')
2958
- }
2959
- catch(error) {
2960
- if (error instanceof Error) {
2961
- await send(event, hostedZoneId, 'FAILED', {}, error.message)
2962
- } else {
2963
- await send(event, hostedZoneId, 'FAILED', {}, 'Unknown error')
2964
- }
2965
- }
2966
- }
2967
-
2968
- const deleteHostedZoneRecords = async (hostedZoneId, records) => {
2969
- records = records.filter(record => ![ 'SOA', 'NS' ].includes(record.Type))
2970
- if(records.length === 0) {
2971
- return
2972
- }
2973
-
2974
- const chunkSize = 100;
2975
- for (let i = 0; i < records.length; i += chunkSize) {
2976
- const chunk = records.slice(i, i + chunkSize);
2977
-
2978
- await client.send(new ChangeResourceRecordSetsCommand({
2979
- HostedZoneId: hostedZoneId,
2980
- ChangeBatch: {
2981
- Changes: chunk.map(record => ({
2982
- Action: 'DELETE',
2983
- ResourceRecordSet: record
2984
- }))
2985
- }
2986
- }))
2987
- }
2988
- }
2989
-
2990
- const listHostedZoneRecords = async (hostedZoneId) => {
2991
-
2992
- const records = []
2993
- let token
2994
-
2995
- while(true) {
2996
- const result = await client.send(new ListResourceRecordSetsCommand({
2997
- HostedZoneId: hostedZoneId,
2998
- NextRecordName: token
2999
- }))
3000
-
3001
- if(result.ResourceRecordSets && result.ResourceRecordSets.length) {
3002
- records.push(...result.ResourceRecordSets)
3003
- }
3004
-
3005
- if(result.NextRecordName) {
3006
- token = result.NextRecordName
3007
- } else {
3008
- return records
3009
- }
3010
- }
3011
- }
3012
- `
3013
- );
3014
-
3015
- // src/formation/resource/cloud-formation/custom-resource.ts
3016
- var CustomResource = class extends Resource {
3017
- constructor(logicalId, props) {
3018
- super("AWS::CloudFormation::CustomResource", logicalId);
3019
- this.props = props;
3020
- }
3021
- getAtt(name) {
3022
- return getAtt(this.logicalId, name);
3075
+ // src/custom/global-exports.ts
3076
+ var GlobalExports = class extends Group {
3077
+ resource;
3078
+ constructor(id, props) {
3079
+ const lambda = new Function(id, {
3080
+ code: Code.fromFeature("global-exports")
3081
+ });
3082
+ lambda.addPermissions({
3083
+ actions: ["cloudformation:ListExports"],
3084
+ resources: ["*"]
3085
+ });
3086
+ const resource = new CustomResource(id, {
3087
+ serviceToken: lambda.arn,
3088
+ properties: {
3089
+ region: props.region
3090
+ }
3091
+ });
3092
+ super([lambda, resource]);
3093
+ this.resource = resource;
3023
3094
  }
3024
- properties() {
3025
- return {
3026
- ServiceToken: this.props.serviceToken,
3027
- ...this.props.properties
3028
- };
3095
+ import(name) {
3096
+ return lazy((stack) => {
3097
+ const attr = formatName(`${stack.app?.name ?? "default"}-${name}`);
3098
+ return this.resource.getAtt(attr);
3099
+ });
3029
3100
  }
3030
3101
  };
3031
3102
 
@@ -3067,36 +3138,39 @@ var domainPlugin = definePlugin({
3067
3138
  if (domains.length === 0) {
3068
3139
  return;
3069
3140
  }
3070
- const lambda = new Function("delete-hosted-zone", {
3141
+ const deleteHostedZoneLambda = new Function("delete-hosted-zone", {
3071
3142
  name: `${config.name}-delete-hosted-zone`,
3072
- code: Code.fromInline(deleteHostedZoneRecordsHandlerCode, "index.handler")
3073
- });
3074
- lambda.addPermissions({
3143
+ code: Code.fromInlineFeature("delete-hosted-zone")
3144
+ }).enableLogs(Duration.days(3)).addPermissions({
3075
3145
  actions: [
3076
3146
  "route53:ListResourceRecordSets",
3077
3147
  "route53:ChangeResourceRecordSets"
3078
3148
  ],
3079
3149
  resources: ["*"]
3080
3150
  });
3081
- usEastBootstrap.add(lambda);
3151
+ usEastBootstrap.add(deleteHostedZoneLambda);
3152
+ const usEastExports = new GlobalExports("us-east-exports", {
3153
+ region: usEastBootstrap.region
3154
+ });
3155
+ bootstrap2.add(usEastExports);
3082
3156
  for (const [domain, records] of domains) {
3083
3157
  const hostedZone = new HostedZone(domain);
3084
3158
  const usEastCertificate = new Certificate(domain, {
3085
3159
  hostedZoneId: hostedZone.id,
3086
3160
  alternativeNames: [`*.${domain}`]
3087
3161
  });
3088
- const custom = new CustomResource(domain, {
3089
- serviceToken: lambda.arn,
3162
+ const deleteHostedZone = new CustomResource(domain, {
3163
+ serviceToken: deleteHostedZoneLambda.arn,
3090
3164
  properties: {
3091
3165
  hostedZoneId: hostedZone.id
3092
3166
  }
3093
- }).dependsOn(hostedZone);
3094
- usEastBootstrap.add(custom).add(hostedZone).add(usEastCertificate).export(`certificate-${domain}-arn`, usEastCertificate.arn).export(`hosted-zone-${domain}-id`, hostedZone.id);
3167
+ }).dependsOn(deleteHostedZoneLambda, hostedZone);
3168
+ usEastBootstrap.add(hostedZone).add(deleteHostedZone).add(usEastCertificate).export(`certificate-${domain}-arn`, usEastCertificate.arn).export(`hosted-zone-${domain}-id`, hostedZone.id);
3095
3169
  const certificate = new Certificate(domain, {
3096
- hostedZoneId: usEastBootstrap.import(`hosted-zone-${domain}-id`),
3170
+ hostedZoneId: usEastExports.import(`hosted-zone-${domain}-id`),
3097
3171
  alternativeNames: [`*.${domain}`]
3098
3172
  });
3099
- bootstrap2.add(certificate).export(`certificate-${domain}-arn`, certificate.arn);
3173
+ bootstrap2.add(certificate).export(`certificate-${domain}-arn`, certificate.arn).export(`hosted-zone-${domain}-id`, usEastExports.import(`hosted-zone-${domain}-id`)).export(`us-east-certificate-${domain}-arn`, usEastExports.import(`certificate-${domain}-arn`));
3100
3174
  if (records.length > 0) {
3101
3175
  const group = new RecordSetGroup(domain, {
3102
3176
  hostedZoneId: hostedZone.id,
@@ -3508,7 +3582,7 @@ var LoadBalancer = class extends Resource {
3508
3582
  };
3509
3583
 
3510
3584
  // src/formation/resource/elb/listener.ts
3511
- import { constantCase as constantCase6 } from "change-case";
3585
+ import { constantCase as constantCase8 } from "change-case";
3512
3586
  var Listener = class extends Resource {
3513
3587
  constructor(logicalId, props) {
3514
3588
  super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
@@ -3524,7 +3598,7 @@ var Listener = class extends Resource {
3524
3598
  return {
3525
3599
  LoadBalancerArn: this.props.loadBalancerArn,
3526
3600
  Port: this.props.port,
3527
- Protocol: constantCase6(this.props.protocol),
3601
+ Protocol: constantCase8(this.props.protocol),
3528
3602
  Certificates: this.props.certificates.map((arn) => ({
3529
3603
  CertificateArn: arn
3530
3604
  })),
@@ -3750,7 +3824,7 @@ var httpPlugin = definePlugin({
3750
3824
  ).optional()
3751
3825
  }).array()
3752
3826
  }),
3753
- onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
3827
+ onApp({ config, bootstrap: bootstrap2 }) {
3754
3828
  if (Object.keys(config.defaults?.http || {}).length === 0) {
3755
3829
  return;
3756
3830
  }
@@ -3789,7 +3863,7 @@ var httpPlugin = definePlugin({
3789
3863
  ]
3790
3864
  }).dependsOn(loadBalancer);
3791
3865
  const record = new RecordSet(`${id}-http`, {
3792
- hostedZoneId: usEastBootstrap.import(`hosted-zone-${props.domain}-id`),
3866
+ hostedZoneId: bootstrap2.import(`hosted-zone-${props.domain}-id`),
3793
3867
  name: props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain,
3794
3868
  type: "A",
3795
3869
  alias: {
@@ -3963,7 +4037,7 @@ var SubnetGroup = class extends Resource {
3963
4037
  };
3964
4038
 
3965
4039
  // src/plugins/cache.ts
3966
- import { constantCase as constantCase7 } from "change-case";
4040
+ import { constantCase as constantCase9 } from "change-case";
3967
4041
  var TypeSchema = z19.enum([
3968
4042
  "t4g.small",
3969
4043
  "t4g.medium",
@@ -4049,7 +4123,7 @@ var cachePlugin = definePlugin({
4049
4123
  }).dependsOn(subnetGroup, securityGroup);
4050
4124
  stack.add(subnetGroup, securityGroup, cluster);
4051
4125
  bind((lambda) => {
4052
- lambda.addEnvironment(`CACHE_${constantCase7(stack.name)}_${constantCase7(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase7(stack.name)}_${constantCase7(id)}_PORT`, props.port.toString());
4126
+ lambda.addEnvironment(`CACHE_${constantCase9(stack.name)}_${constantCase9(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase9(stack.name)}_${constantCase9(id)}_PORT`, props.port.toString());
4053
4127
  });
4054
4128
  }
4055
4129
  }
@@ -4267,7 +4341,7 @@ var restPlugin = definePlugin({
4267
4341
  ).optional()
4268
4342
  }).array()
4269
4343
  }),
4270
- onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
4344
+ onApp({ config, bootstrap: bootstrap2 }) {
4271
4345
  for (const [id, props] of Object.entries(config.defaults?.rest || {})) {
4272
4346
  const api = new Api(id, {
4273
4347
  name: `${config.name}-${id}`,
@@ -4280,7 +4354,7 @@ var restPlugin = definePlugin({
4280
4354
  bootstrap2.add(api, stage).export(`rest-${id}-id`, api.id);
4281
4355
  if (props.domain) {
4282
4356
  const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
4283
- const hostedZoneId = usEastBootstrap.import(`hosted-zone-${props.domain}-id`);
4357
+ const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
4284
4358
  const certificateArn = bootstrap2.import(`certificate-${props.domain}-arn`);
4285
4359
  const domain = new DomainName2(id, {
4286
4360
  name: domainName,
@@ -4291,7 +4365,7 @@ var restPlugin = definePlugin({
4291
4365
  domainName: domain.name,
4292
4366
  stage: stage.name
4293
4367
  }).dependsOn(api, domain, stage);
4294
- const record = new RecordSet(`${id}-rest`, {
4368
+ const record = new RecordSet(`rest-${id}`, {
4295
4369
  hostedZoneId,
4296
4370
  type: "A",
4297
4371
  name: domainName,
@@ -4466,131 +4540,717 @@ var configPlugin = definePlugin({
4466
4540
  }
4467
4541
  });
4468
4542
 
4469
- // src/plugins/index.ts
4470
- var defaultPlugins = [
4471
- extendPlugin,
4472
- vpcPlugin,
4473
- functionPlugin,
4474
- configPlugin,
4475
- cachePlugin,
4476
- cronPlugin,
4477
- queuePlugin,
4478
- tablePlugin,
4479
- storePlugin,
4480
- topicPlugin,
4481
- pubsubPlugin,
4482
- searchPlugin,
4483
- domainPlugin,
4484
- graphqlPlugin,
4485
- httpPlugin,
4486
- restPlugin,
4487
- onFailurePlugin
4488
- ];
4543
+ // src/plugins/site.ts
4544
+ import { z as z24 } from "zod";
4489
4545
 
4490
- // src/formation/app.ts
4491
- var App = class {
4492
- constructor(name) {
4493
- this.name = name;
4546
+ // src/formation/resource/cloud-front/distribution.ts
4547
+ var Distribution = class extends Resource {
4548
+ constructor(logicalId, props) {
4549
+ super("AWS::CloudFront::Distribution", logicalId);
4550
+ this.props = props;
4551
+ this.name = formatName(this.props.name || logicalId);
4552
+ this.tag("name", this.name);
4494
4553
  }
4495
- list = /* @__PURE__ */ new Map();
4496
- add(...stacks) {
4497
- stacks.forEach((stack) => {
4498
- this.list.set(stack.name, stack);
4499
- stack.setApp(this);
4500
- });
4501
- return this;
4554
+ name;
4555
+ get id() {
4556
+ return getAtt(this.logicalId, "Id");
4502
4557
  }
4503
- find(resourceType) {
4504
- return this.stacks.map((stack) => stack.find(resourceType)).flat();
4558
+ get arn() {
4559
+ return sub("arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${id}", {
4560
+ id: this.id
4561
+ });
4505
4562
  }
4506
- [Symbol.iterator]() {
4507
- return this.list.values();
4563
+ get domainName() {
4564
+ return getAtt(this.logicalId, "DomainName");
4508
4565
  }
4509
- get stacks() {
4510
- return [...this.list.values()];
4566
+ properties() {
4567
+ return {
4568
+ DistributionConfig: {
4569
+ Enabled: true,
4570
+ Aliases: this.props.aliases ?? [],
4571
+ PriceClass: "PriceClass_" + (this.props.priceClass ?? "All"),
4572
+ HttpVersion: this.props.httpVersion ?? "http2and3",
4573
+ ViewerCertificate: this.props.certificateArn ? {
4574
+ SslSupportMethod: "sni-only",
4575
+ AcmCertificateArn: this.props.certificateArn
4576
+ } : {},
4577
+ Origins: this.props.origins?.map((origin) => origin.toJSON()) ?? [],
4578
+ OriginGroups: {
4579
+ Quantity: this.props.originGroups?.length ?? 0,
4580
+ Items: this.props.originGroups?.map((originGroup) => originGroup.toJSON()) ?? []
4581
+ },
4582
+ DefaultCacheBehavior: {
4583
+ TargetOriginId: this.props.targetOriginId,
4584
+ ViewerProtocolPolicy: this.props.viewerProtocol ?? "redirect-to-https",
4585
+ AllowedMethods: this.props.allowMethod ?? ["GET", "HEAD", "OPTIONS"],
4586
+ Compress: this.props.compress ?? false,
4587
+ FunctionAssociations: this.props.associations?.map((association) => ({
4588
+ EventType: association.type,
4589
+ FunctionARN: association.functionArn
4590
+ })) ?? [],
4591
+ LambdaFunctionAssociations: this.props.lambdaAssociations?.map((association) => ({
4592
+ EventType: association.type,
4593
+ IncludeBody: association.includeBody ?? false,
4594
+ FunctionARN: association.functionArn
4595
+ })) ?? [],
4596
+ ...this.attr("CachePolicyId", this.props.cachePolicyId),
4597
+ ...this.attr("OriginRequestPolicyId", this.props.originRequestPolicyId),
4598
+ ...this.attr("ResponseHeadersPolicyId", this.props.responseHeadersPolicyId)
4599
+ }
4600
+ }
4601
+ };
4602
+ }
4603
+ };
4604
+ var Origin = class {
4605
+ constructor(props) {
4606
+ this.props = props;
4607
+ }
4608
+ toJSON() {
4609
+ return {
4610
+ Id: this.props.id,
4611
+ DomainName: this.props.domainName,
4612
+ OriginCustomHeaders: Object.entries(this.props.headers ?? {}).map(([name, value]) => ({
4613
+ HeaderName: name,
4614
+ HeaderValue: value
4615
+ })),
4616
+ ...this.props.path ? {
4617
+ OriginPath: this.props.path
4618
+ } : {},
4619
+ ...this.props.protocol ? {
4620
+ CustomOriginConfig: {
4621
+ OriginProtocolPolicy: this.props.protocol
4622
+ }
4623
+ } : {},
4624
+ ...this.props.originAccessIdentityId ? {
4625
+ S3OriginConfig: {
4626
+ OriginAccessIdentity: sub("origin-access-identity/cloudfront/${id}", {
4627
+ id: this.props.originAccessIdentityId
4628
+ })
4629
+ }
4630
+ } : {},
4631
+ ...this.props.originAccessControlId ? {
4632
+ OriginAccessControlId: this.props.originAccessControlId,
4633
+ S3OriginConfig: {
4634
+ OriginAccessIdentity: ""
4635
+ }
4636
+ } : {}
4637
+ };
4638
+ }
4639
+ };
4640
+ var OriginGroup = class {
4641
+ constructor(props) {
4642
+ this.props = props;
4643
+ }
4644
+ toJSON() {
4645
+ return {
4646
+ Id: this.props.id,
4647
+ Members: {
4648
+ Quantity: this.props.members.length,
4649
+ Items: this.props.members.map((member) => ({
4650
+ OriginId: member
4651
+ }))
4652
+ },
4653
+ FailoverCriteria: {
4654
+ StatusCodes: {
4655
+ Quantity: this.props.statusCodes.length,
4656
+ Items: this.props.statusCodes
4657
+ }
4658
+ }
4659
+ };
4511
4660
  }
4512
- // get resources() {
4513
- // return this.stacks.map(stack => stack.resources).flat()
4514
- // }
4515
4661
  };
4516
4662
 
4517
- // src/custom/global-export/handler.ts
4518
- var globalExportsHandlerCode = (
4519
- /* JS */
4520
- `
4521
-
4522
- const { CloudFormationClient, ListExportsCommand } = require('@aws-sdk/client-cloudformation')
4523
-
4524
- ${sendCode}
4525
-
4526
- exports.handler = async (event) => {
4527
- const region = event.ResourceProperties.region
4528
-
4529
- try {
4530
- const data = await listExports(region)
4663
+ // src/schema/local-directory.ts
4664
+ import { stat as stat2 } from "fs/promises";
4665
+ import { z as z23 } from "zod";
4666
+ var LocalDirectorySchema = z23.string().refine(async (path) => {
4667
+ try {
4668
+ const s = await stat2(path);
4669
+ return s.isDirectory();
4670
+ } catch (error) {
4671
+ return false;
4672
+ }
4673
+ }, `Directory doesn't exist`);
4531
4674
 
4532
- await send(event, region, 'SUCCESS', data)
4533
- } catch(error) {
4534
- if (error instanceof Error) {
4535
- await send(event, region, 'FAILED', {}, error.message)
4536
- } else {
4537
- await send(event, region, 'FAILED', {}, 'Unknown error')
4538
- }
4539
- }
4540
- }
4675
+ // src/formation/resource/cloud-front/origin-request-policy.ts
4676
+ import { camelCase as camelCase4 } from "change-case";
4677
+ var OriginRequestPolicy = class extends Resource {
4678
+ constructor(logicalId, props = {}) {
4679
+ super("AWS::CloudFront::OriginRequestPolicy", logicalId);
4680
+ this.props = props;
4681
+ this.name = formatName(this.props.name || logicalId);
4682
+ }
4683
+ name;
4684
+ get id() {
4685
+ return getAtt(this.logicalId, "Id");
4686
+ }
4687
+ properties() {
4688
+ return {
4689
+ OriginRequestPolicyConfig: {
4690
+ Name: this.name,
4691
+ CookiesConfig: {
4692
+ CookieBehavior: camelCase4(this.props.cookie?.behavior ?? "all"),
4693
+ ...this.attr("Cookies", this.props.cookie?.values)
4694
+ },
4695
+ HeadersConfig: {
4696
+ HeaderBehavior: camelCase4(this.props.header?.behavior ?? "allViewer"),
4697
+ ...this.attr("Headers", this.props.header?.values)
4698
+ },
4699
+ QueryStringsConfig: {
4700
+ QueryStringBehavior: camelCase4(this.props.query?.behavior ?? "all"),
4701
+ ...this.attr("QueryStrings", this.props.query?.values)
4702
+ }
4703
+ }
4704
+ };
4705
+ }
4706
+ };
4541
4707
 
4542
- const listExports = async (region) => {
4543
- const client = new CloudFormationClient({ region })
4544
- const data = {}
4708
+ // src/formation/resource/cloud-front/cache-policy.ts
4709
+ var CachePolicy = class extends Resource {
4710
+ constructor(logicalId, props) {
4711
+ super("AWS::CloudFront::CachePolicy", logicalId);
4712
+ this.props = props;
4713
+ this.name = formatName(this.props.name || logicalId);
4714
+ }
4715
+ name;
4716
+ get id() {
4717
+ return getAtt(this.logicalId, "Id");
4718
+ }
4719
+ properties() {
4720
+ return {
4721
+ CachePolicyConfig: {
4722
+ Name: this.name,
4723
+ MinTTL: this.props.minTtl.toSeconds(),
4724
+ MaxTTL: this.props.maxTtl.toSeconds(),
4725
+ DefaultTTL: this.props.defaultTtl.toSeconds(),
4726
+ ParametersInCacheKeyAndForwardedToOrigin: {
4727
+ EnableAcceptEncodingGzip: this.props.acceptGzip ?? false,
4728
+ EnableAcceptEncodingBrotli: this.props.acceptBrotli ?? false,
4729
+ CookiesConfig: {
4730
+ CookieBehavior: this.props.cookies ? "whitelist" : "none",
4731
+ ...this.attr("Cookies", this.props.cookies)
4732
+ },
4733
+ HeadersConfig: {
4734
+ HeaderBehavior: this.props.headers ? "whitelist" : "none",
4735
+ ...this.attr("Headers", this.props.headers)
4736
+ },
4737
+ QueryStringsConfig: {
4738
+ QueryStringBehavior: this.props.queries ? "whitelist" : "none",
4739
+ ...this.attr("QueryStrings", this.props.queries)
4740
+ }
4741
+ }
4742
+ }
4743
+ };
4744
+ }
4745
+ };
4545
4746
 
4546
- let token
4747
+ // src/formation/resource/s3/files.ts
4748
+ import { Glob } from "glob";
4749
+ import JSZip2 from "jszip";
4750
+ import { createHash as createHash2 } from "crypto";
4751
+ import { createReadStream } from "fs";
4752
+ import { join as join4 } from "path";
4753
+ var Files = class extends Asset {
4754
+ constructor(id, props) {
4755
+ super("bucket", id);
4756
+ this.props = props;
4757
+ }
4758
+ hash;
4759
+ bundle;
4760
+ s3;
4761
+ async build({ write }) {
4762
+ const glob = new Glob(this.props.pattern ?? "**/*", {
4763
+ nodir: true,
4764
+ cwd: this.props.directory
4765
+ });
4766
+ const zip = new JSZip2();
4767
+ const hashes = [];
4768
+ let count = 0;
4769
+ for await (const path of glob) {
4770
+ const file = join4(this.props.directory, path);
4771
+ const stream = createReadStream(file);
4772
+ const hash2 = createHash2("sha1");
4773
+ stream.pipe(hash2);
4774
+ hashes.push(hash2);
4775
+ zip.file(path, stream);
4776
+ count++;
4777
+ }
4778
+ this.bundle = await zip.generateAsync({
4779
+ type: "nodebuffer",
4780
+ compression: "DEFLATE",
4781
+ compressionOptions: {
4782
+ level: 9
4783
+ }
4784
+ });
4785
+ const hash = createHash2("sha1");
4786
+ for (const item of hashes) {
4787
+ hash.update(item.digest());
4788
+ }
4789
+ this.hash = hash.digest("hex");
4790
+ await write("HASH", this.hash);
4791
+ await write("bundle.zip", this.bundle);
4792
+ return {
4793
+ files: style.success(String(count)),
4794
+ size: formatByteSize(this.bundle.byteLength)
4795
+ };
4796
+ }
4797
+ async publish({ publish }) {
4798
+ this.s3 = await publish(
4799
+ `${this.id}.zip`,
4800
+ this.bundle,
4801
+ this.hash
4802
+ );
4803
+ }
4804
+ get source() {
4805
+ return this.s3;
4806
+ }
4807
+ };
4547
4808
 
4548
- while(true) {
4549
- const result = await client.send(new ListExportsCommand({
4550
- NextToken: token
4551
- }))
4809
+ // src/formation/resource/s3/bucket-policy.ts
4810
+ import { capitalCase } from "change-case";
4811
+ var BucketPolicy = class extends Resource {
4812
+ constructor(logicalId, props) {
4813
+ super("AWS::S3::BucketPolicy", logicalId);
4814
+ this.props = props;
4815
+ }
4816
+ properties() {
4817
+ return {
4818
+ Bucket: formatName(this.props.bucketName),
4819
+ PolicyDocument: {
4820
+ Version: this.props.version ?? "2012-10-17",
4821
+ Statement: this.props.statements.map((statement) => ({
4822
+ Effect: capitalCase(statement.effect ?? "allow"),
4823
+ ...statement.principal ? {
4824
+ Principal: {
4825
+ Service: statement.principal
4826
+ }
4827
+ } : {},
4828
+ Action: statement.actions,
4829
+ Resource: statement.resources,
4830
+ ...statement.sourceArn ? {
4831
+ Condition: {
4832
+ StringEquals: {
4833
+ "AWS:SourceArn": statement.sourceArn
4834
+ }
4835
+ }
4836
+ } : {}
4837
+ }))
4838
+ }
4839
+ };
4840
+ }
4841
+ };
4552
4842
 
4553
- result.Exports?.forEach(item => {
4554
- data[item.Name] = item.Value
4555
- })
4843
+ // src/formation/resource/cloud-front/origin-access-control.ts
4844
+ var OriginAccessControl = class extends Resource {
4845
+ constructor(logicalId, props) {
4846
+ super("AWS::CloudFront::OriginAccessControl", logicalId);
4847
+ this.props = props;
4848
+ this.name = formatName(this.props.name || logicalId);
4849
+ }
4850
+ name;
4851
+ get id() {
4852
+ return getAtt(this.logicalId, "Id");
4853
+ }
4854
+ properties() {
4855
+ return {
4856
+ OriginAccessControlConfig: {
4857
+ Name: this.name,
4858
+ OriginAccessControlOriginType: this.props.type,
4859
+ SigningBehavior: this.props.behavior ?? "always",
4860
+ SigningProtocol: this.props.protocol ?? "sigv4"
4861
+ }
4862
+ };
4863
+ }
4864
+ };
4556
4865
 
4557
- if(result.NextToken) {
4558
- token = result.NextToken
4559
- } else {
4560
- return data
4561
- }
4562
- }
4563
- }
4564
- `
4565
- );
4866
+ // src/formation/resource/cloud-front/response-headers-policy.ts
4867
+ var ResponseHeadersPolicy = class extends Resource {
4868
+ constructor(logicalId, props) {
4869
+ super("AWS::CloudFront::ResponseHeadersPolicy", logicalId);
4870
+ this.props = props;
4871
+ this.name = formatName(this.props.name || logicalId);
4872
+ }
4873
+ name;
4874
+ get id() {
4875
+ return getAtt(this.logicalId, "Id");
4876
+ }
4877
+ properties() {
4878
+ return {
4879
+ ResponseHeadersPolicyConfig: {
4880
+ Name: this.name,
4881
+ ...this.props.remove && this.props.remove.length > 0 ? {
4882
+ RemoveHeadersConfig: {
4883
+ Items: this.props.remove?.map((value) => ({
4884
+ Header: value
4885
+ }))
4886
+ }
4887
+ } : {},
4888
+ CorsConfig: {
4889
+ OriginOverride: this.props.cors?.override ?? false,
4890
+ AccessControlAllowCredentials: this.props.cors?.credentials ?? false,
4891
+ AccessControlMaxAgeSec: this.props.cors?.maxAge?.toSeconds() ?? Duration.days(365).toSeconds(),
4892
+ AccessControlAllowHeaders: {
4893
+ Items: this.props.cors?.headers ?? ["*"]
4894
+ },
4895
+ AccessControlAllowMethods: {
4896
+ Items: this.props.cors?.methods ?? ["ALL"]
4897
+ },
4898
+ AccessControlAllowOrigins: {
4899
+ Items: this.props.cors?.origins ?? ["*"]
4900
+ },
4901
+ AccessControlExposeHeaders: {
4902
+ Items: this.props.cors?.exposeHeaders ?? ["*"]
4903
+ }
4904
+ },
4905
+ SecurityHeadersConfig: {
4906
+ ...this.props.contentSecurityPolicy ? {
4907
+ ContentSecurityPolicy: {
4908
+ Override: this.props.contentSecurityPolicy?.override ?? false,
4909
+ ContentSecurityPolicy: this.props.contentSecurityPolicy?.contentSecurityPolicy
4910
+ }
4911
+ } : {},
4912
+ ContentTypeOptions: {
4913
+ Override: this.props.contentTypeOptions?.override ?? false
4914
+ },
4915
+ FrameOptions: {
4916
+ Override: this.props.frameOptions?.override ?? false,
4917
+ FrameOption: (this.props.frameOptions?.frameOption ?? "same-origin") === "same-origin" ? "SAMEORIGIN" : "DENY"
4918
+ },
4919
+ ReferrerPolicy: {
4920
+ Override: this.props.referrerPolicy?.override ?? false,
4921
+ ReferrerPolicy: this.props.referrerPolicy?.referrerPolicy ?? "same-origin"
4922
+ },
4923
+ StrictTransportSecurity: {
4924
+ Override: this.props.strictTransportSecurity?.override ?? false,
4925
+ Preload: this.props.strictTransportSecurity?.preload ?? true,
4926
+ AccessControlMaxAgeSec: this.props.strictTransportSecurity?.maxAge?.toSeconds() ?? 31536e3,
4927
+ IncludeSubdomains: this.props.strictTransportSecurity?.includeSubdomains ?? true
4928
+ },
4929
+ XSSProtection: {
4930
+ Override: this.props.xssProtection?.override ?? false,
4931
+ ModeBlock: this.props.xssProtection?.modeBlock ?? true,
4932
+ Protection: this.props.xssProtection?.enable ?? true,
4933
+ ...this.attr("ReportUri", this.props.xssProtection?.reportUri)
4934
+ }
4935
+ }
4936
+ }
4937
+ };
4938
+ }
4939
+ };
4566
4940
 
4567
- // src/custom/global-export/extend.ts
4568
- var extendWithGlobalExports = (appName, importable, exportable) => {
4569
- let crossRegionExports;
4570
- importable.import = (name) => {
4571
- name = formatName(name);
4572
- if (!importable.exports.has(name)) {
4573
- throw new TypeError(`Undefined global export value: ${name}`);
4574
- }
4575
- if (!crossRegionExports) {
4576
- const lambda = new Function("global-exports", {
4577
- name: `${appName}-global-exports`,
4578
- code: Code.fromInline(globalExportsHandlerCode, "index.handler")
4579
- });
4580
- lambda.addPermissions({
4581
- actions: ["cloudformation:ListExports"],
4582
- resources: ["*"]
4941
+ // src/plugins/site.ts
4942
+ var sitePlugin = definePlugin({
4943
+ name: "site",
4944
+ schema: z24.object({
4945
+ stacks: z24.object({
4946
+ /** Define the sites in your stack.
4947
+ * @example
4948
+ * {
4949
+ * sites: {
4950
+ * SITE_NAME: {
4951
+ * static: 'dist/client'
4952
+ * ssr: 'dist/server/index.js'
4953
+ * }
4954
+ * }
4955
+ * }
4956
+ * */
4957
+ sites: z24.record(
4958
+ ResourceIdSchema,
4959
+ z24.object({
4960
+ /** The domain to link your site with. */
4961
+ domain: z24.string(),
4962
+ subDomain: z24.string().optional(),
4963
+ /** Specifies the path to the static files directory. */
4964
+ static: LocalDirectorySchema.optional(),
4965
+ /** Specifies the ssr file. */
4966
+ ssr: FunctionSchema.optional(),
4967
+ /** Define the cors headers. */
4968
+ cors: z24.object({
4969
+ override: z24.boolean().default(false),
4970
+ maxAge: DurationSchema.default("365 days"),
4971
+ exposeHeaders: z24.string().array().optional(),
4972
+ credentials: z24.boolean().default(false),
4973
+ headers: z24.string().array().default(["*"]),
4974
+ origins: z24.string().array().default(["*"]),
4975
+ methods: z24.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
4976
+ }).optional(),
4977
+ /** Define the cors headers. */
4978
+ security: z24.object({
4979
+ // contentSecurityPolicy: z.object({
4980
+ // override: z.boolean().default(false),
4981
+ // policy: z.string(),
4982
+ // })
4983
+ // contentSecurityPolicy?: {
4984
+ // override?: boolean
4985
+ // contentSecurityPolicy: string
4986
+ // }
4987
+ // contentTypeOptions?: {
4988
+ // override?: boolean
4989
+ // }
4990
+ // frameOptions?: {
4991
+ // override?: boolean
4992
+ // frameOption?: 'deny' | 'same-origin'
4993
+ // }
4994
+ // referrerPolicy?: {
4995
+ // override?: boolean
4996
+ // referrerPolicy?: (
4997
+ // 'no-referrer' |
4998
+ // 'no-referrer-when-downgrade' |
4999
+ // 'origin' |
5000
+ // 'origin-when-cross-origin' |
5001
+ // 'same-origin' |
5002
+ // 'strict-origin' |
5003
+ // 'strict-origin-when-cross-origin' |
5004
+ // 'unsafe-url'
5005
+ // )
5006
+ // }
5007
+ // strictTransportSecurity?: {
5008
+ // maxAge?: Duration
5009
+ // includeSubdomains?: boolean
5010
+ // override?: boolean
5011
+ // preload?: boolean
5012
+ // }
5013
+ // xssProtection?: {
5014
+ // override?: boolean
5015
+ // enable?: boolean
5016
+ // modeBlock?: boolean
5017
+ // reportUri?: string
5018
+ // }
5019
+ }).optional(),
5020
+ /** Specifies the cookies, headers, and query values that CloudFront includes in the cache key. */
5021
+ cache: z24.object({
5022
+ /** Specifies the cookies that CloudFront includes in the cache key. */
5023
+ cookies: z24.string().array().optional(),
5024
+ /** Specifies the headers that CloudFront includes in the cache key. */
5025
+ headers: z24.string().array().optional(),
5026
+ /** Specifies the query values that CloudFront includes in the cache key. */
5027
+ queries: z24.string().array().optional()
5028
+ }).optional()
5029
+ })
5030
+ ).optional()
5031
+ }).array()
5032
+ }),
5033
+ onStack(ctx) {
5034
+ const { config, stack, stackConfig, bootstrap: bootstrap2 } = ctx;
5035
+ for (const [id, props] of Object.entries(stackConfig.sites || {})) {
5036
+ const origins = [];
5037
+ const originGroups = [];
5038
+ const deps = [];
5039
+ let bucket;
5040
+ if (props.ssr) {
5041
+ const lambda = toLambdaFunction(ctx, `site-${id}`, props.ssr);
5042
+ const permissions = new Permission2(`site-${id}`, {
5043
+ principal: "*",
5044
+ // principal: 'cloudfront.amazonaws.com',
5045
+ action: "lambda:InvokeFunctionUrl",
5046
+ functionArn: lambda.arn,
5047
+ urlAuthType: "none"
5048
+ // sourceArn: distribution.arn,
5049
+ }).dependsOn(lambda);
5050
+ const url = lambda.addUrl();
5051
+ stack.add(url, lambda, permissions);
5052
+ origins.push(new Origin({
5053
+ id: "lambda",
5054
+ domainName: select(2, split("/", url.url)),
5055
+ protocol: "https-only"
5056
+ }));
5057
+ deps.push(lambda, url, permissions);
5058
+ }
5059
+ if (props.static) {
5060
+ bucket = new Bucket(`site-${id}`, {
5061
+ // name: props.domain,
5062
+ name: `site-${config.name}-${stack.name}-${id}`,
5063
+ accessControl: "private",
5064
+ website: {
5065
+ indexDocument: "index.html",
5066
+ errorDocument: props.ssr ? void 0 : "error.html"
5067
+ }
5068
+ });
5069
+ const accessControl = new OriginAccessControl(`site-${id}`, {
5070
+ type: "s3"
5071
+ });
5072
+ const files = new Files(`site-${id}`, {
5073
+ directory: props.static
5074
+ });
5075
+ const uploadBucketAsset = new CustomResource(`site-${id}-upload-bucket-asset`, {
5076
+ serviceToken: bootstrap2.import("feature-upload-bucket-asset"),
5077
+ properties: {
5078
+ sourceBucketName: lazy(() => files.source?.bucket ?? ""),
5079
+ sourceObjectKey: lazy(() => files.source?.key ?? ""),
5080
+ sourceObjectVersion: lazy(() => files.source?.version ?? ""),
5081
+ destinationBucketName: bucket.name
5082
+ }
5083
+ }).dependsOn(bucket);
5084
+ const deleteBucket = new CustomResource(id, {
5085
+ serviceToken: bootstrap2.import("feature-delete-bucket"),
5086
+ properties: {
5087
+ bucketName: bucket.name
5088
+ }
5089
+ }).dependsOn(bucket);
5090
+ stack.add(bucket, files, uploadBucketAsset, deleteBucket, accessControl);
5091
+ origins.push(new Origin({
5092
+ id: "bucket",
5093
+ // domainName: select(2, split('/', bucket.url)),
5094
+ domainName: bucket.domainName,
5095
+ originAccessControlId: accessControl.id
5096
+ }));
5097
+ deps.push(bucket, accessControl);
5098
+ }
5099
+ if (props.ssr && props.static) {
5100
+ originGroups.push(new OriginGroup({
5101
+ id: "group",
5102
+ members: ["lambda", "bucket"],
5103
+ statusCodes: [403, 404]
5104
+ }));
5105
+ }
5106
+ const cache = new CachePolicy(id, {
5107
+ name: `site-${config.name}-${stack.name}-${id}`,
5108
+ minTtl: Duration.seconds(1),
5109
+ maxTtl: Duration.days(365),
5110
+ defaultTtl: Duration.days(1),
5111
+ ...props.cache
4583
5112
  });
4584
- crossRegionExports = new CustomResource("global-exports", {
4585
- serviceToken: lambda.arn,
4586
- properties: {
4587
- region: importable.region
5113
+ const originRequest = new OriginRequestPolicy(id, {
5114
+ name: `site-${config.name}-${stack.name}-${id}`,
5115
+ header: {
5116
+ behavior: "all-except",
5117
+ values: ["HOST"]
4588
5118
  }
4589
5119
  });
4590
- exportable.add(lambda, crossRegionExports);
5120
+ const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
5121
+ const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
5122
+ const certificateArn = bootstrap2.import(`us-east-certificate-${props.domain}-arn`);
5123
+ const responseHeaders = new ResponseHeadersPolicy(id, {
5124
+ name: `site-${config.name}-${stack.name}-${id}`,
5125
+ cors: props.cors,
5126
+ remove: ["server"]
5127
+ });
5128
+ const distribution = new Distribution(id, {
5129
+ name: `site-${config.name}-${stack.name}-${id}`,
5130
+ certificateArn,
5131
+ compress: true,
5132
+ aliases: [domainName],
5133
+ origins,
5134
+ originGroups,
5135
+ targetOriginId: props.ssr && props.static ? "group" : props.ssr ? "lambda" : "bucket",
5136
+ originRequestPolicyId: originRequest.id,
5137
+ cachePolicyId: cache.id,
5138
+ responseHeadersPolicyId: responseHeaders.id
5139
+ }).dependsOn(originRequest, responseHeaders, cache, ...deps);
5140
+ if (props.static) {
5141
+ const bucketPolicy = new BucketPolicy(`site-${id}`, {
5142
+ bucketName: bucket.name,
5143
+ statements: [
5144
+ {
5145
+ principal: "cloudfront.amazonaws.com",
5146
+ actions: ["s3:GetObject"],
5147
+ resources: [sub("${arn}/*", { arn: bucket.arn })],
5148
+ sourceArn: distribution.arn
5149
+ }
5150
+ // {
5151
+ // principal: distribution.id,
5152
+ // actions: [ 's3:GetObject' ],
5153
+ // resources: [ oac.attrId ]
5154
+ // }
5155
+ ]
5156
+ }).dependsOn(bucket, distribution);
5157
+ stack.add(bucketPolicy);
5158
+ }
5159
+ const record = new RecordSet(`site-${id}`, {
5160
+ hostedZoneId,
5161
+ type: "A",
5162
+ name: domainName,
5163
+ alias: {
5164
+ dnsName: distribution.domainName,
5165
+ hostedZoneId: "Z2FDTNDATAQYW2"
5166
+ }
5167
+ }).dependsOn(distribution);
5168
+ stack.add(
5169
+ distribution,
5170
+ responseHeaders,
5171
+ originRequest,
5172
+ cache,
5173
+ record
5174
+ );
4591
5175
  }
4592
- return crossRegionExports.getAtt(name);
4593
- };
5176
+ }
5177
+ });
5178
+
5179
+ // src/plugins/feature.ts
5180
+ var featurePlugin = definePlugin({
5181
+ name: "feature",
5182
+ onApp({ config, bootstrap: bootstrap2 }) {
5183
+ const deleteBucketLambda = new Function("delete-bucket", {
5184
+ name: `${config.name}-delete-bucket`,
5185
+ code: Code.fromFeature("delete-bucket")
5186
+ }).enableLogs(Duration.days(3)).addPermissions({
5187
+ actions: ["s3:*"],
5188
+ resources: ["*"]
5189
+ });
5190
+ const uploadBucketAssetLambda = new Function("upload-bucket-asset", {
5191
+ name: `${config.name}-upload-bucket-asset`,
5192
+ code: Code.fromFeature("upload-bucket-asset"),
5193
+ memorySize: Size.gigaBytes(2)
5194
+ }).enableLogs(Duration.days(3)).addPermissions({
5195
+ actions: ["s3:*"],
5196
+ resources: ["*"]
5197
+ });
5198
+ bootstrap2.add(
5199
+ deleteBucketLambda,
5200
+ uploadBucketAssetLambda
5201
+ );
5202
+ bootstrap2.export("feature-delete-bucket", deleteBucketLambda.arn).export("feature-upload-bucket-asset", uploadBucketAssetLambda.arn);
5203
+ }
5204
+ });
5205
+
5206
+ // src/plugins/index.ts
5207
+ var defaultPlugins = [
5208
+ extendPlugin,
5209
+ featurePlugin,
5210
+ vpcPlugin,
5211
+ domainPlugin,
5212
+ functionPlugin,
5213
+ configPlugin,
5214
+ cachePlugin,
5215
+ cronPlugin,
5216
+ queuePlugin,
5217
+ tablePlugin,
5218
+ storePlugin,
5219
+ topicPlugin,
5220
+ pubsubPlugin,
5221
+ searchPlugin,
5222
+ graphqlPlugin,
5223
+ httpPlugin,
5224
+ restPlugin,
5225
+ sitePlugin,
5226
+ onFailurePlugin
5227
+ ];
5228
+
5229
+ // src/formation/app.ts
5230
+ var App = class {
5231
+ constructor(name) {
5232
+ this.name = name;
5233
+ }
5234
+ list = /* @__PURE__ */ new Map();
5235
+ add(...stacks) {
5236
+ stacks.forEach((stack) => {
5237
+ this.list.set(stack.name, stack);
5238
+ stack.setApp(this);
5239
+ });
5240
+ return this;
5241
+ }
5242
+ find(resourceType) {
5243
+ return this.stacks.map((stack) => stack.find(resourceType)).flat();
5244
+ }
5245
+ [Symbol.iterator]() {
5246
+ return this.list.values();
5247
+ }
5248
+ get stacks() {
5249
+ return [...this.list.values()];
5250
+ }
5251
+ // get resources() {
5252
+ // return this.stacks.map(stack => stack.resources).flat()
5253
+ // }
4594
5254
  };
4595
5255
 
4596
5256
  // src/app.ts
@@ -4615,7 +5275,6 @@ var toApp = async (config, filters) => {
4615
5275
  debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
4616
5276
  const bootstrap2 = new Stack("bootstrap", config.region);
4617
5277
  const usEastBootstrap = new Stack("us-east-bootstrap", "us-east-1");
4618
- extendWithGlobalExports(config.name, usEastBootstrap, bootstrap2);
4619
5278
  app.add(bootstrap2, usEastBootstrap);
4620
5279
  debug("Run plugin onApp listeners");
4621
5280
  const bindings = [];
@@ -4697,7 +5356,7 @@ var toApp = async (config, filters) => {
4697
5356
  };
4698
5357
 
4699
5358
  // src/config.ts
4700
- import { join as join4 } from "path";
5359
+ import { join as join6 } from "path";
4701
5360
 
4702
5361
  // src/util/account.ts
4703
5362
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -4716,17 +5375,17 @@ var getCredentials = (profile) => {
4716
5375
  };
4717
5376
 
4718
5377
  // src/schema/app.ts
4719
- import { z as z26 } from "zod";
5378
+ import { z as z28 } from "zod";
4720
5379
 
4721
5380
  // src/schema/stack.ts
4722
- import { z as z23 } from "zod";
4723
- var StackSchema = z23.object({
5381
+ import { z as z25 } from "zod";
5382
+ var StackSchema = z25.object({
4724
5383
  name: ResourceIdSchema,
4725
- depends: z23.array(z23.lazy(() => StackSchema)).optional()
5384
+ depends: z25.array(z25.lazy(() => StackSchema)).optional()
4726
5385
  });
4727
5386
 
4728
5387
  // src/schema/region.ts
4729
- import { z as z24 } from "zod";
5388
+ import { z as z26 } from "zod";
4730
5389
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
4731
5390
  var AF = ["af-south-1"];
4732
5391
  var AP = ["ap-east-1", "ap-south-2", "ap-southeast-3", "ap-southeast-4", "ap-south-1", "ap-northeast-3", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1"];
@@ -4743,41 +5402,41 @@ var regions = [
4743
5402
  ...ME,
4744
5403
  ...SA
4745
5404
  ];
4746
- var RegionSchema = z24.enum(regions);
5405
+ var RegionSchema = z26.enum(regions);
4747
5406
 
4748
5407
  // src/schema/plugin.ts
4749
- import { z as z25 } from "zod";
4750
- var PluginSchema = z25.object({
4751
- name: z25.string(),
4752
- schema: z25.custom().optional(),
5408
+ import { z as z27 } from "zod";
5409
+ var PluginSchema = z27.object({
5410
+ name: z27.string(),
5411
+ schema: z27.custom().optional(),
4753
5412
  // depends: z.array(z.lazy(() => PluginSchema)).optional(),
4754
- onApp: z25.function().returns(z25.void()).optional(),
4755
- onStack: z25.function().returns(z25.any()).optional(),
4756
- onResource: z25.function().returns(z25.any()).optional()
5413
+ onApp: z27.function().returns(z27.void()).optional(),
5414
+ onStack: z27.function().returns(z27.any()).optional(),
5415
+ onResource: z27.function().returns(z27.any()).optional()
4757
5416
  // bind: z.function().optional(),
4758
5417
  });
4759
5418
 
4760
5419
  // src/schema/app.ts
4761
- var AppSchema = z26.object({
5420
+ var AppSchema = z28.object({
4762
5421
  /** App name */
4763
5422
  name: ResourceIdSchema,
4764
5423
  /** The AWS region to deploy to. */
4765
5424
  region: RegionSchema,
4766
5425
  /** The AWS profile to deploy to. */
4767
- profile: z26.string(),
5426
+ profile: z28.string(),
4768
5427
  /** The deployment stage.
4769
5428
  * @default 'prod'
4770
5429
  */
4771
- stage: z26.string().regex(/^[a-z]+$/).default("prod"),
5430
+ stage: z28.string().regex(/^[a-z]+$/).default("prod"),
4772
5431
  /** Default properties. */
4773
- defaults: z26.object({}).default({}),
5432
+ defaults: z28.object({}).default({}),
4774
5433
  /** The application stacks. */
4775
- stacks: z26.array(StackSchema).min(1).refine((stacks) => {
5434
+ stacks: z28.array(StackSchema).min(1).refine((stacks) => {
4776
5435
  const unique = new Set(stacks.map((stack) => stack.name));
4777
5436
  return unique.size === stacks.length;
4778
5437
  }, "Must be an array of unique stacks"),
4779
5438
  /** Custom plugins. */
4780
- plugins: z26.array(PluginSchema).optional()
5439
+ plugins: z28.array(PluginSchema).optional()
4781
5440
  });
4782
5441
 
4783
5442
  // src/util/import.ts
@@ -4785,7 +5444,7 @@ import { rollup as rollup2, watch } from "rollup";
4785
5444
  import { swc as swc2 } from "rollup-plugin-swc3";
4786
5445
  import replace from "rollup-plugin-replace";
4787
5446
  import { EventIterator } from "event-iterator";
4788
- import { dirname as dirname2, join as join3 } from "path";
5447
+ import { dirname as dirname2, join as join5 } from "path";
4789
5448
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
4790
5449
  var importFile = async (path) => {
4791
5450
  const bundle = await rollup2({
@@ -4805,7 +5464,7 @@ var importFile = async (path) => {
4805
5464
  })
4806
5465
  ]
4807
5466
  });
4808
- const outputFile = join3(directories.cache, "config.js");
5467
+ const outputFile = join5(directories.cache, "config.js");
4809
5468
  const result = await bundle.generate({
4810
5469
  format: "esm",
4811
5470
  exports: "default"
@@ -4856,7 +5515,7 @@ var watchFile = (path) => {
4856
5515
  event.result.close();
4857
5516
  const output = result.output[0];
4858
5517
  const code = output.code;
4859
- const outputFile = join3(directories.cache, "config.js");
5518
+ const outputFile = join5(directories.cache, "config.js");
4860
5519
  await mkdir2(directories.cache, { recursive: true });
4861
5520
  await writeFile2(outputFile, code);
4862
5521
  debug("Save config file:", style.info(outputFile));
@@ -4874,7 +5533,7 @@ var watchFile = (path) => {
4874
5533
  };
4875
5534
 
4876
5535
  // src/config.ts
4877
- import { z as z27 } from "zod";
5536
+ import { z as z29 } from "zod";
4878
5537
  var ConfigError = class extends Error {
4879
5538
  constructor(error, data) {
4880
5539
  super(error.message);
@@ -4889,7 +5548,7 @@ var importConfig = async (options) => {
4889
5548
  setRoot(root2);
4890
5549
  debug("CWD:", style.info(root2));
4891
5550
  debug("Import config file");
4892
- const fileName = join4(root2, configFile);
5551
+ const fileName = join6(root2, configFile);
4893
5552
  const module = await importFile(fileName);
4894
5553
  const appConfig = typeof module.default === "function" ? await module.default(options) : module.default;
4895
5554
  debug("Validate config file");
@@ -4907,7 +5566,7 @@ var importConfig = async (options) => {
4907
5566
  try {
4908
5567
  config = await schema2.parseAsync(appConfig);
4909
5568
  } catch (error) {
4910
- if (error instanceof z27.ZodError) {
5569
+ if (error instanceof z29.ZodError) {
4911
5570
  throw new ConfigError(error, appConfig);
4912
5571
  }
4913
5572
  throw error;
@@ -4930,7 +5589,7 @@ var watchConfig = async function* (options) {
4930
5589
  setRoot(root2);
4931
5590
  debug("CWD:", style.info(root2));
4932
5591
  debug("Import config file");
4933
- const fileName = join4(root2, configFile);
5592
+ const fileName = join6(root2, configFile);
4934
5593
  for await (const module of watchFile(fileName)) {
4935
5594
  const appConfig = typeof module.default === "function" ? await module.default(options) : module.default;
4936
5595
  debug("Validate config file");
@@ -4948,7 +5607,7 @@ var watchConfig = async function* (options) {
4948
5607
  try {
4949
5608
  config = await schema2.parseAsync(appConfig);
4950
5609
  } catch (error) {
4951
- if (error instanceof z27.ZodError) {
5610
+ if (error instanceof z29.ZodError) {
4952
5611
  throw new ConfigError(error, appConfig);
4953
5612
  }
4954
5613
  throw error;
@@ -5545,7 +6204,7 @@ var flexLine = (term, left, right, reserveSpace = 0) => {
5545
6204
  };
5546
6205
 
5547
6206
  // src/cli/ui/complex/builder.ts
5548
- import { dirname as dirname3, join as join5 } from "path";
6207
+ import { dirname as dirname3, join as join7 } from "path";
5549
6208
  var assetBuilder = (app) => {
5550
6209
  return async (term) => {
5551
6210
  const assets = [];
@@ -5608,7 +6267,7 @@ var assetBuilder = (app) => {
5608
6267
  try {
5609
6268
  const data = await asset.build({
5610
6269
  async write(file, data2) {
5611
- const fullpath = join5(directories.asset, asset.type, app.name, stack.name, asset.id, file);
6270
+ const fullpath = join7(directories.asset, asset.type, app.name, stack.name, asset.id, file);
5612
6271
  const basepath = dirname3(fullpath);
5613
6272
  await mkdir3(basepath, { recursive: true });
5614
6273
  await writeFile3(fullpath, data2);
@@ -5656,14 +6315,14 @@ var cleanUp = async () => {
5656
6315
 
5657
6316
  // src/cli/ui/complex/template.ts
5658
6317
  import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
5659
- import { join as join6 } from "path";
6318
+ import { join as join8 } from "path";
5660
6319
  var templateBuilder = (app) => {
5661
6320
  return async (term) => {
5662
6321
  const done = term.out.write(loadingDialog("Building stack templates..."));
5663
6322
  await Promise.all(app.stacks.map(async (stack) => {
5664
6323
  const template = stack.toString(true);
5665
- const path = join6(directories.template, app.name);
5666
- const file = join6(path, `${stack.name}.json`);
6324
+ const path = join8(directories.template, app.name);
6325
+ const file = join8(path, `${stack.name}.json`);
5667
6326
  await mkdir5(path, { recursive: true });
5668
6327
  await writeFile4(file, template);
5669
6328
  }));
@@ -5708,7 +6367,7 @@ var bootstrapStack = (account, region) => {
5708
6367
  stack.add(new Bucket("assets", {
5709
6368
  name: assetBucketName(account, region),
5710
6369
  accessControl: "private",
5711
- versioned: true
6370
+ versioning: true
5712
6371
  }));
5713
6372
  stack.export("version", version);
5714
6373
  app.add(stack);
@@ -5878,6 +6537,7 @@ var StackClient = class {
5878
6537
  });
5879
6538
  debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
5880
6539
  return {
6540
+ id: stack.StackId,
5881
6541
  status: stack.StackStatus,
5882
6542
  reason: stack.StackStatusReason,
5883
6543
  outputs,
@@ -5924,10 +6584,10 @@ var StackClient = class {
5924
6584
  maxWaitTime: this.maxWaitTime,
5925
6585
  maxDelay: this.maxDelay
5926
6586
  }, {
5927
- StackName: this.stackName(name)
6587
+ StackName: data.id
5928
6588
  });
5929
6589
  } catch (_) {
5930
- const reason = await this.getFailureReason(name, region);
6590
+ const reason = await this.getFailureReason(data.id, region);
5931
6591
  throw new Error(reason);
5932
6592
  }
5933
6593
  }
@@ -6185,7 +6845,7 @@ var status = (program2) => {
6185
6845
 
6186
6846
  // src/cli/ui/complex/publisher.ts
6187
6847
  import { readFile as readFile3 } from "fs/promises";
6188
- import { join as join7 } from "path";
6848
+ import { join as join9 } from "path";
6189
6849
  import { GetObjectCommand, ObjectCannedACL as ObjectCannedACL2, PutObjectCommand as PutObjectCommand2, S3Client as S3Client2, StorageClass as StorageClass2 } from "@aws-sdk/client-s3";
6190
6850
  var assetPublisher = (config, app) => {
6191
6851
  const client = new S3Client2({
@@ -6199,12 +6859,12 @@ var assetPublisher = (config, app) => {
6199
6859
  await Promise.all([...stack.assets].map(async (asset) => {
6200
6860
  await asset.publish?.({
6201
6861
  async read(file) {
6202
- const path = join7(directories.asset, asset.type, app.name, stack.name, asset.id, file);
6862
+ const path = join9(directories.asset, asset.type, app.name, stack.name, asset.id, file);
6203
6863
  const data = await readFile3(path);
6204
6864
  return data;
6205
6865
  },
6206
6866
  async publish(name, data, hash) {
6207
- const key = `${app.name}/${stack.name}/function/${name}`;
6867
+ const key = `${app.name}/${stack.name}/${asset.type}/${name}`;
6208
6868
  const bucket = assetBucketName(config.account, config.region);
6209
6869
  let getResult;
6210
6870
  try {
@@ -6444,16 +7104,6 @@ var secrets = (program2) => {
6444
7104
  commands.forEach((cb) => cb(command));
6445
7105
  };
6446
7106
 
6447
- // src/cli/command/test.ts
6448
- var test = (program2) => {
6449
- program2.command("test").action(async () => {
6450
- await layout(async (config) => {
6451
- const app = new App("test");
6452
- const name = "test5";
6453
- });
6454
- });
6455
- };
6456
-
6457
7107
  // src/cli/command/types.ts
6458
7108
  var types = (program2) => {
6459
7109
  program2.command("types").description("Generate type definition files").action(async () => {
@@ -6477,6 +7127,48 @@ var dev = (program2) => {
6477
7127
  });
6478
7128
  };
6479
7129
 
7130
+ // src/cli/command/delete.ts
7131
+ var del2 = (program2) => {
7132
+ program2.command("delete").argument("[stacks...]", "Optionally filter stacks to delete").description("Delete your app from AWS").action(async (filters) => {
7133
+ await layout(async (config, write) => {
7134
+ const { app, deploymentLine } = await toApp(config, filters);
7135
+ const deletingLine = deploymentLine.reverse();
7136
+ const stackNames = app.stacks.map((stack) => stack.name);
7137
+ const formattedFilter = stackNames.map((i) => style.info(i)).join(style.placeholder(", "));
7138
+ debug("Stacks to delete", formattedFilter);
7139
+ const deployAll = filters.length === 0;
7140
+ const deploySingle = filters.length === 1;
7141
+ const confirm = await write(confirmPrompt(deployAll ? `Are you sure you want to ${style.error("delete")} ${style.warning("all")} stacks?` : deploySingle ? `Are you sure you want to ${style.error("delete")} the ${formattedFilter} stack?` : `Are you sure you want to ${style.error("delete")} the [ ${formattedFilter} ] stacks?`));
7142
+ if (!confirm) {
7143
+ throw new Cancelled();
7144
+ }
7145
+ const doneDeploying = write(loadingDialog("Deleting stacks from AWS..."));
7146
+ const client = new StackClient(app, config.account, config.region, config.credentials);
7147
+ const ui = write(stacksDeployer(deletingLine));
7148
+ for (const line2 of deletingLine) {
7149
+ const results = await Promise.allSettled(line2.map(async (stack) => {
7150
+ const item = ui[stack.name];
7151
+ item.start("deleting");
7152
+ try {
7153
+ await client.delete(stack.name, stack.region);
7154
+ } catch (error) {
7155
+ debugError(error);
7156
+ item.fail("failed");
7157
+ throw error;
7158
+ }
7159
+ item.done("deleted");
7160
+ }));
7161
+ for (const result of results) {
7162
+ if (result.status === "rejected") {
7163
+ throw result.reason;
7164
+ }
7165
+ }
7166
+ }
7167
+ doneDeploying("Done deleting stacks from AWS");
7168
+ });
7169
+ });
7170
+ };
7171
+
6480
7172
  // src/cli/program.ts
6481
7173
  var program = new Command();
6482
7174
  program.name(logo().join("").replace(/\s+/, ""));
@@ -6498,9 +7190,10 @@ var commands2 = [
6498
7190
  types,
6499
7191
  build,
6500
7192
  deploy,
7193
+ del2,
6501
7194
  dev,
6502
- secrets,
6503
- test
7195
+ secrets
7196
+ // test,
6504
7197
  // diff,
6505
7198
  // remove,
6506
7199
  ];