@awsless/awsless 0.0.7 → 0.0.9

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
@@ -195,6 +195,8 @@ var toStack = ({ config: config2, assets, app, stackConfig, plugins }) => {
195
195
  functions.forEach((lambda) => lambda.addToRolePolicy(allowConfigParameters));
196
196
  return {
197
197
  stack,
198
+ functions,
199
+ bindings,
198
200
  depends: stackConfig.depends
199
201
  };
200
202
  };
@@ -204,7 +206,8 @@ import { join } from "path";
204
206
  var rootDir = process.cwd();
205
207
  var outDir = join(rootDir, ".awsless");
206
208
  var assemblyDir = join(outDir, "assembly");
207
- var functionDir = join(outDir, "function");
209
+ var assetDir = join(outDir, "asset");
210
+ var cacheDir = join(outDir, "cache");
208
211
 
209
212
  // src/stack/app-bootstrap.ts
210
213
  import { Stack as Stack3 } from "aws-cdk-lib";
@@ -249,7 +252,7 @@ var ScheduleExpressionSchema = RateExpressionSchema.or(CronExpressionSchema);
249
252
  import { Rule } from "aws-cdk-lib/aws-events";
250
253
 
251
254
  // src/util/resource.ts
252
- import { constantCase, paramCase, pascalCase } from "change-case";
255
+ import { paramCase, pascalCase } from "change-case";
253
256
  var toId = (resource, id) => {
254
257
  return pascalCase(`${resource}-${id}`);
255
258
  };
@@ -257,7 +260,7 @@ var toName = (stack, id) => {
257
260
  return paramCase(`${stack.stackName}-${id}`);
258
261
  };
259
262
  var toEnvKey = (resource, id) => {
260
- return constantCase(`RESOURCE_${resource}_${id}`);
263
+ return `RESOURCE_${resource.toUpperCase()}_${id}`;
261
264
  };
262
265
  var addResourceEnvironment = (stack, resource, id, lambda) => {
263
266
  const key = toEnvKey(resource, id);
@@ -356,43 +359,45 @@ var SizeSchema = z7.custom((value) => {
356
359
  return z7.string().regex(/[0-9]+ (KB|MB|GB)/).safeParse(value).success;
357
360
  }, "Invalid size").transform(toSize);
358
361
 
359
- // src/plugins/function/util/build-worker.ts
360
- import { bundle } from "@swc/core";
361
- import { createHash } from "crypto";
362
+ // src/plugins/function/util/esbuild.ts
363
+ import { build } from "esbuild";
364
+ import { createHash, randomUUID } from "crypto";
365
+ import { join as join2 } from "path";
366
+ import { readFile, rm } from "fs/promises";
362
367
  var defaultBuild = async (file) => {
363
- const output = await bundle({
364
- entry: {
365
- file
366
- },
367
- mode: "production",
368
- target: "node",
369
- externalModules: [
368
+ const random = randomUUID();
369
+ const codeFile = join2(cacheDir, `${random}.mjs`);
370
+ const mapFile = join2(cacheDir, `${random}.mjs.map`);
371
+ await build({
372
+ entryPoints: [file],
373
+ minify: true,
374
+ bundle: true,
375
+ external: [
370
376
  "@aws-sdk/*",
371
377
  "@aws-sdk",
372
378
  "aws-sdk"
373
379
  ],
374
- module: {},
375
- options: {
376
- minify: true,
377
- sourceMaps: true,
378
- jsc: {
379
- target: "es2022"
380
- }
381
- },
382
- output: {
383
- name: "output",
384
- path: ""
385
- }
380
+ sourcemap: "external",
381
+ target: "esnext",
382
+ treeShaking: true,
383
+ // jsxSideEffects:
384
+ format: "esm",
385
+ platform: "node",
386
+ outfile: codeFile
386
387
  });
387
- const hash = createHash("sha1").update(output.file.code).digest("hex");
388
+ const code = await readFile(codeFile, "utf8");
389
+ const map = await readFile(mapFile, "utf8");
390
+ await rm(codeFile);
391
+ await rm(mapFile);
392
+ const hash = createHash("sha1").update(code).digest("hex");
388
393
  return {
389
394
  handler: "index.default",
390
395
  hash,
391
396
  files: [
392
397
  {
393
- name: "index.js",
394
- code: output.file.code,
395
- map: output.file.map?.toString()
398
+ name: "index.mjs",
399
+ code,
400
+ map
396
401
  }
397
402
  ]
398
403
  };
@@ -400,7 +405,7 @@ var defaultBuild = async (file) => {
400
405
 
401
406
  // src/plugins/function/util/build.ts
402
407
  import JSZip from "jszip";
403
- import { basename, join as join2 } from "path";
408
+ import { basename, join as join3 } from "path";
404
409
  import { mkdir, writeFile } from "fs/promises";
405
410
  import { filesize } from "filesize";
406
411
  var zipFiles = (files) => {
@@ -417,36 +422,36 @@ var zipFiles = (files) => {
417
422
  });
418
423
  };
419
424
  var writeBuildHash = async (config2, stack, id, hash) => {
420
- const funcPath = join2(functionDir, config2.name, stack.artifactId, id);
421
- const versionFile = join2(funcPath, "HASH");
425
+ const funcPath = join3(assetDir, "function", config2.name, stack.artifactId, id);
426
+ const versionFile = join3(funcPath, "HASH");
422
427
  await writeFile(versionFile, hash);
423
428
  };
424
429
  var writeBuildFiles = async (config2, stack, id, files) => {
425
- const bundle2 = await zipFiles(files);
426
- const funcPath = join2(functionDir, config2.name, stack.artifactId, id);
427
- const filesPath = join2(funcPath, "files");
428
- const bundleFile = join2(funcPath, "bundle.zip");
429
- debug("Bundle size of", style.info(join2(config2.name, stack.artifactId, id)), "is", style.attr(filesize(bundle2.byteLength)));
430
+ const bundle = await zipFiles(files);
431
+ const funcPath = join3(assetDir, "function", config2.name, stack.artifactId, id);
432
+ const filesPath = join3(funcPath, "files");
433
+ const bundleFile = join3(funcPath, "bundle.zip");
434
+ debug("Bundle size of", style.info(join3(config2.name, stack.artifactId, id)), "is", style.attr(filesize(bundle.byteLength)));
430
435
  await mkdir(filesPath, { recursive: true });
431
- await writeFile(bundleFile, bundle2);
436
+ await writeFile(bundleFile, bundle);
432
437
  await Promise.all(files.map(async (file) => {
433
- const fileName = join2(filesPath, file.name);
438
+ const fileName = join3(filesPath, file.name);
434
439
  await mkdir(basename(fileName), { recursive: true });
435
440
  await writeFile(fileName, file.code);
436
441
  if (file.map) {
437
- const mapName = join2(filesPath, `${file.name}.map`);
442
+ const mapName = join3(filesPath, `${file.name}.map`);
438
443
  await writeFile(mapName, file.map);
439
444
  }
440
445
  }));
441
446
  return {
442
447
  file: bundleFile,
443
- size: bundle2.byteLength
448
+ size: bundle.byteLength
444
449
  };
445
450
  };
446
451
 
447
452
  // src/plugins/function/util/publish.ts
448
- import { join as join3 } from "path";
449
- import { readFile } from "fs/promises";
453
+ import { join as join4 } from "path";
454
+ import { readFile as readFile2 } from "fs/promises";
450
455
  import { GetObjectCommand, ObjectCannedACL, PutObjectCommand, S3Client, StorageClass } from "@aws-sdk/client-s3";
451
456
 
452
457
  // src/stack/bootstrap.ts
@@ -486,11 +491,11 @@ var shouldDeployBootstrap = async (client, name) => {
486
491
  var publishFunctionAsset = async (config2, stack, id) => {
487
492
  const bucket = assetBucketName(config2);
488
493
  const key = `${config2.name}/${stack.artifactId}/function/${id}.zip`;
489
- const funcPath = join3(functionDir, config2.name, stack.artifactId, id);
490
- const bundleFile = join3(funcPath, "bundle.zip");
491
- const hashFile = join3(funcPath, "HASH");
492
- const hash = await readFile(hashFile, "utf8");
493
- const file = await readFile(bundleFile);
494
+ const funcPath = join4(assetDir, "function", config2.name, stack.artifactId, id);
495
+ const bundleFile = join4(funcPath, "bundle.zip");
496
+ const hashFile = join4(funcPath, "HASH");
497
+ const hash = await readFile2(hashFile, "utf8");
498
+ const file = await readFile2(bundleFile);
494
499
  const client = new S3Client({
495
500
  credentials: config2.credentials,
496
501
  region: config2.region
@@ -576,7 +581,7 @@ var functionPlugin = definePlugin({
576
581
  });
577
582
  }
578
583
  });
579
- var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrProps) => {
584
+ var toFunction = ({ config: config2, stack, assets }, id, fileOrProps) => {
580
585
  const props = typeof fileOrProps === "string" ? { ...config2.defaults?.function, file: fileOrProps } : { ...config2.defaults?.function, ...fileOrProps };
581
586
  const lambda = new Function(stack, toId("function", id), {
582
587
  functionName: toName(stack, id),
@@ -587,24 +592,24 @@ var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrPro
587
592
  });
588
593
  lambda.addEnvironment("APP", config2.name, { removeInEdge: true });
589
594
  lambda.addEnvironment("STAGE", config2.stage, { removeInEdge: true });
590
- lambda.addEnvironment("STACK", stackConfig.name, { removeInEdge: true });
595
+ lambda.addEnvironment("STACK", stack.artifactId, { removeInEdge: true });
591
596
  if (lambda.runtime.toString().startsWith("nodejs")) {
592
597
  lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1", {
593
598
  removeInEdge: true
594
599
  });
595
600
  }
596
601
  assets.add({
597
- stack: stackConfig,
602
+ stackName: stack.artifactId,
598
603
  resource: "function",
599
604
  resourceName: id,
600
605
  async build() {
601
606
  const result = await defaultBuild(props.file);
602
- const bundle2 = await writeBuildFiles(config2, stack, id, result.files);
607
+ const bundle = await writeBuildFiles(config2, stack, id, result.files);
603
608
  await writeBuildHash(config2, stack, id, result.hash);
604
609
  const func = lambda.node.defaultChild;
605
610
  func.handler = result.handler;
606
611
  return {
607
- size: formatByteSize(bundle2.size)
612
+ size: formatByteSize(bundle.size)
608
613
  };
609
614
  },
610
615
  async publish() {
@@ -840,7 +845,6 @@ import { z as z18 } from "zod";
840
845
  import { Topic } from "aws-cdk-lib/aws-sns";
841
846
  import { SnsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
842
847
  import { Arn as Arn2, ArnFormat } from "aws-cdk-lib";
843
- import { PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
844
848
  var topicPlugin = definePlugin({
845
849
  name: "topic",
846
850
  schema: z18.object({
@@ -862,12 +866,6 @@ var topicPlugin = definePlugin({
862
866
  },
863
867
  onStack(ctx) {
864
868
  const { config: config2, stack, stackConfig, bind } = ctx;
865
- bind((lambda) => {
866
- lambda.addToRolePolicy(new PolicyStatement2({
867
- actions: ["sns:publish"],
868
- resources: ["*"]
869
- }));
870
- });
871
869
  return Object.entries(stackConfig.topics || {}).map(([id, props]) => {
872
870
  const lambda = toFunction(ctx, id, props);
873
871
  const topic = Topic.fromTopicArn(
@@ -880,6 +878,10 @@ var topicPlugin = definePlugin({
880
878
  }, stack)
881
879
  );
882
880
  lambda.addEventSource(new SnsEventSource(topic));
881
+ bind((lambda2) => {
882
+ addResourceEnvironment(stack, "topic", id, lambda2);
883
+ topic.grantPublish(lambda2);
884
+ });
883
885
  return lambda;
884
886
  });
885
887
  }
@@ -888,7 +890,7 @@ var topicPlugin = definePlugin({
888
890
  // src/plugins/search.ts
889
891
  import { z as z19 } from "zod";
890
892
  import { CfnCollection } from "aws-cdk-lib/aws-opensearchserverless";
891
- import { PolicyStatement as PolicyStatement3 } from "aws-cdk-lib/aws-iam";
893
+ import { PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
892
894
  var searchPlugin = definePlugin({
893
895
  name: "search",
894
896
  schema: z19.object({
@@ -903,7 +905,7 @@ var searchPlugin = definePlugin({
903
905
  type: "SEARCH"
904
906
  });
905
907
  bind((lambda) => {
906
- lambda.addToRolePolicy(new PolicyStatement3({
908
+ lambda.addToRolePolicy(new PolicyStatement2({
907
909
  actions: ["aoss:APIAccessAll"],
908
910
  resources: [collection.attrArn]
909
911
  }));
@@ -912,6 +914,138 @@ var searchPlugin = definePlugin({
912
914
  }
913
915
  });
914
916
 
917
+ // src/plugins/graphql/index.ts
918
+ import { z as z21 } from "zod";
919
+ import { AuthorizationType, CfnGraphQLApi, CfnGraphQLSchema, GraphqlApi, MappingTemplate } from "aws-cdk-lib/aws-appsync";
920
+ import { mergeTypeDefs } from "@graphql-tools/merge";
921
+ import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
922
+
923
+ // src/util/array.ts
924
+ var toArray = (value) => {
925
+ if (Array.isArray(value)) {
926
+ return value;
927
+ }
928
+ return [value];
929
+ };
930
+
931
+ // src/plugins/graphql/index.ts
932
+ import { dirname, join as join5 } from "path";
933
+ import { print } from "graphql";
934
+ import { paramCase as paramCase2 } from "change-case";
935
+
936
+ // src/plugins/graphql/schema/resolver-field.ts
937
+ import { z as z20 } from "zod";
938
+ var ResolverFieldSchema = z20.custom((value) => {
939
+ return z20.string().regex(/([a-z0-9\_]+)(\s){1}([a-z0-9\_]+)/gi).safeParse(value).success;
940
+ }, `Invalid resolver field. Valid example: "Query list"`);
941
+
942
+ // src/plugins/graphql/index.ts
943
+ import { CfnOutput as CfnOutput2, Fn } from "aws-cdk-lib";
944
+ var graphqlPlugin = definePlugin({
945
+ name: "graphql",
946
+ schema: z21.object({
947
+ defaults: z21.object({
948
+ graphql: z21.record(ResourceIdSchema, z21.object({
949
+ authorization: z21.object({
950
+ authorizer: FunctionSchema,
951
+ ttl: DurationSchema.default("1 hour")
952
+ }).optional(),
953
+ mappingTemplate: z21.object({
954
+ request: LocalFileSchema.optional(),
955
+ response: LocalFileSchema.optional()
956
+ }).optional()
957
+ })).optional()
958
+ }).default({}),
959
+ stacks: z21.object({
960
+ graphql: z21.record(ResourceIdSchema, z21.object({
961
+ schema: z21.union([
962
+ LocalFileSchema,
963
+ z21.array(LocalFileSchema).min(1)
964
+ ]).optional(),
965
+ resolvers: z21.record(ResolverFieldSchema, FunctionSchema).optional()
966
+ })).optional()
967
+ }).array()
968
+ }),
969
+ onBootstrap({ config: config2, stack, assets }) {
970
+ const list3 = /* @__PURE__ */ new Set();
971
+ Object.values(config2.stacks).forEach((stackConfig) => {
972
+ Object.keys(stackConfig.graphql || {}).forEach((id) => {
973
+ list3.add(id);
974
+ });
975
+ });
976
+ list3.forEach((id) => {
977
+ const file = join5(assetDir, "graphql", config2.name, id, "schema.graphql");
978
+ const authorization = config2.defaults.graphql?.[id]?.authorization;
979
+ const authProps = {};
980
+ if (authorization) {
981
+ const authorizer = toFunction({ config: config2, assets, stack }, `${id}-authorizer`, authorization.authorizer);
982
+ authProps.additionalAuthenticationProviders = [{
983
+ authenticationType: AuthorizationType.LAMBDA,
984
+ lambdaAuthorizerConfig: {
985
+ authorizerUri: authorizer.functionArn,
986
+ authorizerResultTtlInSeconds: authorization.ttl.toSeconds()
987
+ }
988
+ }];
989
+ }
990
+ const api = new CfnGraphQLApi(stack, toId("graphql", id), {
991
+ ...authProps,
992
+ name: toName(stack, id),
993
+ authenticationType: AuthorizationType.API_KEY
994
+ });
995
+ new CfnOutput2(stack, toId("output", id), {
996
+ exportName: toId("graphql", id),
997
+ value: api.attrApiId
998
+ });
999
+ assets.add({
1000
+ stackName: stack.artifactId,
1001
+ resource: "schema",
1002
+ resourceName: id,
1003
+ async build() {
1004
+ const schemas = [];
1005
+ await Promise.all(Object.values(config2.stacks).map(async (stackConfig) => {
1006
+ const schemaFiles = toArray(stackConfig.graphql?.[id].schema || []);
1007
+ await Promise.all(schemaFiles.map(async (schemaFile) => {
1008
+ const schema3 = await readFile3(schemaFile, "utf8");
1009
+ schemas.push(schema3);
1010
+ }));
1011
+ }));
1012
+ const schema2 = print(mergeTypeDefs(schemas));
1013
+ await mkdir2(dirname(file), { recursive: true });
1014
+ await writeFile2(file, schema2);
1015
+ new CfnGraphQLSchema(stack, toId("schema", id), {
1016
+ apiId: api.attrApiId,
1017
+ definition: schema2
1018
+ });
1019
+ }
1020
+ });
1021
+ });
1022
+ },
1023
+ onStack(ctx) {
1024
+ const { config: config2, stack, stackConfig } = ctx;
1025
+ return Object.entries(stackConfig.graphql || {}).map(([id, props]) => {
1026
+ const defaults = config2.defaults.graphql?.[id] || {};
1027
+ return Object.entries(props.resolvers || {}).map(([typeAndField, functionProps]) => {
1028
+ const api = GraphqlApi.fromGraphqlApiAttributes(stack, toId("graphql", id), {
1029
+ graphqlApiId: Fn.importValue(toId("graphql", id))
1030
+ });
1031
+ const [typeName, fieldName] = typeAndField.split(/[\s]+/g);
1032
+ const functionId = paramCase2(`${id}-${typeName}-${fieldName}`);
1033
+ const lambda = toFunction(ctx, functionId, functionProps);
1034
+ const source = api.addLambdaDataSource(toId("data-source", functionId), lambda, {
1035
+ name: toId("data-source", functionId)
1036
+ });
1037
+ source.createResolver(toId("resolver", functionId), {
1038
+ typeName,
1039
+ fieldName,
1040
+ requestMappingTemplate: defaults.mappingTemplate?.request ? MappingTemplate.fromFile(defaults.mappingTemplate.request) : MappingTemplate.lambdaRequest(),
1041
+ responseMappingTemplate: defaults.mappingTemplate?.response ? MappingTemplate.fromFile(defaults.mappingTemplate.response) : MappingTemplate.lambdaResult()
1042
+ });
1043
+ return lambda;
1044
+ });
1045
+ }).flat();
1046
+ }
1047
+ });
1048
+
915
1049
  // src/plugins/index.ts
916
1050
  var defaultPlugins = [
917
1051
  functionPlugin,
@@ -920,7 +1054,8 @@ var defaultPlugins = [
920
1054
  tablePlugin,
921
1055
  storePlugin,
922
1056
  topicPlugin,
923
- searchPlugin
1057
+ searchPlugin,
1058
+ graphqlPlugin
924
1059
  ];
925
1060
 
926
1061
  // src/stack/app-bootstrap.ts
@@ -933,8 +1068,16 @@ var appBootstrapStack = ({ config: config2, app, assets }) => {
933
1068
  ...config2.plugins || []
934
1069
  ];
935
1070
  debug("Run plugin onBootstrap listeners");
936
- plugins.forEach((plugin) => plugin.onBootstrap?.({ config: config2, stack, app, assets }));
937
- return stack;
1071
+ const functions = plugins.map((plugin) => plugin.onBootstrap?.({
1072
+ config: config2,
1073
+ app,
1074
+ stack,
1075
+ assets
1076
+ })).filter(Boolean).flat().filter(Boolean);
1077
+ return {
1078
+ stack,
1079
+ functions
1080
+ };
938
1081
  };
939
1082
 
940
1083
  // src/util/deployment.ts
@@ -1000,10 +1143,10 @@ var Assets = class {
1000
1143
  assets = {};
1001
1144
  id = 0;
1002
1145
  add(opts) {
1003
- if (!this.assets[opts.stack.name]) {
1004
- this.assets[opts.stack.name] = [];
1146
+ if (!this.assets[opts.stackName]) {
1147
+ this.assets[opts.stackName] = [];
1005
1148
  }
1006
- this.assets[opts.stack.name].push({
1149
+ this.assets[opts.stackName].push({
1007
1150
  ...opts,
1008
1151
  id: this.id++
1009
1152
  });
@@ -1013,12 +1156,12 @@ var Assets = class {
1013
1156
  }
1014
1157
  forEach(cb) {
1015
1158
  Object.values(this.assets).forEach((assets) => {
1016
- cb(assets[0].stack, assets);
1159
+ cb(assets[0].stackName, assets);
1017
1160
  });
1018
1161
  }
1019
1162
  map(cb) {
1020
1163
  return Object.values(this.assets).map((assets) => {
1021
- return cb(assets[0].stack, assets);
1164
+ return cb(assets[0].stackName, assets);
1022
1165
  });
1023
1166
  }
1024
1167
  };
@@ -1056,13 +1199,14 @@ var toApp = async (config2, filters) => {
1056
1199
  debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
1057
1200
  debug("Run plugin onApp listeners");
1058
1201
  plugins.forEach((plugin) => plugin.onApp?.({ config: config2, app, assets }));
1202
+ const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1059
1203
  debug("Stack filters:", filters.map((filter) => style.info(filter)).join(", "));
1060
1204
  const filterdStacks = filters.length === 0 ? config2.stacks : getAllDepends(
1061
1205
  // config.stacks,
1062
1206
  config2.stacks.filter((stack) => filters.includes(stack.name))
1063
1207
  );
1064
1208
  for (const stackConfig of filterdStacks) {
1065
- const { stack } = toStack({
1209
+ const { stack, bindings } = toStack({
1066
1210
  config: config2,
1067
1211
  stackConfig,
1068
1212
  assets,
@@ -1070,14 +1214,14 @@ var toApp = async (config2, filters) => {
1070
1214
  app
1071
1215
  });
1072
1216
  stacks.push({ stack, config: stackConfig });
1217
+ bindings.forEach((cb) => bootstrap2.functions.forEach(cb));
1073
1218
  }
1074
1219
  let dependencyTree;
1075
- const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1076
- if (bootstrap2.node.children.length === 0) {
1220
+ if (bootstrap2.stack.node.children.length === 0) {
1077
1221
  dependencyTree = createDependencyTree(stacks, 0);
1078
1222
  } else {
1079
1223
  dependencyTree = [{
1080
- stack: bootstrap2,
1224
+ stack: bootstrap2.stack,
1081
1225
  level: 0,
1082
1226
  children: createDependencyTree(stacks, 1)
1083
1227
  }];
@@ -1149,7 +1293,7 @@ var footer = () => {
1149
1293
  };
1150
1294
 
1151
1295
  // src/config.ts
1152
- import { join as join5 } from "path";
1296
+ import { join as join7 } from "path";
1153
1297
 
1154
1298
  // src/util/account.ts
1155
1299
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -1168,17 +1312,17 @@ var getCredentials = (profile) => {
1168
1312
  };
1169
1313
 
1170
1314
  // src/schema/app.ts
1171
- import { z as z23 } from "zod";
1315
+ import { z as z25 } from "zod";
1172
1316
 
1173
1317
  // src/schema/stack.ts
1174
- import { z as z20 } from "zod";
1175
- var StackSchema = z20.object({
1318
+ import { z as z22 } from "zod";
1319
+ var StackSchema = z22.object({
1176
1320
  name: ResourceIdSchema,
1177
- depends: z20.array(z20.lazy(() => StackSchema)).optional()
1321
+ depends: z22.array(z22.lazy(() => StackSchema)).optional()
1178
1322
  });
1179
1323
 
1180
1324
  // src/schema/region.ts
1181
- import { z as z21 } from "zod";
1325
+ import { z as z23 } from "zod";
1182
1326
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1183
1327
  var AF = ["af-south-1"];
1184
1328
  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"];
@@ -1195,35 +1339,35 @@ var regions = [
1195
1339
  ...ME,
1196
1340
  ...SA
1197
1341
  ];
1198
- var RegionSchema = z21.enum(regions);
1342
+ var RegionSchema = z23.enum(regions);
1199
1343
 
1200
1344
  // src/schema/plugin.ts
1201
- import { z as z22 } from "zod";
1202
- var PluginSchema = z22.object({
1203
- name: z22.string(),
1204
- schema: z22.custom().optional(),
1205
- depends: z22.array(z22.lazy(() => PluginSchema)).optional(),
1206
- onBootstrap: z22.function().optional(),
1207
- onStack: z22.function().returns(z22.any()).optional(),
1208
- onApp: z22.function().optional()
1345
+ import { z as z24 } from "zod";
1346
+ var PluginSchema = z24.object({
1347
+ name: z24.string(),
1348
+ schema: z24.custom().optional(),
1349
+ // depends: z.array(z.lazy(() => PluginSchema)).optional(),
1350
+ onBootstrap: z24.function().returns(z24.any()).optional(),
1351
+ onStack: z24.function().returns(z24.any()).optional(),
1352
+ onApp: z24.function().returns(z24.void()).optional()
1209
1353
  // bind: z.function().optional(),
1210
1354
  });
1211
1355
 
1212
1356
  // src/schema/app.ts
1213
- var AppSchema = z23.object({
1357
+ var AppSchema = z25.object({
1214
1358
  name: ResourceIdSchema,
1215
1359
  region: RegionSchema,
1216
- profile: z23.string(),
1217
- stage: z23.string().regex(/[a-z]+/).default("prod"),
1218
- defaults: z23.object({}).default({}),
1219
- stacks: z23.array(StackSchema).min(1),
1220
- plugins: z23.array(PluginSchema).optional()
1360
+ profile: z25.string(),
1361
+ stage: z25.string().regex(/[a-z]+/).default("prod"),
1362
+ defaults: z25.object({}).default({}),
1363
+ stacks: z25.array(StackSchema).min(1),
1364
+ plugins: z25.array(PluginSchema).optional()
1221
1365
  });
1222
1366
 
1223
1367
  // src/util/import.ts
1224
1368
  import { transformFile } from "@swc/core";
1225
- import { dirname, join as join4 } from "path";
1226
- import { lstat, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
1369
+ import { dirname as dirname2, join as join6 } from "path";
1370
+ import { lstat, mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1227
1371
  var resolveFileNameExtension = async (path) => {
1228
1372
  const options = [
1229
1373
  "",
@@ -1247,14 +1391,14 @@ var resolveFileNameExtension = async (path) => {
1247
1391
  throw new Error(`Failed to load file: ${path}`);
1248
1392
  };
1249
1393
  var resolveDir = (path) => {
1250
- return dirname(path).replace(rootDir + "/", "");
1394
+ return dirname2(path).replace(rootDir + "/", "");
1251
1395
  };
1252
1396
  var importFile = async (path) => {
1253
1397
  const load = async (file) => {
1254
1398
  let { code: code2 } = await transformFile(file, {
1255
1399
  isModule: true
1256
1400
  });
1257
- const path2 = dirname(file);
1401
+ const path2 = dirname2(file);
1258
1402
  const dir = resolveDir(file);
1259
1403
  code2 = code2.replaceAll("__dirname", `"${dir}"`);
1260
1404
  const matches = code2.match(/import\s*{\s*[a-z0-9\_]+\s*}\s*from\s*('|")(\.[\/a-z0-9\_\-]+)('|");?/ig);
@@ -1263,23 +1407,23 @@ var importFile = async (path) => {
1263
1407
  await Promise.all(matches?.map(async (match) => {
1264
1408
  const parts = /('|")(\.[\/a-z0-9\_\-]+)('|")/ig.exec(match);
1265
1409
  const from = parts[2];
1266
- const file2 = await resolveFileNameExtension(join4(path2, from));
1410
+ const file2 = await resolveFileNameExtension(join6(path2, from));
1267
1411
  const result = await load(file2);
1268
1412
  code2 = code2.replace(match, result);
1269
1413
  }));
1270
1414
  return code2;
1271
1415
  };
1272
1416
  const code = await load(path);
1273
- const outputFile = join4(outDir, "config.js");
1274
- await mkdir2(outDir, { recursive: true });
1275
- await writeFile2(outputFile, code);
1417
+ const outputFile = join6(outDir, "config.js");
1418
+ await mkdir3(outDir, { recursive: true });
1419
+ await writeFile3(outputFile, code);
1276
1420
  return import(outputFile);
1277
1421
  };
1278
1422
 
1279
1423
  // src/config.ts
1280
1424
  var importConfig = async (options) => {
1281
1425
  debug("Import config file");
1282
- const fileName = join5(process.cwd(), options.configFile || "awsless.config.ts");
1426
+ const fileName = join7(process.cwd(), options.configFile || "awsless.config.ts");
1283
1427
  const module = await importFile(fileName);
1284
1428
  const appConfig = typeof module.default === "function" ? await module.default({
1285
1429
  profile: options.profile,
@@ -1493,6 +1637,13 @@ var Interface = class {
1493
1637
  if (this.input.isTTY) {
1494
1638
  this.input.setRawMode(true);
1495
1639
  }
1640
+ this.input.on("keypress", (_, key) => {
1641
+ const action = parseAction(key);
1642
+ if (action === "abort") {
1643
+ this.unref();
1644
+ process.exit(1);
1645
+ }
1646
+ });
1496
1647
  }
1497
1648
  // private subscriber: Actions | undefined
1498
1649
  readline;
@@ -1642,12 +1793,6 @@ var layout = async (cb) => {
1642
1793
  const term = createTerminal();
1643
1794
  term.out.clear();
1644
1795
  term.out.write(logo());
1645
- term.in.captureInput({
1646
- abort: () => {
1647
- term.in.showCursor();
1648
- process.exit(1);
1649
- }
1650
- });
1651
1796
  try {
1652
1797
  const options = program.optsWithGlobals();
1653
1798
  const config2 = await importConfig(options);
@@ -1668,7 +1813,7 @@ var layout = async (cb) => {
1668
1813
  term.in.unref();
1669
1814
  setTimeout(() => {
1670
1815
  process.exit(0);
1671
- }, 50);
1816
+ }, 100);
1672
1817
  }
1673
1818
  };
1674
1819
 
@@ -1699,7 +1844,8 @@ var assetBuilder = (assets) => {
1699
1844
  const groups = new Signal([br()]);
1700
1845
  term.out.write(groups);
1701
1846
  const stackNameSize = Math.max(...Object.keys(assets.list()).map((stack) => stack.length));
1702
- await Promise.all(assets.map(async (stack, assets2) => {
1847
+ const resourceSize = Math.max(...Object.values(assets.list()).map((assets2) => assets2.map((asset) => asset.resource.length)).flat());
1848
+ await Promise.all(assets.map(async (stackName, assets2) => {
1703
1849
  const group = new Signal([]);
1704
1850
  groups.update((groups2) => [...groups2, group]);
1705
1851
  await Promise.all(assets2.map(async (asset) => {
@@ -1708,12 +1854,13 @@ var assetBuilder = (assets) => {
1708
1854
  const line = flexLine(term, [
1709
1855
  icon,
1710
1856
  " ",
1711
- style.label(stack.name),
1712
- " ".repeat(stackNameSize - stack.name.length),
1857
+ style.label(stackName),
1858
+ " ".repeat(stackNameSize - stackName.length),
1713
1859
  " ",
1714
1860
  style.placeholder(symbol.pointerSmall),
1715
1861
  " ",
1716
1862
  style.warning(asset.resource),
1863
+ " ".repeat(resourceSize - asset.resource.length),
1717
1864
  " ",
1718
1865
  style.placeholder(symbol.pointerSmall),
1719
1866
  " ",
@@ -1744,25 +1891,26 @@ var assetBuilder = (assets) => {
1744
1891
  };
1745
1892
 
1746
1893
  // src/util/cleanup.ts
1747
- import { mkdir as mkdir3, rm } from "fs/promises";
1894
+ import { mkdir as mkdir4, rm as rm2 } from "fs/promises";
1748
1895
  var cleanUp = async () => {
1749
1896
  debug("Clean up assembly & asset files");
1750
1897
  const paths = [
1751
1898
  assemblyDir,
1752
- functionDir
1899
+ assetDir,
1900
+ cacheDir
1753
1901
  ];
1754
- await Promise.all(paths.map((path) => rm(path, {
1902
+ await Promise.all(paths.map((path) => rm2(path, {
1755
1903
  recursive: true,
1756
1904
  force: true,
1757
1905
  maxRetries: 2
1758
1906
  })));
1759
- await Promise.all(paths.map((path) => mkdir3(path, {
1907
+ await Promise.all(paths.map((path) => mkdir4(path, {
1760
1908
  recursive: true
1761
1909
  })));
1762
1910
  };
1763
1911
 
1764
1912
  // src/cli/command/build.ts
1765
- var build = (program2) => {
1913
+ var build2 = (program2) => {
1766
1914
  program2.command("build").argument("[stack...]", "Optionally filter stacks to build").description("Build your app").action(async (filters) => {
1767
1915
  await layout(async (config2, write) => {
1768
1916
  const { app, assets } = await toApp(config2, filters);
@@ -1880,7 +2028,7 @@ var StackClient = class {
1880
2028
  stack.Outputs?.forEach((output) => {
1881
2029
  outputs[output.OutputKey] = output.OutputValue;
1882
2030
  });
1883
- debug("Status for: ", style.info(name), "is", stack.StackStatus);
2031
+ debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
1884
2032
  return {
1885
2033
  status: stack.StackStatus,
1886
2034
  reason: stack.StackStatusReason,
@@ -2146,6 +2294,7 @@ var deploy = (program2) => {
2146
2294
  await cleanUp();
2147
2295
  await write(assetBuilder(assets));
2148
2296
  write(br());
2297
+ write(br());
2149
2298
  const donePublishing = write(loadingDialog("Publishing stack assets to AWS..."));
2150
2299
  await Promise.all(assets.map(async (_, assets2) => {
2151
2300
  await Promise.all(assets2.map(async (asset) => {
@@ -2161,21 +2310,28 @@ var deploy = (program2) => {
2161
2310
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
2162
2311
  write(br());
2163
2312
  write(stackTree(dependencyTree, statuses));
2313
+ write(br());
2164
2314
  const client = new StackClient(config2);
2165
2315
  const deploymentLine = createDeploymentLine(dependencyTree);
2166
2316
  for (const stacks of deploymentLine) {
2167
- await Promise.allSettled(stacks.map(async (stack) => {
2317
+ const results = await Promise.allSettled(stacks.map(async (stack) => {
2318
+ const signal = statuses[stack.artifactId];
2168
2319
  const stackArtifect = assembly.stacks.find((item) => item.id === stack.artifactId);
2169
- statuses[stack.artifactId].set(style.warning("deploying"));
2320
+ signal.set(style.warning("deploying"));
2170
2321
  try {
2171
2322
  await client.deploy(stackArtifect);
2172
2323
  } catch (error) {
2173
2324
  debugError(error);
2174
- statuses[stack.artifactId].set(style.error("failed"));
2325
+ signal.set(style.error("failed"));
2175
2326
  throw error;
2176
2327
  }
2177
- statuses[stack.artifactId].set(style.success("deployed"));
2328
+ signal.set(style.success("deployed"));
2178
2329
  }));
2330
+ for (const result of results) {
2331
+ if (result.status === "rejected") {
2332
+ throw result.reason;
2333
+ }
2334
+ }
2179
2335
  }
2180
2336
  doneDeploying("Done deploying stacks to AWS");
2181
2337
  });
@@ -2350,7 +2506,7 @@ program.on("option:verbose", () => {
2350
2506
  var commands2 = [
2351
2507
  bootstrap,
2352
2508
  status,
2353
- build,
2509
+ build2,
2354
2510
  deploy,
2355
2511
  config
2356
2512
  // diff,