@awsless/awsless 0.0.24 → 0.0.25

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.cjs CHANGED
@@ -183,7 +183,9 @@ var getAtt = (logicalId, attr) => {
183
183
  return { "Fn::GetAtt": [logicalId, attr] };
184
184
  };
185
185
  var importValue = (name) => {
186
- return { "Fn::ImportValue": name };
186
+ return new Lazy((stack) => ({
187
+ "Fn::ImportValue": `${stack.app.name}-${name}`
188
+ }));
187
189
  };
188
190
  var formatLogicalId = (id) => {
189
191
  return (0, import_change_case2.pascalCase)(id).replaceAll("_", "");
@@ -453,13 +455,16 @@ var Stack = class {
453
455
  this.name = name;
454
456
  this.region = region;
455
457
  }
456
- app;
458
+ parent;
457
459
  exports = /* @__PURE__ */ new Map();
458
460
  resources = /* @__PURE__ */ new Set();
459
461
  tags = /* @__PURE__ */ new Map();
460
462
  assets = /* @__PURE__ */ new Set();
463
+ get app() {
464
+ return this.parent;
465
+ }
461
466
  setApp(app) {
462
- this.app = app;
467
+ this.parent = app;
463
468
  return this;
464
469
  }
465
470
  add(...resources) {
@@ -2282,6 +2287,9 @@ var Definition = class extends Asset {
2282
2287
  }));
2283
2288
  const defs = (0, import_merge.mergeTypeDefs)(schemas);
2284
2289
  const schema2 = (0, import_graphql.print)(defs);
2290
+ if (schema2.length === 0) {
2291
+ throw new Error(`Graphql schema definition can't be empty. [${this.id}]`);
2292
+ }
2285
2293
  const size = Buffer.from(schema2, "utf8").byteLength;
2286
2294
  await write("schema.gql", schema2);
2287
2295
  this.schema = schema2;
@@ -2947,6 +2955,7 @@ var Vpc = class extends Resource {
2947
2955
  constructor(logicalId, props) {
2948
2956
  super("AWS::EC2::VPC", logicalId);
2949
2957
  this.props = props;
2958
+ this.tag("Name", props.name);
2950
2959
  }
2951
2960
  get id() {
2952
2961
  return ref(this.logicalId);
@@ -3109,6 +3118,7 @@ var vpcPlugin = definePlugin({
3109
3118
  // }),
3110
3119
  onApp({ config, bootstrap: bootstrap2 }) {
3111
3120
  const vpc = new Vpc("main", {
3121
+ name: config.name,
3112
3122
  cidrBlock: Peer.ipv4("10.0.0.0/16")
3113
3123
  });
3114
3124
  const privateRouteTable = new RouteTable("private", {
@@ -4814,20 +4824,26 @@ var assetBuilder = (app) => {
4814
4824
  ]);
4815
4825
  group.update((group2) => [...group2, line]);
4816
4826
  const timer = createTimer();
4817
- const data = await asset.build({
4818
- async write(file, data2) {
4819
- const fullpath = (0, import_path8.join)(directories.asset, asset.type, app.name, stack.name, asset.id, file);
4820
- const basepath = (0, import_path8.dirname)(fullpath);
4821
- await (0, import_promises6.mkdir)(basepath, { recursive: true });
4822
- await (0, import_promises6.writeFile)(fullpath, data2);
4823
- }
4824
- });
4825
- details.set({
4826
- ...data,
4827
- time: timer()
4828
- });
4829
- icon.set(style.success(symbol.success));
4830
- stop();
4827
+ try {
4828
+ const data = await asset.build({
4829
+ async write(file, data2) {
4830
+ const fullpath = (0, import_path8.join)(directories.asset, asset.type, app.name, stack.name, asset.id, file);
4831
+ const basepath = (0, import_path8.dirname)(fullpath);
4832
+ await (0, import_promises6.mkdir)(basepath, { recursive: true });
4833
+ await (0, import_promises6.writeFile)(fullpath, data2);
4834
+ }
4835
+ });
4836
+ details.set({
4837
+ ...data,
4838
+ time: timer()
4839
+ });
4840
+ icon.set(style.success(symbol.success));
4841
+ } catch (error) {
4842
+ icon.set(style.error(symbol.error));
4843
+ throw error;
4844
+ } finally {
4845
+ stop();
4846
+ }
4831
4847
  }));
4832
4848
  }));
4833
4849
  done("Done building stack assets");
@@ -4972,7 +4988,7 @@ var StackClient = class {
4972
4988
  async create(stack, capabilities) {
4973
4989
  debug("Create the", style.info(stack.name), "stack");
4974
4990
  const client = this.getClient(stack.region);
4975
- await client.send(new import_client_cloudformation.CreateStackCommand({
4991
+ const result = await client.send(new import_client_cloudformation.CreateStackCommand({
4976
4992
  StackName: this.stackName(stack.name),
4977
4993
  EnableTerminationProtection: false,
4978
4994
  OnFailure: import_client_cloudformation.OnFailure.DELETE,
@@ -4980,36 +4996,53 @@ var StackClient = class {
4980
4996
  Tags: this.tags(stack),
4981
4997
  ...this.templateProp(stack)
4982
4998
  }));
4983
- await (0, import_client_cloudformation.waitUntilStackCreateComplete)({
4984
- client,
4985
- maxWaitTime: this.maxWaitTime,
4986
- maxDelay: this.maxDelay
4987
- }, {
4988
- StackName: this.stackName(stack.name)
4989
- });
4999
+ try {
5000
+ await (0, import_client_cloudformation.waitUntilStackCreateComplete)({
5001
+ client,
5002
+ maxWaitTime: this.maxWaitTime,
5003
+ maxDelay: this.maxDelay
5004
+ }, {
5005
+ StackName: result.StackId
5006
+ });
5007
+ } catch (_) {
5008
+ const reason = await this.getFailureReason(
5009
+ result.StackId,
5010
+ stack.region
5011
+ );
5012
+ throw new Error(reason);
5013
+ }
4990
5014
  }
4991
5015
  async update(stack, capabilities) {
4992
5016
  debug("Update the", style.info(stack.name), "stack");
4993
5017
  const client = this.getClient(stack.region);
5018
+ let result;
4994
5019
  try {
4995
- await client.send(new import_client_cloudformation.UpdateStackCommand({
5020
+ result = await client.send(new import_client_cloudformation.UpdateStackCommand({
4996
5021
  StackName: this.stackName(stack.name),
4997
5022
  Capabilities: capabilities,
4998
5023
  Tags: this.tags(stack),
4999
5024
  ...this.templateProp(stack)
5000
5025
  }));
5026
+ } catch (error) {
5027
+ if (error instanceof Error && error.name === "ValidationError" && error.message.toLowerCase().includes("no updates")) {
5028
+ return;
5029
+ }
5030
+ throw error;
5031
+ }
5032
+ try {
5001
5033
  await (0, import_client_cloudformation.waitUntilStackUpdateComplete)({
5002
5034
  client,
5003
5035
  maxWaitTime: this.maxWaitTime,
5004
5036
  maxDelay: this.maxDelay
5005
5037
  }, {
5006
- StackName: this.stackName(stack.name)
5038
+ StackName: result.StackId
5007
5039
  });
5008
5040
  } catch (error) {
5009
- if (error instanceof Error && error.name === "ValidationError" && error.message.toLowerCase().includes("no updates")) {
5010
- return;
5011
- }
5012
- throw error;
5041
+ const reason = await this.getFailureReason(
5042
+ result.StackId,
5043
+ stack.region
5044
+ );
5045
+ throw new Error(reason);
5013
5046
  }
5014
5047
  }
5015
5048
  async validate(stack) {
@@ -5090,13 +5123,44 @@ var StackClient = class {
5090
5123
  await client.send(new import_client_cloudformation.DeleteStackCommand({
5091
5124
  StackName: this.stackName(name)
5092
5125
  }));
5093
- await (0, import_client_cloudformation.waitUntilStackDeleteComplete)({
5094
- client,
5095
- maxWaitTime: this.maxWaitTime,
5096
- maxDelay: this.maxDelay
5097
- }, {
5098
- StackName: this.stackName(name)
5099
- });
5126
+ try {
5127
+ await (0, import_client_cloudformation.waitUntilStackDeleteComplete)({
5128
+ client,
5129
+ maxWaitTime: this.maxWaitTime,
5130
+ maxDelay: this.maxDelay
5131
+ }, {
5132
+ StackName: this.stackName(name)
5133
+ });
5134
+ } catch (_) {
5135
+ const reason = await this.getFailureReason(name, region);
5136
+ throw new Error(reason);
5137
+ }
5138
+ }
5139
+ async getFailureReason(name, region) {
5140
+ const client = this.getClient(region);
5141
+ const result = await client.send(await new import_client_cloudformation.DescribeStackEventsCommand({
5142
+ StackName: name
5143
+ }));
5144
+ const failureStatuses = [
5145
+ "UPDATE_ROLLBACK_IN_PROGRESS",
5146
+ "CREATE_FAILED",
5147
+ "UPDATE_FAILED",
5148
+ "DELETE_FAILED"
5149
+ ];
5150
+ let reason = "Unknown failure reason";
5151
+ for (const event of result.StackEvents || []) {
5152
+ if (event.ResourceStatusReason?.toLowerCase() === "user initiated") {
5153
+ break;
5154
+ }
5155
+ if (failureStatuses.includes(event.ResourceStatus || "") && event.ResourceStatusReason) {
5156
+ reason = [
5157
+ `Logical ID: ${event.LogicalResourceId}`,
5158
+ `Type: ${event.ResourceType}`,
5159
+ `Reason: ${event.ResourceStatusReason}`
5160
+ ].join("\n");
5161
+ }
5162
+ }
5163
+ return reason;
5100
5164
  }
5101
5165
  };
5102
5166
 
package/dist/bin.js CHANGED
@@ -163,7 +163,9 @@ var getAtt = (logicalId, attr) => {
163
163
  return { "Fn::GetAtt": [logicalId, attr] };
164
164
  };
165
165
  var importValue = (name) => {
166
- return { "Fn::ImportValue": name };
166
+ return new Lazy((stack) => ({
167
+ "Fn::ImportValue": `${stack.app.name}-${name}`
168
+ }));
167
169
  };
168
170
  var formatLogicalId = (id) => {
169
171
  return pascalCase(id).replaceAll("_", "");
@@ -433,13 +435,16 @@ var Stack = class {
433
435
  this.name = name;
434
436
  this.region = region;
435
437
  }
436
- app;
438
+ parent;
437
439
  exports = /* @__PURE__ */ new Map();
438
440
  resources = /* @__PURE__ */ new Set();
439
441
  tags = /* @__PURE__ */ new Map();
440
442
  assets = /* @__PURE__ */ new Set();
443
+ get app() {
444
+ return this.parent;
445
+ }
441
446
  setApp(app) {
442
- this.app = app;
447
+ this.parent = app;
443
448
  return this;
444
449
  }
445
450
  add(...resources) {
@@ -2259,6 +2264,9 @@ var Definition = class extends Asset {
2259
2264
  }));
2260
2265
  const defs = mergeTypeDefs(schemas);
2261
2266
  const schema2 = print(defs);
2267
+ if (schema2.length === 0) {
2268
+ throw new Error(`Graphql schema definition can't be empty. [${this.id}]`);
2269
+ }
2262
2270
  const size = Buffer.from(schema2, "utf8").byteLength;
2263
2271
  await write("schema.gql", schema2);
2264
2272
  this.schema = schema2;
@@ -2924,6 +2932,7 @@ var Vpc = class extends Resource {
2924
2932
  constructor(logicalId, props) {
2925
2933
  super("AWS::EC2::VPC", logicalId);
2926
2934
  this.props = props;
2935
+ this.tag("Name", props.name);
2927
2936
  }
2928
2937
  get id() {
2929
2938
  return ref(this.logicalId);
@@ -3086,6 +3095,7 @@ var vpcPlugin = definePlugin({
3086
3095
  // }),
3087
3096
  onApp({ config, bootstrap: bootstrap2 }) {
3088
3097
  const vpc = new Vpc("main", {
3098
+ name: config.name,
3089
3099
  cidrBlock: Peer.ipv4("10.0.0.0/16")
3090
3100
  });
3091
3101
  const privateRouteTable = new RouteTable("private", {
@@ -4791,20 +4801,26 @@ var assetBuilder = (app) => {
4791
4801
  ]);
4792
4802
  group.update((group2) => [...group2, line]);
4793
4803
  const timer = createTimer();
4794
- const data = await asset.build({
4795
- async write(file, data2) {
4796
- const fullpath = join4(directories.asset, asset.type, app.name, stack.name, asset.id, file);
4797
- const basepath = dirname3(fullpath);
4798
- await mkdir2(basepath, { recursive: true });
4799
- await writeFile2(fullpath, data2);
4800
- }
4801
- });
4802
- details.set({
4803
- ...data,
4804
- time: timer()
4805
- });
4806
- icon.set(style.success(symbol.success));
4807
- stop();
4804
+ try {
4805
+ const data = await asset.build({
4806
+ async write(file, data2) {
4807
+ const fullpath = join4(directories.asset, asset.type, app.name, stack.name, asset.id, file);
4808
+ const basepath = dirname3(fullpath);
4809
+ await mkdir2(basepath, { recursive: true });
4810
+ await writeFile2(fullpath, data2);
4811
+ }
4812
+ });
4813
+ details.set({
4814
+ ...data,
4815
+ time: timer()
4816
+ });
4817
+ icon.set(style.success(symbol.success));
4818
+ } catch (error) {
4819
+ icon.set(style.error(symbol.error));
4820
+ throw error;
4821
+ } finally {
4822
+ stop();
4823
+ }
4808
4824
  }));
4809
4825
  }));
4810
4826
  done("Done building stack assets");
@@ -4888,7 +4904,7 @@ var shouldDeployBootstrap = async (client, stack) => {
4888
4904
  };
4889
4905
 
4890
4906
  // src/formation/client.ts
4891
- import { CloudFormationClient, CreateStackCommand, DeleteStackCommand, DescribeStacksCommand, GetTemplateCommand, OnFailure, TemplateStage, UpdateStackCommand, ValidateTemplateCommand, waitUntilStackCreateComplete, waitUntilStackDeleteComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
4907
+ import { CloudFormationClient, CreateStackCommand, DeleteStackCommand, DescribeStackEventsCommand, DescribeStacksCommand, GetTemplateCommand, OnFailure, TemplateStage, UpdateStackCommand, ValidateTemplateCommand, waitUntilStackCreateComplete, waitUntilStackDeleteComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
4892
4908
  import { S3Client, PutObjectCommand, ObjectCannedACL, StorageClass } from "@aws-sdk/client-s3";
4893
4909
  import { paramCase as paramCase4 } from "change-case";
4894
4910
  var StackClient = class {
@@ -4949,7 +4965,7 @@ var StackClient = class {
4949
4965
  async create(stack, capabilities) {
4950
4966
  debug("Create the", style.info(stack.name), "stack");
4951
4967
  const client = this.getClient(stack.region);
4952
- await client.send(new CreateStackCommand({
4968
+ const result = await client.send(new CreateStackCommand({
4953
4969
  StackName: this.stackName(stack.name),
4954
4970
  EnableTerminationProtection: false,
4955
4971
  OnFailure: OnFailure.DELETE,
@@ -4957,36 +4973,53 @@ var StackClient = class {
4957
4973
  Tags: this.tags(stack),
4958
4974
  ...this.templateProp(stack)
4959
4975
  }));
4960
- await waitUntilStackCreateComplete({
4961
- client,
4962
- maxWaitTime: this.maxWaitTime,
4963
- maxDelay: this.maxDelay
4964
- }, {
4965
- StackName: this.stackName(stack.name)
4966
- });
4976
+ try {
4977
+ await waitUntilStackCreateComplete({
4978
+ client,
4979
+ maxWaitTime: this.maxWaitTime,
4980
+ maxDelay: this.maxDelay
4981
+ }, {
4982
+ StackName: result.StackId
4983
+ });
4984
+ } catch (_) {
4985
+ const reason = await this.getFailureReason(
4986
+ result.StackId,
4987
+ stack.region
4988
+ );
4989
+ throw new Error(reason);
4990
+ }
4967
4991
  }
4968
4992
  async update(stack, capabilities) {
4969
4993
  debug("Update the", style.info(stack.name), "stack");
4970
4994
  const client = this.getClient(stack.region);
4995
+ let result;
4971
4996
  try {
4972
- await client.send(new UpdateStackCommand({
4997
+ result = await client.send(new UpdateStackCommand({
4973
4998
  StackName: this.stackName(stack.name),
4974
4999
  Capabilities: capabilities,
4975
5000
  Tags: this.tags(stack),
4976
5001
  ...this.templateProp(stack)
4977
5002
  }));
5003
+ } catch (error) {
5004
+ if (error instanceof Error && error.name === "ValidationError" && error.message.toLowerCase().includes("no updates")) {
5005
+ return;
5006
+ }
5007
+ throw error;
5008
+ }
5009
+ try {
4978
5010
  await waitUntilStackUpdateComplete({
4979
5011
  client,
4980
5012
  maxWaitTime: this.maxWaitTime,
4981
5013
  maxDelay: this.maxDelay
4982
5014
  }, {
4983
- StackName: this.stackName(stack.name)
5015
+ StackName: result.StackId
4984
5016
  });
4985
5017
  } catch (error) {
4986
- if (error instanceof Error && error.name === "ValidationError" && error.message.toLowerCase().includes("no updates")) {
4987
- return;
4988
- }
4989
- throw error;
5018
+ const reason = await this.getFailureReason(
5019
+ result.StackId,
5020
+ stack.region
5021
+ );
5022
+ throw new Error(reason);
4990
5023
  }
4991
5024
  }
4992
5025
  async validate(stack) {
@@ -5067,13 +5100,44 @@ var StackClient = class {
5067
5100
  await client.send(new DeleteStackCommand({
5068
5101
  StackName: this.stackName(name)
5069
5102
  }));
5070
- await waitUntilStackDeleteComplete({
5071
- client,
5072
- maxWaitTime: this.maxWaitTime,
5073
- maxDelay: this.maxDelay
5074
- }, {
5075
- StackName: this.stackName(name)
5076
- });
5103
+ try {
5104
+ await waitUntilStackDeleteComplete({
5105
+ client,
5106
+ maxWaitTime: this.maxWaitTime,
5107
+ maxDelay: this.maxDelay
5108
+ }, {
5109
+ StackName: this.stackName(name)
5110
+ });
5111
+ } catch (_) {
5112
+ const reason = await this.getFailureReason(name, region);
5113
+ throw new Error(reason);
5114
+ }
5115
+ }
5116
+ async getFailureReason(name, region) {
5117
+ const client = this.getClient(region);
5118
+ const result = await client.send(await new DescribeStackEventsCommand({
5119
+ StackName: name
5120
+ }));
5121
+ const failureStatuses = [
5122
+ "UPDATE_ROLLBACK_IN_PROGRESS",
5123
+ "CREATE_FAILED",
5124
+ "UPDATE_FAILED",
5125
+ "DELETE_FAILED"
5126
+ ];
5127
+ let reason = "Unknown failure reason";
5128
+ for (const event of result.StackEvents || []) {
5129
+ if (event.ResourceStatusReason?.toLowerCase() === "user initiated") {
5130
+ break;
5131
+ }
5132
+ if (failureStatuses.includes(event.ResourceStatus || "") && event.ResourceStatusReason) {
5133
+ reason = [
5134
+ `Logical ID: ${event.LogicalResourceId}`,
5135
+ `Type: ${event.ResourceType}`,
5136
+ `Reason: ${event.ResourceStatusReason}`
5137
+ ].join("\n");
5138
+ }
5139
+ }
5140
+ return reason;
5077
5141
  }
5078
5142
  };
5079
5143
 
package/dist/index.d.ts CHANGED
@@ -2320,12 +2320,13 @@ type ConstructorOf<C> = {
2320
2320
  declare class Stack {
2321
2321
  readonly name: string;
2322
2322
  readonly region: Region;
2323
- private app?;
2323
+ private parent?;
2324
2324
  readonly exports: Map<string, string>;
2325
2325
  readonly resources: Set<Resource>;
2326
2326
  readonly tags: Map<string, string>;
2327
2327
  readonly assets: Set<Asset>;
2328
2328
  constructor(name: string, region: Region);
2329
+ get app(): App | undefined;
2329
2330
  setApp(app: App): this;
2330
2331
  add(...resources: (Resource | Asset | Group)[]): this;
2331
2332
  export(name: string, value: string): this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awsless/awsless",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {