@awsless/awsless 0.0.40 → 0.0.42

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
@@ -597,7 +597,7 @@ var createDeploymentLine = (stacks) => {
597
597
  depends: config?.depends?.map((dep) => dep.name) || []
598
598
  }));
599
599
  const names = stacks.map(({ stack }) => stack.name);
600
- const line = [];
600
+ const line2 = [];
601
601
  const deps = [];
602
602
  let limit = 100;
603
603
  while (deps.length < list3.length) {
@@ -612,9 +612,9 @@ var createDeploymentLine = (stacks) => {
612
612
  throw new Error(`Circular stack dependencies arn't allowed: ${circularNames}`);
613
613
  }
614
614
  deps.push(...local.map((stack) => stack.name));
615
- line.push(local);
615
+ line2.push(local);
616
616
  }
617
- return line;
617
+ return line2;
618
618
  };
619
619
 
620
620
  // src/plugins/cron/index.ts
@@ -624,23 +624,30 @@ import { z as z7 } from "zod";
624
624
  import { z } from "zod";
625
625
  import { awsCronExpressionValidator } from "aws-cron-expression-validator";
626
626
  var RateExpressionSchema = z.custom((value) => {
627
- return z.string().regex(/rate\([0-9]+ (seconds?|minutes?|hours?|days?)\)/).refine((rate) => {
628
- const [str] = rate.substring(5).split(" ");
627
+ return z.string().regex(/^[0-9]+ (seconds?|minutes?|hours?|days?)$/).refine((rate) => {
628
+ const [str] = rate.split(" ");
629
629
  const number = parseInt(str);
630
630
  return number > 0;
631
631
  }).safeParse(value).success;
632
- }, "Invalid rate expression");
632
+ }, { message: "Invalid rate expression" }).transform((rate) => {
633
+ const [str] = rate.split(" ");
634
+ const number = parseInt(str);
635
+ const more = rate.endsWith("s");
636
+ if (more && number === 1) {
637
+ return `rate(${rate.substring(0, rate.length - 1)})`;
638
+ }
639
+ return `rate(${rate})`;
640
+ });
633
641
  var CronExpressionSchema = z.custom((value) => {
634
- return z.string().startsWith("cron(").endsWith(")").safeParse(value).success;
635
- }, "Invalid cron expression").superRefine((value, ctx) => {
636
- const cron = value.substring(5, value.length - 1);
642
+ return z.string().safeParse(value).success;
643
+ }, { message: "Invalid cron expression" }).superRefine((value, ctx) => {
637
644
  try {
638
- awsCronExpressionValidator(cron);
645
+ awsCronExpressionValidator(value);
639
646
  } catch (error) {
640
647
  if (error instanceof Error) {
641
648
  ctx.addIssue({
642
649
  code: z.ZodIssueCode.custom,
643
- message: error.message
650
+ message: `Invalid cron expression: ${error.message}`
644
651
  });
645
652
  } else {
646
653
  ctx.addIssue({
@@ -649,6 +656,8 @@ var CronExpressionSchema = z.custom((value) => {
649
656
  });
650
657
  }
651
658
  }
659
+ }).transform((value) => {
660
+ return `cron(${value.trim()})`;
652
661
  });
653
662
  var ScheduleExpressionSchema = RateExpressionSchema.or(CronExpressionSchema);
654
663
 
@@ -712,7 +721,7 @@ function toDuration(duration) {
712
721
  return Duration.days(0);
713
722
  }
714
723
  var DurationSchema = z2.custom((value) => {
715
- return z2.string().regex(/[0-9]+ (seconds?|minutes?|hours?|days?)/).safeParse(value).success;
724
+ return z2.string().regex(/^[0-9]+ (seconds?|minutes?|hours?|days?)$/).safeParse(value).success;
716
725
  }, "Invalid duration").transform(toDuration);
717
726
  var durationMin = (min) => {
718
727
  return (duration) => {
@@ -739,7 +748,7 @@ var LocalFileSchema = z3.string().refine(async (path) => {
739
748
 
740
749
  // src/schema/resource-id.ts
741
750
  import { z as z4 } from "zod";
742
- var ResourceIdSchema = z4.string().min(3).max(24).regex(/[a-z\-]+/, "Invalid resource ID");
751
+ var ResourceIdSchema = z4.string().min(3).max(24).regex(/^[a-z\-]+$/, "Invalid resource ID");
743
752
 
744
753
  // src/schema/size.ts
745
754
  import { z as z5 } from "zod";
@@ -789,7 +798,7 @@ function toSize(size) {
789
798
  throw new TypeError(`Invalid size ${size}`);
790
799
  }
791
800
  var SizeSchema = z5.custom((value) => {
792
- return z5.string().regex(/[0-9]+ (KB|MB|GB)/).safeParse(value).success;
801
+ return z5.string().regex(/^[0-9]+ (KB|MB|GB)$/).safeParse(value).success;
793
802
  }, "Invalid size").transform(toSize);
794
803
  var sizeMin = (min) => {
795
804
  return (size) => {
@@ -1294,6 +1303,7 @@ import { InvokeOptions } from '@awsless/lambda'
1294
1303
  type Invoke<Name extends string, Func extends (...args: any[]) => any> = {
1295
1304
  name: Name
1296
1305
  (payload: Parameters<Func>[0], options?: Omit<InvokeOptions, 'name' | 'payload'>): ReturnType<Func>
1306
+ async: (payload: Parameters<Func>[0], options?: Omit<InvokeOptions, 'name' | 'payload' | 'type'>) => ReturnType<Func>
1297
1307
  }`;
1298
1308
  var functionPlugin = definePlugin({
1299
1309
  name: "function",
@@ -1455,7 +1465,7 @@ var cronPlugin = definePlugin({
1455
1465
  * crons: {
1456
1466
  * CRON_NAME: {
1457
1467
  * consumer: 'function.ts',
1458
- * schedule: 'rate(5 minutes)',
1468
+ * schedule: '5 minutes',
1459
1469
  * }
1460
1470
  * }
1461
1471
  * }
@@ -1464,8 +1474,8 @@ var cronPlugin = definePlugin({
1464
1474
  /** The consuming lambda function properties. */
1465
1475
  consumer: FunctionSchema,
1466
1476
  /** The scheduling expression.
1467
- * @example 'cron(0 20 * * ? *)'
1468
- * @example 'rate(5 minutes)'
1477
+ * @example '0 20 * * ? *'
1478
+ * @example '5 minutes'
1469
1479
  */
1470
1480
  schedule: ScheduleExpressionSchema,
1471
1481
  // Valid JSON passed to the consumer.
@@ -1607,6 +1617,8 @@ var SqsEventSource = class extends Group {
1607
1617
  };
1608
1618
 
1609
1619
  // src/plugins/queue.ts
1620
+ import { camelCase as camelCase3, constantCase as constantCase2 } from "change-case";
1621
+ import { relative as relative3 } from "path";
1610
1622
  var RetentionPeriodSchema = DurationSchema.refine(durationMin(Duration.minutes(1)), "Minimum retention period is 1 minute").refine(durationMax(Duration.days(14)), "Maximum retention period is 14 days");
1611
1623
  var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
1612
1624
  var DeliveryDelaySchema = DurationSchema.refine(durationMax(Duration.minutes(15)), "Maximum delivery delay is 15 minutes");
@@ -1616,11 +1628,14 @@ var BatchSizeSchema = z8.number().int().min(1, "Minimum batch size is 1").max(1e
1616
1628
  var MaxConcurrencySchema = z8.number().int().min(2, "Minimum max concurrency is 2").max(1e3, "Maximum max concurrency is 1000");
1617
1629
  var MaxBatchingWindow = DurationSchema.refine(durationMax(Duration.minutes(5)), "Maximum max batching window is 5 minutes");
1618
1630
  var typeGenCode2 = `
1619
- import { SendMessageOptions } from '@awsless/sqs'
1631
+ import { SendMessageOptions, SendMessageBatchOptions, BatchItem } from '@awsless/sqs'
1632
+
1633
+ type Payload<Func extends (...args: any[]) => any> = Parameters<Func>[0]['Records'][number]['body']
1620
1634
 
1621
- type Send<Name extends string> = {
1635
+ type Send<Name extends string, Func extends (...args: any[]) => any> = {
1622
1636
  name: Name
1623
- (payload: unknown, options?: Omit<SendMessageOptions, 'queue' | 'payload'>): Promise<void>
1637
+ batch(items:BatchItem<Payload<Func>>[], options?:Omit<SendMessageBatchOptions, 'queue' | 'items'>): Promise<void>
1638
+ (payload: Payload<Func>, options?: Omit<SendMessageOptions, 'queue' | 'payload'>): Promise<void>
1624
1639
  }`;
1625
1640
  var queuePlugin = definePlugin({
1626
1641
  name: "queue",
@@ -1726,9 +1741,13 @@ var queuePlugin = definePlugin({
1726
1741
  types2.addCode(typeGenCode2);
1727
1742
  for (const stack of config.stacks) {
1728
1743
  const list3 = new TypeObject();
1729
- for (const name of Object.keys(stack.queues || {})) {
1744
+ for (const [name, fileOrProps] of Object.entries(stack.queues || {})) {
1745
+ const varName = camelCase3(`${stack.name}-${name}`);
1730
1746
  const queueName = formatName(`${config.name}-${stack.name}-${name}`);
1731
- list3.addType(name, `Send<'${queueName}'>`);
1747
+ const file = typeof fileOrProps === "string" ? fileOrProps : typeof fileOrProps.consumer === "string" ? fileOrProps.consumer : fileOrProps.consumer.file;
1748
+ const relFile = relative3(directories.types, file);
1749
+ types2.addImport(varName, relFile);
1750
+ list3.addType(name, `Send<'${queueName}', typeof ${varName}>`);
1732
1751
  }
1733
1752
  types2.addType(stack.name, list3.toString());
1734
1753
  }
@@ -1753,6 +1772,7 @@ var queuePlugin = definePlugin({
1753
1772
  stack.add(queue2, lambda, source);
1754
1773
  bind((lambda2) => {
1755
1774
  lambda2.addPermissions(queue2.permissions);
1775
+ lambda2.addEnvironment(`QUEUE_${constantCase2(stack.name)}_${constantCase2(id)}_URL`, queue2.url);
1756
1776
  });
1757
1777
  }
1758
1778
  }
@@ -1762,7 +1782,7 @@ var queuePlugin = definePlugin({
1762
1782
  import { z as z9 } from "zod";
1763
1783
 
1764
1784
  // src/formation/resource/dynamodb/table.ts
1765
- import { constantCase as constantCase2 } from "change-case";
1785
+ import { constantCase as constantCase3 } from "change-case";
1766
1786
  var Table = class extends Resource {
1767
1787
  constructor(logicalId, props) {
1768
1788
  super("AWS::DynamoDB::Table", logicalId);
@@ -1835,7 +1855,7 @@ var Table = class extends Resource {
1835
1855
  return {
1836
1856
  TableName: this.name,
1837
1857
  BillingMode: "PAY_PER_REQUEST",
1838
- TableClass: constantCase2(this.props.class || "standard"),
1858
+ TableClass: constantCase3(this.props.class || "standard"),
1839
1859
  PointInTimeRecoverySpecification: {
1840
1860
  PointInTimeRecoveryEnabled: this.props.pointInTimeRecovery || false
1841
1861
  },
@@ -1846,7 +1866,7 @@ var Table = class extends Resource {
1846
1866
  AttributeDefinitions: this.attributeDefinitions(),
1847
1867
  ...this.props.stream ? {
1848
1868
  StreamSpecification: {
1849
- StreamViewType: constantCase2(this.props.stream)
1869
+ StreamViewType: constantCase3(this.props.stream)
1850
1870
  }
1851
1871
  } : {},
1852
1872
  ...this.props.timeToLiveAttribute ? {
@@ -1863,7 +1883,7 @@ var Table = class extends Resource {
1863
1883
  ...props.sort ? [{ KeyType: "RANGE", AttributeName: props.sort }] : []
1864
1884
  ],
1865
1885
  Projection: {
1866
- ProjectionType: constantCase2(props.projection || "all")
1886
+ ProjectionType: constantCase3(props.projection || "all")
1867
1887
  }
1868
1888
  }))
1869
1889
  } : {}
@@ -2402,7 +2422,7 @@ var toArray = (value) => {
2402
2422
  import { paramCase as paramCase3 } from "change-case";
2403
2423
 
2404
2424
  // src/formation/resource/appsync/graphql-api.ts
2405
- import { constantCase as constantCase3 } from "change-case";
2425
+ import { constantCase as constantCase4 } from "change-case";
2406
2426
  var GraphQLApi = class extends Resource {
2407
2427
  constructor(logicalId, props) {
2408
2428
  super("AWS::AppSync::GraphQLApi", logicalId);
@@ -2434,7 +2454,7 @@ var GraphQLApi = class extends Resource {
2434
2454
  properties() {
2435
2455
  return {
2436
2456
  Name: this.name,
2437
- AuthenticationType: constantCase3(this.props.authenticationType || "api-key"),
2457
+ AuthenticationType: constantCase4(this.props.authenticationType || "api-key"),
2438
2458
  AdditionalAuthenticationProviders: this.lambdaAuthProviders.map((provider) => ({
2439
2459
  AuthenticationType: "AWS_LAMBDA",
2440
2460
  LambdaAuthorizerConfig: {
@@ -2742,9 +2762,6 @@ export function response(ctx) {
2742
2762
  return ctx.result
2743
2763
  }
2744
2764
  `;
2745
- var ResolverFieldSchema = z14.custom((value) => {
2746
- return z14.string().regex(/([a-z0-9\_]+)(\s){1}([a-z0-9\_]+)/gi).safeParse(value).success;
2747
- }, `Invalid resolver field. Valid example: "Query list"`);
2748
2765
  var graphqlPlugin = definePlugin({
2749
2766
  name: "graphql",
2750
2767
  schema: z14.object({
@@ -2765,7 +2782,13 @@ var graphqlPlugin = definePlugin({
2765
2782
  LocalFileSchema,
2766
2783
  z14.array(LocalFileSchema).min(1)
2767
2784
  ]).optional(),
2768
- resolvers: z14.record(ResolverFieldSchema, FunctionSchema).optional()
2785
+ resolvers: z14.record(
2786
+ z14.string(),
2787
+ z14.record(
2788
+ z14.string(),
2789
+ FunctionSchema
2790
+ )
2791
+ ).optional()
2769
2792
  })).optional()
2770
2793
  }).array()
2771
2794
  }),
@@ -2830,17 +2853,18 @@ var graphqlPlugin = definePlugin({
2830
2853
  const { stack, stackConfig, bootstrap: bootstrap2 } = ctx;
2831
2854
  for (const [id, props] of Object.entries(stackConfig.graphql || {})) {
2832
2855
  const apiId = bootstrap2.import(`graphql-${id}`);
2833
- for (const [typeAndField, functionProps] of Object.entries(props.resolvers || {})) {
2834
- const [typeName, fieldName] = typeAndField.split(/[\s]+/g);
2835
- const entryId = paramCase3(`${id}-${typeName}-${fieldName}`);
2836
- const lambda = toLambdaFunction(ctx, `graphql-${entryId}`, functionProps);
2837
- const source = new AppsyncEventSource(entryId, lambda, {
2838
- apiId,
2839
- typeName,
2840
- fieldName,
2841
- code: Code2.fromInline(entryId, defaultResolver)
2842
- });
2843
- stack.add(lambda, source);
2856
+ for (const [typeName, fields] of Object.entries(props.resolvers || {})) {
2857
+ for (const [fieldName, functionProps] of Object.entries(fields || {})) {
2858
+ const entryId = paramCase3(`${id}-${typeName}-${fieldName}`);
2859
+ const lambda = toLambdaFunction(ctx, `graphql-${entryId}`, functionProps);
2860
+ const source = new AppsyncEventSource(entryId, lambda, {
2861
+ apiId,
2862
+ typeName,
2863
+ fieldName,
2864
+ code: Code2.fromInline(entryId, defaultResolver)
2865
+ });
2866
+ stack.add(lambda, source);
2867
+ }
2844
2868
  }
2845
2869
  }
2846
2870
  }
@@ -3516,7 +3540,7 @@ var LoadBalancer = class extends Resource {
3516
3540
  };
3517
3541
 
3518
3542
  // src/formation/resource/elb/listener.ts
3519
- import { constantCase as constantCase4 } from "change-case";
3543
+ import { constantCase as constantCase5 } from "change-case";
3520
3544
  var Listener = class extends Resource {
3521
3545
  constructor(logicalId, props) {
3522
3546
  super("AWS::ElasticLoadBalancingV2::Listener", logicalId);
@@ -3532,7 +3556,7 @@ var Listener = class extends Resource {
3532
3556
  return {
3533
3557
  LoadBalancerArn: this.props.loadBalancerArn,
3534
3558
  Port: this.props.port,
3535
- Protocol: constantCase4(this.props.protocol),
3559
+ Protocol: constantCase5(this.props.protocol),
3536
3560
  Certificates: this.props.certificates.map((arn) => ({
3537
3561
  CertificateArn: arn
3538
3562
  })),
@@ -3971,6 +3995,7 @@ var SubnetGroup = class extends Resource {
3971
3995
  };
3972
3996
 
3973
3997
  // src/plugins/cache.ts
3998
+ import { constantCase as constantCase6 } from "change-case";
3974
3999
  var TypeSchema = z19.enum([
3975
4000
  "t4g.small",
3976
4001
  "t4g.medium",
@@ -4023,7 +4048,7 @@ var cachePlugin = definePlugin({
4023
4048
  for (const stack of config.stacks) {
4024
4049
  const list3 = new TypeObject();
4025
4050
  for (const name of Object.keys(stack.caches || {})) {
4026
- list3.addType(name, `{ host: string, port:number }`);
4051
+ list3.addType(name, `{ host: string, port: number }`);
4027
4052
  }
4028
4053
  gen.addType(stack.name, list3.toString());
4029
4054
  }
@@ -4056,7 +4081,7 @@ var cachePlugin = definePlugin({
4056
4081
  }).dependsOn(subnetGroup, securityGroup);
4057
4082
  stack.add(subnetGroup, securityGroup, cluster);
4058
4083
  bind((lambda) => {
4059
- lambda.addEnvironment(`CACHE_${stack.name}_${id}_HOST`, cluster.address).addEnvironment(`CACHE_${stack.name}_${id}_PORT`, props.port.toString());
4084
+ lambda.addEnvironment(`CACHE_${constantCase6(stack.name)}_${constantCase6(id)}_HOST`, cluster.address).addEnvironment(`CACHE_${constantCase6(stack.name)}_${constantCase6(id)}_PORT`, props.port.toString());
4060
4085
  });
4061
4086
  }
4062
4087
  }
@@ -4383,7 +4408,7 @@ var AppSchema = z23.object({
4383
4408
  /** The deployment stage.
4384
4409
  * @default 'prod'
4385
4410
  */
4386
- stage: z23.string().regex(/[a-z]+/).default("prod"),
4411
+ stage: z23.string().regex(/^[a-z]+$/).default("prod"),
4387
4412
  /** Default properties. */
4388
4413
  defaults: z23.object({}).default({}),
4389
4414
  /** The application stacks. */
@@ -4489,6 +4514,14 @@ var watchFile = (path) => {
4489
4514
  };
4490
4515
 
4491
4516
  // src/config.ts
4517
+ import { z as z24 } from "zod";
4518
+ var ConfigError = class extends Error {
4519
+ constructor(error, data) {
4520
+ super(error.message);
4521
+ this.error = error;
4522
+ this.data = data;
4523
+ }
4524
+ };
4492
4525
  var importConfig = async (options) => {
4493
4526
  debug("Find the root directory");
4494
4527
  const configFile = options.configFile || "awsless.config.ts";
@@ -4510,7 +4543,15 @@ var importConfig = async (options) => {
4510
4543
  schema2 = schema2.and(plugin.schema);
4511
4544
  }
4512
4545
  }
4513
- const config = await schema2.parseAsync(appConfig);
4546
+ let config;
4547
+ try {
4548
+ config = await schema2.parseAsync(appConfig);
4549
+ } catch (error) {
4550
+ if (error instanceof z24.ZodError) {
4551
+ throw new ConfigError(error, appConfig);
4552
+ }
4553
+ throw error;
4554
+ }
4514
4555
  debug("Load credentials", style.info(config.profile));
4515
4556
  const credentials = getCredentials(config.profile);
4516
4557
  debug("Load AWS account ID");
@@ -4543,7 +4584,15 @@ var watchConfig = async function* (options) {
4543
4584
  schema2 = schema2.and(plugin.schema);
4544
4585
  }
4545
4586
  }
4546
- const config = await schema2.parseAsync(appConfig);
4587
+ let config;
4588
+ try {
4589
+ config = await schema2.parseAsync(appConfig);
4590
+ } catch (error) {
4591
+ if (error instanceof z24.ZodError) {
4592
+ throw new ConfigError(error, appConfig);
4593
+ }
4594
+ throw error;
4595
+ }
4547
4596
  debug("Load credentials", style.info(config.profile));
4548
4597
  const credentials = getCredentials(config.profile);
4549
4598
  debug("Load AWS account ID");
@@ -4668,11 +4717,11 @@ var dialog = (type, lines) => {
4668
4717
  const padding = 3;
4669
4718
  const icon = style[type](symbol[type].padEnd(padding));
4670
4719
  return (term) => {
4671
- term.out.write(lines.map((line, i) => {
4720
+ term.out.write(lines.map((line2, i) => {
4672
4721
  if (i === 0) {
4673
- return icon + wrapAnsi(line, term.out.width(), { hard: true });
4722
+ return icon + wrapAnsi(line2, term.out.width(), { hard: true });
4674
4723
  }
4675
- return wrapAnsi(" ".repeat(padding) + line, term.out.width(), { hard: true });
4724
+ return wrapAnsi(" ".repeat(padding) + line2, term.out.width(), { hard: true });
4676
4725
  }).join(br()) + br());
4677
4726
  };
4678
4727
  };
@@ -4995,6 +5044,86 @@ var logs = () => {
4995
5044
  };
4996
5045
  };
4997
5046
 
5047
+ // src/cli/ui/layout/zod-error.ts
5048
+ var line = (value, level = 0, highlight = false) => {
5049
+ return [
5050
+ highlight ? style.error(symbol.pointerSmall) + style.placeholder(" | ") : style.placeholder.dim(" | "),
5051
+ " ".repeat(level),
5052
+ value,
5053
+ br()
5054
+ ];
5055
+ };
5056
+ var format = (value) => {
5057
+ if (Array.isArray(value)) {
5058
+ return "[ ... ]";
5059
+ }
5060
+ if (value === null) {
5061
+ return "null";
5062
+ }
5063
+ switch (typeof value) {
5064
+ case "function":
5065
+ return "() => { ... }";
5066
+ case "bigint":
5067
+ return `${value}n`;
5068
+ case "symbol":
5069
+ return "Symbol()";
5070
+ case "object":
5071
+ return "{ ... }";
5072
+ case "undefined":
5073
+ case "string":
5074
+ case "number":
5075
+ case "boolean":
5076
+ return JSON.stringify(value);
5077
+ }
5078
+ return "";
5079
+ };
5080
+ var zodError = (error, data) => {
5081
+ return (term) => {
5082
+ for (const issue of error.issues) {
5083
+ term.out.gap();
5084
+ term.out.write(dialog("error", [
5085
+ style.error(issue.message)
5086
+ ]));
5087
+ term.out.gap();
5088
+ term.out.write(line("{"));
5089
+ let context = data;
5090
+ const inStack = issue.path[0] === "stacks" && typeof issue.path[1] === "number";
5091
+ const length2 = issue.path.length;
5092
+ const end = [];
5093
+ issue.path.forEach((path, i) => {
5094
+ const index = i + 1;
5095
+ context = context[path];
5096
+ if (typeof path === "string") {
5097
+ const key = path + `: `;
5098
+ if (index === length2) {
5099
+ const space = " ".repeat(key.length);
5100
+ const value = format(context);
5101
+ const error2 = "^".repeat(value.length);
5102
+ term.out.write(line(key + style.warning(value), index));
5103
+ term.out.write(line(space + style.error(error2), index, true));
5104
+ } else if (Array.isArray(context)) {
5105
+ term.out.write(line(key + "[", index));
5106
+ end.unshift(line("]", index));
5107
+ } else if (typeof context === "object") {
5108
+ if (inStack && index === 3) {
5109
+ const name = data.stacks[issue.path[1]].name;
5110
+ term.out.write(line("name: " + style.info(`"${name}"`) + ",", index));
5111
+ }
5112
+ term.out.write(line(key + "{", index));
5113
+ end.unshift(line("}", index));
5114
+ }
5115
+ } else if (typeof context === "object") {
5116
+ term.out.write(line("{", index));
5117
+ end.unshift(line("}", index));
5118
+ }
5119
+ });
5120
+ term.out.write(end);
5121
+ term.out.write(line("}"));
5122
+ term.out.gap();
5123
+ }
5124
+ };
5125
+ };
5126
+
4998
5127
  // src/cli/ui/layout/layout.ts
4999
5128
  var layout = async (cb) => {
5000
5129
  const term = createTerminal();
@@ -5010,7 +5139,9 @@ var layout = async (cb) => {
5010
5139
  await cb(config, term.out.write.bind(term.out), term);
5011
5140
  } catch (error) {
5012
5141
  term.out.gap();
5013
- if (error instanceof Error) {
5142
+ if (error instanceof ConfigError) {
5143
+ term.out.write(zodError(error.error, error.data));
5144
+ } else if (error instanceof Error) {
5014
5145
  term.out.write(dialog("error", [error.message]));
5015
5146
  } else if (typeof error === "string") {
5016
5147
  term.out.write(dialog("error", [error]));
@@ -5088,7 +5219,7 @@ var assetBuilder = (app) => {
5088
5219
  }
5089
5220
  const [icon, stop] = createSpinner();
5090
5221
  const details = new Signal({});
5091
- const line = flexLine(term, [
5222
+ const line2 = flexLine(term, [
5092
5223
  icon,
5093
5224
  " ",
5094
5225
  style.label(stack.name),
@@ -5112,7 +5243,7 @@ var assetBuilder = (app) => {
5112
5243
  }),
5113
5244
  br()
5114
5245
  ]);
5115
- group.update((group2) => [...group2, line]);
5246
+ group.update((group2) => [...group2, line2]);
5116
5247
  const timer = createTimer();
5117
5248
  try {
5118
5249
  const data = await asset.build({
@@ -5583,13 +5714,13 @@ var bootstrap = (program2) => {
5583
5714
 
5584
5715
  // src/cli/ui/complex/deployer.ts
5585
5716
  var stacksDeployer = (deploymentLine) => {
5586
- const stackNames = deploymentLine.map((line) => line.map((stack) => stack.name)).flat();
5717
+ const stackNames = deploymentLine.map((line2) => line2.map((stack) => stack.name)).flat();
5587
5718
  const stackNameSize = Math.max(...stackNames.map((name) => name.length));
5588
5719
  return (term) => {
5589
5720
  const ui = {};
5590
5721
  term.out.gap();
5591
5722
  for (const i in deploymentLine) {
5592
- const line = flexLine(
5723
+ const line2 = flexLine(
5593
5724
  term,
5594
5725
  [" "],
5595
5726
  [
@@ -5598,7 +5729,7 @@ var stacksDeployer = (deploymentLine) => {
5598
5729
  style.placeholder(" \u2500\u2500")
5599
5730
  ]
5600
5731
  );
5601
- term.out.write(line);
5732
+ term.out.write(line2);
5602
5733
  term.out.write(br());
5603
5734
  for (const stack of deploymentLine[i]) {
5604
5735
  const icon = new Signal(" ");
@@ -5778,8 +5909,8 @@ var deploy = (program2) => {
5778
5909
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
5779
5910
  const client = new StackClient(app, config.account, config.region, config.credentials);
5780
5911
  const ui = write(stacksDeployer(deploymentLine));
5781
- for (const line of deploymentLine) {
5782
- const results = await Promise.allSettled(line.map(async (stack) => {
5912
+ for (const line2 of deploymentLine) {
5913
+ const results = await Promise.allSettled(line2.map(async (stack) => {
5783
5914
  const item = ui[stack.name];
5784
5915
  item.start("deploying");
5785
5916
  try {
package/dist/index.cjs CHANGED
@@ -93,6 +93,14 @@ var Function = createProxy((stackName) => {
93
93
  });
94
94
  };
95
95
  call.name = name;
96
+ call.async = (payload, options = {}) => {
97
+ return (0, import_lambda.invoke)({
98
+ ...options,
99
+ type: "Event",
100
+ name,
101
+ payload
102
+ });
103
+ };
96
104
  return call;
97
105
  });
98
106
  });
@@ -125,25 +133,38 @@ var Topic = createProxy((topic) => {
125
133
 
126
134
  // src/node/queue.ts
127
135
  var import_sqs = require("@awsless/sqs");
136
+ var import_change_case2 = require("change-case");
128
137
  var getQueueName = getLocalResourceName;
138
+ var getQueueUrl = (name, stack = STACK) => {
139
+ return process.env[`QUEUE_${(0, import_change_case2.constantCase)(stack)}_${(0, import_change_case2.constantCase)(name)}_URL`];
140
+ };
129
141
  var Queue = createProxy((stack) => {
130
142
  return createProxy((queue) => {
131
- const name = getQueueName(queue, stack);
132
- const send = (payload, options) => {
143
+ const url = getQueueUrl(queue, stack);
144
+ const send = (payload, options = {}) => {
133
145
  return (0, import_sqs.sendMessage)({
134
146
  ...options,
135
- queue: name,
147
+ queue: url,
136
148
  payload
137
149
  });
138
150
  };
139
- send.name = name;
151
+ send.url = url;
152
+ send.name = getQueueName(queue, stack);
153
+ send.batch = (items, options = {}) => {
154
+ return (0, import_sqs.sendMessageBatch)({
155
+ ...options,
156
+ queue: url,
157
+ items
158
+ });
159
+ };
140
160
  return send;
141
161
  });
142
162
  });
143
163
 
144
164
  // src/node/cache.ts
165
+ var import_change_case3 = require("change-case");
145
166
  var getCacheProps = (name, stack = STACK) => {
146
- const prefix = `CACHE_${stack}_${name}`;
167
+ const prefix = `CACHE_${(0, import_change_case3.constantCase)(stack)}_${(0, import_change_case3.constantCase)(name)}`;
147
168
  return {
148
169
  host: process.env[`${prefix}_HOST`],
149
170
  port: parseInt(process.env[`${prefix}_PORT`], 10)
@@ -151,7 +172,12 @@ var getCacheProps = (name, stack = STACK) => {
151
172
  };
152
173
  var Cache = createProxy((stack) => {
153
174
  return createProxy((name) => {
154
- return getCacheProps(name, stack);
175
+ const call = () => {
176
+ };
177
+ const { host, port } = getCacheProps(name, stack);
178
+ call.host = host;
179
+ call.port = port;
180
+ return call;
155
181
  });
156
182
  });
157
183