@awsless/awsless 0.0.8 → 0.0.10

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_lib6 = require("aws-cdk-lib");
30
+ var import_aws_cdk_lib7 = require("aws-cdk-lib");
31
31
 
32
32
  // src/stack.ts
33
33
  var import_aws_cdk_lib = require("aws-cdk-lib");
@@ -215,6 +215,8 @@ var toStack = ({ config: config2, assets, app, stackConfig, plugins }) => {
215
215
  functions.forEach((lambda) => lambda.addToRolePolicy(allowConfigParameters));
216
216
  return {
217
217
  stack,
218
+ functions,
219
+ bindings,
218
220
  depends: stackConfig.depends
219
221
  };
220
222
  };
@@ -224,10 +226,11 @@ var import_path = require("path");
224
226
  var rootDir = process.cwd();
225
227
  var outDir = (0, import_path.join)(rootDir, ".awsless");
226
228
  var assemblyDir = (0, import_path.join)(outDir, "assembly");
227
- var functionDir = (0, import_path.join)(outDir, "function");
229
+ var assetDir = (0, import_path.join)(outDir, "asset");
230
+ var cacheDir = (0, import_path.join)(outDir, "cache");
228
231
 
229
232
  // src/stack/app-bootstrap.ts
230
- var import_aws_cdk_lib5 = require("aws-cdk-lib");
233
+ var import_aws_cdk_lib6 = require("aws-cdk-lib");
231
234
 
232
235
  // src/plugin.ts
233
236
  var definePlugin = (plugin) => plugin;
@@ -280,7 +283,7 @@ var toName = (stack, id) => {
280
283
  return (0, import_change_case.paramCase)(`${stack.stackName}-${id}`);
281
284
  };
282
285
  var toEnvKey = (resource, id) => {
283
- return (0, import_change_case.constantCase)(`RESOURCE_${resource}_${id}`);
286
+ return `RESOURCE_${resource.toUpperCase()}_${id}`;
284
287
  };
285
288
  var addResourceEnvironment = (stack, resource, id, lambda) => {
286
289
  const key = toEnvKey(resource, id);
@@ -379,72 +382,6 @@ var SizeSchema = import_zod7.z.custom((value) => {
379
382
  return import_zod7.z.string().regex(/[0-9]+ (KB|MB|GB)/).safeParse(value).success;
380
383
  }, "Invalid size").transform(toSize);
381
384
 
382
- // src/plugins/function/util/build-worker.ts
383
- var import_worker_threads = require("worker_threads");
384
- var cjs = typeof require !== "undefined";
385
- var importESM = `
386
- import { bundle } from "@awsless/code";
387
- import { createHash } from "crypto";
388
- import { parentPort, workerData } from "worker_threads";
389
- `;
390
- var importCJS = `
391
- const { bundle } = require("@awsless/code");
392
- const { createHash } = require("crypto");
393
- const { parentPort, workerData } = require("worker_threads");
394
- `;
395
- var workerCode = `
396
- ${cjs ? importCJS : importESM}
397
-
398
- const build = async (file) => {
399
- const { code, map } = await bundle(file, {
400
- format: 'esm',
401
- sourceMap: true,
402
- minimize: true,
403
- onwarn: () => {},
404
- moduleSideEffects: (id) => file === id,
405
- external: (importee) => (
406
- importee.startsWith('aws-sdk') ||
407
- importee.startsWith('@aws-sdk')
408
- ),
409
- })
410
-
411
- const hash = createHash('sha1').update(code).digest('hex')
412
-
413
- parentPort.postMessage(JSON.stringify({
414
- handler: 'index.default',
415
- hash,
416
- files: [
417
- { name: 'index.js', code, map: map?.toString() }
418
- ]
419
- }))
420
- }
421
-
422
- build(workerData)
423
- `;
424
- var defaultBuild = async (file) => {
425
- return new Promise((resolve, reject) => {
426
- const worker = new import_worker_threads.Worker(workerCode, { workerData: file, eval: true });
427
- const cleanUp2 = () => {
428
- worker.removeAllListeners();
429
- worker.terminate();
430
- };
431
- worker.on("message", (data) => {
432
- resolve(JSON.parse(data.toString("utf8")));
433
- cleanUp2();
434
- });
435
- worker.on("error", (data) => {
436
- reject(data);
437
- cleanUp2();
438
- });
439
- worker.on("exit", (code) => {
440
- if (code !== 0) {
441
- reject(new Error(`Worker exited with code ${code}`));
442
- cleanUp2();
443
- }
444
- });
445
- });
446
- };
447
-
448
385
  // src/plugins/function/util/build.ts
449
386
  var import_jszip = __toESM(require("jszip"), 1);
450
387
  var import_path3 = require("path");
@@ -464,13 +401,13 @@ var zipFiles = (files) => {
464
401
  });
465
402
  };
466
403
  var writeBuildHash = async (config2, stack, id, hash) => {
467
- const funcPath = (0, import_path3.join)(functionDir, config2.name, stack.artifactId, id);
404
+ const funcPath = (0, import_path3.join)(assetDir, "function", config2.name, stack.artifactId, id);
468
405
  const versionFile = (0, import_path3.join)(funcPath, "HASH");
469
406
  await (0, import_promises2.writeFile)(versionFile, hash);
470
407
  };
471
408
  var writeBuildFiles = async (config2, stack, id, files) => {
472
409
  const bundle = await zipFiles(files);
473
- const funcPath = (0, import_path3.join)(functionDir, config2.name, stack.artifactId, id);
410
+ const funcPath = (0, import_path3.join)(assetDir, "function", config2.name, stack.artifactId, id);
474
411
  const filesPath = (0, import_path3.join)(funcPath, "files");
475
412
  const bundleFile = (0, import_path3.join)(funcPath, "bundle.zip");
476
413
  debug("Bundle size of", style.info((0, import_path3.join)(config2.name, stack.artifactId, id)), "is", style.attr((0, import_filesize.filesize)(bundle.byteLength)));
@@ -533,7 +470,7 @@ var shouldDeployBootstrap = async (client, name) => {
533
470
  var publishFunctionAsset = async (config2, stack, id) => {
534
471
  const bucket = assetBucketName(config2);
535
472
  const key = `${config2.name}/${stack.artifactId}/function/${id}.zip`;
536
- const funcPath = (0, import_path5.join)(functionDir, config2.name, stack.artifactId, id);
473
+ const funcPath = (0, import_path5.join)(assetDir, "function", config2.name, stack.artifactId, id);
537
474
  const bundleFile = (0, import_path5.join)(funcPath, "bundle.zip");
538
475
  const hashFile = (0, import_path5.join)(funcPath, "HASH");
539
476
  const hash = await (0, import_promises3.readFile)(hashFile, "utf8");
@@ -581,6 +518,53 @@ var formatByteSize = (size) => {
581
518
  return style.attr(number) + style.attr.dim(unit);
582
519
  };
583
520
 
521
+ // src/plugins/function/util/bundler/rollup.ts
522
+ var import_rollup = require("rollup");
523
+ var import_crypto = require("crypto");
524
+ var import_rollup_plugin_swc3 = require("rollup-plugin-swc3");
525
+ var import_plugin_commonjs = __toESM(require("@rollup/plugin-commonjs"), 1);
526
+ var import_plugin_node_resolve = __toESM(require("@rollup/plugin-node-resolve"), 1);
527
+ var rollupBuild = async (input) => {
528
+ const bundle = await (0, import_rollup.rollup)({
529
+ input,
530
+ external: (importee) => {
531
+ return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk");
532
+ },
533
+ onwarn: (error) => {
534
+ debugError(error.message);
535
+ },
536
+ treeshake: {
537
+ moduleSideEffects: (id) => input === id
538
+ },
539
+ plugins: [
540
+ (0, import_plugin_commonjs.default)({ sourceMap: true }),
541
+ (0, import_plugin_node_resolve.default)({
542
+ preferBuiltins: true
543
+ }),
544
+ (0, import_rollup_plugin_swc3.swc)({
545
+ minify: true,
546
+ jsc: { minify: { sourceMap: true } },
547
+ sourceMaps: true
548
+ })
549
+ ]
550
+ });
551
+ const { output: [output] } = await bundle.generate({
552
+ format: "esm",
553
+ sourcemap: "hidden",
554
+ exports: "default"
555
+ });
556
+ const hash = (0, import_crypto.createHash)("sha1").update(output.code).digest("hex");
557
+ return {
558
+ handler: "index.default",
559
+ hash,
560
+ files: [{
561
+ name: "index.mjs",
562
+ code: output.code,
563
+ map: output.map?.toString()
564
+ }]
565
+ };
566
+ };
567
+
584
568
  // src/plugins/function/index.ts
585
569
  var FunctionSchema = import_zod9.z.union([
586
570
  LocalFileSchema,
@@ -623,7 +607,7 @@ var functionPlugin = definePlugin({
623
607
  });
624
608
  }
625
609
  });
626
- var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrProps) => {
610
+ var toFunction = ({ config: config2, stack, assets }, id, fileOrProps) => {
627
611
  const props = typeof fileOrProps === "string" ? { ...config2.defaults?.function, file: fileOrProps } : { ...config2.defaults?.function, ...fileOrProps };
628
612
  const lambda = new import_aws_lambda3.Function(stack, toId("function", id), {
629
613
  functionName: toName(stack, id),
@@ -634,18 +618,18 @@ var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrPro
634
618
  });
635
619
  lambda.addEnvironment("APP", config2.name, { removeInEdge: true });
636
620
  lambda.addEnvironment("STAGE", config2.stage, { removeInEdge: true });
637
- lambda.addEnvironment("STACK", stackConfig.name, { removeInEdge: true });
621
+ lambda.addEnvironment("STACK", stack.artifactId, { removeInEdge: true });
638
622
  if (lambda.runtime.toString().startsWith("nodejs")) {
639
623
  lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1", {
640
624
  removeInEdge: true
641
625
  });
642
626
  }
643
627
  assets.add({
644
- stack: stackConfig,
628
+ stackName: stack.artifactId,
645
629
  resource: "function",
646
630
  resourceName: id,
647
631
  async build() {
648
- const result = await defaultBuild(props.file);
632
+ const result = await rollupBuild(props.file);
649
633
  const bundle = await writeBuildFiles(config2, stack, id, result.files);
650
634
  await writeBuildHash(config2, stack, id, result.hash);
651
635
  const func = lambda.node.defaultChild;
@@ -887,7 +871,6 @@ var import_zod18 = require("zod");
887
871
  var import_aws_sns = require("aws-cdk-lib/aws-sns");
888
872
  var import_aws_lambda_event_sources2 = require("aws-cdk-lib/aws-lambda-event-sources");
889
873
  var import_aws_cdk_lib4 = require("aws-cdk-lib");
890
- var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
891
874
  var topicPlugin = definePlugin({
892
875
  name: "topic",
893
876
  schema: import_zod18.z.object({
@@ -909,12 +892,6 @@ var topicPlugin = definePlugin({
909
892
  },
910
893
  onStack(ctx) {
911
894
  const { config: config2, stack, stackConfig, bind } = ctx;
912
- bind((lambda) => {
913
- lambda.addToRolePolicy(new import_aws_iam2.PolicyStatement({
914
- actions: ["sns:publish"],
915
- resources: ["*"]
916
- }));
917
- });
918
895
  return Object.entries(stackConfig.topics || {}).map(([id, props]) => {
919
896
  const lambda = toFunction(ctx, id, props);
920
897
  const topic = import_aws_sns.Topic.fromTopicArn(
@@ -927,6 +904,10 @@ var topicPlugin = definePlugin({
927
904
  }, stack)
928
905
  );
929
906
  lambda.addEventSource(new import_aws_lambda_event_sources2.SnsEventSource(topic));
907
+ bind((lambda2) => {
908
+ addResourceEnvironment(stack, "topic", id, lambda2);
909
+ topic.grantPublish(lambda2);
910
+ });
930
911
  return lambda;
931
912
  });
932
913
  }
@@ -935,7 +916,7 @@ var topicPlugin = definePlugin({
935
916
  // src/plugins/search.ts
936
917
  var import_zod19 = require("zod");
937
918
  var import_aws_opensearchserverless = require("aws-cdk-lib/aws-opensearchserverless");
938
- var import_aws_iam3 = require("aws-cdk-lib/aws-iam");
919
+ var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
939
920
  var searchPlugin = definePlugin({
940
921
  name: "search",
941
922
  schema: import_zod19.z.object({
@@ -950,7 +931,7 @@ var searchPlugin = definePlugin({
950
931
  type: "SEARCH"
951
932
  });
952
933
  bind((lambda) => {
953
- lambda.addToRolePolicy(new import_aws_iam3.PolicyStatement({
934
+ lambda.addToRolePolicy(new import_aws_iam2.PolicyStatement({
954
935
  actions: ["aoss:APIAccessAll"],
955
936
  resources: [collection.attrArn]
956
937
  }));
@@ -959,6 +940,138 @@ var searchPlugin = definePlugin({
959
940
  }
960
941
  });
961
942
 
943
+ // src/plugins/graphql/index.ts
944
+ var import_zod21 = require("zod");
945
+ var import_aws_appsync = require("aws-cdk-lib/aws-appsync");
946
+ var import_merge = require("@graphql-tools/merge");
947
+ var import_promises4 = require("fs/promises");
948
+
949
+ // src/util/array.ts
950
+ var toArray = (value) => {
951
+ if (Array.isArray(value)) {
952
+ return value;
953
+ }
954
+ return [value];
955
+ };
956
+
957
+ // src/plugins/graphql/index.ts
958
+ var import_path6 = require("path");
959
+ var import_graphql = require("graphql");
960
+ var import_change_case2 = require("change-case");
961
+
962
+ // src/plugins/graphql/schema/resolver-field.ts
963
+ var import_zod20 = require("zod");
964
+ var ResolverFieldSchema = import_zod20.z.custom((value) => {
965
+ return import_zod20.z.string().regex(/([a-z0-9\_]+)(\s){1}([a-z0-9\_]+)/gi).safeParse(value).success;
966
+ }, `Invalid resolver field. Valid example: "Query list"`);
967
+
968
+ // src/plugins/graphql/index.ts
969
+ var import_aws_cdk_lib5 = require("aws-cdk-lib");
970
+ var graphqlPlugin = definePlugin({
971
+ name: "graphql",
972
+ schema: import_zod21.z.object({
973
+ defaults: import_zod21.z.object({
974
+ graphql: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
975
+ authorization: import_zod21.z.object({
976
+ authorizer: FunctionSchema,
977
+ ttl: DurationSchema.default("1 hour")
978
+ }).optional(),
979
+ mappingTemplate: import_zod21.z.object({
980
+ request: LocalFileSchema.optional(),
981
+ response: LocalFileSchema.optional()
982
+ }).optional()
983
+ })).optional()
984
+ }).default({}),
985
+ stacks: import_zod21.z.object({
986
+ graphql: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
987
+ schema: import_zod21.z.union([
988
+ LocalFileSchema,
989
+ import_zod21.z.array(LocalFileSchema).min(1)
990
+ ]).optional(),
991
+ resolvers: import_zod21.z.record(ResolverFieldSchema, FunctionSchema).optional()
992
+ })).optional()
993
+ }).array()
994
+ }),
995
+ onBootstrap({ config: config2, stack, assets }) {
996
+ const list3 = /* @__PURE__ */ new Set();
997
+ Object.values(config2.stacks).forEach((stackConfig) => {
998
+ Object.keys(stackConfig.graphql || {}).forEach((id) => {
999
+ list3.add(id);
1000
+ });
1001
+ });
1002
+ list3.forEach((id) => {
1003
+ const file = (0, import_path6.join)(assetDir, "graphql", config2.name, id, "schema.graphql");
1004
+ const authorization = config2.defaults.graphql?.[id]?.authorization;
1005
+ const authProps = {};
1006
+ if (authorization) {
1007
+ const authorizer = toFunction({ config: config2, assets, stack }, `${id}-authorizer`, authorization.authorizer);
1008
+ authProps.additionalAuthenticationProviders = [{
1009
+ authenticationType: import_aws_appsync.AuthorizationType.LAMBDA,
1010
+ lambdaAuthorizerConfig: {
1011
+ authorizerUri: authorizer.functionArn,
1012
+ authorizerResultTtlInSeconds: authorization.ttl.toSeconds()
1013
+ }
1014
+ }];
1015
+ }
1016
+ const api = new import_aws_appsync.CfnGraphQLApi(stack, toId("graphql", id), {
1017
+ ...authProps,
1018
+ name: toName(stack, id),
1019
+ authenticationType: import_aws_appsync.AuthorizationType.API_KEY
1020
+ });
1021
+ new import_aws_cdk_lib5.CfnOutput(stack, toId("output", id), {
1022
+ exportName: toId("graphql", id),
1023
+ value: api.attrApiId
1024
+ });
1025
+ assets.add({
1026
+ stackName: stack.artifactId,
1027
+ resource: "schema",
1028
+ resourceName: id,
1029
+ async build() {
1030
+ const schemas = [];
1031
+ await Promise.all(Object.values(config2.stacks).map(async (stackConfig) => {
1032
+ const schemaFiles = toArray(stackConfig.graphql?.[id].schema || []);
1033
+ await Promise.all(schemaFiles.map(async (schemaFile) => {
1034
+ const schema3 = await (0, import_promises4.readFile)(schemaFile, "utf8");
1035
+ schemas.push(schema3);
1036
+ }));
1037
+ }));
1038
+ const schema2 = (0, import_graphql.print)((0, import_merge.mergeTypeDefs)(schemas));
1039
+ await (0, import_promises4.mkdir)((0, import_path6.dirname)(file), { recursive: true });
1040
+ await (0, import_promises4.writeFile)(file, schema2);
1041
+ new import_aws_appsync.CfnGraphQLSchema(stack, toId("schema", id), {
1042
+ apiId: api.attrApiId,
1043
+ definition: schema2
1044
+ });
1045
+ }
1046
+ });
1047
+ });
1048
+ },
1049
+ onStack(ctx) {
1050
+ const { config: config2, stack, stackConfig } = ctx;
1051
+ return Object.entries(stackConfig.graphql || {}).map(([id, props]) => {
1052
+ const defaults = config2.defaults.graphql?.[id] || {};
1053
+ return Object.entries(props.resolvers || {}).map(([typeAndField, functionProps]) => {
1054
+ const api = import_aws_appsync.GraphqlApi.fromGraphqlApiAttributes(stack, toId("graphql", id), {
1055
+ graphqlApiId: import_aws_cdk_lib5.Fn.importValue(toId("graphql", id))
1056
+ });
1057
+ const [typeName, fieldName] = typeAndField.split(/[\s]+/g);
1058
+ const functionId = (0, import_change_case2.paramCase)(`${id}-${typeName}-${fieldName}`);
1059
+ const lambda = toFunction(ctx, functionId, functionProps);
1060
+ const source = api.addLambdaDataSource(toId("data-source", functionId), lambda, {
1061
+ name: toId("data-source", functionId)
1062
+ });
1063
+ source.createResolver(toId("resolver", functionId), {
1064
+ typeName,
1065
+ fieldName,
1066
+ requestMappingTemplate: defaults.mappingTemplate?.request ? import_aws_appsync.MappingTemplate.fromFile(defaults.mappingTemplate.request) : import_aws_appsync.MappingTemplate.lambdaRequest(),
1067
+ responseMappingTemplate: defaults.mappingTemplate?.response ? import_aws_appsync.MappingTemplate.fromFile(defaults.mappingTemplate.response) : import_aws_appsync.MappingTemplate.lambdaResult()
1068
+ });
1069
+ return lambda;
1070
+ });
1071
+ }).flat();
1072
+ }
1073
+ });
1074
+
962
1075
  // src/plugins/index.ts
963
1076
  var defaultPlugins = [
964
1077
  functionPlugin,
@@ -967,12 +1080,13 @@ var defaultPlugins = [
967
1080
  tablePlugin,
968
1081
  storePlugin,
969
1082
  topicPlugin,
970
- searchPlugin
1083
+ searchPlugin,
1084
+ graphqlPlugin
971
1085
  ];
972
1086
 
973
1087
  // src/stack/app-bootstrap.ts
974
1088
  var appBootstrapStack = ({ config: config2, app, assets }) => {
975
- const stack = new import_aws_cdk_lib5.Stack(app, "bootstrap", {
1089
+ const stack = new import_aws_cdk_lib6.Stack(app, "bootstrap", {
976
1090
  stackName: `${config2.name}-bootstrap`
977
1091
  });
978
1092
  const plugins = [
@@ -980,8 +1094,16 @@ var appBootstrapStack = ({ config: config2, app, assets }) => {
980
1094
  ...config2.plugins || []
981
1095
  ];
982
1096
  debug("Run plugin onBootstrap listeners");
983
- plugins.forEach((plugin) => plugin.onBootstrap?.({ config: config2, stack, app, assets }));
984
- return stack;
1097
+ const functions = plugins.map((plugin) => plugin.onBootstrap?.({
1098
+ config: config2,
1099
+ app,
1100
+ stack,
1101
+ assets
1102
+ })).filter(Boolean).flat().filter(Boolean);
1103
+ return {
1104
+ stack,
1105
+ functions
1106
+ };
985
1107
  };
986
1108
 
987
1109
  // src/util/deployment.ts
@@ -1047,10 +1169,10 @@ var Assets = class {
1047
1169
  assets = {};
1048
1170
  id = 0;
1049
1171
  add(opts) {
1050
- if (!this.assets[opts.stack.name]) {
1051
- this.assets[opts.stack.name] = [];
1172
+ if (!this.assets[opts.stackName]) {
1173
+ this.assets[opts.stackName] = [];
1052
1174
  }
1053
- this.assets[opts.stack.name].push({
1175
+ this.assets[opts.stackName].push({
1054
1176
  ...opts,
1055
1177
  id: this.id++
1056
1178
  });
@@ -1060,21 +1182,21 @@ var Assets = class {
1060
1182
  }
1061
1183
  forEach(cb) {
1062
1184
  Object.values(this.assets).forEach((assets) => {
1063
- cb(assets[0].stack, assets);
1185
+ cb(assets[0].stackName, assets);
1064
1186
  });
1065
1187
  }
1066
1188
  map(cb) {
1067
1189
  return Object.values(this.assets).map((assets) => {
1068
- return cb(assets[0].stack, assets);
1190
+ return cb(assets[0].stackName, assets);
1069
1191
  });
1070
1192
  }
1071
1193
  };
1072
1194
 
1073
1195
  // src/app.ts
1074
1196
  var makeApp = (config2) => {
1075
- return new import_aws_cdk_lib6.App({
1197
+ return new import_aws_cdk_lib7.App({
1076
1198
  outdir: assemblyDir,
1077
- defaultStackSynthesizer: new import_aws_cdk_lib6.DefaultStackSynthesizer({
1199
+ defaultStackSynthesizer: new import_aws_cdk_lib7.DefaultStackSynthesizer({
1078
1200
  fileAssetsBucketName: assetBucketName(config2),
1079
1201
  fileAssetPublishingRoleArn: "",
1080
1202
  generateBootstrapVersionRule: false
@@ -1103,13 +1225,14 @@ var toApp = async (config2, filters) => {
1103
1225
  debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
1104
1226
  debug("Run plugin onApp listeners");
1105
1227
  plugins.forEach((plugin) => plugin.onApp?.({ config: config2, app, assets }));
1228
+ const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1106
1229
  debug("Stack filters:", filters.map((filter) => style.info(filter)).join(", "));
1107
1230
  const filterdStacks = filters.length === 0 ? config2.stacks : getAllDepends(
1108
1231
  // config.stacks,
1109
1232
  config2.stacks.filter((stack) => filters.includes(stack.name))
1110
1233
  );
1111
1234
  for (const stackConfig of filterdStacks) {
1112
- const { stack } = toStack({
1235
+ const { stack, bindings } = toStack({
1113
1236
  config: config2,
1114
1237
  stackConfig,
1115
1238
  assets,
@@ -1117,14 +1240,14 @@ var toApp = async (config2, filters) => {
1117
1240
  app
1118
1241
  });
1119
1242
  stacks.push({ stack, config: stackConfig });
1243
+ bindings.forEach((cb) => bootstrap2.functions.forEach(cb));
1120
1244
  }
1121
1245
  let dependencyTree;
1122
- const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1123
- if (bootstrap2.node.children.length === 0) {
1246
+ if (bootstrap2.stack.node.children.length === 0) {
1124
1247
  dependencyTree = createDependencyTree(stacks, 0);
1125
1248
  } else {
1126
1249
  dependencyTree = [{
1127
- stack: bootstrap2,
1250
+ stack: bootstrap2.stack,
1128
1251
  level: 0,
1129
1252
  children: createDependencyTree(stacks, 1)
1130
1253
  }];
@@ -1196,7 +1319,7 @@ var footer = () => {
1196
1319
  };
1197
1320
 
1198
1321
  // src/config.ts
1199
- var import_path9 = require("path");
1322
+ var import_path11 = require("path");
1200
1323
 
1201
1324
  // src/util/account.ts
1202
1325
  var import_client_sts = require("@aws-sdk/client-sts");
@@ -1215,17 +1338,17 @@ var getCredentials = (profile) => {
1215
1338
  };
1216
1339
 
1217
1340
  // src/schema/app.ts
1218
- var import_zod23 = require("zod");
1341
+ var import_zod25 = require("zod");
1219
1342
 
1220
1343
  // src/schema/stack.ts
1221
- var import_zod20 = require("zod");
1222
- var StackSchema = import_zod20.z.object({
1344
+ var import_zod22 = require("zod");
1345
+ var StackSchema = import_zod22.z.object({
1223
1346
  name: ResourceIdSchema,
1224
- depends: import_zod20.z.array(import_zod20.z.lazy(() => StackSchema)).optional()
1347
+ depends: import_zod22.z.array(import_zod22.z.lazy(() => StackSchema)).optional()
1225
1348
  });
1226
1349
 
1227
1350
  // src/schema/region.ts
1228
- var import_zod21 = require("zod");
1351
+ var import_zod23 = require("zod");
1229
1352
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1230
1353
  var AF = ["af-south-1"];
1231
1354
  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"];
@@ -1242,35 +1365,35 @@ var regions = [
1242
1365
  ...ME,
1243
1366
  ...SA
1244
1367
  ];
1245
- var RegionSchema = import_zod21.z.enum(regions);
1368
+ var RegionSchema = import_zod23.z.enum(regions);
1246
1369
 
1247
1370
  // src/schema/plugin.ts
1248
- var import_zod22 = require("zod");
1249
- var PluginSchema = import_zod22.z.object({
1250
- name: import_zod22.z.string(),
1251
- schema: import_zod22.z.custom().optional(),
1252
- depends: import_zod22.z.array(import_zod22.z.lazy(() => PluginSchema)).optional(),
1253
- onBootstrap: import_zod22.z.function().optional(),
1254
- onStack: import_zod22.z.function().returns(import_zod22.z.any()).optional(),
1255
- onApp: import_zod22.z.function().optional()
1371
+ var import_zod24 = require("zod");
1372
+ var PluginSchema = import_zod24.z.object({
1373
+ name: import_zod24.z.string(),
1374
+ schema: import_zod24.z.custom().optional(),
1375
+ // depends: z.array(z.lazy(() => PluginSchema)).optional(),
1376
+ onBootstrap: import_zod24.z.function().returns(import_zod24.z.any()).optional(),
1377
+ onStack: import_zod24.z.function().returns(import_zod24.z.any()).optional(),
1378
+ onApp: import_zod24.z.function().returns(import_zod24.z.void()).optional()
1256
1379
  // bind: z.function().optional(),
1257
1380
  });
1258
1381
 
1259
1382
  // src/schema/app.ts
1260
- var AppSchema = import_zod23.z.object({
1383
+ var AppSchema = import_zod25.z.object({
1261
1384
  name: ResourceIdSchema,
1262
1385
  region: RegionSchema,
1263
- profile: import_zod23.z.string(),
1264
- stage: import_zod23.z.string().regex(/[a-z]+/).default("prod"),
1265
- defaults: import_zod23.z.object({}).default({}),
1266
- stacks: import_zod23.z.array(StackSchema).min(1),
1267
- plugins: import_zod23.z.array(PluginSchema).optional()
1386
+ profile: import_zod25.z.string(),
1387
+ stage: import_zod25.z.string().regex(/[a-z]+/).default("prod"),
1388
+ defaults: import_zod25.z.object({}).default({}),
1389
+ stacks: import_zod25.z.array(StackSchema).min(1),
1390
+ plugins: import_zod25.z.array(PluginSchema).optional()
1268
1391
  });
1269
1392
 
1270
1393
  // src/util/import.ts
1271
1394
  var import_core3 = require("@swc/core");
1272
- var import_path7 = require("path");
1273
- var import_promises4 = require("fs/promises");
1395
+ var import_path9 = require("path");
1396
+ var import_promises5 = require("fs/promises");
1274
1397
  var resolveFileNameExtension = async (path) => {
1275
1398
  const options = [
1276
1399
  "",
@@ -1283,7 +1406,7 @@ var resolveFileNameExtension = async (path) => {
1283
1406
  const file = path + option;
1284
1407
  let stat;
1285
1408
  try {
1286
- stat = await (0, import_promises4.lstat)(file);
1409
+ stat = await (0, import_promises5.lstat)(file);
1287
1410
  } catch (error) {
1288
1411
  continue;
1289
1412
  }
@@ -1294,14 +1417,14 @@ var resolveFileNameExtension = async (path) => {
1294
1417
  throw new Error(`Failed to load file: ${path}`);
1295
1418
  };
1296
1419
  var resolveDir = (path) => {
1297
- return (0, import_path7.dirname)(path).replace(rootDir + "/", "");
1420
+ return (0, import_path9.dirname)(path).replace(rootDir + "/", "");
1298
1421
  };
1299
1422
  var importFile = async (path) => {
1300
1423
  const load = async (file) => {
1301
1424
  let { code: code2 } = await (0, import_core3.transformFile)(file, {
1302
1425
  isModule: true
1303
1426
  });
1304
- const path2 = (0, import_path7.dirname)(file);
1427
+ const path2 = (0, import_path9.dirname)(file);
1305
1428
  const dir = resolveDir(file);
1306
1429
  code2 = code2.replaceAll("__dirname", `"${dir}"`);
1307
1430
  const matches = code2.match(/import\s*{\s*[a-z0-9\_]+\s*}\s*from\s*('|")(\.[\/a-z0-9\_\-]+)('|");?/ig);
@@ -1310,23 +1433,23 @@ var importFile = async (path) => {
1310
1433
  await Promise.all(matches?.map(async (match) => {
1311
1434
  const parts = /('|")(\.[\/a-z0-9\_\-]+)('|")/ig.exec(match);
1312
1435
  const from = parts[2];
1313
- const file2 = await resolveFileNameExtension((0, import_path7.join)(path2, from));
1436
+ const file2 = await resolveFileNameExtension((0, import_path9.join)(path2, from));
1314
1437
  const result = await load(file2);
1315
1438
  code2 = code2.replace(match, result);
1316
1439
  }));
1317
1440
  return code2;
1318
1441
  };
1319
1442
  const code = await load(path);
1320
- const outputFile = (0, import_path7.join)(outDir, "config.js");
1321
- await (0, import_promises4.mkdir)(outDir, { recursive: true });
1322
- await (0, import_promises4.writeFile)(outputFile, code);
1443
+ const outputFile = (0, import_path9.join)(outDir, "config.js");
1444
+ await (0, import_promises5.mkdir)(outDir, { recursive: true });
1445
+ await (0, import_promises5.writeFile)(outputFile, code);
1323
1446
  return import(outputFile);
1324
1447
  };
1325
1448
 
1326
1449
  // src/config.ts
1327
1450
  var importConfig = async (options) => {
1328
1451
  debug("Import config file");
1329
- const fileName = (0, import_path9.join)(process.cwd(), options.configFile || "awsless.config.ts");
1452
+ const fileName = (0, import_path11.join)(process.cwd(), options.configFile || "awsless.config.ts");
1330
1453
  const module2 = await importFile(fileName);
1331
1454
  const appConfig = typeof module2.default === "function" ? await module2.default({
1332
1455
  profile: options.profile,
@@ -1540,6 +1663,13 @@ var Interface = class {
1540
1663
  if (this.input.isTTY) {
1541
1664
  this.input.setRawMode(true);
1542
1665
  }
1666
+ this.input.on("keypress", (_, key) => {
1667
+ const action = parseAction(key);
1668
+ if (action === "abort") {
1669
+ this.unref();
1670
+ process.exit(1);
1671
+ }
1672
+ });
1543
1673
  }
1544
1674
  // private subscriber: Actions | undefined
1545
1675
  readline;
@@ -1689,12 +1819,6 @@ var layout = async (cb) => {
1689
1819
  const term = createTerminal();
1690
1820
  term.out.clear();
1691
1821
  term.out.write(logo());
1692
- term.in.captureInput({
1693
- abort: () => {
1694
- term.in.showCursor();
1695
- process.exit(1);
1696
- }
1697
- });
1698
1822
  try {
1699
1823
  const options = program.optsWithGlobals();
1700
1824
  const config2 = await importConfig(options);
@@ -1715,7 +1839,7 @@ var layout = async (cb) => {
1715
1839
  term.in.unref();
1716
1840
  setTimeout(() => {
1717
1841
  process.exit(0);
1718
- }, 50);
1842
+ }, 100);
1719
1843
  }
1720
1844
  };
1721
1845
 
@@ -1746,7 +1870,8 @@ var assetBuilder = (assets) => {
1746
1870
  const groups = new Signal([br()]);
1747
1871
  term.out.write(groups);
1748
1872
  const stackNameSize = Math.max(...Object.keys(assets.list()).map((stack) => stack.length));
1749
- await Promise.all(assets.map(async (stack, assets2) => {
1873
+ const resourceSize = Math.max(...Object.values(assets.list()).map((assets2) => assets2.map((asset) => asset.resource.length)).flat());
1874
+ await Promise.all(assets.map(async (stackName, assets2) => {
1750
1875
  const group = new Signal([]);
1751
1876
  groups.update((groups2) => [...groups2, group]);
1752
1877
  await Promise.all(assets2.map(async (asset) => {
@@ -1755,12 +1880,13 @@ var assetBuilder = (assets) => {
1755
1880
  const line = flexLine(term, [
1756
1881
  icon,
1757
1882
  " ",
1758
- style.label(stack.name),
1759
- " ".repeat(stackNameSize - stack.name.length),
1883
+ style.label(stackName),
1884
+ " ".repeat(stackNameSize - stackName.length),
1760
1885
  " ",
1761
1886
  style.placeholder(symbol.pointerSmall),
1762
1887
  " ",
1763
1888
  style.warning(asset.resource),
1889
+ " ".repeat(resourceSize - asset.resource.length),
1764
1890
  " ",
1765
1891
  style.placeholder(symbol.pointerSmall),
1766
1892
  " ",
@@ -1791,19 +1917,20 @@ var assetBuilder = (assets) => {
1791
1917
  };
1792
1918
 
1793
1919
  // src/util/cleanup.ts
1794
- var import_promises5 = require("fs/promises");
1920
+ var import_promises6 = require("fs/promises");
1795
1921
  var cleanUp = async () => {
1796
1922
  debug("Clean up assembly & asset files");
1797
1923
  const paths = [
1798
1924
  assemblyDir,
1799
- functionDir
1925
+ assetDir,
1926
+ cacheDir
1800
1927
  ];
1801
- await Promise.all(paths.map((path) => (0, import_promises5.rm)(path, {
1928
+ await Promise.all(paths.map((path) => (0, import_promises6.rm)(path, {
1802
1929
  recursive: true,
1803
1930
  force: true,
1804
1931
  maxRetries: 2
1805
1932
  })));
1806
- await Promise.all(paths.map((path) => (0, import_promises5.mkdir)(path, {
1933
+ await Promise.all(paths.map((path) => (0, import_promises6.mkdir)(path, {
1807
1934
  recursive: true
1808
1935
  })));
1809
1936
  };
@@ -1927,7 +2054,7 @@ var StackClient = class {
1927
2054
  stack.Outputs?.forEach((output) => {
1928
2055
  outputs[output.OutputKey] = output.OutputValue;
1929
2056
  });
1930
- debug("Status for: ", style.info(name), "is", stack.StackStatus);
2057
+ debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
1931
2058
  return {
1932
2059
  status: stack.StackStatus,
1933
2060
  reason: stack.StackStatusReason,
@@ -2193,6 +2320,7 @@ var deploy = (program2) => {
2193
2320
  await cleanUp();
2194
2321
  await write(assetBuilder(assets));
2195
2322
  write(br());
2323
+ write(br());
2196
2324
  const donePublishing = write(loadingDialog("Publishing stack assets to AWS..."));
2197
2325
  await Promise.all(assets.map(async (_, assets2) => {
2198
2326
  await Promise.all(assets2.map(async (asset) => {
@@ -2208,21 +2336,28 @@ var deploy = (program2) => {
2208
2336
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
2209
2337
  write(br());
2210
2338
  write(stackTree(dependencyTree, statuses));
2339
+ write(br());
2211
2340
  const client = new StackClient(config2);
2212
2341
  const deploymentLine = createDeploymentLine(dependencyTree);
2213
2342
  for (const stacks of deploymentLine) {
2214
- await Promise.allSettled(stacks.map(async (stack) => {
2343
+ const results = await Promise.allSettled(stacks.map(async (stack) => {
2344
+ const signal = statuses[stack.artifactId];
2215
2345
  const stackArtifect = assembly.stacks.find((item) => item.id === stack.artifactId);
2216
- statuses[stack.artifactId].set(style.warning("deploying"));
2346
+ signal.set(style.warning("deploying"));
2217
2347
  try {
2218
2348
  await client.deploy(stackArtifect);
2219
2349
  } catch (error) {
2220
2350
  debugError(error);
2221
- statuses[stack.artifactId].set(style.error("failed"));
2351
+ signal.set(style.error("failed"));
2222
2352
  throw error;
2223
2353
  }
2224
- statuses[stack.artifactId].set(style.success("deployed"));
2354
+ signal.set(style.success("deployed"));
2225
2355
  }));
2356
+ for (const result of results) {
2357
+ if (result.status === "rejected") {
2358
+ throw result.reason;
2359
+ }
2360
+ }
2226
2361
  }
2227
2362
  doneDeploying("Done deploying stacks to AWS");
2228
2363
  });