@awsless/awsless 0.0.44 → 0.0.46

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,18 +1223,28 @@ 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({
1099
1235
  /** The file path of the function code. */
1100
1236
  file: LocalFileSchema,
1237
+ // /** */
1238
+ // handler: z.string().optional(),
1101
1239
  /** Put the function inside your global VPC.
1102
1240
  * @default false
1103
1241
  */
1104
1242
  vpc: z6.boolean().optional(),
1243
+ /** Enable logging to a CloudWatch log group.
1244
+ * Providing a duration value will set the log retention time.
1245
+ * @default false
1246
+ */
1247
+ log: LogSchema.optional(),
1105
1248
  /** The amount of time that Lambda allows a function to run before stopping it.
1106
1249
  * You can specify a size value from 1 second to 15 minutes.
1107
1250
  * @default '10 seconds'
@@ -1158,6 +1301,10 @@ var schema = z6.object({
1158
1301
  * @default false
1159
1302
  */
1160
1303
  vpc: z6.boolean().default(false),
1304
+ /** Enable logging to a CloudWatch log group.
1305
+ * @default false
1306
+ */
1307
+ log: LogSchema.default(false),
1161
1308
  /** The amount of time that Lambda allows a function to run before stopping it.
1162
1309
  * You can specify a size value from 1 second to 15 minutes.
1163
1310
  * @default '10 seconds'
@@ -1270,22 +1417,26 @@ var functionPlugin = definePlugin({
1270
1417
  var toLambdaFunction = (ctx, id, fileOrProps) => {
1271
1418
  const config = ctx.config;
1272
1419
  const stack = ctx.stack;
1420
+ const bootstrap2 = ctx.bootstrap;
1273
1421
  const props = typeof fileOrProps === "string" ? { ...config.defaults?.function, file: fileOrProps } : { ...config.defaults?.function, ...fileOrProps };
1274
1422
  const lambda = new Function(id, {
1275
- name: `${config.name}--${stack.name}--${id}`,
1423
+ name: `${config.name}-${stack.name}-${id}`,
1276
1424
  code: Code.fromFile(id, props.file),
1277
1425
  ...props,
1278
1426
  vpc: void 0
1279
1427
  });
1280
1428
  lambda.addEnvironment("APP", config.name).addEnvironment("STAGE", config.stage).addEnvironment("STACK", stack.name);
1429
+ if (props.log) {
1430
+ lambda.enableLogs(props.log instanceof Duration ? props.log : void 0);
1431
+ }
1281
1432
  if (props.vpc) {
1282
1433
  lambda.setVpc({
1283
1434
  securityGroupIds: [
1284
- ctx.bootstrap.import(`vpc-security-group-id`)
1435
+ bootstrap2.import(`vpc-security-group-id`)
1285
1436
  ],
1286
1437
  subnetIds: [
1287
- ctx.bootstrap.import(`public-subnet-1`),
1288
- ctx.bootstrap.import(`public-subnet-2`)
1438
+ bootstrap2.import(`public-subnet-1`),
1439
+ bootstrap2.import(`public-subnet-2`)
1289
1440
  ]
1290
1441
  }).addPermissions({
1291
1442
  actions: [
@@ -1298,9 +1449,6 @@ var toLambdaFunction = (ctx, id, fileOrProps) => {
1298
1449
  resources: ["*"]
1299
1450
  });
1300
1451
  }
1301
- if (props.runtime.startsWith("nodejs")) {
1302
- lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1");
1303
- }
1304
1452
  ctx.bind((other) => {
1305
1453
  other.addPermissions(lambda.permissions);
1306
1454
  });
@@ -1340,6 +1488,7 @@ var Rule = class extends Resource {
1340
1488
  };
1341
1489
 
1342
1490
  // src/formation/resource/lambda/permission.ts
1491
+ import { constantCase as constantCase3 } from "change-case";
1343
1492
  var Permission2 = class extends Resource {
1344
1493
  constructor(logicalId, props) {
1345
1494
  super("AWS::Lambda::Permission", logicalId);
@@ -1350,6 +1499,7 @@ var Permission2 = class extends Resource {
1350
1499
  FunctionName: this.props.functionArn,
1351
1500
  Action: this.props.action || "lambda:InvokeFunction",
1352
1501
  Principal: this.props.principal,
1502
+ ...this.attr("FunctionUrlAuthType", this.props.urlAuthType && constantCase3(this.props.urlAuthType)),
1353
1503
  ...this.attr("SourceArn", this.props.sourceArn)
1354
1504
  };
1355
1505
  }
@@ -1476,7 +1626,7 @@ var Queue = class extends Resource {
1476
1626
  };
1477
1627
 
1478
1628
  // src/formation/resource/lambda/event-source-mapping.ts
1479
- import { constantCase as constantCase2 } from "change-case";
1629
+ import { constantCase as constantCase4 } from "change-case";
1480
1630
  var EventSourceMapping = class extends Resource {
1481
1631
  constructor(logicalId, props) {
1482
1632
  super("AWS::Lambda::EventSourceMapping", logicalId);
@@ -1498,7 +1648,7 @@ var EventSourceMapping = class extends Resource {
1498
1648
  ...this.attr("ParallelizationFactor", this.props.parallelizationFactor),
1499
1649
  ...this.attr("TumblingWindowInSeconds", this.props.tumblingWindow?.toSeconds()),
1500
1650
  ...this.attr("BisectBatchOnFunctionError", this.props.bisectBatchOnError),
1501
- ...this.attr("StartingPosition", this.props.startingPosition && constantCase2(this.props.startingPosition)),
1651
+ ...this.attr("StartingPosition", this.props.startingPosition && constantCase4(this.props.startingPosition)),
1502
1652
  ...this.attr("StartingPositionTimestamp", this.props.startingPositionTimestamp),
1503
1653
  ...this.props.maxConcurrency ? {
1504
1654
  ScalingConfig: {
@@ -1539,7 +1689,7 @@ var SqsEventSource = class extends Group {
1539
1689
  };
1540
1690
 
1541
1691
  // src/plugins/queue.ts
1542
- import { camelCase as camelCase3, constantCase as constantCase3 } from "change-case";
1692
+ import { camelCase as camelCase3, constantCase as constantCase5 } from "change-case";
1543
1693
  import { relative as relative3 } from "path";
1544
1694
  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
1695
  var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
@@ -1694,7 +1844,7 @@ var queuePlugin = definePlugin({
1694
1844
  stack.add(queue2, lambda, source);
1695
1845
  bind((lambda2) => {
1696
1846
  lambda2.addPermissions(queue2.permissions);
1697
- lambda2.addEnvironment(`QUEUE_${constantCase3(stack.name)}_${constantCase3(id)}_URL`, queue2.url);
1847
+ lambda2.addEnvironment(`QUEUE_${constantCase5(stack.name)}_${constantCase5(id)}_URL`, queue2.url);
1698
1848
  });
1699
1849
  }
1700
1850
  }
@@ -1704,7 +1854,7 @@ var queuePlugin = definePlugin({
1704
1854
  import { z as z9 } from "zod";
1705
1855
 
1706
1856
  // src/formation/resource/dynamodb/table.ts
1707
- import { constantCase as constantCase4 } from "change-case";
1857
+ import { constantCase as constantCase6 } from "change-case";
1708
1858
  var Table = class extends Resource {
1709
1859
  constructor(logicalId, props) {
1710
1860
  super("AWS::DynamoDB::Table", logicalId);
@@ -1777,7 +1927,7 @@ var Table = class extends Resource {
1777
1927
  return {
1778
1928
  TableName: this.name,
1779
1929
  BillingMode: "PAY_PER_REQUEST",
1780
- TableClass: constantCase4(this.props.class || "standard"),
1930
+ TableClass: constantCase6(this.props.class || "standard"),
1781
1931
  PointInTimeRecoverySpecification: {
1782
1932
  PointInTimeRecoveryEnabled: this.props.pointInTimeRecovery || false
1783
1933
  },
@@ -1788,7 +1938,7 @@ var Table = class extends Resource {
1788
1938
  AttributeDefinitions: this.attributeDefinitions(),
1789
1939
  ...this.props.stream ? {
1790
1940
  StreamSpecification: {
1791
- StreamViewType: constantCase4(this.props.stream)
1941
+ StreamViewType: constantCase6(this.props.stream)
1792
1942
  }
1793
1943
  } : {},
1794
1944
  ...this.props.timeToLiveAttribute ? {
@@ -1805,7 +1955,7 @@ var Table = class extends Resource {
1805
1955
  ...props.sort ? [{ KeyType: "RANGE", AttributeName: props.sort }] : []
1806
1956
  ],
1807
1957
  Projection: {
1808
- ProjectionType: constantCase4(props.projection || "all")
1958
+ ProjectionType: constantCase6(props.projection || "all")
1809
1959
  }
1810
1960
  }))
1811
1961
  } : {}
@@ -1931,21 +2081,6 @@ var tablePlugin = definePlugin({
1931
2081
  projection: z9.enum(["all", "keys-only"]).default("all")
1932
2082
  })).optional()
1933
2083
  })
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
2084
  ).optional()
1950
2085
  }).array()
1951
2086
  }),
@@ -2000,11 +2135,20 @@ var Bucket = class extends Resource {
2000
2135
  }
2001
2136
  name;
2002
2137
  get arn() {
2003
- return ref(this.logicalId);
2138
+ return getAtt(this.logicalId, "Arn");
2004
2139
  }
2005
2140
  get domainName() {
2006
2141
  return getAtt(this.logicalId, "DomainName");
2007
2142
  }
2143
+ get dealStackDomainName() {
2144
+ return getAtt(this.logicalId, "DualStackDomainName");
2145
+ }
2146
+ get regionalDomainName() {
2147
+ return getAtt(this.logicalId, "RegionalDomainName");
2148
+ }
2149
+ get url() {
2150
+ return getAtt(this.logicalId, "WebsiteURL");
2151
+ }
2008
2152
  get permissions() {
2009
2153
  return {
2010
2154
  actions: [
@@ -2026,15 +2170,38 @@ var Bucket = class extends Resource {
2026
2170
  return {
2027
2171
  BucketName: this.name,
2028
2172
  AccessControl: pascalCase2(this.props.accessControl ?? "private"),
2029
- ...this.props.versioned ? {
2173
+ ...this.props.versioning ? {
2030
2174
  VersioningConfiguration: {
2031
2175
  Status: "Enabled"
2032
2176
  }
2177
+ } : {},
2178
+ ...this.props.website ? {
2179
+ WebsiteConfiguration: {
2180
+ ...this.attr("IndexDocument", this.props.website.indexDocument),
2181
+ ...this.attr("ErrorDocument", this.props.website.errorDocument)
2182
+ }
2033
2183
  } : {}
2034
2184
  };
2035
2185
  }
2036
2186
  };
2037
2187
 
2188
+ // src/formation/resource/cloud-formation/custom-resource.ts
2189
+ var CustomResource = class extends Resource {
2190
+ constructor(logicalId, props) {
2191
+ super("AWS::CloudFormation::CustomResource", logicalId);
2192
+ this.props = props;
2193
+ }
2194
+ getAtt(name) {
2195
+ return getAtt(this.logicalId, name);
2196
+ }
2197
+ properties() {
2198
+ return {
2199
+ ServiceToken: this.props.serviceToken,
2200
+ ...this.props.properties
2201
+ };
2202
+ }
2203
+ };
2204
+
2038
2205
  // src/plugins/store.ts
2039
2206
  var storePlugin = definePlugin({
2040
2207
  name: "store",
@@ -2061,13 +2228,19 @@ var storePlugin = definePlugin({
2061
2228
  }
2062
2229
  return types2.toString();
2063
2230
  },
2064
- onStack({ config, stack, stackConfig, bind }) {
2231
+ onStack({ config, stack, stackConfig, bootstrap: bootstrap2, bind }) {
2065
2232
  for (const id of stackConfig.stores || []) {
2066
2233
  const bucket = new Bucket(id, {
2067
- name: `${config.name}-${stack.name}-${id}`,
2234
+ name: `store-${config.name}-${stack.name}-${id}`,
2068
2235
  accessControl: "private"
2069
2236
  });
2070
- stack.add(bucket);
2237
+ const custom = new CustomResource(id, {
2238
+ serviceToken: bootstrap2.import("feature-delete-bucket"),
2239
+ properties: {
2240
+ bucketName: bucket.name
2241
+ }
2242
+ }).dependsOn(bucket);
2243
+ stack.add(bucket, custom);
2071
2244
  bind((lambda) => {
2072
2245
  lambda.addPermissions(bucket.permissions);
2073
2246
  });
@@ -2371,7 +2544,7 @@ var toArray = (value) => {
2371
2544
  import { paramCase as paramCase4 } from "change-case";
2372
2545
 
2373
2546
  // src/formation/resource/appsync/graphql-api.ts
2374
- import { constantCase as constantCase5 } from "change-case";
2547
+ import { constantCase as constantCase7 } from "change-case";
2375
2548
  var GraphQLApi = class extends Resource {
2376
2549
  constructor(logicalId, props) {
2377
2550
  super("AWS::AppSync::GraphQLApi", logicalId);
@@ -2403,7 +2576,7 @@ var GraphQLApi = class extends Resource {
2403
2576
  properties() {
2404
2577
  return {
2405
2578
  Name: this.name,
2406
- AuthenticationType: constantCase5(this.props.authenticationType || "api-key"),
2579
+ AuthenticationType: constantCase7(this.props.authenticationType || "api-key"),
2407
2580
  AdditionalAuthenticationProviders: this.lambdaAuthProviders.map((provider) => ({
2408
2581
  AuthenticationType: "AWS_LAMBDA",
2409
2582
  LambdaAuthorizerConfig: {
@@ -2750,7 +2923,7 @@ var graphqlPlugin = definePlugin({
2750
2923
  }).array()
2751
2924
  }),
2752
2925
  onApp(ctx) {
2753
- const { config, bootstrap: bootstrap2, usEastBootstrap } = ctx;
2926
+ const { config, bootstrap: bootstrap2 } = ctx;
2754
2927
  const apis = /* @__PURE__ */ new Set();
2755
2928
  for (const stackConfig of config.stacks) {
2756
2929
  for (const id of Object.keys(stackConfig.graphql || {})) {
@@ -2783,8 +2956,9 @@ var graphqlPlugin = definePlugin({
2783
2956
  }
2784
2957
  if (props.domain) {
2785
2958
  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`);
2959
+ const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
2960
+ const certificateArn = bootstrap2.import(`us-east-certificate-${props.domain}-arn`);
2961
+ debug("DEBUG CERT", certificateArn);
2788
2962
  const domain = new DomainName(id, {
2789
2963
  domainName,
2790
2964
  certificateArn
@@ -2900,132 +3074,31 @@ var RecordSetGroup = class extends Resource {
2900
3074
  }
2901
3075
  };
2902
3076
 
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);
3077
+ // src/custom/global-exports.ts
3078
+ var GlobalExports = class extends Group {
3079
+ resource;
3080
+ constructor(id, props) {
3081
+ const lambda = new Function(id, {
3082
+ code: Code.fromFeature("global-exports")
3083
+ });
3084
+ lambda.addPermissions({
3085
+ actions: ["cloudformation:ListExports"],
3086
+ resources: ["*"]
3087
+ });
3088
+ const resource = new CustomResource(id, {
3089
+ serviceToken: lambda.arn,
3090
+ properties: {
3091
+ region: props.region
3092
+ }
3093
+ });
3094
+ super([lambda, resource]);
3095
+ this.resource = resource;
3023
3096
  }
3024
- properties() {
3025
- return {
3026
- ServiceToken: this.props.serviceToken,
3027
- ...this.props.properties
3028
- };
3097
+ import(name) {
3098
+ return lazy((stack) => {
3099
+ const attr = formatName(`${stack.app?.name ?? "default"}-${name}`);
3100
+ return this.resource.getAtt(attr);
3101
+ });
3029
3102
  }
3030
3103
  };
3031
3104
 
@@ -3067,36 +3140,39 @@ var domainPlugin = definePlugin({
3067
3140
  if (domains.length === 0) {
3068
3141
  return;
3069
3142
  }
3070
- const lambda = new Function("delete-hosted-zone", {
3143
+ const deleteHostedZoneLambda = new Function("delete-hosted-zone", {
3071
3144
  name: `${config.name}-delete-hosted-zone`,
3072
- code: Code.fromInline(deleteHostedZoneRecordsHandlerCode, "index.handler")
3073
- });
3074
- lambda.addPermissions({
3145
+ code: Code.fromInlineFeature("delete-hosted-zone")
3146
+ }).enableLogs(Duration.days(3)).addPermissions({
3075
3147
  actions: [
3076
3148
  "route53:ListResourceRecordSets",
3077
3149
  "route53:ChangeResourceRecordSets"
3078
3150
  ],
3079
3151
  resources: ["*"]
3080
3152
  });
3081
- usEastBootstrap.add(lambda);
3153
+ usEastBootstrap.add(deleteHostedZoneLambda);
3154
+ const usEastExports = new GlobalExports("us-east-exports", {
3155
+ region: usEastBootstrap.region
3156
+ });
3157
+ bootstrap2.add(usEastExports);
3082
3158
  for (const [domain, records] of domains) {
3083
3159
  const hostedZone = new HostedZone(domain);
3084
3160
  const usEastCertificate = new Certificate(domain, {
3085
3161
  hostedZoneId: hostedZone.id,
3086
3162
  alternativeNames: [`*.${domain}`]
3087
3163
  });
3088
- const custom = new CustomResource(domain, {
3089
- serviceToken: lambda.arn,
3164
+ const deleteHostedZone = new CustomResource(domain, {
3165
+ serviceToken: deleteHostedZoneLambda.arn,
3090
3166
  properties: {
3091
3167
  hostedZoneId: hostedZone.id
3092
3168
  }
3093
- }).dependsOn(hostedZone);
3094
- usEastBootstrap.add(custom).add(hostedZone).add(usEastCertificate).export(`certificate-${domain}-arn`, usEastCertificate.arn).export(`hosted-zone-${domain}-id`, hostedZone.id);
3169
+ }).dependsOn(deleteHostedZoneLambda, hostedZone);
3170
+ usEastBootstrap.add(hostedZone).add(deleteHostedZone).add(usEastCertificate).export(`certificate-${domain}-arn`, usEastCertificate.arn).export(`hosted-zone-${domain}-id`, hostedZone.id);
3095
3171
  const certificate = new Certificate(domain, {
3096
- hostedZoneId: usEastBootstrap.import(`hosted-zone-${domain}-id`),
3172
+ hostedZoneId: usEastExports.import(`hosted-zone-${domain}-id`),
3097
3173
  alternativeNames: [`*.${domain}`]
3098
3174
  });
3099
- bootstrap2.add(certificate).export(`certificate-${domain}-arn`, certificate.arn);
3175
+ 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
3176
  if (records.length > 0) {
3101
3177
  const group = new RecordSetGroup(domain, {
3102
3178
  hostedZoneId: hostedZone.id,
@@ -3508,7 +3584,7 @@ var LoadBalancer = class extends Resource {
3508
3584
  };
3509
3585
 
3510
3586
  // src/formation/resource/elb/listener.ts
3511
- import { constantCase as constantCase6 } from "change-case";
3587
+ import { constantCase as constantCase8 } from "change-case";
3512
3588
  var Listener = class extends Resource {
3513
3589
  constructor(logicalId, props) {
3514
3590
  super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
@@ -3524,7 +3600,7 @@ var Listener = class extends Resource {
3524
3600
  return {
3525
3601
  LoadBalancerArn: this.props.loadBalancerArn,
3526
3602
  Port: this.props.port,
3527
- Protocol: constantCase6(this.props.protocol),
3603
+ Protocol: constantCase8(this.props.protocol),
3528
3604
  Certificates: this.props.certificates.map((arn) => ({
3529
3605
  CertificateArn: arn
3530
3606
  })),
@@ -3750,7 +3826,7 @@ var httpPlugin = definePlugin({
3750
3826
  ).optional()
3751
3827
  }).array()
3752
3828
  }),
3753
- onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
3829
+ onApp({ config, bootstrap: bootstrap2 }) {
3754
3830
  if (Object.keys(config.defaults?.http || {}).length === 0) {
3755
3831
  return;
3756
3832
  }
@@ -3789,7 +3865,7 @@ var httpPlugin = definePlugin({
3789
3865
  ]
3790
3866
  }).dependsOn(loadBalancer);
3791
3867
  const record = new RecordSet(`${id}-http`, {
3792
- hostedZoneId: usEastBootstrap.import(`hosted-zone-${props.domain}-id`),
3868
+ hostedZoneId: bootstrap2.import(`hosted-zone-${props.domain}-id`),
3793
3869
  name: props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain,
3794
3870
  type: "A",
3795
3871
  alias: {
@@ -3963,7 +4039,7 @@ var SubnetGroup = class extends Resource {
3963
4039
  };
3964
4040
 
3965
4041
  // src/plugins/cache.ts
3966
- import { constantCase as constantCase7 } from "change-case";
4042
+ import { constantCase as constantCase9 } from "change-case";
3967
4043
  var TypeSchema = z19.enum([
3968
4044
  "t4g.small",
3969
4045
  "t4g.medium",
@@ -4049,7 +4125,7 @@ var cachePlugin = definePlugin({
4049
4125
  }).dependsOn(subnetGroup, securityGroup);
4050
4126
  stack.add(subnetGroup, securityGroup, cluster);
4051
4127
  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());
4128
+ lambda.addEnvironment(`CACHE_${constantCase9(stack.name)}_${constantCase9(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase9(stack.name)}_${constantCase9(id)}_PORT`, props.port.toString());
4053
4129
  });
4054
4130
  }
4055
4131
  }
@@ -4267,7 +4343,7 @@ var restPlugin = definePlugin({
4267
4343
  ).optional()
4268
4344
  }).array()
4269
4345
  }),
4270
- onApp({ config, bootstrap: bootstrap2, usEastBootstrap }) {
4346
+ onApp({ config, bootstrap: bootstrap2 }) {
4271
4347
  for (const [id, props] of Object.entries(config.defaults?.rest || {})) {
4272
4348
  const api = new Api(id, {
4273
4349
  name: `${config.name}-${id}`,
@@ -4280,7 +4356,7 @@ var restPlugin = definePlugin({
4280
4356
  bootstrap2.add(api, stage).export(`rest-${id}-id`, api.id);
4281
4357
  if (props.domain) {
4282
4358
  const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
4283
- const hostedZoneId = usEastBootstrap.import(`hosted-zone-${props.domain}-id`);
4359
+ const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
4284
4360
  const certificateArn = bootstrap2.import(`certificate-${props.domain}-arn`);
4285
4361
  const domain = new DomainName2(id, {
4286
4362
  name: domainName,
@@ -4291,7 +4367,7 @@ var restPlugin = definePlugin({
4291
4367
  domainName: domain.name,
4292
4368
  stage: stage.name
4293
4369
  }).dependsOn(api, domain, stage);
4294
- const record = new RecordSet(`${id}-rest`, {
4370
+ const record = new RecordSet(`rest-${id}`, {
4295
4371
  hostedZoneId,
4296
4372
  type: "A",
4297
4373
  name: domainName,
@@ -4466,131 +4542,717 @@ var configPlugin = definePlugin({
4466
4542
  }
4467
4543
  });
4468
4544
 
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
- ];
4545
+ // src/plugins/site.ts
4546
+ import { z as z24 } from "zod";
4489
4547
 
4490
- // src/formation/app.ts
4491
- var App = class {
4492
- constructor(name) {
4493
- this.name = name;
4548
+ // src/formation/resource/cloud-front/distribution.ts
4549
+ var Distribution = class extends Resource {
4550
+ constructor(logicalId, props) {
4551
+ super("AWS::CloudFront::Distribution", logicalId);
4552
+ this.props = props;
4553
+ this.name = formatName(this.props.name || logicalId);
4554
+ this.tag("name", this.name);
4494
4555
  }
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;
4556
+ name;
4557
+ get id() {
4558
+ return getAtt(this.logicalId, "Id");
4502
4559
  }
4503
- find(resourceType) {
4504
- return this.stacks.map((stack) => stack.find(resourceType)).flat();
4560
+ get arn() {
4561
+ return sub("arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${id}", {
4562
+ id: this.id
4563
+ });
4505
4564
  }
4506
- [Symbol.iterator]() {
4507
- return this.list.values();
4565
+ get domainName() {
4566
+ return getAtt(this.logicalId, "DomainName");
4508
4567
  }
4509
- get stacks() {
4510
- return [...this.list.values()];
4568
+ properties() {
4569
+ return {
4570
+ DistributionConfig: {
4571
+ Enabled: true,
4572
+ Aliases: this.props.aliases ?? [],
4573
+ PriceClass: "PriceClass_" + (this.props.priceClass ?? "All"),
4574
+ HttpVersion: this.props.httpVersion ?? "http2and3",
4575
+ ViewerCertificate: this.props.certificateArn ? {
4576
+ SslSupportMethod: "sni-only",
4577
+ AcmCertificateArn: this.props.certificateArn
4578
+ } : {},
4579
+ Origins: this.props.origins?.map((origin) => origin.toJSON()) ?? [],
4580
+ OriginGroups: {
4581
+ Quantity: this.props.originGroups?.length ?? 0,
4582
+ Items: this.props.originGroups?.map((originGroup) => originGroup.toJSON()) ?? []
4583
+ },
4584
+ DefaultCacheBehavior: {
4585
+ TargetOriginId: this.props.targetOriginId,
4586
+ ViewerProtocolPolicy: this.props.viewerProtocol ?? "redirect-to-https",
4587
+ AllowedMethods: this.props.allowMethod ?? ["GET", "HEAD", "OPTIONS"],
4588
+ Compress: this.props.compress ?? false,
4589
+ FunctionAssociations: this.props.associations?.map((association) => ({
4590
+ EventType: association.type,
4591
+ FunctionARN: association.functionArn
4592
+ })) ?? [],
4593
+ LambdaFunctionAssociations: this.props.lambdaAssociations?.map((association) => ({
4594
+ EventType: association.type,
4595
+ IncludeBody: association.includeBody ?? false,
4596
+ FunctionARN: association.functionArn
4597
+ })) ?? [],
4598
+ ...this.attr("CachePolicyId", this.props.cachePolicyId),
4599
+ ...this.attr("OriginRequestPolicyId", this.props.originRequestPolicyId),
4600
+ ...this.attr("ResponseHeadersPolicyId", this.props.responseHeadersPolicyId)
4601
+ }
4602
+ }
4603
+ };
4604
+ }
4605
+ };
4606
+ var Origin = class {
4607
+ constructor(props) {
4608
+ this.props = props;
4609
+ }
4610
+ toJSON() {
4611
+ return {
4612
+ Id: this.props.id,
4613
+ DomainName: this.props.domainName,
4614
+ OriginCustomHeaders: Object.entries(this.props.headers ?? {}).map(([name, value]) => ({
4615
+ HeaderName: name,
4616
+ HeaderValue: value
4617
+ })),
4618
+ ...this.props.path ? {
4619
+ OriginPath: this.props.path
4620
+ } : {},
4621
+ ...this.props.protocol ? {
4622
+ CustomOriginConfig: {
4623
+ OriginProtocolPolicy: this.props.protocol
4624
+ }
4625
+ } : {},
4626
+ ...this.props.originAccessIdentityId ? {
4627
+ S3OriginConfig: {
4628
+ OriginAccessIdentity: sub("origin-access-identity/cloudfront/${id}", {
4629
+ id: this.props.originAccessIdentityId
4630
+ })
4631
+ }
4632
+ } : {},
4633
+ ...this.props.originAccessControlId ? {
4634
+ OriginAccessControlId: this.props.originAccessControlId,
4635
+ S3OriginConfig: {
4636
+ OriginAccessIdentity: ""
4637
+ }
4638
+ } : {}
4639
+ };
4640
+ }
4641
+ };
4642
+ var OriginGroup = class {
4643
+ constructor(props) {
4644
+ this.props = props;
4645
+ }
4646
+ toJSON() {
4647
+ return {
4648
+ Id: this.props.id,
4649
+ Members: {
4650
+ Quantity: this.props.members.length,
4651
+ Items: this.props.members.map((member) => ({
4652
+ OriginId: member
4653
+ }))
4654
+ },
4655
+ FailoverCriteria: {
4656
+ StatusCodes: {
4657
+ Quantity: this.props.statusCodes.length,
4658
+ Items: this.props.statusCodes
4659
+ }
4660
+ }
4661
+ };
4511
4662
  }
4512
- // get resources() {
4513
- // return this.stacks.map(stack => stack.resources).flat()
4514
- // }
4515
4663
  };
4516
4664
 
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)
4665
+ // src/schema/local-directory.ts
4666
+ import { stat as stat2 } from "fs/promises";
4667
+ import { z as z23 } from "zod";
4668
+ var LocalDirectorySchema = z23.string().refine(async (path) => {
4669
+ try {
4670
+ const s = await stat2(path);
4671
+ return s.isDirectory();
4672
+ } catch (error) {
4673
+ return false;
4674
+ }
4675
+ }, `Directory doesn't exist`);
4531
4676
 
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
- }
4677
+ // src/formation/resource/cloud-front/origin-request-policy.ts
4678
+ import { camelCase as camelCase4 } from "change-case";
4679
+ var OriginRequestPolicy = class extends Resource {
4680
+ constructor(logicalId, props = {}) {
4681
+ super("AWS::CloudFront::OriginRequestPolicy", logicalId);
4682
+ this.props = props;
4683
+ this.name = formatName(this.props.name || logicalId);
4684
+ }
4685
+ name;
4686
+ get id() {
4687
+ return getAtt(this.logicalId, "Id");
4688
+ }
4689
+ properties() {
4690
+ return {
4691
+ OriginRequestPolicyConfig: {
4692
+ Name: this.name,
4693
+ CookiesConfig: {
4694
+ CookieBehavior: camelCase4(this.props.cookie?.behavior ?? "all"),
4695
+ ...this.attr("Cookies", this.props.cookie?.values)
4696
+ },
4697
+ HeadersConfig: {
4698
+ HeaderBehavior: camelCase4(this.props.header?.behavior ?? "allViewer"),
4699
+ ...this.attr("Headers", this.props.header?.values)
4700
+ },
4701
+ QueryStringsConfig: {
4702
+ QueryStringBehavior: camelCase4(this.props.query?.behavior ?? "all"),
4703
+ ...this.attr("QueryStrings", this.props.query?.values)
4704
+ }
4705
+ }
4706
+ };
4707
+ }
4708
+ };
4541
4709
 
4542
- const listExports = async (region) => {
4543
- const client = new CloudFormationClient({ region })
4544
- const data = {}
4710
+ // src/formation/resource/cloud-front/cache-policy.ts
4711
+ var CachePolicy = class extends Resource {
4712
+ constructor(logicalId, props) {
4713
+ super("AWS::CloudFront::CachePolicy", logicalId);
4714
+ this.props = props;
4715
+ this.name = formatName(this.props.name || logicalId);
4716
+ }
4717
+ name;
4718
+ get id() {
4719
+ return getAtt(this.logicalId, "Id");
4720
+ }
4721
+ properties() {
4722
+ return {
4723
+ CachePolicyConfig: {
4724
+ Name: this.name,
4725
+ MinTTL: this.props.minTtl.toSeconds(),
4726
+ MaxTTL: this.props.maxTtl.toSeconds(),
4727
+ DefaultTTL: this.props.defaultTtl.toSeconds(),
4728
+ ParametersInCacheKeyAndForwardedToOrigin: {
4729
+ EnableAcceptEncodingGzip: this.props.acceptGzip ?? false,
4730
+ EnableAcceptEncodingBrotli: this.props.acceptBrotli ?? false,
4731
+ CookiesConfig: {
4732
+ CookieBehavior: this.props.cookies ? "whitelist" : "none",
4733
+ ...this.attr("Cookies", this.props.cookies)
4734
+ },
4735
+ HeadersConfig: {
4736
+ HeaderBehavior: this.props.headers ? "whitelist" : "none",
4737
+ ...this.attr("Headers", this.props.headers)
4738
+ },
4739
+ QueryStringsConfig: {
4740
+ QueryStringBehavior: this.props.queries ? "whitelist" : "none",
4741
+ ...this.attr("QueryStrings", this.props.queries)
4742
+ }
4743
+ }
4744
+ }
4745
+ };
4746
+ }
4747
+ };
4545
4748
 
4546
- let token
4749
+ // src/formation/resource/s3/files.ts
4750
+ import { Glob } from "glob";
4751
+ import JSZip2 from "jszip";
4752
+ import { createHash as createHash2 } from "crypto";
4753
+ import { createReadStream } from "fs";
4754
+ import { join as join4 } from "path";
4755
+ var Files = class extends Asset {
4756
+ constructor(id, props) {
4757
+ super("bucket", id);
4758
+ this.props = props;
4759
+ }
4760
+ hash;
4761
+ bundle;
4762
+ s3;
4763
+ async build({ write }) {
4764
+ const glob = new Glob(this.props.pattern ?? "**/*", {
4765
+ nodir: true,
4766
+ cwd: this.props.directory
4767
+ });
4768
+ const zip = new JSZip2();
4769
+ const hashes = [];
4770
+ let count = 0;
4771
+ for await (const path of glob) {
4772
+ const file = join4(this.props.directory, path);
4773
+ const stream = createReadStream(file);
4774
+ const hash2 = createHash2("sha1");
4775
+ stream.pipe(hash2);
4776
+ hashes.push(hash2);
4777
+ zip.file(path, stream);
4778
+ count++;
4779
+ }
4780
+ this.bundle = await zip.generateAsync({
4781
+ type: "nodebuffer",
4782
+ compression: "DEFLATE",
4783
+ compressionOptions: {
4784
+ level: 9
4785
+ }
4786
+ });
4787
+ const hash = createHash2("sha1");
4788
+ for (const item of hashes) {
4789
+ hash.update(item.digest());
4790
+ }
4791
+ this.hash = hash.digest("hex");
4792
+ await write("HASH", this.hash);
4793
+ await write("bundle.zip", this.bundle);
4794
+ return {
4795
+ files: style.success(String(count)),
4796
+ size: formatByteSize(this.bundle.byteLength)
4797
+ };
4798
+ }
4799
+ async publish({ publish }) {
4800
+ this.s3 = await publish(
4801
+ `${this.id}.zip`,
4802
+ this.bundle,
4803
+ this.hash
4804
+ );
4805
+ }
4806
+ get source() {
4807
+ return this.s3;
4808
+ }
4809
+ };
4547
4810
 
4548
- while(true) {
4549
- const result = await client.send(new ListExportsCommand({
4550
- NextToken: token
4551
- }))
4811
+ // src/formation/resource/s3/bucket-policy.ts
4812
+ import { capitalCase } from "change-case";
4813
+ var BucketPolicy = class extends Resource {
4814
+ constructor(logicalId, props) {
4815
+ super("AWS::S3::BucketPolicy", logicalId);
4816
+ this.props = props;
4817
+ }
4818
+ properties() {
4819
+ return {
4820
+ Bucket: formatName(this.props.bucketName),
4821
+ PolicyDocument: {
4822
+ Version: this.props.version ?? "2012-10-17",
4823
+ Statement: this.props.statements.map((statement) => ({
4824
+ Effect: capitalCase(statement.effect ?? "allow"),
4825
+ ...statement.principal ? {
4826
+ Principal: {
4827
+ Service: statement.principal
4828
+ }
4829
+ } : {},
4830
+ Action: statement.actions,
4831
+ Resource: statement.resources,
4832
+ ...statement.sourceArn ? {
4833
+ Condition: {
4834
+ StringEquals: {
4835
+ "AWS:SourceArn": statement.sourceArn
4836
+ }
4837
+ }
4838
+ } : {}
4839
+ }))
4840
+ }
4841
+ };
4842
+ }
4843
+ };
4552
4844
 
4553
- result.Exports?.forEach(item => {
4554
- data[item.Name] = item.Value
4555
- })
4845
+ // src/formation/resource/cloud-front/origin-access-control.ts
4846
+ var OriginAccessControl = class extends Resource {
4847
+ constructor(logicalId, props) {
4848
+ super("AWS::CloudFront::OriginAccessControl", logicalId);
4849
+ this.props = props;
4850
+ this.name = formatName(this.props.name || logicalId);
4851
+ }
4852
+ name;
4853
+ get id() {
4854
+ return getAtt(this.logicalId, "Id");
4855
+ }
4856
+ properties() {
4857
+ return {
4858
+ OriginAccessControlConfig: {
4859
+ Name: this.name,
4860
+ OriginAccessControlOriginType: this.props.type,
4861
+ SigningBehavior: this.props.behavior ?? "always",
4862
+ SigningProtocol: this.props.protocol ?? "sigv4"
4863
+ }
4864
+ };
4865
+ }
4866
+ };
4556
4867
 
4557
- if(result.NextToken) {
4558
- token = result.NextToken
4559
- } else {
4560
- return data
4561
- }
4562
- }
4563
- }
4564
- `
4565
- );
4868
+ // src/formation/resource/cloud-front/response-headers-policy.ts
4869
+ var ResponseHeadersPolicy = class extends Resource {
4870
+ constructor(logicalId, props) {
4871
+ super("AWS::CloudFront::ResponseHeadersPolicy", logicalId);
4872
+ this.props = props;
4873
+ this.name = formatName(this.props.name || logicalId);
4874
+ }
4875
+ name;
4876
+ get id() {
4877
+ return getAtt(this.logicalId, "Id");
4878
+ }
4879
+ properties() {
4880
+ return {
4881
+ ResponseHeadersPolicyConfig: {
4882
+ Name: this.name,
4883
+ ...this.props.remove && this.props.remove.length > 0 ? {
4884
+ RemoveHeadersConfig: {
4885
+ Items: this.props.remove?.map((value) => ({
4886
+ Header: value
4887
+ }))
4888
+ }
4889
+ } : {},
4890
+ CorsConfig: {
4891
+ OriginOverride: this.props.cors?.override ?? false,
4892
+ AccessControlAllowCredentials: this.props.cors?.credentials ?? false,
4893
+ AccessControlMaxAgeSec: this.props.cors?.maxAge?.toSeconds() ?? Duration.days(365).toSeconds(),
4894
+ AccessControlAllowHeaders: {
4895
+ Items: this.props.cors?.headers ?? ["*"]
4896
+ },
4897
+ AccessControlAllowMethods: {
4898
+ Items: this.props.cors?.methods ?? ["ALL"]
4899
+ },
4900
+ AccessControlAllowOrigins: {
4901
+ Items: this.props.cors?.origins ?? ["*"]
4902
+ },
4903
+ AccessControlExposeHeaders: {
4904
+ Items: this.props.cors?.exposeHeaders ?? ["*"]
4905
+ }
4906
+ },
4907
+ SecurityHeadersConfig: {
4908
+ ...this.props.contentSecurityPolicy ? {
4909
+ ContentSecurityPolicy: {
4910
+ Override: this.props.contentSecurityPolicy?.override ?? false,
4911
+ ContentSecurityPolicy: this.props.contentSecurityPolicy?.contentSecurityPolicy
4912
+ }
4913
+ } : {},
4914
+ ContentTypeOptions: {
4915
+ Override: this.props.contentTypeOptions?.override ?? false
4916
+ },
4917
+ FrameOptions: {
4918
+ Override: this.props.frameOptions?.override ?? false,
4919
+ FrameOption: (this.props.frameOptions?.frameOption ?? "same-origin") === "same-origin" ? "SAMEORIGIN" : "DENY"
4920
+ },
4921
+ ReferrerPolicy: {
4922
+ Override: this.props.referrerPolicy?.override ?? false,
4923
+ ReferrerPolicy: this.props.referrerPolicy?.referrerPolicy ?? "same-origin"
4924
+ },
4925
+ StrictTransportSecurity: {
4926
+ Override: this.props.strictTransportSecurity?.override ?? false,
4927
+ Preload: this.props.strictTransportSecurity?.preload ?? true,
4928
+ AccessControlMaxAgeSec: this.props.strictTransportSecurity?.maxAge?.toSeconds() ?? 31536e3,
4929
+ IncludeSubdomains: this.props.strictTransportSecurity?.includeSubdomains ?? true
4930
+ },
4931
+ XSSProtection: {
4932
+ Override: this.props.xssProtection?.override ?? false,
4933
+ ModeBlock: this.props.xssProtection?.modeBlock ?? true,
4934
+ Protection: this.props.xssProtection?.enable ?? true,
4935
+ ...this.attr("ReportUri", this.props.xssProtection?.reportUri)
4936
+ }
4937
+ }
4938
+ }
4939
+ };
4940
+ }
4941
+ };
4566
4942
 
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: ["*"]
4943
+ // src/plugins/site.ts
4944
+ var sitePlugin = definePlugin({
4945
+ name: "site",
4946
+ schema: z24.object({
4947
+ stacks: z24.object({
4948
+ /** Define the sites in your stack.
4949
+ * @example
4950
+ * {
4951
+ * sites: {
4952
+ * SITE_NAME: {
4953
+ * static: 'dist/client'
4954
+ * ssr: 'dist/server/index.js'
4955
+ * }
4956
+ * }
4957
+ * }
4958
+ * */
4959
+ sites: z24.record(
4960
+ ResourceIdSchema,
4961
+ z24.object({
4962
+ /** The domain to link your site with. */
4963
+ domain: z24.string(),
4964
+ subDomain: z24.string().optional(),
4965
+ /** Specifies the path to the static files directory. */
4966
+ static: LocalDirectorySchema.optional(),
4967
+ /** Specifies the ssr file. */
4968
+ ssr: FunctionSchema.optional(),
4969
+ /** Define the cors headers. */
4970
+ cors: z24.object({
4971
+ override: z24.boolean().default(false),
4972
+ maxAge: DurationSchema.default("365 days"),
4973
+ exposeHeaders: z24.string().array().optional(),
4974
+ credentials: z24.boolean().default(false),
4975
+ headers: z24.string().array().default(["*"]),
4976
+ origins: z24.string().array().default(["*"]),
4977
+ methods: z24.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
4978
+ }).optional(),
4979
+ /** Define the cors headers. */
4980
+ security: z24.object({
4981
+ // contentSecurityPolicy: z.object({
4982
+ // override: z.boolean().default(false),
4983
+ // policy: z.string(),
4984
+ // })
4985
+ // contentSecurityPolicy?: {
4986
+ // override?: boolean
4987
+ // contentSecurityPolicy: string
4988
+ // }
4989
+ // contentTypeOptions?: {
4990
+ // override?: boolean
4991
+ // }
4992
+ // frameOptions?: {
4993
+ // override?: boolean
4994
+ // frameOption?: 'deny' | 'same-origin'
4995
+ // }
4996
+ // referrerPolicy?: {
4997
+ // override?: boolean
4998
+ // referrerPolicy?: (
4999
+ // 'no-referrer' |
5000
+ // 'no-referrer-when-downgrade' |
5001
+ // 'origin' |
5002
+ // 'origin-when-cross-origin' |
5003
+ // 'same-origin' |
5004
+ // 'strict-origin' |
5005
+ // 'strict-origin-when-cross-origin' |
5006
+ // 'unsafe-url'
5007
+ // )
5008
+ // }
5009
+ // strictTransportSecurity?: {
5010
+ // maxAge?: Duration
5011
+ // includeSubdomains?: boolean
5012
+ // override?: boolean
5013
+ // preload?: boolean
5014
+ // }
5015
+ // xssProtection?: {
5016
+ // override?: boolean
5017
+ // enable?: boolean
5018
+ // modeBlock?: boolean
5019
+ // reportUri?: string
5020
+ // }
5021
+ }).optional(),
5022
+ /** Specifies the cookies, headers, and query values that CloudFront includes in the cache key. */
5023
+ cache: z24.object({
5024
+ /** Specifies the cookies that CloudFront includes in the cache key. */
5025
+ cookies: z24.string().array().optional(),
5026
+ /** Specifies the headers that CloudFront includes in the cache key. */
5027
+ headers: z24.string().array().optional(),
5028
+ /** Specifies the query values that CloudFront includes in the cache key. */
5029
+ queries: z24.string().array().optional()
5030
+ }).optional()
5031
+ })
5032
+ ).optional()
5033
+ }).array()
5034
+ }),
5035
+ onStack(ctx) {
5036
+ const { config, stack, stackConfig, bootstrap: bootstrap2 } = ctx;
5037
+ for (const [id, props] of Object.entries(stackConfig.sites || {})) {
5038
+ const origins = [];
5039
+ const originGroups = [];
5040
+ const deps = [];
5041
+ let bucket;
5042
+ if (props.ssr) {
5043
+ const lambda = toLambdaFunction(ctx, `site-${id}`, props.ssr);
5044
+ const permissions = new Permission2(`site-${id}`, {
5045
+ principal: "*",
5046
+ // principal: 'cloudfront.amazonaws.com',
5047
+ action: "lambda:InvokeFunctionUrl",
5048
+ functionArn: lambda.arn,
5049
+ urlAuthType: "none"
5050
+ // sourceArn: distribution.arn,
5051
+ }).dependsOn(lambda);
5052
+ const url = lambda.addUrl();
5053
+ stack.add(url, lambda, permissions);
5054
+ origins.push(new Origin({
5055
+ id: "lambda",
5056
+ domainName: select(2, split("/", url.url)),
5057
+ protocol: "https-only"
5058
+ }));
5059
+ deps.push(lambda, url, permissions);
5060
+ }
5061
+ if (props.static) {
5062
+ bucket = new Bucket(`site-${id}`, {
5063
+ // name: props.domain,
5064
+ name: `site-${config.name}-${stack.name}-${id}`,
5065
+ accessControl: "private",
5066
+ website: {
5067
+ indexDocument: "index.html",
5068
+ errorDocument: props.ssr ? void 0 : "error.html"
5069
+ }
5070
+ });
5071
+ const accessControl = new OriginAccessControl(`site-${id}`, {
5072
+ type: "s3"
5073
+ });
5074
+ const files = new Files(`site-${id}`, {
5075
+ directory: props.static
5076
+ });
5077
+ const uploadBucketAsset = new CustomResource(`site-${id}-upload-bucket-asset`, {
5078
+ serviceToken: bootstrap2.import("feature-upload-bucket-asset"),
5079
+ properties: {
5080
+ sourceBucketName: lazy(() => files.source?.bucket ?? ""),
5081
+ sourceObjectKey: lazy(() => files.source?.key ?? ""),
5082
+ sourceObjectVersion: lazy(() => files.source?.version ?? ""),
5083
+ destinationBucketName: bucket.name
5084
+ }
5085
+ }).dependsOn(bucket);
5086
+ const deleteBucket = new CustomResource(id, {
5087
+ serviceToken: bootstrap2.import("feature-delete-bucket"),
5088
+ properties: {
5089
+ bucketName: bucket.name
5090
+ }
5091
+ }).dependsOn(bucket);
5092
+ stack.add(bucket, files, uploadBucketAsset, deleteBucket, accessControl);
5093
+ origins.push(new Origin({
5094
+ id: "bucket",
5095
+ // domainName: select(2, split('/', bucket.url)),
5096
+ domainName: bucket.domainName,
5097
+ originAccessControlId: accessControl.id
5098
+ }));
5099
+ deps.push(bucket, accessControl);
5100
+ }
5101
+ if (props.ssr && props.static) {
5102
+ originGroups.push(new OriginGroup({
5103
+ id: "group",
5104
+ members: ["lambda", "bucket"],
5105
+ statusCodes: [403, 404]
5106
+ }));
5107
+ }
5108
+ const cache = new CachePolicy(id, {
5109
+ name: `site-${config.name}-${stack.name}-${id}`,
5110
+ minTtl: Duration.seconds(1),
5111
+ maxTtl: Duration.days(365),
5112
+ defaultTtl: Duration.days(1),
5113
+ ...props.cache
4583
5114
  });
4584
- crossRegionExports = new CustomResource("global-exports", {
4585
- serviceToken: lambda.arn,
4586
- properties: {
4587
- region: importable.region
5115
+ const originRequest = new OriginRequestPolicy(id, {
5116
+ name: `site-${config.name}-${stack.name}-${id}`,
5117
+ header: {
5118
+ behavior: "all-except",
5119
+ values: ["HOST"]
4588
5120
  }
4589
5121
  });
4590
- exportable.add(lambda, crossRegionExports);
5122
+ const domainName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
5123
+ const hostedZoneId = bootstrap2.import(`hosted-zone-${props.domain}-id`);
5124
+ const certificateArn = bootstrap2.import(`us-east-certificate-${props.domain}-arn`);
5125
+ const responseHeaders = new ResponseHeadersPolicy(id, {
5126
+ name: `site-${config.name}-${stack.name}-${id}`,
5127
+ cors: props.cors,
5128
+ remove: ["server"]
5129
+ });
5130
+ const distribution = new Distribution(id, {
5131
+ name: `site-${config.name}-${stack.name}-${id}`,
5132
+ certificateArn,
5133
+ compress: true,
5134
+ aliases: [domainName],
5135
+ origins,
5136
+ originGroups,
5137
+ targetOriginId: props.ssr && props.static ? "group" : props.ssr ? "lambda" : "bucket",
5138
+ originRequestPolicyId: originRequest.id,
5139
+ cachePolicyId: cache.id,
5140
+ responseHeadersPolicyId: responseHeaders.id
5141
+ }).dependsOn(originRequest, responseHeaders, cache, ...deps);
5142
+ if (props.static) {
5143
+ const bucketPolicy = new BucketPolicy(`site-${id}`, {
5144
+ bucketName: bucket.name,
5145
+ statements: [
5146
+ {
5147
+ principal: "cloudfront.amazonaws.com",
5148
+ actions: ["s3:GetObject"],
5149
+ resources: [sub("${arn}/*", { arn: bucket.arn })],
5150
+ sourceArn: distribution.arn
5151
+ }
5152
+ // {
5153
+ // principal: distribution.id,
5154
+ // actions: [ 's3:GetObject' ],
5155
+ // resources: [ oac.attrId ]
5156
+ // }
5157
+ ]
5158
+ }).dependsOn(bucket, distribution);
5159
+ stack.add(bucketPolicy);
5160
+ }
5161
+ const record = new RecordSet(`site-${id}`, {
5162
+ hostedZoneId,
5163
+ type: "A",
5164
+ name: domainName,
5165
+ alias: {
5166
+ dnsName: distribution.domainName,
5167
+ hostedZoneId: "Z2FDTNDATAQYW2"
5168
+ }
5169
+ }).dependsOn(distribution);
5170
+ stack.add(
5171
+ distribution,
5172
+ responseHeaders,
5173
+ originRequest,
5174
+ cache,
5175
+ record
5176
+ );
4591
5177
  }
4592
- return crossRegionExports.getAtt(name);
4593
- };
5178
+ }
5179
+ });
5180
+
5181
+ // src/plugins/feature.ts
5182
+ var featurePlugin = definePlugin({
5183
+ name: "feature",
5184
+ onApp({ config, bootstrap: bootstrap2 }) {
5185
+ const deleteBucketLambda = new Function("delete-bucket", {
5186
+ name: `${config.name}-delete-bucket`,
5187
+ code: Code.fromFeature("delete-bucket")
5188
+ }).enableLogs(Duration.days(3)).addPermissions({
5189
+ actions: ["s3:*"],
5190
+ resources: ["*"]
5191
+ });
5192
+ const uploadBucketAssetLambda = new Function("upload-bucket-asset", {
5193
+ name: `${config.name}-upload-bucket-asset`,
5194
+ code: Code.fromFeature("upload-bucket-asset"),
5195
+ memorySize: Size.gigaBytes(2)
5196
+ }).enableLogs(Duration.days(3)).addPermissions({
5197
+ actions: ["s3:*"],
5198
+ resources: ["*"]
5199
+ });
5200
+ bootstrap2.add(
5201
+ deleteBucketLambda,
5202
+ uploadBucketAssetLambda
5203
+ );
5204
+ bootstrap2.export("feature-delete-bucket", deleteBucketLambda.arn).export("feature-upload-bucket-asset", uploadBucketAssetLambda.arn);
5205
+ }
5206
+ });
5207
+
5208
+ // src/plugins/index.ts
5209
+ var defaultPlugins = [
5210
+ extendPlugin,
5211
+ featurePlugin,
5212
+ vpcPlugin,
5213
+ domainPlugin,
5214
+ functionPlugin,
5215
+ configPlugin,
5216
+ cachePlugin,
5217
+ cronPlugin,
5218
+ queuePlugin,
5219
+ tablePlugin,
5220
+ storePlugin,
5221
+ topicPlugin,
5222
+ pubsubPlugin,
5223
+ searchPlugin,
5224
+ graphqlPlugin,
5225
+ httpPlugin,
5226
+ restPlugin,
5227
+ sitePlugin,
5228
+ onFailurePlugin
5229
+ ];
5230
+
5231
+ // src/formation/app.ts
5232
+ var App = class {
5233
+ constructor(name) {
5234
+ this.name = name;
5235
+ }
5236
+ list = /* @__PURE__ */ new Map();
5237
+ add(...stacks) {
5238
+ stacks.forEach((stack) => {
5239
+ this.list.set(stack.name, stack);
5240
+ stack.setApp(this);
5241
+ });
5242
+ return this;
5243
+ }
5244
+ find(resourceType) {
5245
+ return this.stacks.map((stack) => stack.find(resourceType)).flat();
5246
+ }
5247
+ [Symbol.iterator]() {
5248
+ return this.list.values();
5249
+ }
5250
+ get stacks() {
5251
+ return [...this.list.values()];
5252
+ }
5253
+ // get resources() {
5254
+ // return this.stacks.map(stack => stack.resources).flat()
5255
+ // }
4594
5256
  };
4595
5257
 
4596
5258
  // src/app.ts
@@ -4615,7 +5277,6 @@ var toApp = async (config, filters) => {
4615
5277
  debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
4616
5278
  const bootstrap2 = new Stack("bootstrap", config.region);
4617
5279
  const usEastBootstrap = new Stack("us-east-bootstrap", "us-east-1");
4618
- extendWithGlobalExports(config.name, usEastBootstrap, bootstrap2);
4619
5280
  app.add(bootstrap2, usEastBootstrap);
4620
5281
  debug("Run plugin onApp listeners");
4621
5282
  const bindings = [];
@@ -4697,7 +5358,7 @@ var toApp = async (config, filters) => {
4697
5358
  };
4698
5359
 
4699
5360
  // src/config.ts
4700
- import { join as join4 } from "path";
5361
+ import { join as join6 } from "path";
4701
5362
 
4702
5363
  // src/util/account.ts
4703
5364
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -4716,17 +5377,17 @@ var getCredentials = (profile) => {
4716
5377
  };
4717
5378
 
4718
5379
  // src/schema/app.ts
4719
- import { z as z26 } from "zod";
5380
+ import { z as z28 } from "zod";
4720
5381
 
4721
5382
  // src/schema/stack.ts
4722
- import { z as z23 } from "zod";
4723
- var StackSchema = z23.object({
5383
+ import { z as z25 } from "zod";
5384
+ var StackSchema = z25.object({
4724
5385
  name: ResourceIdSchema,
4725
- depends: z23.array(z23.lazy(() => StackSchema)).optional()
5386
+ depends: z25.array(z25.lazy(() => StackSchema)).optional()
4726
5387
  });
4727
5388
 
4728
5389
  // src/schema/region.ts
4729
- import { z as z24 } from "zod";
5390
+ import { z as z26 } from "zod";
4730
5391
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
4731
5392
  var AF = ["af-south-1"];
4732
5393
  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 +5404,41 @@ var regions = [
4743
5404
  ...ME,
4744
5405
  ...SA
4745
5406
  ];
4746
- var RegionSchema = z24.enum(regions);
5407
+ var RegionSchema = z26.enum(regions);
4747
5408
 
4748
5409
  // 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(),
5410
+ import { z as z27 } from "zod";
5411
+ var PluginSchema = z27.object({
5412
+ name: z27.string(),
5413
+ schema: z27.custom().optional(),
4753
5414
  // 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()
5415
+ onApp: z27.function().returns(z27.void()).optional(),
5416
+ onStack: z27.function().returns(z27.any()).optional(),
5417
+ onResource: z27.function().returns(z27.any()).optional()
4757
5418
  // bind: z.function().optional(),
4758
5419
  });
4759
5420
 
4760
5421
  // src/schema/app.ts
4761
- var AppSchema = z26.object({
5422
+ var AppSchema = z28.object({
4762
5423
  /** App name */
4763
5424
  name: ResourceIdSchema,
4764
5425
  /** The AWS region to deploy to. */
4765
5426
  region: RegionSchema,
4766
5427
  /** The AWS profile to deploy to. */
4767
- profile: z26.string(),
5428
+ profile: z28.string(),
4768
5429
  /** The deployment stage.
4769
5430
  * @default 'prod'
4770
5431
  */
4771
- stage: z26.string().regex(/^[a-z]+$/).default("prod"),
5432
+ stage: z28.string().regex(/^[a-z]+$/).default("prod"),
4772
5433
  /** Default properties. */
4773
- defaults: z26.object({}).default({}),
5434
+ defaults: z28.object({}).default({}),
4774
5435
  /** The application stacks. */
4775
- stacks: z26.array(StackSchema).min(1).refine((stacks) => {
5436
+ stacks: z28.array(StackSchema).min(1).refine((stacks) => {
4776
5437
  const unique = new Set(stacks.map((stack) => stack.name));
4777
5438
  return unique.size === stacks.length;
4778
5439
  }, "Must be an array of unique stacks"),
4779
5440
  /** Custom plugins. */
4780
- plugins: z26.array(PluginSchema).optional()
5441
+ plugins: z28.array(PluginSchema).optional()
4781
5442
  });
4782
5443
 
4783
5444
  // src/util/import.ts
@@ -4785,7 +5446,7 @@ import { rollup as rollup2, watch } from "rollup";
4785
5446
  import { swc as swc2 } from "rollup-plugin-swc3";
4786
5447
  import replace from "rollup-plugin-replace";
4787
5448
  import { EventIterator } from "event-iterator";
4788
- import { dirname as dirname2, join as join3 } from "path";
5449
+ import { dirname as dirname2, join as join5 } from "path";
4789
5450
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
4790
5451
  var importFile = async (path) => {
4791
5452
  const bundle = await rollup2({
@@ -4805,7 +5466,7 @@ var importFile = async (path) => {
4805
5466
  })
4806
5467
  ]
4807
5468
  });
4808
- const outputFile = join3(directories.cache, "config.js");
5469
+ const outputFile = join5(directories.cache, "config.js");
4809
5470
  const result = await bundle.generate({
4810
5471
  format: "esm",
4811
5472
  exports: "default"
@@ -4856,7 +5517,7 @@ var watchFile = (path) => {
4856
5517
  event.result.close();
4857
5518
  const output = result.output[0];
4858
5519
  const code = output.code;
4859
- const outputFile = join3(directories.cache, "config.js");
5520
+ const outputFile = join5(directories.cache, "config.js");
4860
5521
  await mkdir2(directories.cache, { recursive: true });
4861
5522
  await writeFile2(outputFile, code);
4862
5523
  debug("Save config file:", style.info(outputFile));
@@ -4874,7 +5535,7 @@ var watchFile = (path) => {
4874
5535
  };
4875
5536
 
4876
5537
  // src/config.ts
4877
- import { z as z27 } from "zod";
5538
+ import { z as z29 } from "zod";
4878
5539
  var ConfigError = class extends Error {
4879
5540
  constructor(error, data) {
4880
5541
  super(error.message);
@@ -4889,7 +5550,7 @@ var importConfig = async (options) => {
4889
5550
  setRoot(root2);
4890
5551
  debug("CWD:", style.info(root2));
4891
5552
  debug("Import config file");
4892
- const fileName = join4(root2, configFile);
5553
+ const fileName = join6(root2, configFile);
4893
5554
  const module = await importFile(fileName);
4894
5555
  const appConfig = typeof module.default === "function" ? await module.default(options) : module.default;
4895
5556
  debug("Validate config file");
@@ -4907,7 +5568,7 @@ var importConfig = async (options) => {
4907
5568
  try {
4908
5569
  config = await schema2.parseAsync(appConfig);
4909
5570
  } catch (error) {
4910
- if (error instanceof z27.ZodError) {
5571
+ if (error instanceof z29.ZodError) {
4911
5572
  throw new ConfigError(error, appConfig);
4912
5573
  }
4913
5574
  throw error;
@@ -4930,7 +5591,7 @@ var watchConfig = async function* (options) {
4930
5591
  setRoot(root2);
4931
5592
  debug("CWD:", style.info(root2));
4932
5593
  debug("Import config file");
4933
- const fileName = join4(root2, configFile);
5594
+ const fileName = join6(root2, configFile);
4934
5595
  for await (const module of watchFile(fileName)) {
4935
5596
  const appConfig = typeof module.default === "function" ? await module.default(options) : module.default;
4936
5597
  debug("Validate config file");
@@ -4948,7 +5609,7 @@ var watchConfig = async function* (options) {
4948
5609
  try {
4949
5610
  config = await schema2.parseAsync(appConfig);
4950
5611
  } catch (error) {
4951
- if (error instanceof z27.ZodError) {
5612
+ if (error instanceof z29.ZodError) {
4952
5613
  throw new ConfigError(error, appConfig);
4953
5614
  }
4954
5615
  throw error;
@@ -5545,7 +6206,7 @@ var flexLine = (term, left, right, reserveSpace = 0) => {
5545
6206
  };
5546
6207
 
5547
6208
  // src/cli/ui/complex/builder.ts
5548
- import { dirname as dirname3, join as join5 } from "path";
6209
+ import { dirname as dirname3, join as join7 } from "path";
5549
6210
  var assetBuilder = (app) => {
5550
6211
  return async (term) => {
5551
6212
  const assets = [];
@@ -5608,7 +6269,7 @@ var assetBuilder = (app) => {
5608
6269
  try {
5609
6270
  const data = await asset.build({
5610
6271
  async write(file, data2) {
5611
- const fullpath = join5(directories.asset, asset.type, app.name, stack.name, asset.id, file);
6272
+ const fullpath = join7(directories.asset, asset.type, app.name, stack.name, asset.id, file);
5612
6273
  const basepath = dirname3(fullpath);
5613
6274
  await mkdir3(basepath, { recursive: true });
5614
6275
  await writeFile3(fullpath, data2);
@@ -5656,14 +6317,14 @@ var cleanUp = async () => {
5656
6317
 
5657
6318
  // src/cli/ui/complex/template.ts
5658
6319
  import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
5659
- import { join as join6 } from "path";
6320
+ import { join as join8 } from "path";
5660
6321
  var templateBuilder = (app) => {
5661
6322
  return async (term) => {
5662
6323
  const done = term.out.write(loadingDialog("Building stack templates..."));
5663
6324
  await Promise.all(app.stacks.map(async (stack) => {
5664
6325
  const template = stack.toString(true);
5665
- const path = join6(directories.template, app.name);
5666
- const file = join6(path, `${stack.name}.json`);
6326
+ const path = join8(directories.template, app.name);
6327
+ const file = join8(path, `${stack.name}.json`);
5667
6328
  await mkdir5(path, { recursive: true });
5668
6329
  await writeFile4(file, template);
5669
6330
  }));
@@ -5708,7 +6369,7 @@ var bootstrapStack = (account, region) => {
5708
6369
  stack.add(new Bucket("assets", {
5709
6370
  name: assetBucketName(account, region),
5710
6371
  accessControl: "private",
5711
- versioned: true
6372
+ versioning: true
5712
6373
  }));
5713
6374
  stack.export("version", version);
5714
6375
  app.add(stack);
@@ -5878,6 +6539,7 @@ var StackClient = class {
5878
6539
  });
5879
6540
  debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
5880
6541
  return {
6542
+ id: stack.StackId,
5881
6543
  status: stack.StackStatus,
5882
6544
  reason: stack.StackStatusReason,
5883
6545
  outputs,
@@ -5924,10 +6586,10 @@ var StackClient = class {
5924
6586
  maxWaitTime: this.maxWaitTime,
5925
6587
  maxDelay: this.maxDelay
5926
6588
  }, {
5927
- StackName: this.stackName(name)
6589
+ StackName: data.id
5928
6590
  });
5929
6591
  } catch (_) {
5930
- const reason = await this.getFailureReason(name, region);
6592
+ const reason = await this.getFailureReason(data.id, region);
5931
6593
  throw new Error(reason);
5932
6594
  }
5933
6595
  }
@@ -6185,7 +6847,7 @@ var status = (program2) => {
6185
6847
 
6186
6848
  // src/cli/ui/complex/publisher.ts
6187
6849
  import { readFile as readFile3 } from "fs/promises";
6188
- import { join as join7 } from "path";
6850
+ import { join as join9 } from "path";
6189
6851
  import { GetObjectCommand, ObjectCannedACL as ObjectCannedACL2, PutObjectCommand as PutObjectCommand2, S3Client as S3Client2, StorageClass as StorageClass2 } from "@aws-sdk/client-s3";
6190
6852
  var assetPublisher = (config, app) => {
6191
6853
  const client = new S3Client2({
@@ -6199,12 +6861,12 @@ var assetPublisher = (config, app) => {
6199
6861
  await Promise.all([...stack.assets].map(async (asset) => {
6200
6862
  await asset.publish?.({
6201
6863
  async read(file) {
6202
- const path = join7(directories.asset, asset.type, app.name, stack.name, asset.id, file);
6864
+ const path = join9(directories.asset, asset.type, app.name, stack.name, asset.id, file);
6203
6865
  const data = await readFile3(path);
6204
6866
  return data;
6205
6867
  },
6206
6868
  async publish(name, data, hash) {
6207
- const key = `${app.name}/${stack.name}/function/${name}`;
6869
+ const key = `${app.name}/${stack.name}/${asset.type}/${name}`;
6208
6870
  const bucket = assetBucketName(config.account, config.region);
6209
6871
  let getResult;
6210
6872
  try {
@@ -6444,16 +7106,6 @@ var secrets = (program2) => {
6444
7106
  commands.forEach((cb) => cb(command));
6445
7107
  };
6446
7108
 
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
7109
  // src/cli/command/types.ts
6458
7110
  var types = (program2) => {
6459
7111
  program2.command("types").description("Generate type definition files").action(async () => {
@@ -6477,6 +7129,48 @@ var dev = (program2) => {
6477
7129
  });
6478
7130
  };
6479
7131
 
7132
+ // src/cli/command/delete.ts
7133
+ var del2 = (program2) => {
7134
+ program2.command("delete").argument("[stacks...]", "Optionally filter stacks to delete").description("Delete your app from AWS").action(async (filters) => {
7135
+ await layout(async (config, write) => {
7136
+ const { app, deploymentLine } = await toApp(config, filters);
7137
+ const deletingLine = deploymentLine.reverse();
7138
+ const stackNames = app.stacks.map((stack) => stack.name);
7139
+ const formattedFilter = stackNames.map((i) => style.info(i)).join(style.placeholder(", "));
7140
+ debug("Stacks to delete", formattedFilter);
7141
+ const deployAll = filters.length === 0;
7142
+ const deploySingle = filters.length === 1;
7143
+ 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?`));
7144
+ if (!confirm) {
7145
+ throw new Cancelled();
7146
+ }
7147
+ const doneDeploying = write(loadingDialog("Deleting stacks from AWS..."));
7148
+ const client = new StackClient(app, config.account, config.region, config.credentials);
7149
+ const ui = write(stacksDeployer(deletingLine));
7150
+ for (const line2 of deletingLine) {
7151
+ const results = await Promise.allSettled(line2.map(async (stack) => {
7152
+ const item = ui[stack.name];
7153
+ item.start("deleting");
7154
+ try {
7155
+ await client.delete(stack.name, stack.region);
7156
+ } catch (error) {
7157
+ debugError(error);
7158
+ item.fail("failed");
7159
+ throw error;
7160
+ }
7161
+ item.done("deleted");
7162
+ }));
7163
+ for (const result of results) {
7164
+ if (result.status === "rejected") {
7165
+ throw result.reason;
7166
+ }
7167
+ }
7168
+ }
7169
+ doneDeploying("Done deleting stacks from AWS");
7170
+ });
7171
+ });
7172
+ };
7173
+
6480
7174
  // src/cli/program.ts
6481
7175
  var program = new Command();
6482
7176
  program.name(logo().join("").replace(/\s+/, ""));
@@ -6498,9 +7192,10 @@ var commands2 = [
6498
7192
  types,
6499
7193
  build,
6500
7194
  deploy,
7195
+ del2,
6501
7196
  dev,
6502
- secrets,
6503
- test
7197
+ secrets
7198
+ // test,
6504
7199
  // diff,
6505
7200
  // remove,
6506
7201
  ];