@awsless/awsless 0.0.8 → 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
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- __require,
4
3
  definePlugin
5
- } from "./chunk-6KILQ5DR.js";
4
+ } from "./chunk-PFTL6L4F.js";
6
5
 
7
6
  // src/cli/program.ts
8
7
  import { Command } from "commander";
@@ -196,6 +195,8 @@ var toStack = ({ config: config2, assets, app, stackConfig, plugins }) => {
196
195
  functions.forEach((lambda) => lambda.addToRolePolicy(allowConfigParameters));
197
196
  return {
198
197
  stack,
198
+ functions,
199
+ bindings,
199
200
  depends: stackConfig.depends
200
201
  };
201
202
  };
@@ -205,7 +206,8 @@ import { join } from "path";
205
206
  var rootDir = process.cwd();
206
207
  var outDir = join(rootDir, ".awsless");
207
208
  var assemblyDir = join(outDir, "assembly");
208
- var functionDir = join(outDir, "function");
209
+ var assetDir = join(outDir, "asset");
210
+ var cacheDir = join(outDir, "cache");
209
211
 
210
212
  // src/stack/app-bootstrap.ts
211
213
  import { Stack as Stack3 } from "aws-cdk-lib";
@@ -250,7 +252,7 @@ var ScheduleExpressionSchema = RateExpressionSchema.or(CronExpressionSchema);
250
252
  import { Rule } from "aws-cdk-lib/aws-events";
251
253
 
252
254
  // src/util/resource.ts
253
- import { constantCase, paramCase, pascalCase } from "change-case";
255
+ import { paramCase, pascalCase } from "change-case";
254
256
  var toId = (resource, id) => {
255
257
  return pascalCase(`${resource}-${id}`);
256
258
  };
@@ -258,7 +260,7 @@ var toName = (stack, id) => {
258
260
  return paramCase(`${stack.stackName}-${id}`);
259
261
  };
260
262
  var toEnvKey = (resource, id) => {
261
- return constantCase(`RESOURCE_${resource}_${id}`);
263
+ return `RESOURCE_${resource.toUpperCase()}_${id}`;
262
264
  };
263
265
  var addResourceEnvironment = (stack, resource, id, lambda) => {
264
266
  const key = toEnvKey(resource, id);
@@ -357,75 +359,53 @@ var SizeSchema = z7.custom((value) => {
357
359
  return z7.string().regex(/[0-9]+ (KB|MB|GB)/).safeParse(value).success;
358
360
  }, "Invalid size").transform(toSize);
359
361
 
360
- // src/plugins/function/util/build-worker.ts
361
- import { Worker } from "worker_threads";
362
- var cjs = typeof __require !== "undefined";
363
- var importESM = `
364
- import { bundle } from "@awsless/code";
365
- import { createHash } from "crypto";
366
- import { parentPort, workerData } from "worker_threads";
367
- `;
368
- var importCJS = `
369
- const { bundle } = require("@awsless/code");
370
- const { createHash } = require("crypto");
371
- const { parentPort, workerData } = require("worker_threads");
372
- `;
373
- var workerCode = `
374
- ${cjs ? importCJS : importESM}
375
-
376
- const build = async (file) => {
377
- const { code, map } = await bundle(file, {
378
- format: 'esm',
379
- sourceMap: true,
380
- minimize: true,
381
- onwarn: () => {},
382
- moduleSideEffects: (id) => file === id,
383
- external: (importee) => (
384
- importee.startsWith('aws-sdk') ||
385
- importee.startsWith('@aws-sdk')
386
- ),
387
- })
388
-
389
- const hash = createHash('sha1').update(code).digest('hex')
390
-
391
- parentPort.postMessage(JSON.stringify({
392
- handler: 'index.default',
393
- hash,
394
- files: [
395
- { name: 'index.js', code, map: map?.toString() }
396
- ]
397
- }))
398
- }
399
-
400
- build(workerData)
401
- `;
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";
402
367
  var defaultBuild = async (file) => {
403
- return new Promise((resolve, reject) => {
404
- const worker = new Worker(workerCode, { workerData: file, eval: true });
405
- const cleanUp2 = () => {
406
- worker.removeAllListeners();
407
- worker.terminate();
408
- };
409
- worker.on("message", (data) => {
410
- resolve(JSON.parse(data.toString("utf8")));
411
- cleanUp2();
412
- });
413
- worker.on("error", (data) => {
414
- reject(data);
415
- cleanUp2();
416
- });
417
- worker.on("exit", (code) => {
418
- if (code !== 0) {
419
- reject(new Error(`Worker exited with code ${code}`));
420
- cleanUp2();
421
- }
422
- });
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: [
376
+ "@aws-sdk/*",
377
+ "@aws-sdk",
378
+ "aws-sdk"
379
+ ],
380
+ sourcemap: "external",
381
+ target: "esnext",
382
+ treeShaking: true,
383
+ // jsxSideEffects:
384
+ format: "esm",
385
+ platform: "node",
386
+ outfile: codeFile
423
387
  });
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");
393
+ return {
394
+ handler: "index.default",
395
+ hash,
396
+ files: [
397
+ {
398
+ name: "index.mjs",
399
+ code,
400
+ map
401
+ }
402
+ ]
403
+ };
424
404
  };
425
405
 
426
406
  // src/plugins/function/util/build.ts
427
407
  import JSZip from "jszip";
428
- import { basename, join as join2 } from "path";
408
+ import { basename, join as join3 } from "path";
429
409
  import { mkdir, writeFile } from "fs/promises";
430
410
  import { filesize } from "filesize";
431
411
  var zipFiles = (files) => {
@@ -442,24 +422,24 @@ var zipFiles = (files) => {
442
422
  });
443
423
  };
444
424
  var writeBuildHash = async (config2, stack, id, hash) => {
445
- const funcPath = join2(functionDir, config2.name, stack.artifactId, id);
446
- const versionFile = join2(funcPath, "HASH");
425
+ const funcPath = join3(assetDir, "function", config2.name, stack.artifactId, id);
426
+ const versionFile = join3(funcPath, "HASH");
447
427
  await writeFile(versionFile, hash);
448
428
  };
449
429
  var writeBuildFiles = async (config2, stack, id, files) => {
450
430
  const bundle = await zipFiles(files);
451
- const funcPath = join2(functionDir, config2.name, stack.artifactId, id);
452
- const filesPath = join2(funcPath, "files");
453
- const bundleFile = join2(funcPath, "bundle.zip");
454
- debug("Bundle size of", style.info(join2(config2.name, stack.artifactId, id)), "is", style.attr(filesize(bundle.byteLength)));
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)));
455
435
  await mkdir(filesPath, { recursive: true });
456
436
  await writeFile(bundleFile, bundle);
457
437
  await Promise.all(files.map(async (file) => {
458
- const fileName = join2(filesPath, file.name);
438
+ const fileName = join3(filesPath, file.name);
459
439
  await mkdir(basename(fileName), { recursive: true });
460
440
  await writeFile(fileName, file.code);
461
441
  if (file.map) {
462
- const mapName = join2(filesPath, `${file.name}.map`);
442
+ const mapName = join3(filesPath, `${file.name}.map`);
463
443
  await writeFile(mapName, file.map);
464
444
  }
465
445
  }));
@@ -470,8 +450,8 @@ var writeBuildFiles = async (config2, stack, id, files) => {
470
450
  };
471
451
 
472
452
  // src/plugins/function/util/publish.ts
473
- import { join as join3 } from "path";
474
- import { readFile } from "fs/promises";
453
+ import { join as join4 } from "path";
454
+ import { readFile as readFile2 } from "fs/promises";
475
455
  import { GetObjectCommand, ObjectCannedACL, PutObjectCommand, S3Client, StorageClass } from "@aws-sdk/client-s3";
476
456
 
477
457
  // src/stack/bootstrap.ts
@@ -511,11 +491,11 @@ var shouldDeployBootstrap = async (client, name) => {
511
491
  var publishFunctionAsset = async (config2, stack, id) => {
512
492
  const bucket = assetBucketName(config2);
513
493
  const key = `${config2.name}/${stack.artifactId}/function/${id}.zip`;
514
- const funcPath = join3(functionDir, config2.name, stack.artifactId, id);
515
- const bundleFile = join3(funcPath, "bundle.zip");
516
- const hashFile = join3(funcPath, "HASH");
517
- const hash = await readFile(hashFile, "utf8");
518
- 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);
519
499
  const client = new S3Client({
520
500
  credentials: config2.credentials,
521
501
  region: config2.region
@@ -601,7 +581,7 @@ var functionPlugin = definePlugin({
601
581
  });
602
582
  }
603
583
  });
604
- var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrProps) => {
584
+ var toFunction = ({ config: config2, stack, assets }, id, fileOrProps) => {
605
585
  const props = typeof fileOrProps === "string" ? { ...config2.defaults?.function, file: fileOrProps } : { ...config2.defaults?.function, ...fileOrProps };
606
586
  const lambda = new Function(stack, toId("function", id), {
607
587
  functionName: toName(stack, id),
@@ -612,14 +592,14 @@ var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrPro
612
592
  });
613
593
  lambda.addEnvironment("APP", config2.name, { removeInEdge: true });
614
594
  lambda.addEnvironment("STAGE", config2.stage, { removeInEdge: true });
615
- lambda.addEnvironment("STACK", stackConfig.name, { removeInEdge: true });
595
+ lambda.addEnvironment("STACK", stack.artifactId, { removeInEdge: true });
616
596
  if (lambda.runtime.toString().startsWith("nodejs")) {
617
597
  lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1", {
618
598
  removeInEdge: true
619
599
  });
620
600
  }
621
601
  assets.add({
622
- stack: stackConfig,
602
+ stackName: stack.artifactId,
623
603
  resource: "function",
624
604
  resourceName: id,
625
605
  async build() {
@@ -865,7 +845,6 @@ import { z as z18 } from "zod";
865
845
  import { Topic } from "aws-cdk-lib/aws-sns";
866
846
  import { SnsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
867
847
  import { Arn as Arn2, ArnFormat } from "aws-cdk-lib";
868
- import { PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
869
848
  var topicPlugin = definePlugin({
870
849
  name: "topic",
871
850
  schema: z18.object({
@@ -887,12 +866,6 @@ var topicPlugin = definePlugin({
887
866
  },
888
867
  onStack(ctx) {
889
868
  const { config: config2, stack, stackConfig, bind } = ctx;
890
- bind((lambda) => {
891
- lambda.addToRolePolicy(new PolicyStatement2({
892
- actions: ["sns:publish"],
893
- resources: ["*"]
894
- }));
895
- });
896
869
  return Object.entries(stackConfig.topics || {}).map(([id, props]) => {
897
870
  const lambda = toFunction(ctx, id, props);
898
871
  const topic = Topic.fromTopicArn(
@@ -905,6 +878,10 @@ var topicPlugin = definePlugin({
905
878
  }, stack)
906
879
  );
907
880
  lambda.addEventSource(new SnsEventSource(topic));
881
+ bind((lambda2) => {
882
+ addResourceEnvironment(stack, "topic", id, lambda2);
883
+ topic.grantPublish(lambda2);
884
+ });
908
885
  return lambda;
909
886
  });
910
887
  }
@@ -913,7 +890,7 @@ var topicPlugin = definePlugin({
913
890
  // src/plugins/search.ts
914
891
  import { z as z19 } from "zod";
915
892
  import { CfnCollection } from "aws-cdk-lib/aws-opensearchserverless";
916
- import { PolicyStatement as PolicyStatement3 } from "aws-cdk-lib/aws-iam";
893
+ import { PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
917
894
  var searchPlugin = definePlugin({
918
895
  name: "search",
919
896
  schema: z19.object({
@@ -928,7 +905,7 @@ var searchPlugin = definePlugin({
928
905
  type: "SEARCH"
929
906
  });
930
907
  bind((lambda) => {
931
- lambda.addToRolePolicy(new PolicyStatement3({
908
+ lambda.addToRolePolicy(new PolicyStatement2({
932
909
  actions: ["aoss:APIAccessAll"],
933
910
  resources: [collection.attrArn]
934
911
  }));
@@ -937,6 +914,138 @@ var searchPlugin = definePlugin({
937
914
  }
938
915
  });
939
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
+
940
1049
  // src/plugins/index.ts
941
1050
  var defaultPlugins = [
942
1051
  functionPlugin,
@@ -945,7 +1054,8 @@ var defaultPlugins = [
945
1054
  tablePlugin,
946
1055
  storePlugin,
947
1056
  topicPlugin,
948
- searchPlugin
1057
+ searchPlugin,
1058
+ graphqlPlugin
949
1059
  ];
950
1060
 
951
1061
  // src/stack/app-bootstrap.ts
@@ -958,8 +1068,16 @@ var appBootstrapStack = ({ config: config2, app, assets }) => {
958
1068
  ...config2.plugins || []
959
1069
  ];
960
1070
  debug("Run plugin onBootstrap listeners");
961
- plugins.forEach((plugin) => plugin.onBootstrap?.({ config: config2, stack, app, assets }));
962
- 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
+ };
963
1081
  };
964
1082
 
965
1083
  // src/util/deployment.ts
@@ -1025,10 +1143,10 @@ var Assets = class {
1025
1143
  assets = {};
1026
1144
  id = 0;
1027
1145
  add(opts) {
1028
- if (!this.assets[opts.stack.name]) {
1029
- this.assets[opts.stack.name] = [];
1146
+ if (!this.assets[opts.stackName]) {
1147
+ this.assets[opts.stackName] = [];
1030
1148
  }
1031
- this.assets[opts.stack.name].push({
1149
+ this.assets[opts.stackName].push({
1032
1150
  ...opts,
1033
1151
  id: this.id++
1034
1152
  });
@@ -1038,12 +1156,12 @@ var Assets = class {
1038
1156
  }
1039
1157
  forEach(cb) {
1040
1158
  Object.values(this.assets).forEach((assets) => {
1041
- cb(assets[0].stack, assets);
1159
+ cb(assets[0].stackName, assets);
1042
1160
  });
1043
1161
  }
1044
1162
  map(cb) {
1045
1163
  return Object.values(this.assets).map((assets) => {
1046
- return cb(assets[0].stack, assets);
1164
+ return cb(assets[0].stackName, assets);
1047
1165
  });
1048
1166
  }
1049
1167
  };
@@ -1081,13 +1199,14 @@ var toApp = async (config2, filters) => {
1081
1199
  debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
1082
1200
  debug("Run plugin onApp listeners");
1083
1201
  plugins.forEach((plugin) => plugin.onApp?.({ config: config2, app, assets }));
1202
+ const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1084
1203
  debug("Stack filters:", filters.map((filter) => style.info(filter)).join(", "));
1085
1204
  const filterdStacks = filters.length === 0 ? config2.stacks : getAllDepends(
1086
1205
  // config.stacks,
1087
1206
  config2.stacks.filter((stack) => filters.includes(stack.name))
1088
1207
  );
1089
1208
  for (const stackConfig of filterdStacks) {
1090
- const { stack } = toStack({
1209
+ const { stack, bindings } = toStack({
1091
1210
  config: config2,
1092
1211
  stackConfig,
1093
1212
  assets,
@@ -1095,14 +1214,14 @@ var toApp = async (config2, filters) => {
1095
1214
  app
1096
1215
  });
1097
1216
  stacks.push({ stack, config: stackConfig });
1217
+ bindings.forEach((cb) => bootstrap2.functions.forEach(cb));
1098
1218
  }
1099
1219
  let dependencyTree;
1100
- const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1101
- if (bootstrap2.node.children.length === 0) {
1220
+ if (bootstrap2.stack.node.children.length === 0) {
1102
1221
  dependencyTree = createDependencyTree(stacks, 0);
1103
1222
  } else {
1104
1223
  dependencyTree = [{
1105
- stack: bootstrap2,
1224
+ stack: bootstrap2.stack,
1106
1225
  level: 0,
1107
1226
  children: createDependencyTree(stacks, 1)
1108
1227
  }];
@@ -1174,7 +1293,7 @@ var footer = () => {
1174
1293
  };
1175
1294
 
1176
1295
  // src/config.ts
1177
- import { join as join5 } from "path";
1296
+ import { join as join7 } from "path";
1178
1297
 
1179
1298
  // src/util/account.ts
1180
1299
  import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
@@ -1193,17 +1312,17 @@ var getCredentials = (profile) => {
1193
1312
  };
1194
1313
 
1195
1314
  // src/schema/app.ts
1196
- import { z as z23 } from "zod";
1315
+ import { z as z25 } from "zod";
1197
1316
 
1198
1317
  // src/schema/stack.ts
1199
- import { z as z20 } from "zod";
1200
- var StackSchema = z20.object({
1318
+ import { z as z22 } from "zod";
1319
+ var StackSchema = z22.object({
1201
1320
  name: ResourceIdSchema,
1202
- depends: z20.array(z20.lazy(() => StackSchema)).optional()
1321
+ depends: z22.array(z22.lazy(() => StackSchema)).optional()
1203
1322
  });
1204
1323
 
1205
1324
  // src/schema/region.ts
1206
- import { z as z21 } from "zod";
1325
+ import { z as z23 } from "zod";
1207
1326
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1208
1327
  var AF = ["af-south-1"];
1209
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"];
@@ -1220,35 +1339,35 @@ var regions = [
1220
1339
  ...ME,
1221
1340
  ...SA
1222
1341
  ];
1223
- var RegionSchema = z21.enum(regions);
1342
+ var RegionSchema = z23.enum(regions);
1224
1343
 
1225
1344
  // src/schema/plugin.ts
1226
- import { z as z22 } from "zod";
1227
- var PluginSchema = z22.object({
1228
- name: z22.string(),
1229
- schema: z22.custom().optional(),
1230
- depends: z22.array(z22.lazy(() => PluginSchema)).optional(),
1231
- onBootstrap: z22.function().optional(),
1232
- onStack: z22.function().returns(z22.any()).optional(),
1233
- 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()
1234
1353
  // bind: z.function().optional(),
1235
1354
  });
1236
1355
 
1237
1356
  // src/schema/app.ts
1238
- var AppSchema = z23.object({
1357
+ var AppSchema = z25.object({
1239
1358
  name: ResourceIdSchema,
1240
1359
  region: RegionSchema,
1241
- profile: z23.string(),
1242
- stage: z23.string().regex(/[a-z]+/).default("prod"),
1243
- defaults: z23.object({}).default({}),
1244
- stacks: z23.array(StackSchema).min(1),
1245
- 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()
1246
1365
  });
1247
1366
 
1248
1367
  // src/util/import.ts
1249
1368
  import { transformFile } from "@swc/core";
1250
- import { dirname, join as join4 } from "path";
1251
- 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";
1252
1371
  var resolveFileNameExtension = async (path) => {
1253
1372
  const options = [
1254
1373
  "",
@@ -1272,14 +1391,14 @@ var resolveFileNameExtension = async (path) => {
1272
1391
  throw new Error(`Failed to load file: ${path}`);
1273
1392
  };
1274
1393
  var resolveDir = (path) => {
1275
- return dirname(path).replace(rootDir + "/", "");
1394
+ return dirname2(path).replace(rootDir + "/", "");
1276
1395
  };
1277
1396
  var importFile = async (path) => {
1278
1397
  const load = async (file) => {
1279
1398
  let { code: code2 } = await transformFile(file, {
1280
1399
  isModule: true
1281
1400
  });
1282
- const path2 = dirname(file);
1401
+ const path2 = dirname2(file);
1283
1402
  const dir = resolveDir(file);
1284
1403
  code2 = code2.replaceAll("__dirname", `"${dir}"`);
1285
1404
  const matches = code2.match(/import\s*{\s*[a-z0-9\_]+\s*}\s*from\s*('|")(\.[\/a-z0-9\_\-]+)('|");?/ig);
@@ -1288,23 +1407,23 @@ var importFile = async (path) => {
1288
1407
  await Promise.all(matches?.map(async (match) => {
1289
1408
  const parts = /('|")(\.[\/a-z0-9\_\-]+)('|")/ig.exec(match);
1290
1409
  const from = parts[2];
1291
- const file2 = await resolveFileNameExtension(join4(path2, from));
1410
+ const file2 = await resolveFileNameExtension(join6(path2, from));
1292
1411
  const result = await load(file2);
1293
1412
  code2 = code2.replace(match, result);
1294
1413
  }));
1295
1414
  return code2;
1296
1415
  };
1297
1416
  const code = await load(path);
1298
- const outputFile = join4(outDir, "config.js");
1299
- await mkdir2(outDir, { recursive: true });
1300
- await writeFile2(outputFile, code);
1417
+ const outputFile = join6(outDir, "config.js");
1418
+ await mkdir3(outDir, { recursive: true });
1419
+ await writeFile3(outputFile, code);
1301
1420
  return import(outputFile);
1302
1421
  };
1303
1422
 
1304
1423
  // src/config.ts
1305
1424
  var importConfig = async (options) => {
1306
1425
  debug("Import config file");
1307
- const fileName = join5(process.cwd(), options.configFile || "awsless.config.ts");
1426
+ const fileName = join7(process.cwd(), options.configFile || "awsless.config.ts");
1308
1427
  const module = await importFile(fileName);
1309
1428
  const appConfig = typeof module.default === "function" ? await module.default({
1310
1429
  profile: options.profile,
@@ -1518,6 +1637,13 @@ var Interface = class {
1518
1637
  if (this.input.isTTY) {
1519
1638
  this.input.setRawMode(true);
1520
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
+ });
1521
1647
  }
1522
1648
  // private subscriber: Actions | undefined
1523
1649
  readline;
@@ -1667,12 +1793,6 @@ var layout = async (cb) => {
1667
1793
  const term = createTerminal();
1668
1794
  term.out.clear();
1669
1795
  term.out.write(logo());
1670
- term.in.captureInput({
1671
- abort: () => {
1672
- term.in.showCursor();
1673
- process.exit(1);
1674
- }
1675
- });
1676
1796
  try {
1677
1797
  const options = program.optsWithGlobals();
1678
1798
  const config2 = await importConfig(options);
@@ -1693,7 +1813,7 @@ var layout = async (cb) => {
1693
1813
  term.in.unref();
1694
1814
  setTimeout(() => {
1695
1815
  process.exit(0);
1696
- }, 50);
1816
+ }, 100);
1697
1817
  }
1698
1818
  };
1699
1819
 
@@ -1724,7 +1844,8 @@ var assetBuilder = (assets) => {
1724
1844
  const groups = new Signal([br()]);
1725
1845
  term.out.write(groups);
1726
1846
  const stackNameSize = Math.max(...Object.keys(assets.list()).map((stack) => stack.length));
1727
- 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) => {
1728
1849
  const group = new Signal([]);
1729
1850
  groups.update((groups2) => [...groups2, group]);
1730
1851
  await Promise.all(assets2.map(async (asset) => {
@@ -1733,12 +1854,13 @@ var assetBuilder = (assets) => {
1733
1854
  const line = flexLine(term, [
1734
1855
  icon,
1735
1856
  " ",
1736
- style.label(stack.name),
1737
- " ".repeat(stackNameSize - stack.name.length),
1857
+ style.label(stackName),
1858
+ " ".repeat(stackNameSize - stackName.length),
1738
1859
  " ",
1739
1860
  style.placeholder(symbol.pointerSmall),
1740
1861
  " ",
1741
1862
  style.warning(asset.resource),
1863
+ " ".repeat(resourceSize - asset.resource.length),
1742
1864
  " ",
1743
1865
  style.placeholder(symbol.pointerSmall),
1744
1866
  " ",
@@ -1769,25 +1891,26 @@ var assetBuilder = (assets) => {
1769
1891
  };
1770
1892
 
1771
1893
  // src/util/cleanup.ts
1772
- import { mkdir as mkdir3, rm } from "fs/promises";
1894
+ import { mkdir as mkdir4, rm as rm2 } from "fs/promises";
1773
1895
  var cleanUp = async () => {
1774
1896
  debug("Clean up assembly & asset files");
1775
1897
  const paths = [
1776
1898
  assemblyDir,
1777
- functionDir
1899
+ assetDir,
1900
+ cacheDir
1778
1901
  ];
1779
- await Promise.all(paths.map((path) => rm(path, {
1902
+ await Promise.all(paths.map((path) => rm2(path, {
1780
1903
  recursive: true,
1781
1904
  force: true,
1782
1905
  maxRetries: 2
1783
1906
  })));
1784
- await Promise.all(paths.map((path) => mkdir3(path, {
1907
+ await Promise.all(paths.map((path) => mkdir4(path, {
1785
1908
  recursive: true
1786
1909
  })));
1787
1910
  };
1788
1911
 
1789
1912
  // src/cli/command/build.ts
1790
- var build = (program2) => {
1913
+ var build2 = (program2) => {
1791
1914
  program2.command("build").argument("[stack...]", "Optionally filter stacks to build").description("Build your app").action(async (filters) => {
1792
1915
  await layout(async (config2, write) => {
1793
1916
  const { app, assets } = await toApp(config2, filters);
@@ -1905,7 +2028,7 @@ var StackClient = class {
1905
2028
  stack.Outputs?.forEach((output) => {
1906
2029
  outputs[output.OutputKey] = output.OutputValue;
1907
2030
  });
1908
- debug("Status for: ", style.info(name), "is", stack.StackStatus);
2031
+ debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
1909
2032
  return {
1910
2033
  status: stack.StackStatus,
1911
2034
  reason: stack.StackStatusReason,
@@ -2171,6 +2294,7 @@ var deploy = (program2) => {
2171
2294
  await cleanUp();
2172
2295
  await write(assetBuilder(assets));
2173
2296
  write(br());
2297
+ write(br());
2174
2298
  const donePublishing = write(loadingDialog("Publishing stack assets to AWS..."));
2175
2299
  await Promise.all(assets.map(async (_, assets2) => {
2176
2300
  await Promise.all(assets2.map(async (asset) => {
@@ -2186,21 +2310,28 @@ var deploy = (program2) => {
2186
2310
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
2187
2311
  write(br());
2188
2312
  write(stackTree(dependencyTree, statuses));
2313
+ write(br());
2189
2314
  const client = new StackClient(config2);
2190
2315
  const deploymentLine = createDeploymentLine(dependencyTree);
2191
2316
  for (const stacks of deploymentLine) {
2192
- await Promise.allSettled(stacks.map(async (stack) => {
2317
+ const results = await Promise.allSettled(stacks.map(async (stack) => {
2318
+ const signal = statuses[stack.artifactId];
2193
2319
  const stackArtifect = assembly.stacks.find((item) => item.id === stack.artifactId);
2194
- statuses[stack.artifactId].set(style.warning("deploying"));
2320
+ signal.set(style.warning("deploying"));
2195
2321
  try {
2196
2322
  await client.deploy(stackArtifect);
2197
2323
  } catch (error) {
2198
2324
  debugError(error);
2199
- statuses[stack.artifactId].set(style.error("failed"));
2325
+ signal.set(style.error("failed"));
2200
2326
  throw error;
2201
2327
  }
2202
- statuses[stack.artifactId].set(style.success("deployed"));
2328
+ signal.set(style.success("deployed"));
2203
2329
  }));
2330
+ for (const result of results) {
2331
+ if (result.status === "rejected") {
2332
+ throw result.reason;
2333
+ }
2334
+ }
2204
2335
  }
2205
2336
  doneDeploying("Done deploying stacks to AWS");
2206
2337
  });
@@ -2375,7 +2506,7 @@ program.on("option:verbose", () => {
2375
2506
  var commands2 = [
2376
2507
  bootstrap,
2377
2508
  status,
2378
- build,
2509
+ build2,
2379
2510
  deploy,
2380
2511
  config
2381
2512
  // diff,