@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.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,76 +382,54 @@ 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
- `;
385
+ // src/plugins/function/util/esbuild.ts
386
+ var import_esbuild = require("esbuild");
387
+ var import_crypto = require("crypto");
388
+ var import_path3 = require("path");
389
+ var import_promises2 = require("fs/promises");
424
390
  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
- });
391
+ const random = (0, import_crypto.randomUUID)();
392
+ const codeFile = (0, import_path3.join)(cacheDir, `${random}.mjs`);
393
+ const mapFile = (0, import_path3.join)(cacheDir, `${random}.mjs.map`);
394
+ await (0, import_esbuild.build)({
395
+ entryPoints: [file],
396
+ minify: true,
397
+ bundle: true,
398
+ external: [
399
+ "@aws-sdk/*",
400
+ "@aws-sdk",
401
+ "aws-sdk"
402
+ ],
403
+ sourcemap: "external",
404
+ target: "esnext",
405
+ treeShaking: true,
406
+ // jsxSideEffects:
407
+ format: "esm",
408
+ platform: "node",
409
+ outfile: codeFile
445
410
  });
411
+ const code = await (0, import_promises2.readFile)(codeFile, "utf8");
412
+ const map = await (0, import_promises2.readFile)(mapFile, "utf8");
413
+ await (0, import_promises2.rm)(codeFile);
414
+ await (0, import_promises2.rm)(mapFile);
415
+ const hash = (0, import_crypto.createHash)("sha1").update(code).digest("hex");
416
+ return {
417
+ handler: "index.default",
418
+ hash,
419
+ files: [
420
+ {
421
+ name: "index.mjs",
422
+ code,
423
+ map
424
+ }
425
+ ]
426
+ };
446
427
  };
447
428
 
448
429
  // src/plugins/function/util/build.ts
449
430
  var import_jszip = __toESM(require("jszip"), 1);
450
- var import_path3 = require("path");
451
- var import_promises2 = require("fs/promises");
431
+ var import_path5 = require("path");
432
+ var import_promises3 = require("fs/promises");
452
433
  var import_filesize = require("filesize");
453
434
  var zipFiles = (files) => {
454
435
  const zip = new import_jszip.default();
@@ -464,25 +445,25 @@ var zipFiles = (files) => {
464
445
  });
465
446
  };
466
447
  var writeBuildHash = async (config2, stack, id, hash) => {
467
- const funcPath = (0, import_path3.join)(functionDir, config2.name, stack.artifactId, id);
468
- const versionFile = (0, import_path3.join)(funcPath, "HASH");
469
- await (0, import_promises2.writeFile)(versionFile, hash);
448
+ const funcPath = (0, import_path5.join)(assetDir, "function", config2.name, stack.artifactId, id);
449
+ const versionFile = (0, import_path5.join)(funcPath, "HASH");
450
+ await (0, import_promises3.writeFile)(versionFile, hash);
470
451
  };
471
452
  var writeBuildFiles = async (config2, stack, id, files) => {
472
453
  const bundle = await zipFiles(files);
473
- const funcPath = (0, import_path3.join)(functionDir, config2.name, stack.artifactId, id);
474
- const filesPath = (0, import_path3.join)(funcPath, "files");
475
- const bundleFile = (0, import_path3.join)(funcPath, "bundle.zip");
476
- debug("Bundle size of", style.info((0, import_path3.join)(config2.name, stack.artifactId, id)), "is", style.attr((0, import_filesize.filesize)(bundle.byteLength)));
477
- await (0, import_promises2.mkdir)(filesPath, { recursive: true });
478
- await (0, import_promises2.writeFile)(bundleFile, bundle);
454
+ const funcPath = (0, import_path5.join)(assetDir, "function", config2.name, stack.artifactId, id);
455
+ const filesPath = (0, import_path5.join)(funcPath, "files");
456
+ const bundleFile = (0, import_path5.join)(funcPath, "bundle.zip");
457
+ debug("Bundle size of", style.info((0, import_path5.join)(config2.name, stack.artifactId, id)), "is", style.attr((0, import_filesize.filesize)(bundle.byteLength)));
458
+ await (0, import_promises3.mkdir)(filesPath, { recursive: true });
459
+ await (0, import_promises3.writeFile)(bundleFile, bundle);
479
460
  await Promise.all(files.map(async (file) => {
480
- const fileName = (0, import_path3.join)(filesPath, file.name);
481
- await (0, import_promises2.mkdir)((0, import_path3.basename)(fileName), { recursive: true });
482
- await (0, import_promises2.writeFile)(fileName, file.code);
461
+ const fileName = (0, import_path5.join)(filesPath, file.name);
462
+ await (0, import_promises3.mkdir)((0, import_path5.basename)(fileName), { recursive: true });
463
+ await (0, import_promises3.writeFile)(fileName, file.code);
483
464
  if (file.map) {
484
- const mapName = (0, import_path3.join)(filesPath, `${file.name}.map`);
485
- await (0, import_promises2.writeFile)(mapName, file.map);
465
+ const mapName = (0, import_path5.join)(filesPath, `${file.name}.map`);
466
+ await (0, import_promises3.writeFile)(mapName, file.map);
486
467
  }
487
468
  }));
488
469
  return {
@@ -492,8 +473,8 @@ var writeBuildFiles = async (config2, stack, id, files) => {
492
473
  };
493
474
 
494
475
  // src/plugins/function/util/publish.ts
495
- var import_path5 = require("path");
496
- var import_promises3 = require("fs/promises");
476
+ var import_path7 = require("path");
477
+ var import_promises4 = require("fs/promises");
497
478
  var import_client_s3 = require("@aws-sdk/client-s3");
498
479
 
499
480
  // src/stack/bootstrap.ts
@@ -533,11 +514,11 @@ var shouldDeployBootstrap = async (client, name) => {
533
514
  var publishFunctionAsset = async (config2, stack, id) => {
534
515
  const bucket = assetBucketName(config2);
535
516
  const key = `${config2.name}/${stack.artifactId}/function/${id}.zip`;
536
- const funcPath = (0, import_path5.join)(functionDir, config2.name, stack.artifactId, id);
537
- const bundleFile = (0, import_path5.join)(funcPath, "bundle.zip");
538
- const hashFile = (0, import_path5.join)(funcPath, "HASH");
539
- const hash = await (0, import_promises3.readFile)(hashFile, "utf8");
540
- const file = await (0, import_promises3.readFile)(bundleFile);
517
+ const funcPath = (0, import_path7.join)(assetDir, "function", config2.name, stack.artifactId, id);
518
+ const bundleFile = (0, import_path7.join)(funcPath, "bundle.zip");
519
+ const hashFile = (0, import_path7.join)(funcPath, "HASH");
520
+ const hash = await (0, import_promises4.readFile)(hashFile, "utf8");
521
+ const file = await (0, import_promises4.readFile)(bundleFile);
541
522
  const client = new import_client_s3.S3Client({
542
523
  credentials: config2.credentials,
543
524
  region: config2.region
@@ -623,7 +604,7 @@ var functionPlugin = definePlugin({
623
604
  });
624
605
  }
625
606
  });
626
- var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrProps) => {
607
+ var toFunction = ({ config: config2, stack, assets }, id, fileOrProps) => {
627
608
  const props = typeof fileOrProps === "string" ? { ...config2.defaults?.function, file: fileOrProps } : { ...config2.defaults?.function, ...fileOrProps };
628
609
  const lambda = new import_aws_lambda3.Function(stack, toId("function", id), {
629
610
  functionName: toName(stack, id),
@@ -634,14 +615,14 @@ var toFunction = ({ config: config2, stack, stackConfig, assets }, id, fileOrPro
634
615
  });
635
616
  lambda.addEnvironment("APP", config2.name, { removeInEdge: true });
636
617
  lambda.addEnvironment("STAGE", config2.stage, { removeInEdge: true });
637
- lambda.addEnvironment("STACK", stackConfig.name, { removeInEdge: true });
618
+ lambda.addEnvironment("STACK", stack.artifactId, { removeInEdge: true });
638
619
  if (lambda.runtime.toString().startsWith("nodejs")) {
639
620
  lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1", {
640
621
  removeInEdge: true
641
622
  });
642
623
  }
643
624
  assets.add({
644
- stack: stackConfig,
625
+ stackName: stack.artifactId,
645
626
  resource: "function",
646
627
  resourceName: id,
647
628
  async build() {
@@ -887,7 +868,6 @@ var import_zod18 = require("zod");
887
868
  var import_aws_sns = require("aws-cdk-lib/aws-sns");
888
869
  var import_aws_lambda_event_sources2 = require("aws-cdk-lib/aws-lambda-event-sources");
889
870
  var import_aws_cdk_lib4 = require("aws-cdk-lib");
890
- var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
891
871
  var topicPlugin = definePlugin({
892
872
  name: "topic",
893
873
  schema: import_zod18.z.object({
@@ -909,12 +889,6 @@ var topicPlugin = definePlugin({
909
889
  },
910
890
  onStack(ctx) {
911
891
  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
892
  return Object.entries(stackConfig.topics || {}).map(([id, props]) => {
919
893
  const lambda = toFunction(ctx, id, props);
920
894
  const topic = import_aws_sns.Topic.fromTopicArn(
@@ -927,6 +901,10 @@ var topicPlugin = definePlugin({
927
901
  }, stack)
928
902
  );
929
903
  lambda.addEventSource(new import_aws_lambda_event_sources2.SnsEventSource(topic));
904
+ bind((lambda2) => {
905
+ addResourceEnvironment(stack, "topic", id, lambda2);
906
+ topic.grantPublish(lambda2);
907
+ });
930
908
  return lambda;
931
909
  });
932
910
  }
@@ -935,7 +913,7 @@ var topicPlugin = definePlugin({
935
913
  // src/plugins/search.ts
936
914
  var import_zod19 = require("zod");
937
915
  var import_aws_opensearchserverless = require("aws-cdk-lib/aws-opensearchserverless");
938
- var import_aws_iam3 = require("aws-cdk-lib/aws-iam");
916
+ var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
939
917
  var searchPlugin = definePlugin({
940
918
  name: "search",
941
919
  schema: import_zod19.z.object({
@@ -950,7 +928,7 @@ var searchPlugin = definePlugin({
950
928
  type: "SEARCH"
951
929
  });
952
930
  bind((lambda) => {
953
- lambda.addToRolePolicy(new import_aws_iam3.PolicyStatement({
931
+ lambda.addToRolePolicy(new import_aws_iam2.PolicyStatement({
954
932
  actions: ["aoss:APIAccessAll"],
955
933
  resources: [collection.attrArn]
956
934
  }));
@@ -959,6 +937,138 @@ var searchPlugin = definePlugin({
959
937
  }
960
938
  });
961
939
 
940
+ // src/plugins/graphql/index.ts
941
+ var import_zod21 = require("zod");
942
+ var import_aws_appsync = require("aws-cdk-lib/aws-appsync");
943
+ var import_merge = require("@graphql-tools/merge");
944
+ var import_promises5 = require("fs/promises");
945
+
946
+ // src/util/array.ts
947
+ var toArray = (value) => {
948
+ if (Array.isArray(value)) {
949
+ return value;
950
+ }
951
+ return [value];
952
+ };
953
+
954
+ // src/plugins/graphql/index.ts
955
+ var import_path8 = require("path");
956
+ var import_graphql = require("graphql");
957
+ var import_change_case2 = require("change-case");
958
+
959
+ // src/plugins/graphql/schema/resolver-field.ts
960
+ var import_zod20 = require("zod");
961
+ var ResolverFieldSchema = import_zod20.z.custom((value) => {
962
+ return import_zod20.z.string().regex(/([a-z0-9\_]+)(\s){1}([a-z0-9\_]+)/gi).safeParse(value).success;
963
+ }, `Invalid resolver field. Valid example: "Query list"`);
964
+
965
+ // src/plugins/graphql/index.ts
966
+ var import_aws_cdk_lib5 = require("aws-cdk-lib");
967
+ var graphqlPlugin = definePlugin({
968
+ name: "graphql",
969
+ schema: import_zod21.z.object({
970
+ defaults: import_zod21.z.object({
971
+ graphql: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
972
+ authorization: import_zod21.z.object({
973
+ authorizer: FunctionSchema,
974
+ ttl: DurationSchema.default("1 hour")
975
+ }).optional(),
976
+ mappingTemplate: import_zod21.z.object({
977
+ request: LocalFileSchema.optional(),
978
+ response: LocalFileSchema.optional()
979
+ }).optional()
980
+ })).optional()
981
+ }).default({}),
982
+ stacks: import_zod21.z.object({
983
+ graphql: import_zod21.z.record(ResourceIdSchema, import_zod21.z.object({
984
+ schema: import_zod21.z.union([
985
+ LocalFileSchema,
986
+ import_zod21.z.array(LocalFileSchema).min(1)
987
+ ]).optional(),
988
+ resolvers: import_zod21.z.record(ResolverFieldSchema, FunctionSchema).optional()
989
+ })).optional()
990
+ }).array()
991
+ }),
992
+ onBootstrap({ config: config2, stack, assets }) {
993
+ const list3 = /* @__PURE__ */ new Set();
994
+ Object.values(config2.stacks).forEach((stackConfig) => {
995
+ Object.keys(stackConfig.graphql || {}).forEach((id) => {
996
+ list3.add(id);
997
+ });
998
+ });
999
+ list3.forEach((id) => {
1000
+ const file = (0, import_path8.join)(assetDir, "graphql", config2.name, id, "schema.graphql");
1001
+ const authorization = config2.defaults.graphql?.[id]?.authorization;
1002
+ const authProps = {};
1003
+ if (authorization) {
1004
+ const authorizer = toFunction({ config: config2, assets, stack }, `${id}-authorizer`, authorization.authorizer);
1005
+ authProps.additionalAuthenticationProviders = [{
1006
+ authenticationType: import_aws_appsync.AuthorizationType.LAMBDA,
1007
+ lambdaAuthorizerConfig: {
1008
+ authorizerUri: authorizer.functionArn,
1009
+ authorizerResultTtlInSeconds: authorization.ttl.toSeconds()
1010
+ }
1011
+ }];
1012
+ }
1013
+ const api = new import_aws_appsync.CfnGraphQLApi(stack, toId("graphql", id), {
1014
+ ...authProps,
1015
+ name: toName(stack, id),
1016
+ authenticationType: import_aws_appsync.AuthorizationType.API_KEY
1017
+ });
1018
+ new import_aws_cdk_lib5.CfnOutput(stack, toId("output", id), {
1019
+ exportName: toId("graphql", id),
1020
+ value: api.attrApiId
1021
+ });
1022
+ assets.add({
1023
+ stackName: stack.artifactId,
1024
+ resource: "schema",
1025
+ resourceName: id,
1026
+ async build() {
1027
+ const schemas = [];
1028
+ await Promise.all(Object.values(config2.stacks).map(async (stackConfig) => {
1029
+ const schemaFiles = toArray(stackConfig.graphql?.[id].schema || []);
1030
+ await Promise.all(schemaFiles.map(async (schemaFile) => {
1031
+ const schema3 = await (0, import_promises5.readFile)(schemaFile, "utf8");
1032
+ schemas.push(schema3);
1033
+ }));
1034
+ }));
1035
+ const schema2 = (0, import_graphql.print)((0, import_merge.mergeTypeDefs)(schemas));
1036
+ await (0, import_promises5.mkdir)((0, import_path8.dirname)(file), { recursive: true });
1037
+ await (0, import_promises5.writeFile)(file, schema2);
1038
+ new import_aws_appsync.CfnGraphQLSchema(stack, toId("schema", id), {
1039
+ apiId: api.attrApiId,
1040
+ definition: schema2
1041
+ });
1042
+ }
1043
+ });
1044
+ });
1045
+ },
1046
+ onStack(ctx) {
1047
+ const { config: config2, stack, stackConfig } = ctx;
1048
+ return Object.entries(stackConfig.graphql || {}).map(([id, props]) => {
1049
+ const defaults = config2.defaults.graphql?.[id] || {};
1050
+ return Object.entries(props.resolvers || {}).map(([typeAndField, functionProps]) => {
1051
+ const api = import_aws_appsync.GraphqlApi.fromGraphqlApiAttributes(stack, toId("graphql", id), {
1052
+ graphqlApiId: import_aws_cdk_lib5.Fn.importValue(toId("graphql", id))
1053
+ });
1054
+ const [typeName, fieldName] = typeAndField.split(/[\s]+/g);
1055
+ const functionId = (0, import_change_case2.paramCase)(`${id}-${typeName}-${fieldName}`);
1056
+ const lambda = toFunction(ctx, functionId, functionProps);
1057
+ const source = api.addLambdaDataSource(toId("data-source", functionId), lambda, {
1058
+ name: toId("data-source", functionId)
1059
+ });
1060
+ source.createResolver(toId("resolver", functionId), {
1061
+ typeName,
1062
+ fieldName,
1063
+ requestMappingTemplate: defaults.mappingTemplate?.request ? import_aws_appsync.MappingTemplate.fromFile(defaults.mappingTemplate.request) : import_aws_appsync.MappingTemplate.lambdaRequest(),
1064
+ responseMappingTemplate: defaults.mappingTemplate?.response ? import_aws_appsync.MappingTemplate.fromFile(defaults.mappingTemplate.response) : import_aws_appsync.MappingTemplate.lambdaResult()
1065
+ });
1066
+ return lambda;
1067
+ });
1068
+ }).flat();
1069
+ }
1070
+ });
1071
+
962
1072
  // src/plugins/index.ts
963
1073
  var defaultPlugins = [
964
1074
  functionPlugin,
@@ -967,12 +1077,13 @@ var defaultPlugins = [
967
1077
  tablePlugin,
968
1078
  storePlugin,
969
1079
  topicPlugin,
970
- searchPlugin
1080
+ searchPlugin,
1081
+ graphqlPlugin
971
1082
  ];
972
1083
 
973
1084
  // src/stack/app-bootstrap.ts
974
1085
  var appBootstrapStack = ({ config: config2, app, assets }) => {
975
- const stack = new import_aws_cdk_lib5.Stack(app, "bootstrap", {
1086
+ const stack = new import_aws_cdk_lib6.Stack(app, "bootstrap", {
976
1087
  stackName: `${config2.name}-bootstrap`
977
1088
  });
978
1089
  const plugins = [
@@ -980,8 +1091,16 @@ var appBootstrapStack = ({ config: config2, app, assets }) => {
980
1091
  ...config2.plugins || []
981
1092
  ];
982
1093
  debug("Run plugin onBootstrap listeners");
983
- plugins.forEach((plugin) => plugin.onBootstrap?.({ config: config2, stack, app, assets }));
984
- return stack;
1094
+ const functions = plugins.map((plugin) => plugin.onBootstrap?.({
1095
+ config: config2,
1096
+ app,
1097
+ stack,
1098
+ assets
1099
+ })).filter(Boolean).flat().filter(Boolean);
1100
+ return {
1101
+ stack,
1102
+ functions
1103
+ };
985
1104
  };
986
1105
 
987
1106
  // src/util/deployment.ts
@@ -1047,10 +1166,10 @@ var Assets = class {
1047
1166
  assets = {};
1048
1167
  id = 0;
1049
1168
  add(opts) {
1050
- if (!this.assets[opts.stack.name]) {
1051
- this.assets[opts.stack.name] = [];
1169
+ if (!this.assets[opts.stackName]) {
1170
+ this.assets[opts.stackName] = [];
1052
1171
  }
1053
- this.assets[opts.stack.name].push({
1172
+ this.assets[opts.stackName].push({
1054
1173
  ...opts,
1055
1174
  id: this.id++
1056
1175
  });
@@ -1060,21 +1179,21 @@ var Assets = class {
1060
1179
  }
1061
1180
  forEach(cb) {
1062
1181
  Object.values(this.assets).forEach((assets) => {
1063
- cb(assets[0].stack, assets);
1182
+ cb(assets[0].stackName, assets);
1064
1183
  });
1065
1184
  }
1066
1185
  map(cb) {
1067
1186
  return Object.values(this.assets).map((assets) => {
1068
- return cb(assets[0].stack, assets);
1187
+ return cb(assets[0].stackName, assets);
1069
1188
  });
1070
1189
  }
1071
1190
  };
1072
1191
 
1073
1192
  // src/app.ts
1074
1193
  var makeApp = (config2) => {
1075
- return new import_aws_cdk_lib6.App({
1194
+ return new import_aws_cdk_lib7.App({
1076
1195
  outdir: assemblyDir,
1077
- defaultStackSynthesizer: new import_aws_cdk_lib6.DefaultStackSynthesizer({
1196
+ defaultStackSynthesizer: new import_aws_cdk_lib7.DefaultStackSynthesizer({
1078
1197
  fileAssetsBucketName: assetBucketName(config2),
1079
1198
  fileAssetPublishingRoleArn: "",
1080
1199
  generateBootstrapVersionRule: false
@@ -1103,13 +1222,14 @@ var toApp = async (config2, filters) => {
1103
1222
  debug("Plugins detected:", plugins.map((plugin) => style.info(plugin.name)).join(", "));
1104
1223
  debug("Run plugin onApp listeners");
1105
1224
  plugins.forEach((plugin) => plugin.onApp?.({ config: config2, app, assets }));
1225
+ const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1106
1226
  debug("Stack filters:", filters.map((filter) => style.info(filter)).join(", "));
1107
1227
  const filterdStacks = filters.length === 0 ? config2.stacks : getAllDepends(
1108
1228
  // config.stacks,
1109
1229
  config2.stacks.filter((stack) => filters.includes(stack.name))
1110
1230
  );
1111
1231
  for (const stackConfig of filterdStacks) {
1112
- const { stack } = toStack({
1232
+ const { stack, bindings } = toStack({
1113
1233
  config: config2,
1114
1234
  stackConfig,
1115
1235
  assets,
@@ -1117,14 +1237,14 @@ var toApp = async (config2, filters) => {
1117
1237
  app
1118
1238
  });
1119
1239
  stacks.push({ stack, config: stackConfig });
1240
+ bindings.forEach((cb) => bootstrap2.functions.forEach(cb));
1120
1241
  }
1121
1242
  let dependencyTree;
1122
- const bootstrap2 = appBootstrapStack({ config: config2, app, assets });
1123
- if (bootstrap2.node.children.length === 0) {
1243
+ if (bootstrap2.stack.node.children.length === 0) {
1124
1244
  dependencyTree = createDependencyTree(stacks, 0);
1125
1245
  } else {
1126
1246
  dependencyTree = [{
1127
- stack: bootstrap2,
1247
+ stack: bootstrap2.stack,
1128
1248
  level: 0,
1129
1249
  children: createDependencyTree(stacks, 1)
1130
1250
  }];
@@ -1196,7 +1316,7 @@ var footer = () => {
1196
1316
  };
1197
1317
 
1198
1318
  // src/config.ts
1199
- var import_path9 = require("path");
1319
+ var import_path13 = require("path");
1200
1320
 
1201
1321
  // src/util/account.ts
1202
1322
  var import_client_sts = require("@aws-sdk/client-sts");
@@ -1215,17 +1335,17 @@ var getCredentials = (profile) => {
1215
1335
  };
1216
1336
 
1217
1337
  // src/schema/app.ts
1218
- var import_zod23 = require("zod");
1338
+ var import_zod25 = require("zod");
1219
1339
 
1220
1340
  // src/schema/stack.ts
1221
- var import_zod20 = require("zod");
1222
- var StackSchema = import_zod20.z.object({
1341
+ var import_zod22 = require("zod");
1342
+ var StackSchema = import_zod22.z.object({
1223
1343
  name: ResourceIdSchema,
1224
- depends: import_zod20.z.array(import_zod20.z.lazy(() => StackSchema)).optional()
1344
+ depends: import_zod22.z.array(import_zod22.z.lazy(() => StackSchema)).optional()
1225
1345
  });
1226
1346
 
1227
1347
  // src/schema/region.ts
1228
- var import_zod21 = require("zod");
1348
+ var import_zod23 = require("zod");
1229
1349
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1230
1350
  var AF = ["af-south-1"];
1231
1351
  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 +1362,35 @@ var regions = [
1242
1362
  ...ME,
1243
1363
  ...SA
1244
1364
  ];
1245
- var RegionSchema = import_zod21.z.enum(regions);
1365
+ var RegionSchema = import_zod23.z.enum(regions);
1246
1366
 
1247
1367
  // 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()
1368
+ var import_zod24 = require("zod");
1369
+ var PluginSchema = import_zod24.z.object({
1370
+ name: import_zod24.z.string(),
1371
+ schema: import_zod24.z.custom().optional(),
1372
+ // depends: z.array(z.lazy(() => PluginSchema)).optional(),
1373
+ onBootstrap: import_zod24.z.function().returns(import_zod24.z.any()).optional(),
1374
+ onStack: import_zod24.z.function().returns(import_zod24.z.any()).optional(),
1375
+ onApp: import_zod24.z.function().returns(import_zod24.z.void()).optional()
1256
1376
  // bind: z.function().optional(),
1257
1377
  });
1258
1378
 
1259
1379
  // src/schema/app.ts
1260
- var AppSchema = import_zod23.z.object({
1380
+ var AppSchema = import_zod25.z.object({
1261
1381
  name: ResourceIdSchema,
1262
1382
  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()
1383
+ profile: import_zod25.z.string(),
1384
+ stage: import_zod25.z.string().regex(/[a-z]+/).default("prod"),
1385
+ defaults: import_zod25.z.object({}).default({}),
1386
+ stacks: import_zod25.z.array(StackSchema).min(1),
1387
+ plugins: import_zod25.z.array(PluginSchema).optional()
1268
1388
  });
1269
1389
 
1270
1390
  // src/util/import.ts
1271
1391
  var import_core3 = require("@swc/core");
1272
- var import_path7 = require("path");
1273
- var import_promises4 = require("fs/promises");
1392
+ var import_path11 = require("path");
1393
+ var import_promises6 = require("fs/promises");
1274
1394
  var resolveFileNameExtension = async (path) => {
1275
1395
  const options = [
1276
1396
  "",
@@ -1283,7 +1403,7 @@ var resolveFileNameExtension = async (path) => {
1283
1403
  const file = path + option;
1284
1404
  let stat;
1285
1405
  try {
1286
- stat = await (0, import_promises4.lstat)(file);
1406
+ stat = await (0, import_promises6.lstat)(file);
1287
1407
  } catch (error) {
1288
1408
  continue;
1289
1409
  }
@@ -1294,14 +1414,14 @@ var resolveFileNameExtension = async (path) => {
1294
1414
  throw new Error(`Failed to load file: ${path}`);
1295
1415
  };
1296
1416
  var resolveDir = (path) => {
1297
- return (0, import_path7.dirname)(path).replace(rootDir + "/", "");
1417
+ return (0, import_path11.dirname)(path).replace(rootDir + "/", "");
1298
1418
  };
1299
1419
  var importFile = async (path) => {
1300
1420
  const load = async (file) => {
1301
1421
  let { code: code2 } = await (0, import_core3.transformFile)(file, {
1302
1422
  isModule: true
1303
1423
  });
1304
- const path2 = (0, import_path7.dirname)(file);
1424
+ const path2 = (0, import_path11.dirname)(file);
1305
1425
  const dir = resolveDir(file);
1306
1426
  code2 = code2.replaceAll("__dirname", `"${dir}"`);
1307
1427
  const matches = code2.match(/import\s*{\s*[a-z0-9\_]+\s*}\s*from\s*('|")(\.[\/a-z0-9\_\-]+)('|");?/ig);
@@ -1310,23 +1430,23 @@ var importFile = async (path) => {
1310
1430
  await Promise.all(matches?.map(async (match) => {
1311
1431
  const parts = /('|")(\.[\/a-z0-9\_\-]+)('|")/ig.exec(match);
1312
1432
  const from = parts[2];
1313
- const file2 = await resolveFileNameExtension((0, import_path7.join)(path2, from));
1433
+ const file2 = await resolveFileNameExtension((0, import_path11.join)(path2, from));
1314
1434
  const result = await load(file2);
1315
1435
  code2 = code2.replace(match, result);
1316
1436
  }));
1317
1437
  return code2;
1318
1438
  };
1319
1439
  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);
1440
+ const outputFile = (0, import_path11.join)(outDir, "config.js");
1441
+ await (0, import_promises6.mkdir)(outDir, { recursive: true });
1442
+ await (0, import_promises6.writeFile)(outputFile, code);
1323
1443
  return import(outputFile);
1324
1444
  };
1325
1445
 
1326
1446
  // src/config.ts
1327
1447
  var importConfig = async (options) => {
1328
1448
  debug("Import config file");
1329
- const fileName = (0, import_path9.join)(process.cwd(), options.configFile || "awsless.config.ts");
1449
+ const fileName = (0, import_path13.join)(process.cwd(), options.configFile || "awsless.config.ts");
1330
1450
  const module2 = await importFile(fileName);
1331
1451
  const appConfig = typeof module2.default === "function" ? await module2.default({
1332
1452
  profile: options.profile,
@@ -1540,6 +1660,13 @@ var Interface = class {
1540
1660
  if (this.input.isTTY) {
1541
1661
  this.input.setRawMode(true);
1542
1662
  }
1663
+ this.input.on("keypress", (_, key) => {
1664
+ const action = parseAction(key);
1665
+ if (action === "abort") {
1666
+ this.unref();
1667
+ process.exit(1);
1668
+ }
1669
+ });
1543
1670
  }
1544
1671
  // private subscriber: Actions | undefined
1545
1672
  readline;
@@ -1689,12 +1816,6 @@ var layout = async (cb) => {
1689
1816
  const term = createTerminal();
1690
1817
  term.out.clear();
1691
1818
  term.out.write(logo());
1692
- term.in.captureInput({
1693
- abort: () => {
1694
- term.in.showCursor();
1695
- process.exit(1);
1696
- }
1697
- });
1698
1819
  try {
1699
1820
  const options = program.optsWithGlobals();
1700
1821
  const config2 = await importConfig(options);
@@ -1715,7 +1836,7 @@ var layout = async (cb) => {
1715
1836
  term.in.unref();
1716
1837
  setTimeout(() => {
1717
1838
  process.exit(0);
1718
- }, 50);
1839
+ }, 100);
1719
1840
  }
1720
1841
  };
1721
1842
 
@@ -1746,7 +1867,8 @@ var assetBuilder = (assets) => {
1746
1867
  const groups = new Signal([br()]);
1747
1868
  term.out.write(groups);
1748
1869
  const stackNameSize = Math.max(...Object.keys(assets.list()).map((stack) => stack.length));
1749
- await Promise.all(assets.map(async (stack, assets2) => {
1870
+ const resourceSize = Math.max(...Object.values(assets.list()).map((assets2) => assets2.map((asset) => asset.resource.length)).flat());
1871
+ await Promise.all(assets.map(async (stackName, assets2) => {
1750
1872
  const group = new Signal([]);
1751
1873
  groups.update((groups2) => [...groups2, group]);
1752
1874
  await Promise.all(assets2.map(async (asset) => {
@@ -1755,12 +1877,13 @@ var assetBuilder = (assets) => {
1755
1877
  const line = flexLine(term, [
1756
1878
  icon,
1757
1879
  " ",
1758
- style.label(stack.name),
1759
- " ".repeat(stackNameSize - stack.name.length),
1880
+ style.label(stackName),
1881
+ " ".repeat(stackNameSize - stackName.length),
1760
1882
  " ",
1761
1883
  style.placeholder(symbol.pointerSmall),
1762
1884
  " ",
1763
1885
  style.warning(asset.resource),
1886
+ " ".repeat(resourceSize - asset.resource.length),
1764
1887
  " ",
1765
1888
  style.placeholder(symbol.pointerSmall),
1766
1889
  " ",
@@ -1791,25 +1914,26 @@ var assetBuilder = (assets) => {
1791
1914
  };
1792
1915
 
1793
1916
  // src/util/cleanup.ts
1794
- var import_promises5 = require("fs/promises");
1917
+ var import_promises7 = require("fs/promises");
1795
1918
  var cleanUp = async () => {
1796
1919
  debug("Clean up assembly & asset files");
1797
1920
  const paths = [
1798
1921
  assemblyDir,
1799
- functionDir
1922
+ assetDir,
1923
+ cacheDir
1800
1924
  ];
1801
- await Promise.all(paths.map((path) => (0, import_promises5.rm)(path, {
1925
+ await Promise.all(paths.map((path) => (0, import_promises7.rm)(path, {
1802
1926
  recursive: true,
1803
1927
  force: true,
1804
1928
  maxRetries: 2
1805
1929
  })));
1806
- await Promise.all(paths.map((path) => (0, import_promises5.mkdir)(path, {
1930
+ await Promise.all(paths.map((path) => (0, import_promises7.mkdir)(path, {
1807
1931
  recursive: true
1808
1932
  })));
1809
1933
  };
1810
1934
 
1811
1935
  // src/cli/command/build.ts
1812
- var build = (program2) => {
1936
+ var build2 = (program2) => {
1813
1937
  program2.command("build").argument("[stack...]", "Optionally filter stacks to build").description("Build your app").action(async (filters) => {
1814
1938
  await layout(async (config2, write) => {
1815
1939
  const { app, assets } = await toApp(config2, filters);
@@ -1927,7 +2051,7 @@ var StackClient = class {
1927
2051
  stack.Outputs?.forEach((output) => {
1928
2052
  outputs[output.OutputKey] = output.OutputValue;
1929
2053
  });
1930
- debug("Status for: ", style.info(name), "is", stack.StackStatus);
2054
+ debug("Status for:", style.info(name), "is", style.attr(stack.StackStatus));
1931
2055
  return {
1932
2056
  status: stack.StackStatus,
1933
2057
  reason: stack.StackStatusReason,
@@ -2193,6 +2317,7 @@ var deploy = (program2) => {
2193
2317
  await cleanUp();
2194
2318
  await write(assetBuilder(assets));
2195
2319
  write(br());
2320
+ write(br());
2196
2321
  const donePublishing = write(loadingDialog("Publishing stack assets to AWS..."));
2197
2322
  await Promise.all(assets.map(async (_, assets2) => {
2198
2323
  await Promise.all(assets2.map(async (asset) => {
@@ -2208,21 +2333,28 @@ var deploy = (program2) => {
2208
2333
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
2209
2334
  write(br());
2210
2335
  write(stackTree(dependencyTree, statuses));
2336
+ write(br());
2211
2337
  const client = new StackClient(config2);
2212
2338
  const deploymentLine = createDeploymentLine(dependencyTree);
2213
2339
  for (const stacks of deploymentLine) {
2214
- await Promise.allSettled(stacks.map(async (stack) => {
2340
+ const results = await Promise.allSettled(stacks.map(async (stack) => {
2341
+ const signal = statuses[stack.artifactId];
2215
2342
  const stackArtifect = assembly.stacks.find((item) => item.id === stack.artifactId);
2216
- statuses[stack.artifactId].set(style.warning("deploying"));
2343
+ signal.set(style.warning("deploying"));
2217
2344
  try {
2218
2345
  await client.deploy(stackArtifect);
2219
2346
  } catch (error) {
2220
2347
  debugError(error);
2221
- statuses[stack.artifactId].set(style.error("failed"));
2348
+ signal.set(style.error("failed"));
2222
2349
  throw error;
2223
2350
  }
2224
- statuses[stack.artifactId].set(style.success("deployed"));
2351
+ signal.set(style.success("deployed"));
2225
2352
  }));
2353
+ for (const result of results) {
2354
+ if (result.status === "rejected") {
2355
+ throw result.reason;
2356
+ }
2357
+ }
2226
2358
  }
2227
2359
  doneDeploying("Done deploying stacks to AWS");
2228
2360
  });
@@ -2397,7 +2529,7 @@ program.on("option:verbose", () => {
2397
2529
  var commands2 = [
2398
2530
  bootstrap,
2399
2531
  status,
2400
- build,
2532
+ build2,
2401
2533
  deploy,
2402
2534
  config
2403
2535
  // diff,