@awsless/awsless 0.0.13 → 0.0.14

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
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  var import_commander = require("commander");
28
28
 
29
29
  // src/app.ts
30
- var import_aws_cdk_lib7 = require("aws-cdk-lib");
30
+ var import_aws_cdk_lib9 = require("aws-cdk-lib");
31
31
 
32
32
  // src/stack.ts
33
33
  var import_aws_cdk_lib = require("aws-cdk-lib");
@@ -170,6 +170,10 @@ var toStack = ({ config, assets, app, stackConfig, plugins }) => {
170
170
  const stackName = `${config.name}-${stackConfig.name}`;
171
171
  const stack = new import_aws_cdk_lib.Stack(app, stackConfig.name, {
172
172
  stackName,
173
+ env: {
174
+ account: config.account,
175
+ region: config.region
176
+ },
173
177
  tags: {
174
178
  APP: config.name,
175
179
  STAGE: config.stage,
@@ -230,7 +234,7 @@ var assetDir = (0, import_path.join)(outDir, "asset");
230
234
  var cacheDir = (0, import_path.join)(outDir, "cache");
231
235
 
232
236
  // src/stack/app-bootstrap.ts
233
- var import_aws_cdk_lib6 = require("aws-cdk-lib");
237
+ var import_aws_cdk_lib8 = require("aws-cdk-lib");
234
238
 
235
239
  // src/plugin.ts
236
240
  var definePlugin = (plugin) => plugin;
@@ -282,6 +286,9 @@ var toId = (resource, id) => {
282
286
  var toName = (stack, id) => {
283
287
  return (0, import_change_case.paramCase)(`${stack.stackName}-${id}`);
284
288
  };
289
+ var toExportName = (name) => {
290
+ return (0, import_change_case.paramCase)(name);
291
+ };
285
292
  var toEnvKey = (resource, id) => {
286
293
  return `RESOURCE_${resource.toUpperCase()}_${id}`;
287
294
  };
@@ -415,7 +422,7 @@ var writeBuildFiles = async (config, stack, id, files) => {
415
422
  await (0, import_promises2.writeFile)(bundleFile, bundle);
416
423
  await Promise.all(files.map(async (file) => {
417
424
  const fileName = (0, import_path3.join)(filesPath, file.name);
418
- await (0, import_promises2.mkdir)((0, import_path3.basename)(fileName), { recursive: true });
425
+ await (0, import_promises2.mkdir)((0, import_path3.dirname)(fileName), { recursive: true });
419
426
  await (0, import_promises2.writeFile)(fileName, file.code);
420
427
  if (file.map) {
421
428
  const mapName = (0, import_path3.join)(filesPath, `${file.name}.map`);
@@ -443,7 +450,7 @@ var assetBucketUrl = (config, stackName) => {
443
450
  const bucket = assetBucketName(config);
444
451
  return `https://s3-${config.region}.amazonaws.com/${bucket}/${stackName}/cloudformation.json`;
445
452
  };
446
- var version = "2";
453
+ var version = "1";
447
454
  var bootstrapStack = (config, app) => {
448
455
  const stack = new import_aws_cdk_lib2.Stack(app, "bootstrap", {
449
456
  stackName: `awsless-bootstrap`
@@ -918,35 +925,8 @@ var topicPlugin = definePlugin({
918
925
  }
919
926
  });
920
927
 
921
- // src/plugins/search.ts
922
- var import_zod19 = require("zod");
923
- var import_aws_opensearchserverless = require("aws-cdk-lib/aws-opensearchserverless");
924
- var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
925
- var searchPlugin = definePlugin({
926
- name: "search",
927
- schema: import_zod19.z.object({
928
- stacks: import_zod19.z.object({
929
- searchs: import_zod19.z.array(ResourceIdSchema).optional()
930
- }).array()
931
- }),
932
- onStack({ stack, stackConfig, bind }) {
933
- (stackConfig.searchs || []).forEach((id) => {
934
- const collection = new import_aws_opensearchserverless.CfnCollection(stack, toId("search", id), {
935
- name: toName(stack, id),
936
- type: "SEARCH"
937
- });
938
- bind((lambda) => {
939
- lambda.addToRolePolicy(new import_aws_iam2.PolicyStatement({
940
- actions: ["aoss:APIAccessAll"],
941
- resources: [collection.attrArn]
942
- }));
943
- });
944
- });
945
- }
946
- });
947
-
948
928
  // src/plugins/graphql/index.ts
949
- var import_zod21 = require("zod");
929
+ var import_zod20 = require("zod");
950
930
  var import_aws_appsync = require("aws-cdk-lib/aws-appsync");
951
931
  var import_merge = require("@graphql-tools/merge");
952
932
  var import_promises4 = require("fs/promises");
@@ -965,35 +945,35 @@ var import_graphql = require("graphql");
965
945
  var import_change_case2 = require("change-case");
966
946
 
967
947
  // src/plugins/graphql/schema/resolver-field.ts
968
- var import_zod20 = require("zod");
969
- var ResolverFieldSchema = import_zod20.z.custom((value) => {
970
- return import_zod20.z.string().regex(/([a-z0-9\_]+)(\s){1}([a-z0-9\_]+)/gi).safeParse(value).success;
948
+ var import_zod19 = require("zod");
949
+ var ResolverFieldSchema = import_zod19.z.custom((value) => {
950
+ return import_zod19.z.string().regex(/([a-z0-9\_]+)(\s){1}([a-z0-9\_]+)/gi).safeParse(value).success;
971
951
  }, `Invalid resolver field. Valid example: "Query list"`);
972
952
 
973
953
  // src/plugins/graphql/index.ts
974
954
  var import_aws_cdk_lib5 = require("aws-cdk-lib");
975
955
  var graphqlPlugin = definePlugin({
976
956
  name: "graphql",
977
- schema: import_zod21.z.object({
978
- defaults: import_zod21.z.object({
979
- graphql: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
980
- authorization: import_zod21.z.object({
957
+ schema: import_zod20.z.object({
958
+ defaults: import_zod20.z.object({
959
+ graphql: import_zod20.z.record(ResourceIdSchema, import_zod20.z.object({
960
+ authorization: import_zod20.z.object({
981
961
  authorizer: FunctionSchema,
982
962
  ttl: DurationSchema.default("1 hour")
983
963
  }).optional(),
984
- mappingTemplate: import_zod21.z.object({
964
+ mappingTemplate: import_zod20.z.object({
985
965
  request: LocalFileSchema.optional(),
986
966
  response: LocalFileSchema.optional()
987
967
  }).optional()
988
968
  })).optional()
989
969
  }).default({}),
990
- stacks: import_zod21.z.object({
991
- graphql: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
992
- schema: import_zod21.z.union([
970
+ stacks: import_zod20.z.object({
971
+ graphql: import_zod20.z.record(ResourceIdSchema, import_zod20.z.object({
972
+ schema: import_zod20.z.union([
993
973
  LocalFileSchema,
994
- import_zod21.z.array(LocalFileSchema).min(1)
974
+ import_zod20.z.array(LocalFileSchema).min(1)
995
975
  ]).optional(),
996
- resolvers: import_zod21.z.record(ResolverFieldSchema, FunctionSchema).optional()
976
+ resolvers: import_zod20.z.record(ResolverFieldSchema, FunctionSchema).optional()
997
977
  })).optional()
998
978
  }).array()
999
979
  }),
@@ -1078,16 +1058,17 @@ var graphqlPlugin = definePlugin({
1078
1058
  });
1079
1059
 
1080
1060
  // src/plugins/pubsub.ts
1081
- var import_zod22 = require("zod");
1061
+ var import_zod21 = require("zod");
1082
1062
  var import_aws_iot = require("aws-cdk-lib/aws-iot");
1083
- var import_aws_iam3 = require("aws-cdk-lib/aws-iam");
1063
+ var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
1064
+ var import_change_case3 = require("change-case");
1084
1065
  var pubsubPlugin = definePlugin({
1085
1066
  name: "pubsub",
1086
- schema: import_zod22.z.object({
1087
- stacks: import_zod22.z.object({
1088
- pubsub: import_zod22.z.record(ResourceIdSchema, import_zod22.z.object({
1089
- sql: import_zod22.z.string(),
1090
- sqlVersion: import_zod22.z.enum(["2015-10-08", "2016-03-23", "beta"]).default("2016-03-23"),
1067
+ schema: import_zod21.z.object({
1068
+ stacks: import_zod21.z.object({
1069
+ pubsub: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
1070
+ sql: import_zod21.z.string(),
1071
+ sqlVersion: import_zod21.z.enum(["2015-10-08", "2016-03-23", "beta"]).default("2016-03-23"),
1091
1072
  consumer: FunctionSchema
1092
1073
  })).optional()
1093
1074
  }).array()
@@ -1095,7 +1076,7 @@ var pubsubPlugin = definePlugin({
1095
1076
  onStack(ctx) {
1096
1077
  const { stack, stackConfig, bind } = ctx;
1097
1078
  bind((lambda) => {
1098
- lambda.addToRolePolicy(new import_aws_iam3.PolicyStatement({
1079
+ lambda.addToRolePolicy(new import_aws_iam2.PolicyStatement({
1099
1080
  actions: ["iot:publish"],
1100
1081
  resources: ["*"]
1101
1082
  }));
@@ -1103,7 +1084,7 @@ var pubsubPlugin = definePlugin({
1103
1084
  return Object.entries(stackConfig.pubsub || {}).map(([id, props]) => {
1104
1085
  const lambda = toFunction(ctx, id, props.consumer);
1105
1086
  new import_aws_iot.CfnTopicRule(stack, toId("pubsub", id), {
1106
- ruleName: toName(stack, id),
1087
+ ruleName: (0, import_change_case3.snakeCase)(toName(stack, id)),
1107
1088
  topicRulePayload: {
1108
1089
  sql: props.sql,
1109
1090
  awsIotSqlVersion: props.sqlVersion,
@@ -1119,6 +1100,229 @@ var pubsubPlugin = definePlugin({
1119
1100
  }
1120
1101
  });
1121
1102
 
1103
+ // src/plugins/http/index.ts
1104
+ var import_zod23 = require("zod");
1105
+ var import_aws_ec2 = require("aws-cdk-lib/aws-ec2");
1106
+ var import_aws_elasticloadbalancingv2 = require("aws-cdk-lib/aws-elasticloadbalancingv2");
1107
+ var import_aws_route53 = require("aws-cdk-lib/aws-route53");
1108
+ var import_aws_route53_targets = require("aws-cdk-lib/aws-route53-targets");
1109
+ var import_aws_elasticloadbalancingv2_targets = require("aws-cdk-lib/aws-elasticloadbalancingv2-targets");
1110
+ var import_aws_cdk_lib6 = require("aws-cdk-lib");
1111
+ var import_aws_certificatemanager = require("aws-cdk-lib/aws-certificatemanager");
1112
+ var import_change_case4 = require("change-case");
1113
+
1114
+ // src/plugins/http/schema/route.ts
1115
+ var import_zod22 = require("zod");
1116
+ var RouteSchema = import_zod22.z.custom((route) => {
1117
+ return import_zod22.z.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS)(\s\/[a-z0-9\+\_\-\/]*)$/ig).safeParse(route).success;
1118
+ }, "Invalid route");
1119
+
1120
+ // src/plugins/http/util/priority.ts
1121
+ var strToInt = (str) => {
1122
+ return parseInt(Buffer.from(str, "utf8").toString("hex"), 16);
1123
+ };
1124
+ var generatePriority = (stackName, route) => {
1125
+ const start = strToInt(stackName) % 500 + 1;
1126
+ const end = strToInt(route) % 100;
1127
+ const priority = start + "" + end;
1128
+ return parseInt(priority, 10);
1129
+ };
1130
+
1131
+ // src/plugins/http/index.ts
1132
+ var httpPlugin = definePlugin({
1133
+ name: "http",
1134
+ schema: import_zod23.z.object({
1135
+ defaults: import_zod23.z.object({
1136
+ http: import_zod23.z.record(
1137
+ ResourceIdSchema,
1138
+ import_zod23.z.object({
1139
+ domain: import_zod23.z.string(),
1140
+ subDomain: import_zod23.z.string()
1141
+ })
1142
+ ).optional()
1143
+ }).default({}),
1144
+ stacks: import_zod23.z.object({
1145
+ http: import_zod23.z.record(
1146
+ ResourceIdSchema,
1147
+ import_zod23.z.record(RouteSchema, FunctionSchema)
1148
+ ).optional()
1149
+ }).array()
1150
+ }),
1151
+ onBootstrap({ stack, config }) {
1152
+ if (Object.keys(config.defaults?.http || {}).length === 0) {
1153
+ return;
1154
+ }
1155
+ const vpc = new import_aws_ec2.Vpc(stack, toId("vpc", "http"), {
1156
+ subnetConfiguration: [{
1157
+ name: "public",
1158
+ subnetType: import_aws_ec2.SubnetType.PUBLIC,
1159
+ cidrMask: 24
1160
+ }],
1161
+ availabilityZones: [
1162
+ config.region + "a",
1163
+ config.region + "b",
1164
+ config.region + "c"
1165
+ ]
1166
+ });
1167
+ const securityGroup = new import_aws_ec2.SecurityGroup(stack, toId("security-group", "http"), {
1168
+ vpc
1169
+ });
1170
+ securityGroup.addIngressRule(import_aws_ec2.Peer.anyIpv4(), import_aws_ec2.Port.tcp(443));
1171
+ securityGroup.addIngressRule(import_aws_ec2.Peer.anyIpv6(), import_aws_ec2.Port.tcp(443));
1172
+ new import_aws_cdk_lib6.CfnOutput(stack, toId("output", "http-vpc"), {
1173
+ exportName: "http-vpc-id",
1174
+ value: vpc.vpcId
1175
+ });
1176
+ new import_aws_cdk_lib6.CfnOutput(stack, toId("output", "http-security-group"), {
1177
+ exportName: "http-security-group-id",
1178
+ value: securityGroup.securityGroupId
1179
+ });
1180
+ Object.entries(config.defaults?.http || {}).forEach(([id, props]) => {
1181
+ const loadBalancer = new import_aws_elasticloadbalancingv2.ApplicationLoadBalancer(stack, toId("load-balancer", id), {
1182
+ vpc,
1183
+ securityGroup
1184
+ });
1185
+ const zone = import_aws_route53.HostedZone.fromHostedZoneAttributes(
1186
+ stack,
1187
+ toId("hosted-zone", id),
1188
+ {
1189
+ hostedZoneId: import_aws_cdk_lib6.Token.asString(import_aws_cdk_lib6.Fn.ref(toId("hosted-zone", props.domain))),
1190
+ zoneName: props.domain + "."
1191
+ }
1192
+ );
1193
+ const certificate = import_aws_certificatemanager.Certificate.fromCertificateArn(
1194
+ stack,
1195
+ toId("certificate", id),
1196
+ import_aws_cdk_lib6.Token.asString(import_aws_cdk_lib6.Fn.ref(toId("certificate", props.domain)))
1197
+ );
1198
+ const target = import_aws_route53.RecordTarget.fromAlias(new import_aws_route53_targets.LoadBalancerTarget(loadBalancer));
1199
+ const recordName = props.subDomain ? `${props.subDomain}.${props.domain}` : props.domain;
1200
+ new import_aws_route53.RecordSet(stack, toId("record-set", id), {
1201
+ zone,
1202
+ target,
1203
+ recordName,
1204
+ recordType: import_aws_route53.RecordType.A
1205
+ });
1206
+ const listener = loadBalancer.addListener(toId("listener", id), {
1207
+ port: 443,
1208
+ protocol: import_aws_elasticloadbalancingv2.ApplicationProtocol.HTTPS,
1209
+ certificates: [certificate],
1210
+ defaultAction: import_aws_elasticloadbalancingv2.ListenerAction.fixedResponse(404, {
1211
+ contentType: "application/json",
1212
+ messageBody: JSON.stringify({
1213
+ message: "Route not found"
1214
+ })
1215
+ })
1216
+ });
1217
+ new import_aws_cdk_lib6.CfnOutput(stack, toId("output", `http-${id}-listener`), {
1218
+ exportName: `http-${id}-listener-arn`,
1219
+ value: listener.listenerArn
1220
+ });
1221
+ });
1222
+ },
1223
+ onStack(ctx) {
1224
+ const { stack, stackConfig } = ctx;
1225
+ return Object.entries(stackConfig.http || {}).map(([id, routes]) => {
1226
+ const listener = import_aws_elasticloadbalancingv2.ApplicationListener.fromApplicationListenerAttributes(stack, toId("listener", id), {
1227
+ listenerArn: import_aws_cdk_lib6.Fn.importValue(`http-${id}-listener-arn`),
1228
+ securityGroup: import_aws_ec2.SecurityGroup.fromLookupById(
1229
+ stack,
1230
+ toId("security-group", id),
1231
+ "http-security-group-id"
1232
+ )
1233
+ });
1234
+ return Object.entries(routes).map(([route, props]) => {
1235
+ const lambda = toFunction(ctx, (0, import_change_case4.paramCase)(route), props);
1236
+ const [method, ...paths] = route.split(" ");
1237
+ const path = paths.join(" ");
1238
+ new import_aws_elasticloadbalancingv2.ApplicationListenerRule(stack, toId("listener-rule", route), {
1239
+ listener,
1240
+ priority: generatePriority(stackConfig.name, route),
1241
+ action: import_aws_elasticloadbalancingv2.ListenerAction.forward([
1242
+ new import_aws_elasticloadbalancingv2.ApplicationTargetGroup(stack, toId("target-group", route), {
1243
+ targets: [new import_aws_elasticloadbalancingv2_targets.LambdaTarget(lambda)]
1244
+ })
1245
+ ]),
1246
+ conditions: [
1247
+ import_aws_elasticloadbalancingv2.ListenerCondition.httpRequestMethods([method]),
1248
+ import_aws_elasticloadbalancingv2.ListenerCondition.pathPatterns([path])
1249
+ ]
1250
+ });
1251
+ return lambda;
1252
+ });
1253
+ }).flat();
1254
+ }
1255
+ });
1256
+
1257
+ // src/plugins/domain/index.ts
1258
+ var import_zod26 = require("zod");
1259
+ var import_aws_route533 = require("aws-cdk-lib/aws-route53");
1260
+ var import_aws_certificatemanager2 = require("aws-cdk-lib/aws-certificatemanager");
1261
+
1262
+ // src/plugins/domain/schema/record-type.ts
1263
+ var import_aws_route532 = require("aws-cdk-lib/aws-route53");
1264
+ var import_zod24 = require("zod");
1265
+ var types4 = {
1266
+ "A": import_aws_route532.RecordType.A,
1267
+ "AAAA": import_aws_route532.RecordType.AAAA,
1268
+ "MX": import_aws_route532.RecordType.MX,
1269
+ "TXT": import_aws_route532.RecordType.TXT,
1270
+ "CNAME": import_aws_route532.RecordType.CNAME
1271
+ };
1272
+ var RecordTypeSchema = import_zod24.z.enum(Object.keys(types4)).transform((value) => types4[value]);
1273
+
1274
+ // src/plugins/domain/schema/domain-name.ts
1275
+ var import_zod25 = require("zod");
1276
+ var DomainNameSchema = import_zod25.z.string().regex(/[a-z\-\_\.]/g, "Invalid domain name");
1277
+
1278
+ // src/plugins/domain/index.ts
1279
+ var import_aws_cdk_lib7 = require("aws-cdk-lib");
1280
+ var domainPlugin = definePlugin({
1281
+ name: "domain",
1282
+ schema: import_zod26.z.object({
1283
+ domains: import_zod26.z.record(DomainNameSchema, import_zod26.z.object({
1284
+ name: DomainNameSchema.optional(),
1285
+ type: RecordTypeSchema,
1286
+ ttl: DurationSchema,
1287
+ records: import_zod26.z.string().array()
1288
+ }).array()).optional()
1289
+ }),
1290
+ onBootstrap({ config, stack }) {
1291
+ Object.entries(config.domains || {}).forEach(([domain, dnsRecords]) => {
1292
+ const hostedZone = new import_aws_route533.HostedZone(stack, toId("hosted-zone", domain), {
1293
+ zoneName: domain,
1294
+ addTrailingDot: true
1295
+ });
1296
+ hostedZone.node.defaultChild.overrideLogicalId(toId("hosted-zone", domain));
1297
+ const certificate = new import_aws_certificatemanager2.Certificate(stack, toId("certificate", domain), {
1298
+ domainName: domain,
1299
+ validation: import_aws_certificatemanager2.CertificateValidation.fromDns(hostedZone),
1300
+ subjectAlternativeNames: [`*.${domain}`]
1301
+ });
1302
+ certificate.node.defaultChild.overrideLogicalId(toId("certificate", domain));
1303
+ new import_aws_cdk_lib7.CfnOutput(stack, toId("output-hosted-zone", domain), {
1304
+ exportName: toExportName(`hosted-zone-${domain}-id`),
1305
+ value: hostedZone.hostedZoneId
1306
+ });
1307
+ new import_aws_cdk_lib7.CfnOutput(stack, toId("output-certificate", domain), {
1308
+ exportName: toExportName(`certificate-${domain}-arn`),
1309
+ value: certificate.certificateArn
1310
+ });
1311
+ if (dnsRecords.length > 0) {
1312
+ new import_aws_route533.CfnRecordSetGroup(stack, toId("record-set-group", domain), {
1313
+ hostedZoneId: hostedZone.hostedZoneId,
1314
+ recordSets: dnsRecords.map((props) => ({
1315
+ name: props.name || "",
1316
+ type: props.type,
1317
+ ttl: props.ttl.toSeconds().toString(),
1318
+ resourceRecords: props.records
1319
+ }))
1320
+ });
1321
+ }
1322
+ });
1323
+ }
1324
+ });
1325
+
1122
1326
  // src/plugins/index.ts
1123
1327
  var defaultPlugins = [
1124
1328
  functionPlugin,
@@ -1127,14 +1331,16 @@ var defaultPlugins = [
1127
1331
  tablePlugin,
1128
1332
  storePlugin,
1129
1333
  topicPlugin,
1130
- searchPlugin,
1334
+ // searchPlugin,
1131
1335
  graphqlPlugin,
1132
- pubsubPlugin
1336
+ pubsubPlugin,
1337
+ domainPlugin,
1338
+ httpPlugin
1133
1339
  ];
1134
1340
 
1135
1341
  // src/stack/app-bootstrap.ts
1136
1342
  var appBootstrapStack = ({ config, app, assets }) => {
1137
- const stack = new import_aws_cdk_lib6.Stack(app, "bootstrap", {
1343
+ const stack = new import_aws_cdk_lib8.Stack(app, "bootstrap", {
1138
1344
  stackName: `${config.name}-bootstrap`
1139
1345
  });
1140
1346
  const plugins = [
@@ -1242,9 +1448,9 @@ var Assets = class {
1242
1448
 
1243
1449
  // src/app.ts
1244
1450
  var makeApp = (config) => {
1245
- return new import_aws_cdk_lib7.App({
1451
+ return new import_aws_cdk_lib9.App({
1246
1452
  outdir: assemblyDir,
1247
- defaultStackSynthesizer: new import_aws_cdk_lib7.DefaultStackSynthesizer({
1453
+ defaultStackSynthesizer: new import_aws_cdk_lib9.DefaultStackSynthesizer({
1248
1454
  fileAssetsBucketName: assetBucketName(config),
1249
1455
  fileAssetPublishingRoleArn: "",
1250
1456
  generateBootstrapVersionRule: false
@@ -1309,63 +1515,6 @@ var toApp = async (config, filters) => {
1309
1515
  };
1310
1516
  };
1311
1517
 
1312
- // src/cli/ui/layout/basic.ts
1313
- var br = () => {
1314
- return "\n";
1315
- };
1316
- var hr = () => {
1317
- return (term) => {
1318
- term.out.write([
1319
- style.placeholder("\u2500".repeat(term.out.width())),
1320
- br()
1321
- ]);
1322
- };
1323
- };
1324
-
1325
- // src/cli/ui/layout/logs.ts
1326
- var import_wrap_ansi = __toESM(require("wrap-ansi"), 1);
1327
- var previous = /* @__PURE__ */ new Date();
1328
- var logs = () => {
1329
- if (!process.env.VERBOSE) {
1330
- return [];
1331
- }
1332
- const logs2 = flushDebug();
1333
- return (term) => {
1334
- term.out.write([
1335
- hr(),
1336
- br(),
1337
- " ".repeat(3),
1338
- style.label("Debug Logs:"),
1339
- br(),
1340
- br(),
1341
- logs2.map((log) => {
1342
- const diff = log.date.getTime() - previous.getTime();
1343
- const time = `+${diff}`.padStart(8);
1344
- previous = log.date;
1345
- return (0, import_wrap_ansi.default)([
1346
- style.attr(`${time}${style.attr.dim("ms")}`),
1347
- " [ ",
1348
- log.type,
1349
- " ] ",
1350
- log.message,
1351
- br(),
1352
- log.type === "error" ? br() : ""
1353
- ].join(""), term.out.width(), { hard: true, trim: false });
1354
- }),
1355
- br(),
1356
- hr()
1357
- ]);
1358
- };
1359
- };
1360
-
1361
- // src/cli/ui/layout/footer.ts
1362
- var footer = () => {
1363
- return [
1364
- br(),
1365
- logs()
1366
- ];
1367
- };
1368
-
1369
1518
  // src/config.ts
1370
1519
  var import_path11 = require("path");
1371
1520
 
@@ -1386,17 +1535,17 @@ var getCredentials = (profile) => {
1386
1535
  };
1387
1536
 
1388
1537
  // src/schema/app.ts
1389
- var import_zod26 = require("zod");
1538
+ var import_zod30 = require("zod");
1390
1539
 
1391
1540
  // src/schema/stack.ts
1392
- var import_zod23 = require("zod");
1393
- var StackSchema = import_zod23.z.object({
1541
+ var import_zod27 = require("zod");
1542
+ var StackSchema = import_zod27.z.object({
1394
1543
  name: ResourceIdSchema,
1395
- depends: import_zod23.z.array(import_zod23.z.lazy(() => StackSchema)).optional()
1544
+ depends: import_zod27.z.array(import_zod27.z.lazy(() => StackSchema)).optional()
1396
1545
  });
1397
1546
 
1398
1547
  // src/schema/region.ts
1399
- var import_zod24 = require("zod");
1548
+ var import_zod28 = require("zod");
1400
1549
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1401
1550
  var AF = ["af-south-1"];
1402
1551
  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"];
@@ -1413,29 +1562,29 @@ var regions = [
1413
1562
  ...ME,
1414
1563
  ...SA
1415
1564
  ];
1416
- var RegionSchema = import_zod24.z.enum(regions);
1565
+ var RegionSchema = import_zod28.z.enum(regions);
1417
1566
 
1418
1567
  // src/schema/plugin.ts
1419
- var import_zod25 = require("zod");
1420
- var PluginSchema = import_zod25.z.object({
1421
- name: import_zod25.z.string(),
1422
- schema: import_zod25.z.custom().optional(),
1568
+ var import_zod29 = require("zod");
1569
+ var PluginSchema = import_zod29.z.object({
1570
+ name: import_zod29.z.string(),
1571
+ schema: import_zod29.z.custom().optional(),
1423
1572
  // depends: z.array(z.lazy(() => PluginSchema)).optional(),
1424
- onBootstrap: import_zod25.z.function().returns(import_zod25.z.any()).optional(),
1425
- onStack: import_zod25.z.function().returns(import_zod25.z.any()).optional(),
1426
- onApp: import_zod25.z.function().returns(import_zod25.z.void()).optional()
1573
+ onBootstrap: import_zod29.z.function().returns(import_zod29.z.any()).optional(),
1574
+ onStack: import_zod29.z.function().returns(import_zod29.z.any()).optional(),
1575
+ onApp: import_zod29.z.function().returns(import_zod29.z.void()).optional()
1427
1576
  // bind: z.function().optional(),
1428
1577
  });
1429
1578
 
1430
1579
  // src/schema/app.ts
1431
- var AppSchema = import_zod26.z.object({
1580
+ var AppSchema = import_zod30.z.object({
1432
1581
  name: ResourceIdSchema,
1433
1582
  region: RegionSchema,
1434
- profile: import_zod26.z.string(),
1435
- stage: import_zod26.z.string().regex(/[a-z]+/).default("prod"),
1436
- defaults: import_zod26.z.object({}).default({}),
1437
- stacks: import_zod26.z.array(StackSchema).min(1),
1438
- plugins: import_zod26.z.array(PluginSchema).optional()
1583
+ profile: import_zod30.z.string(),
1584
+ stage: import_zod30.z.string().regex(/[a-z]+/).default("prod"),
1585
+ defaults: import_zod30.z.object({}).default({}),
1586
+ stacks: import_zod30.z.array(StackSchema).min(1),
1587
+ plugins: import_zod30.z.array(PluginSchema).optional()
1439
1588
  });
1440
1589
 
1441
1590
  // src/util/import.ts
@@ -1451,7 +1600,7 @@ var resolveFileNameExtension = async (path) => {
1451
1600
  "/index.js"
1452
1601
  ];
1453
1602
  for (const option of options) {
1454
- const file = path + option;
1603
+ const file = path.replace(/\.js$/, "") + option;
1455
1604
  let stat;
1456
1605
  try {
1457
1606
  stat = await (0, import_promises5.lstat)(file);
@@ -1469,17 +1618,18 @@ var resolveDir = (path) => {
1469
1618
  };
1470
1619
  var importFile = async (path) => {
1471
1620
  const load = async (file) => {
1621
+ debug("Load file", file);
1472
1622
  let { code: code2 } = await (0, import_core3.transformFile)(file, {
1473
1623
  isModule: true
1474
1624
  });
1475
1625
  const path2 = (0, import_path9.dirname)(file);
1476
1626
  const dir = resolveDir(file);
1477
1627
  code2 = code2.replaceAll("__dirname", `"${dir}"`);
1478
- const matches = code2.match(/import\s*{\s*[a-z0-9\_]+\s*}\s*from\s*('|")(\.[\/a-z0-9\_\-]+)('|");?/ig);
1628
+ const matches = code2.match(/(import|export)\s*{\s*[a-z0-9\_\,\s\*]+\s*}\s*from\s*('|")(\.\.?[\/a-z0-9\_\-\.]+)('|");?/ig);
1479
1629
  if (!matches)
1480
1630
  return code2;
1481
1631
  await Promise.all(matches?.map(async (match) => {
1482
- const parts = /('|")(\.[\/a-z0-9\_\-]+)('|")/ig.exec(match);
1632
+ const parts = /('|")(\.\.?[\/a-z0-9\_\-\.]+)('|")/ig.exec(match);
1483
1633
  const from = parts[2];
1484
1634
  const file2 = await resolveFileNameExtension((0, import_path9.join)(path2, from));
1485
1635
  const result = await load(file2);
@@ -1499,11 +1649,7 @@ var importConfig = async (options) => {
1499
1649
  debug("Import config file");
1500
1650
  const fileName = (0, import_path11.join)(process.cwd(), options.configFile || "awsless.config.ts");
1501
1651
  const module2 = await importFile(fileName);
1502
- const appConfig = typeof module2.default === "function" ? await module2.default({
1503
- profile: options.profile,
1504
- region: options.region,
1505
- stage: options.stage
1506
- }) : module2.default;
1652
+ const appConfig = typeof module2.default === "function" ? await module2.default(options) : module2.default;
1507
1653
  debug("Validate config file");
1508
1654
  const plugins = [
1509
1655
  ...defaultPlugins,
@@ -1528,6 +1674,19 @@ var importConfig = async (options) => {
1528
1674
  };
1529
1675
  };
1530
1676
 
1677
+ // src/cli/ui/layout/basic.ts
1678
+ var br = () => {
1679
+ return "\n";
1680
+ };
1681
+ var hr = () => {
1682
+ return (term) => {
1683
+ term.out.write([
1684
+ style.placeholder("\u2500".repeat(term.out.width())),
1685
+ br()
1686
+ ]);
1687
+ };
1688
+ };
1689
+
1531
1690
  // src/cli/ui/layout/list.ts
1532
1691
  var list = (data) => {
1533
1692
  const padding = 3;
@@ -1535,26 +1694,26 @@ var list = (data) => {
1535
1694
  const size = Object.keys(data).reduce((total, name) => {
1536
1695
  return name.length > total ? name.length : total;
1537
1696
  }, 0);
1538
- return Object.entries(data).map(([name, value]) => [
1539
- " ".repeat(padding),
1540
- style.label((name + ":").padEnd(size + gap + 1)),
1541
- value,
1542
- br()
1543
- ]);
1697
+ return (term) => {
1698
+ term.out.gap();
1699
+ term.out.write(Object.entries(data).map(([name, value]) => [
1700
+ " ".repeat(padding),
1701
+ style.label((name + ":").padEnd(size + gap + 1)),
1702
+ value,
1703
+ br()
1704
+ ]));
1705
+ term.out.gap();
1706
+ };
1544
1707
  };
1545
1708
 
1546
1709
  // src/cli/ui/layout/header.ts
1547
1710
  var header = (config) => {
1548
- return [
1549
- br(),
1550
- list({
1551
- App: config.name,
1552
- Stage: config.stage,
1553
- Region: config.region,
1554
- Profile: config.profile
1555
- }),
1556
- br()
1557
- ];
1711
+ return list({
1712
+ App: config.name,
1713
+ Stage: config.stage,
1714
+ Region: config.region,
1715
+ Profile: config.profile
1716
+ });
1558
1717
  };
1559
1718
 
1560
1719
  // src/util/timer.ts
@@ -1621,16 +1780,16 @@ var createSpinner = () => {
1621
1780
  };
1622
1781
 
1623
1782
  // src/cli/ui/layout/dialog.ts
1624
- var import_wrap_ansi2 = __toESM(require("wrap-ansi"), 1);
1783
+ var import_wrap_ansi = __toESM(require("wrap-ansi"), 1);
1625
1784
  var dialog = (type, lines) => {
1626
1785
  const padding = 3;
1627
1786
  const icon = style[type](symbol[type].padEnd(padding));
1628
1787
  return (term) => {
1629
1788
  term.out.write(lines.map((line, i) => {
1630
1789
  if (i === 0) {
1631
- return icon + (0, import_wrap_ansi2.default)(line, term.out.width(), { hard: true });
1790
+ return icon + (0, import_wrap_ansi.default)(line, term.out.width(), { hard: true });
1632
1791
  }
1633
- return (0, import_wrap_ansi2.default)(" ".repeat(padding) + line, term.out.width(), { hard: true });
1792
+ return (0, import_wrap_ansi.default)(" ".repeat(padding) + line, term.out.width(), { hard: true });
1634
1793
  }).join(br()) + br());
1635
1794
  };
1636
1795
  };
@@ -1772,6 +1931,7 @@ var Renderer = class {
1772
1931
  fragments = [];
1773
1932
  unsubs = [];
1774
1933
  timeout;
1934
+ flushing = false;
1775
1935
  screen = [];
1776
1936
  width() {
1777
1937
  return this.output.columns;
@@ -1791,14 +1951,58 @@ var Renderer = class {
1791
1951
  this.update();
1792
1952
  return fragment;
1793
1953
  }
1954
+ gap() {
1955
+ const walk = (fragment) => {
1956
+ if (typeof fragment === "string") {
1957
+ return fragment;
1958
+ }
1959
+ if (Array.isArray(fragment)) {
1960
+ return fragment.map(walk).join("");
1961
+ }
1962
+ return walk(fragment.get());
1963
+ };
1964
+ const end = walk(this.fragments.slice(-2));
1965
+ if (end.endsWith("\n\n")) {
1966
+ } else if (end.endsWith("\n")) {
1967
+ this.fragments.push("\n");
1968
+ } else {
1969
+ this.fragments.push("\n\n");
1970
+ }
1971
+ this.update();
1972
+ }
1794
1973
  update() {
1795
1974
  clearTimeout(this.timeout);
1796
1975
  this.timeout = setTimeout(() => {
1797
1976
  this.flush();
1798
1977
  }, 0);
1799
1978
  }
1800
- flush() {
1979
+ async end() {
1980
+ this.gap();
1981
+ await this.flush();
1982
+ const y = this.screen.length - 1;
1983
+ await this.setCursor(0, y);
1984
+ }
1985
+ setCursor(x, y) {
1986
+ return new Promise((resolve) => {
1987
+ this.output.cursorTo?.(x, y, () => resolve(void 0));
1988
+ });
1989
+ }
1990
+ writeString(value) {
1991
+ return new Promise((resolve) => {
1992
+ this.output.write?.(value, () => resolve(void 0));
1993
+ });
1994
+ }
1995
+ clearLine() {
1996
+ return new Promise((resolve) => {
1997
+ this.output.clearLine?.(1, () => resolve(void 0));
1998
+ });
1999
+ }
2000
+ async flush() {
1801
2001
  clearTimeout(this.timeout);
2002
+ if (this.flushing) {
2003
+ this.update();
2004
+ return;
2005
+ }
1802
2006
  const walk = (fragment) => {
1803
2007
  if (typeof fragment === "string") {
1804
2008
  return fragment;
@@ -1814,34 +2018,40 @@ var Renderer = class {
1814
2018
  this.unsubs.forEach((unsub) => unsub());
1815
2019
  this.unsubs = [];
1816
2020
  const screen = walk(this.fragments).split("\n");
2021
+ const height = this.height();
1817
2022
  const oldSize = this.screen.length;
1818
2023
  const newSize = screen.length;
1819
2024
  const size = Math.max(oldSize, newSize);
1820
- const height = this.height();
1821
2025
  const start = Math.max(oldSize - height, 0);
2026
+ this.flushing = true;
1822
2027
  for (let y = start; y < size; y++) {
1823
- const line = screen[y];
1824
- if (line !== this.screen[y]) {
1825
- if (y > oldSize) {
1826
- const x = (this.screen[y - 1]?.length || 0) - 1;
1827
- this.output.cursorTo?.(x, y - 1 - start);
1828
- this.output.write?.("\n" + line);
2028
+ const newLine = screen[y];
2029
+ const oldLine = this.screen[y];
2030
+ if (newLine !== oldLine) {
2031
+ if (y >= oldSize && y !== 0) {
2032
+ const p = y - start - 1;
2033
+ const x = screen[y - 1]?.length || 0;
2034
+ await this.setCursor(x, p);
2035
+ await this.writeString("\n" + newLine);
1829
2036
  } else {
1830
- this.output.cursorTo?.(0, y - start);
1831
- this.output.write?.(line);
2037
+ await this.setCursor(0, y - start);
2038
+ await this.writeString(newLine);
2039
+ await this.clearLine();
1832
2040
  }
1833
- this.output.clearLine?.(1);
1834
2041
  }
1835
2042
  }
1836
2043
  this.screen = screen;
1837
- }
1838
- clear() {
1839
- let count = this.output.rows;
1840
- while (count--) {
1841
- this.output.write("\n");
2044
+ this.flushing = false;
2045
+ }
2046
+ async clear() {
2047
+ await this.setCursor(0, 0);
2048
+ await this.writeString("\n".repeat(this.height()));
2049
+ await this.setCursor(0, 0);
2050
+ if (this.output.clearScreenDown) {
2051
+ await new Promise((resolve) => {
2052
+ this.output.clearScreenDown(() => resolve(void 0));
2053
+ });
1842
2054
  }
1843
- this.output.cursorTo?.(0, 0);
1844
- this.output.clearScreenDown?.();
1845
2055
  }
1846
2056
  };
1847
2057
 
@@ -1857,22 +2067,62 @@ var logo = () => {
1857
2067
  return [
1858
2068
  style.warning("\u26A1\uFE0F "),
1859
2069
  style.primary("AWS"),
1860
- style.primary.dim("LESS"),
1861
- br()
2070
+ style.primary.dim("LESS")
1862
2071
  ];
1863
2072
  };
1864
2073
 
2074
+ // src/cli/ui/layout/logs.ts
2075
+ var import_wrap_ansi2 = __toESM(require("wrap-ansi"), 1);
2076
+ var previous = /* @__PURE__ */ new Date();
2077
+ var logs = () => {
2078
+ if (!process.env.VERBOSE) {
2079
+ return [];
2080
+ }
2081
+ const logs2 = flushDebug();
2082
+ return (term) => {
2083
+ term.out.gap();
2084
+ term.out.write([
2085
+ hr(),
2086
+ br(),
2087
+ " ".repeat(3),
2088
+ style.label("Debug Logs:"),
2089
+ br(),
2090
+ br(),
2091
+ logs2.map((log) => {
2092
+ const diff = log.date.getTime() - previous.getTime();
2093
+ const time = `+${diff}`.padStart(8);
2094
+ previous = log.date;
2095
+ return (0, import_wrap_ansi2.default)([
2096
+ style.attr(`${time}${style.attr.dim("ms")}`),
2097
+ " [ ",
2098
+ log.type,
2099
+ " ] ",
2100
+ log.message,
2101
+ br(),
2102
+ log.type === "error" ? br() : ""
2103
+ ].join(""), term.out.width(), { hard: true, trim: false });
2104
+ }),
2105
+ br(),
2106
+ hr()
2107
+ ]);
2108
+ };
2109
+ };
2110
+
1865
2111
  // src/cli/ui/layout/layout.ts
1866
2112
  var layout = async (cb) => {
1867
2113
  const term = createTerminal();
1868
- term.out.clear();
2114
+ await term.out.clear();
2115
+ term.out.write(br());
1869
2116
  term.out.write(logo());
2117
+ term.out.gap();
1870
2118
  try {
1871
2119
  const options = program.optsWithGlobals();
1872
2120
  const config = await importConfig(options);
1873
2121
  term.out.write(header(config));
2122
+ term.out.gap();
1874
2123
  await cb(config, term.out.write.bind(term.out), term);
1875
2124
  } catch (error) {
2125
+ term.out.gap();
1876
2126
  if (error instanceof Error) {
1877
2127
  term.out.write(dialog("error", [error.message]));
1878
2128
  } else if (typeof error === "string") {
@@ -1883,7 +2133,9 @@ var layout = async (cb) => {
1883
2133
  debugError(error);
1884
2134
  } finally {
1885
2135
  debug("Exit");
1886
- term.out.write(footer());
2136
+ term.out.gap();
2137
+ term.out.write(logs());
2138
+ await term.out.end();
1887
2139
  term.in.unref();
1888
2140
  setTimeout(() => {
1889
2141
  process.exit(0);
@@ -1915,7 +2167,8 @@ var flexLine = (term, left, right, reserveSpace = 0) => {
1915
2167
  var assetBuilder = (assets) => {
1916
2168
  return async (term) => {
1917
2169
  const done = term.out.write(loadingDialog("Building stack assets..."));
1918
- const groups = new Signal([br()]);
2170
+ const groups = new Signal([""]);
2171
+ term.out.gap();
1919
2172
  term.out.write(groups);
1920
2173
  const stackNameSize = Math.max(...Object.keys(assets.list()).map((stack) => stack.length));
1921
2174
  const resourceSize = Math.max(...Object.values(assets.list()).map((assets2) => assets2.map((asset) => asset.resource.length)).flat());
@@ -1961,6 +2214,7 @@ var assetBuilder = (assets) => {
1961
2214
  }));
1962
2215
  }));
1963
2216
  done("Done building stack assets");
2217
+ term.out.gap();
1964
2218
  };
1965
2219
  };
1966
2220
 
@@ -2300,7 +2554,9 @@ var stackTree = (nodes, statuses) => {
2300
2554
  render(node.children, deep + 1, [...parents, more]);
2301
2555
  });
2302
2556
  };
2557
+ term.out.gap();
2303
2558
  render(nodes);
2559
+ term.out.gap();
2304
2560
  };
2305
2561
  };
2306
2562
 
@@ -2311,7 +2567,6 @@ var status = (program2) => {
2311
2567
  const { app, assets, dependencyTree } = await toApp(config, filters);
2312
2568
  await cleanUp();
2313
2569
  await write(assetBuilder(assets));
2314
- write(br());
2315
2570
  const assembly = app.synth();
2316
2571
  const doneLoading = write(loadingDialog("Loading stack information..."));
2317
2572
  const client = new StackClient(config);
@@ -2320,9 +2575,7 @@ var status = (program2) => {
2320
2575
  assembly.stacks.forEach((stack) => {
2321
2576
  stackStatuses[stack.id] = new Signal(style.info("Loading..."));
2322
2577
  });
2323
- write(br());
2324
2578
  write(stackTree(dependencyTree, stackStatuses));
2325
- write(br());
2326
2579
  debug("Load metadata for all deployed stacks on AWS");
2327
2580
  await Promise.all(assembly.stacks.map(async (stack, i) => {
2328
2581
  const info = await client.get(stack.stackName);
@@ -2367,8 +2620,6 @@ var deploy = (program2) => {
2367
2620
  }
2368
2621
  await cleanUp();
2369
2622
  await write(assetBuilder(assets));
2370
- write(br());
2371
- write(br());
2372
2623
  const donePublishing = write(loadingDialog("Publishing stack assets to AWS..."));
2373
2624
  await Promise.all(assets.map(async (_, assets2) => {
2374
2625
  await Promise.all(assets2.map(async (asset) => {
@@ -2382,9 +2633,7 @@ var deploy = (program2) => {
2382
2633
  statuses[stack.id] = new Signal(style.info("waiting"));
2383
2634
  });
2384
2635
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
2385
- write(br());
2386
2636
  write(stackTree(dependencyTree, statuses));
2387
- write(br());
2388
2637
  const client = new StackClient(config);
2389
2638
  const deploymentLine = createDeploymentLine(dependencyTree);
2390
2639
  for (const stacks of deploymentLine) {
@@ -2482,7 +2731,6 @@ var set = (program2) => {
2482
2731
  write(list({
2483
2732
  "Set secret parameter": style.info(name)
2484
2733
  }));
2485
- write(br());
2486
2734
  const value = await write(textPrompt("Enter secret value"));
2487
2735
  if (value === "") {
2488
2736
  write(dialog("error", [`Provided secret value can't be empty`]));
@@ -2503,7 +2751,6 @@ var get = (program2) => {
2503
2751
  const done = write(loadingDialog(`Getting remote secret parameter`));
2504
2752
  const value = await params.get(name);
2505
2753
  done(`Done getting remote secret parameter`);
2506
- write(br());
2507
2754
  write(list({
2508
2755
  Name: name,
2509
2756
  Value: value || style.error("(empty)")
@@ -2526,7 +2773,6 @@ var del = (program2) => {
2526
2773
  const value = await params.get(name);
2527
2774
  await params.delete(name);
2528
2775
  done(`Done deleting remote secret parameter`);
2529
- write(br());
2530
2776
  write(list({
2531
2777
  Name: name,
2532
2778
  Value: value || style.error("(empty)")
@@ -2544,7 +2790,6 @@ var list2 = (program2) => {
2544
2790
  const values = await params.list();
2545
2791
  done("Done loading secret values");
2546
2792
  if (Object.keys(values).length > 0) {
2547
- write(br());
2548
2793
  write(list(values));
2549
2794
  } else {
2550
2795
  write(dialog("warning", ["No secret parameters found"]));
@@ -2567,13 +2812,16 @@ var secrets = (program2) => {
2567
2812
 
2568
2813
  // src/cli/program.ts
2569
2814
  var program = new import_commander.Command();
2570
- program.name("awsless");
2815
+ program.name(logo().join("").replace(/\s+/, ""));
2571
2816
  program.option("--config-file <string>", "The config file location");
2572
2817
  program.option("--stage <string>", "The stage to use, defaults to prod stage", "prod");
2573
2818
  program.option("--profile <string>", "The AWS profile to use");
2574
2819
  program.option("--region <string>", "The AWS region to use");
2575
2820
  program.option("-m --mute", "Mute sound effects");
2576
2821
  program.option("-v --verbose", "Print verbose logs");
2822
+ program.exitOverride(() => {
2823
+ process.exit(0);
2824
+ });
2577
2825
  program.on("option:verbose", () => {
2578
2826
  process.env.VERBOSE = program.opts().verbose ? "1" : void 0;
2579
2827
  });
@@ -2585,10 +2833,8 @@ var commands2 = [
2585
2833
  secrets
2586
2834
  // diff,
2587
2835
  // remove,
2588
- // test,
2589
- // test2,
2590
2836
  ];
2591
- commands2.forEach((command) => command(program));
2837
+ commands2.forEach((fn) => fn(program));
2592
2838
 
2593
2839
  // src/bin.ts
2594
2840
  program.parse(process.argv);