@awsless/awsless 0.0.18 → 0.0.20

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.
Files changed (4) hide show
  1. package/dist/bin.cjs +548 -175
  2. package/dist/bin.js +549 -176
  3. package/dist/index.d.ts +441 -18
  4. package/package.json +3 -1
package/dist/bin.js CHANGED
@@ -171,6 +171,12 @@ var formatLogicalId = (id) => {
171
171
  var formatName = (name) => {
172
172
  return paramCase2(name);
173
173
  };
174
+ var formatArn = (props) => {
175
+ return sub("arn:${AWS::Partition}:${service}:${AWS::Region}:${AWS::AccountId}:${resource}${seperator}${resourceName}", {
176
+ seperator: "/",
177
+ ...props
178
+ });
179
+ };
174
180
 
175
181
  // src/formation/resource.ts
176
182
  var Resource = class {
@@ -180,13 +186,19 @@ var Resource = class {
180
186
  this.logicalId = formatLogicalId(`${logicalId}-${type.replace(/^AWS::/, "")}`);
181
187
  }
182
188
  logicalId;
189
+ tags = /* @__PURE__ */ new Map();
183
190
  deps = /* @__PURE__ */ new Set();
191
+ stack;
184
192
  dependsOn(...dependencies) {
185
193
  for (const dependency of dependencies) {
186
194
  this.deps.add(dependency);
187
195
  }
188
196
  return this;
189
197
  }
198
+ tag(key, value) {
199
+ this.tags.set(key, value);
200
+ return this;
201
+ }
190
202
  attr(name, value) {
191
203
  if (typeof value === "undefined") {
192
204
  return {};
@@ -195,12 +207,41 @@ var Resource = class {
195
207
  [name]: value
196
208
  };
197
209
  }
210
+ setStack(stack) {
211
+ this.stack = stack;
212
+ return this;
213
+ }
214
+ ref() {
215
+ return this.getAtt("ref");
216
+ }
217
+ getAtt(attr) {
218
+ return new Lazy((stack) => {
219
+ if (!this.stack) {
220
+ throw new TypeError("Resource stack not defined before building template");
221
+ }
222
+ const value = attr === "ref" ? ref(this.logicalId) : getAtt(this.logicalId, attr);
223
+ if (stack === this.stack) {
224
+ return value;
225
+ }
226
+ const name = `${this.stack.name}-${this.logicalId}-${attr}`;
227
+ this.stack.export(name, value);
228
+ return this.stack.import(name);
229
+ });
230
+ }
198
231
  toJSON() {
199
232
  return {
200
233
  [this.logicalId]: {
201
234
  Type: this.type,
202
235
  DependsOn: [...this.deps].map((dep) => dep.logicalId),
203
- Properties: this.properties()
236
+ Properties: {
237
+ ...this.tags.size ? {
238
+ Tags: Array.from(this.tags.entries()).map(([key, value]) => ({
239
+ Key: key,
240
+ Value: value
241
+ }))
242
+ } : {},
243
+ ...this.properties()
244
+ }
204
245
  }
205
246
  };
206
247
  }
@@ -210,6 +251,11 @@ var Group = class {
210
251
  this.children = children;
211
252
  }
212
253
  };
254
+ var Lazy = class {
255
+ constructor(callback) {
256
+ this.callback = callback;
257
+ }
258
+ };
213
259
 
214
260
  // src/formation/resource/iam/inline-policy.ts
215
261
  var InlinePolicy = class {
@@ -315,6 +361,7 @@ var Function = class extends Resource {
315
361
  this.policy = policy;
316
362
  this.name = formatName(this.props.name || logicalId);
317
363
  this.environmentVariables = props.environment ? { ...props.environment } : {};
364
+ this.tag("name", this.name);
318
365
  }
319
366
  name;
320
367
  role;
@@ -328,11 +375,15 @@ var Function = class extends Resource {
328
375
  this.environmentVariables[name] = value;
329
376
  return this;
330
377
  }
378
+ setVpc(vpc) {
379
+ this.props.vpc = vpc;
380
+ return this;
381
+ }
331
382
  get id() {
332
- return ref(this.logicalId);
383
+ return this.ref();
333
384
  }
334
385
  get arn() {
335
- return getAtt(this.logicalId, "Arn");
386
+ return this.getAtt("Arn");
336
387
  }
337
388
  get permissions() {
338
389
  return {
@@ -340,7 +391,14 @@ var Function = class extends Resource {
340
391
  "lambda:InvokeFunction",
341
392
  "lambda:InvokeAsync"
342
393
  ],
343
- resources: [this.arn]
394
+ resources: [
395
+ formatArn({
396
+ service: "lambda",
397
+ resource: "function",
398
+ resourceName: this.name,
399
+ seperator: ":"
400
+ })
401
+ ]
344
402
  };
345
403
  }
346
404
  properties() {
@@ -351,10 +409,17 @@ var Function = class extends Resource {
351
409
  Timeout: this.props.timeout?.toSeconds() ?? 10,
352
410
  Architectures: [this.props.architecture ?? "arm64"],
353
411
  Role: this.role.arn,
412
+ ...this.attr("ReservedConcurrentExecutions", this.props.reserved),
354
413
  ...this.props.code.toCodeJson(),
355
414
  EphemeralStorage: {
356
415
  Size: this.props.ephemeralStorageSize?.toMegaBytes() ?? 512
357
416
  },
417
+ ...this.props.vpc ? {
418
+ VpcConfig: {
419
+ SecurityGroupIds: this.props.vpc.securityGroupIds,
420
+ SubnetIds: this.props.vpc.subnetIds
421
+ }
422
+ } : {},
358
423
  Environment: {
359
424
  Variables: this.environmentVariables
360
425
  }
@@ -379,6 +444,7 @@ var Stack = class {
379
444
  } else {
380
445
  this.add(...item.children);
381
446
  if (item instanceof Resource) {
447
+ item.setStack(this);
382
448
  this.resources.add(item);
383
449
  }
384
450
  }
@@ -422,8 +488,24 @@ var Stack = class {
422
488
  toJSON() {
423
489
  const resources = {};
424
490
  const outputs = {};
491
+ const walk = (object) => {
492
+ for (const [key, value] of Object.entries(object)) {
493
+ if (!object.hasOwnProperty(key)) {
494
+ continue;
495
+ }
496
+ if (value instanceof Lazy) {
497
+ object[key] = value.callback(this);
498
+ continue;
499
+ }
500
+ if (typeof value === "object" && value !== null) {
501
+ walk(value);
502
+ }
503
+ }
504
+ };
425
505
  for (const resource of this) {
426
- Object.assign(resources, resource.toJSON());
506
+ const json2 = resource.toJSON();
507
+ walk(json2);
508
+ Object.assign(resources, json2);
427
509
  }
428
510
  for (const [name, value] of this.exports.entries()) {
429
511
  Object.assign(outputs, {
@@ -491,54 +573,33 @@ var toStack = ({ config, app, stackConfig, bootstrap: bootstrap2, usEastBootstra
491
573
  }
492
574
  return {
493
575
  stack,
494
- depends: stackConfig.depends
576
+ bindings
577
+ // depends: stackConfig.depends,
495
578
  };
496
579
  };
497
580
 
498
581
  // src/util/deployment.ts
499
- var createDependencyTree = (stacks) => {
582
+ var createDeploymentLine = (stacks) => {
500
583
  const list3 = stacks.map(({ stack, config }) => ({
501
584
  stack,
502
585
  depends: config?.depends?.map((dep) => dep.name) || []
503
586
  }));
504
- const findChildren = (list4, parents) => {
505
- const children = [];
506
- const rests = [];
507
- for (const item of list4) {
508
- const isChild = item.depends.filter((dep) => !parents.includes(dep)).length === 0;
509
- if (isChild) {
510
- children.push(item);
511
- } else {
512
- rests.push(item);
587
+ const line = [];
588
+ const deps = [];
589
+ let limit = 10;
590
+ while (deps.length < list3.length) {
591
+ const local = [];
592
+ for (const { stack, depends } of list3) {
593
+ if (!deps.includes(stack.name) && depends.filter((dep) => !deps.includes(dep)).length === 0) {
594
+ local.push(stack);
513
595
  }
514
596
  }
515
- if (!rests.length) {
516
- return children.map(({ stack }) => ({
517
- stack,
518
- children: []
519
- }));
597
+ if (limit-- <= 0) {
598
+ throw new Error(`Circular stack dependencies arn't allowed.`);
520
599
  }
521
- return children.map(({ stack }) => {
522
- return {
523
- stack,
524
- children: findChildren(rests, [...parents, stack.name])
525
- };
526
- });
527
- };
528
- return findChildren(list3, []);
529
- };
530
- var createDeploymentLine = (stacks) => {
531
- const line = [];
532
- const walk = (stacks2, level) => {
533
- stacks2.forEach((node) => {
534
- if (!line[level]) {
535
- line[level] = [];
536
- }
537
- line[level].push(node.stack);
538
- walk(node.children, level + 1);
539
- });
540
- };
541
- walk(stacks, 0);
600
+ deps.push(...local.map((stack) => stack.name));
601
+ line.push(local);
602
+ }
542
603
  return line;
543
604
  };
544
605
 
@@ -924,6 +985,7 @@ var hasOnFailure = (config) => {
924
985
  var MemorySizeSchema = SizeSchema.refine(sizeMin(Size.megaBytes(128)), "Minimum memory size is 128 MB").refine(sizeMax(Size.gigaBytes(10)), "Minimum memory size is 10 GB");
925
986
  var TimeoutSchema = DurationSchema.refine(durationMin(Duration.seconds(10)), "Minimum timeout duration is 10 seconds").refine(durationMax(Duration.minutes(15)), "Maximum timeout duration is 15 minutes");
926
987
  var EphemeralStorageSizeSchema = SizeSchema.refine(sizeMin(Size.megaBytes(512)), "Minimum ephemeral storage size is 512 MB").refine(sizeMax(Size.gigaBytes(10)), "Minimum ephemeral storage size is 10 GB");
988
+ var ReservedConcurrentExecutionsSchema = z6.number().int().min(0);
927
989
  var EnvironmentSchema = z6.record(z6.string(), z6.string()).optional();
928
990
  var ArchitectureSchema = z6.enum(["x86_64", "arm64"]);
929
991
  var RetryAttemptsSchema = z6.number().int().min(0).max(2);
@@ -934,8 +996,12 @@ var RuntimeSchema = z6.enum([
934
996
  var FunctionSchema = z6.union([
935
997
  LocalFileSchema,
936
998
  z6.object({
937
- /** The file path ofthe function code. */
999
+ /** The file path of the function code. */
938
1000
  file: LocalFileSchema,
1001
+ /** Put the function inside your global VPC.
1002
+ * @default false
1003
+ */
1004
+ vpc: z6.boolean().optional(),
939
1005
  /** The amount of time that Lambda allows a function to run before stopping it.
940
1006
  * You can specify a size value from 1 second to 15 minutes.
941
1007
  * @default '10 seconds'
@@ -966,6 +1032,10 @@ var FunctionSchema = z6.union([
966
1032
  * @default 2
967
1033
  */
968
1034
  retryAttempts: RetryAttemptsSchema.optional(),
1035
+ /** The number of simultaneous executions to reserve for the function.
1036
+ * You can specify a number from 0.
1037
+ */
1038
+ reserved: ReservedConcurrentExecutionsSchema.optional(),
969
1039
  /** Environment variable key-value pairs.
970
1040
  * @example
971
1041
  * {
@@ -981,6 +1051,10 @@ var FunctionSchema = z6.union([
981
1051
  var schema = z6.object({
982
1052
  defaults: z6.object({
983
1053
  function: z6.object({
1054
+ /** Put the function inside your global VPC.
1055
+ * @default false
1056
+ */
1057
+ vpc: z6.boolean().default(false),
984
1058
  /** The amount of time that Lambda allows a function to run before stopping it.
985
1059
  * You can specify a size value from 1 second to 15 minutes.
986
1060
  * @default '10 seconds'
@@ -1011,6 +1085,10 @@ var schema = z6.object({
1011
1085
  * @default 2
1012
1086
  */
1013
1087
  retryAttempts: RetryAttemptsSchema.default(2),
1088
+ /** The number of simultaneous executions to reserve for the function.
1089
+ * You can specify a number from 0.
1090
+ */
1091
+ reserved: ReservedConcurrentExecutionsSchema.optional(),
1014
1092
  /** Environment variable key-value pairs.
1015
1093
  * @example
1016
1094
  * {
@@ -1051,6 +1129,12 @@ var functionPlugin = definePlugin({
1051
1129
  retryAttempts: props.retryAttempts,
1052
1130
  onFailure: getGlobalOnFailure(ctx)
1053
1131
  }).dependsOn(lambda);
1132
+ if (hasOnFailure(ctx.config)) {
1133
+ lambda.addPermissions({
1134
+ actions: ["sqs:SendMessage"],
1135
+ resources: [getGlobalOnFailure(ctx)]
1136
+ });
1137
+ }
1054
1138
  stack.add(invoke, lambda);
1055
1139
  }
1056
1140
  }
@@ -1062,12 +1146,36 @@ var toLambdaFunction = (ctx, id, fileOrProps) => {
1062
1146
  const lambda = new Function(id, {
1063
1147
  name: `${config.name}-${stack.name}-${id}`,
1064
1148
  code: Code.fromFile(id, props.file),
1065
- ...props
1149
+ ...props,
1150
+ vpc: void 0
1066
1151
  });
1067
1152
  lambda.addEnvironment("APP", config.name).addEnvironment("STAGE", config.stage).addEnvironment("STACK", stack.name);
1153
+ if (props.vpc) {
1154
+ lambda.setVpc({
1155
+ securityGroupIds: [
1156
+ ctx.bootstrap.import(`vpc-security-group-id`)
1157
+ ],
1158
+ subnetIds: [
1159
+ ctx.bootstrap.import(`public-subnet-1`),
1160
+ ctx.bootstrap.import(`public-subnet-2`)
1161
+ ]
1162
+ }).addPermissions({
1163
+ actions: [
1164
+ "ec2:CreateNetworkInterface",
1165
+ "ec2:DescribeNetworkInterfaces",
1166
+ "ec2:DeleteNetworkInterface",
1167
+ "ec2:AssignPrivateIpAddresses",
1168
+ "ec2:UnassignPrivateIpAddresses"
1169
+ ],
1170
+ resources: ["*"]
1171
+ });
1172
+ }
1068
1173
  if (props.runtime.startsWith("nodejs")) {
1069
1174
  lambda.addEnvironment("AWS_NODEJS_CONNECTION_REUSE_ENABLED", "1");
1070
1175
  }
1176
+ ctx.bind((other) => {
1177
+ other.addPermissions(lambda.permissions);
1178
+ });
1071
1179
  return lambda;
1072
1180
  };
1073
1181
 
@@ -1145,7 +1253,7 @@ var cronPlugin = definePlugin({
1145
1253
  name: "cron",
1146
1254
  schema: z7.object({
1147
1255
  stacks: z7.object({
1148
- /** Define the crons in your stack
1256
+ /** Define the crons in your stack.
1149
1257
  * @example
1150
1258
  * {
1151
1259
  * crons: {
@@ -1157,7 +1265,7 @@ var cronPlugin = definePlugin({
1157
1265
  * }
1158
1266
  * */
1159
1267
  crons: z7.record(ResourceIdSchema, z7.object({
1160
- /** The consuming lambda function properties */
1268
+ /** The consuming lambda function properties. */
1161
1269
  consumer: FunctionSchema,
1162
1270
  /** The scheduling expression.
1163
1271
  * @example 'cron(0 20 * * ? *)'
@@ -1191,6 +1299,7 @@ var Queue = class extends Resource {
1191
1299
  super("AWS::SQS::Queue", logicalId);
1192
1300
  this.props = props;
1193
1301
  this.name = formatName(this.props.name || logicalId);
1302
+ this.tag("name", this.name);
1194
1303
  }
1195
1304
  name;
1196
1305
  setDeadLetter(arn) {
@@ -1211,7 +1320,13 @@ var Queue = class extends Resource {
1211
1320
  "sqs:GetQueueUrl",
1212
1321
  "sqs:GetQueueAttributes"
1213
1322
  ],
1214
- resources: [this.arn]
1323
+ resources: [
1324
+ formatArn({
1325
+ service: "sqs",
1326
+ resource: "queue",
1327
+ resourceName: this.name
1328
+ })
1329
+ ]
1215
1330
  };
1216
1331
  }
1217
1332
  properties() {
@@ -1224,7 +1339,8 @@ var Queue = class extends Resource {
1224
1339
  VisibilityTimeout: this.props.visibilityTimeout?.toSeconds() ?? 30,
1225
1340
  ...this.props.deadLetterArn ? {
1226
1341
  RedrivePolicy: {
1227
- deadLetterTargetArn: this.props.deadLetterArn
1342
+ deadLetterTargetArn: this.props.deadLetterArn,
1343
+ maxReceiveCount: this.props.maxReceiveCount ?? 100
1228
1344
  }
1229
1345
  } : {}
1230
1346
  };
@@ -1280,8 +1396,7 @@ var SqsEventSource = class extends Group {
1280
1396
  sourceArn: props.queueArn,
1281
1397
  batchSize: props.batchSize ?? 10,
1282
1398
  maxBatchingWindow: props.maxBatchingWindow,
1283
- maxConcurrency: props.maxConcurrency,
1284
- onFailure: props.onFailure
1399
+ maxConcurrency: props.maxConcurrency
1285
1400
  });
1286
1401
  lambda.addPermissions({
1287
1402
  actions: [
@@ -1296,6 +1411,14 @@ var SqsEventSource = class extends Group {
1296
1411
  };
1297
1412
 
1298
1413
  // src/plugins/queue.ts
1414
+ 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");
1415
+ var VisibilityTimeoutSchema = DurationSchema.refine(durationMax(Duration.hours(12)), "Maximum visibility timeout is 12 hours");
1416
+ var DeliveryDelaySchema = DurationSchema.refine(durationMax(Duration.minutes(15)), "Maximum delivery delay is 15 minutes");
1417
+ var ReceiveMessageWaitTimeSchema = DurationSchema.refine(durationMin(Duration.seconds(1)), "Minimum receive message wait time is 1 second").refine(durationMax(Duration.seconds(20)), "Maximum receive message wait time is 20 seconds");
1418
+ var MaxMessageSizeSchema = SizeSchema.refine(sizeMin(Size.kiloBytes(1)), "Minimum max message size is 1 KB").refine(sizeMax(Size.kiloBytes(256)), "Maximum max message size is 256 KB");
1419
+ var BatchSizeSchema = z8.number().int().min(1, "Minimum batch size is 1").max(1e4, "Maximum batch size is 10000");
1420
+ var MaxConcurrencySchema = z8.number().int().min(2, "Minimum max concurrency is 2").max(1e3, "Maximum max concurrency is 1000");
1421
+ var MaxBatchingWindow = DurationSchema.refine(durationMax(Duration.minutes(5)), "Maximum max batching window is 5 minutes");
1299
1422
  var queuePlugin = definePlugin({
1300
1423
  name: "queue",
1301
1424
  schema: z8.object({
@@ -1303,29 +1426,40 @@ var queuePlugin = definePlugin({
1303
1426
  /** Define the defaults properties for all queue's in your app. */
1304
1427
  queue: z8.object({
1305
1428
  /** The number of seconds that Amazon SQS retains a message.
1306
- * You can specify a duration value from 1 minute to 14 days.
1429
+ * You can specify a duration from 1 minute to 14 days.
1307
1430
  * @default '7 days' */
1308
- retentionPeriod: DurationSchema.default("7 days"),
1431
+ retentionPeriod: RetentionPeriodSchema.default("7 days"),
1309
1432
  /** The length of time during which a message will be unavailable after a message is delivered from the queue.
1310
1433
  * This blocks other components from receiving the same message and gives the initial component time to process and delete the message from the queue.
1311
- * You can specify a duration value from 0 to 12 hours.
1434
+ * You can specify a duration from 0 to 12 hours.
1312
1435
  * @default '30 seconds' */
1313
- visibilityTimeout: DurationSchema.default("30 seconds"),
1436
+ visibilityTimeout: VisibilityTimeoutSchema.default("30 seconds"),
1314
1437
  /** The time in seconds for which the delivery of all messages in the queue is delayed.
1315
- * You can specify a duration value from 0 to 15 minutes.
1438
+ * You can specify a duration from 0 to 15 minutes.
1316
1439
  * @default '0 seconds' */
1317
- deliveryDelay: DurationSchema.default("0 seconds"),
1440
+ deliveryDelay: DeliveryDelaySchema.default("0 seconds"),
1318
1441
  /** Specifies the duration, in seconds,
1319
1442
  * that the ReceiveMessage action call waits until a message is in the queue in order to include it in the response,
1320
1443
  * rather than returning an empty response if a message isn't yet available.
1321
- * You can specify an integer from 1 to 20.
1322
- * You can specify a duration value from 1 to 20 seconds.
1323
- * @default '0 seconds' */
1324
- receiveMessageWaitTime: DurationSchema.default("0 seconds"),
1444
+ * You can specify a duration from 1 to 20 seconds.
1445
+ * Short polling is used as the default. */
1446
+ receiveMessageWaitTime: ReceiveMessageWaitTimeSchema.optional(),
1325
1447
  /** The limit of how many bytes that a message can contain before Amazon SQS rejects it.
1326
- * You can specify an size value from 1 KB to 256 KB.
1448
+ * You can specify an size from 1 KB to 256 KB.
1327
1449
  * @default '256 KB' */
1328
- maxMessageSize: SizeSchema.default("256 KB")
1450
+ maxMessageSize: MaxMessageSizeSchema.default("256 KB"),
1451
+ /** The maximum number of records in each batch that Lambda pulls from your queue and sends to your function.
1452
+ * Lambda passes all of the records in the batch to the function in a single call, up to the payload limit for synchronous invocation (6 MB).
1453
+ * You can specify an integer from 1 to 10000.
1454
+ * @default 10 */
1455
+ batchSize: BatchSizeSchema.default(10),
1456
+ /** Limits the number of concurrent instances that the queue worker can invoke.
1457
+ * You can specify an integer from 2 to 1000. */
1458
+ maxConcurrency: MaxConcurrencySchema.optional(),
1459
+ /** The maximum amount of time, that Lambda spends gathering records before invoking the function.
1460
+ * You can specify an duration from 0 seconds to 5 minutes.
1461
+ * @default '0 seconds' */
1462
+ maxBatchingWindow: MaxBatchingWindow.optional()
1329
1463
  }).default({})
1330
1464
  }).default({}),
1331
1465
  stacks: z8.object({
@@ -1347,26 +1481,38 @@ var queuePlugin = definePlugin({
1347
1481
  /** The number of seconds that Amazon SQS retains a message.
1348
1482
  * You can specify a duration value from 1 minute to 14 days.
1349
1483
  * @default '7 days' */
1350
- retentionPeriod: DurationSchema.optional(),
1484
+ retentionPeriod: RetentionPeriodSchema.optional(),
1351
1485
  /** The length of time during which a message will be unavailable after a message is delivered from the queue.
1352
1486
  * This blocks other components from receiving the same message and gives the initial component time to process and delete the message from the queue.
1353
1487
  * You can specify a duration value from 0 to 12 hours.
1354
1488
  * @default '30 seconds' */
1355
- visibilityTimeout: DurationSchema.optional(),
1489
+ visibilityTimeout: VisibilityTimeoutSchema.optional(),
1356
1490
  /** The time in seconds for which the delivery of all messages in the queue is delayed.
1357
1491
  * You can specify a duration value from 0 to 15 minutes.
1358
1492
  * @default '0 seconds' */
1359
- deliveryDelay: DurationSchema.optional(),
1493
+ deliveryDelay: DeliveryDelaySchema.optional(),
1360
1494
  /** Specifies the duration, in seconds,
1361
1495
  * that the ReceiveMessage action call waits until a message is in the queue in order to include it in the response,
1362
1496
  * rather than returning an empty response if a message isn't yet available.
1363
1497
  * You can specify a duration value from 1 to 20 seconds.
1364
- * @default '0 seconds' */
1365
- receiveMessageWaitTime: DurationSchema.optional(),
1498
+ * Short polling is used as the default. */
1499
+ receiveMessageWaitTime: ReceiveMessageWaitTimeSchema.optional(),
1366
1500
  /** The limit of how many bytes that a message can contain before Amazon SQS rejects it.
1367
1501
  * You can specify an size value from 1 KB to 256 KB.
1368
1502
  * @default '256 KB' */
1369
- maxMessageSize: SizeSchema.optional()
1503
+ maxMessageSize: MaxMessageSizeSchema.optional(),
1504
+ /** The maximum number of records in each batch that Lambda pulls from your queue and sends to your function.
1505
+ * Lambda passes all of the records in the batch to the function in a single call, up to the payload limit for synchronous invocation (6 MB).
1506
+ * You can specify an integer from 1 to 10000.
1507
+ * @default 10 */
1508
+ batchSize: BatchSizeSchema.optional(),
1509
+ /** Limits the number of concurrent instances that the queue worker can invoke.
1510
+ * You can specify an integer from 2 to 1000. */
1511
+ maxConcurrency: MaxConcurrencySchema.optional(),
1512
+ /** The maximum amount of time, that Lambda spends gathering records before invoking the function.
1513
+ * You can specify an duration from 0 seconds to 5 minutes.
1514
+ * @default '0 seconds' */
1515
+ maxBatchingWindow: MaxBatchingWindow.optional()
1370
1516
  })
1371
1517
  ])
1372
1518
  ).optional()
@@ -1378,12 +1524,15 @@ var queuePlugin = definePlugin({
1378
1524
  const props = typeof functionOrProps === "string" ? { ...config.defaults.queue, consumer: functionOrProps } : { ...config.defaults.queue, ...functionOrProps };
1379
1525
  const queue2 = new Queue(id, {
1380
1526
  name: `${config.name}-${stack.name}-${id}`,
1527
+ deadLetterArn: getGlobalOnFailure(ctx),
1381
1528
  ...props
1382
1529
  });
1383
1530
  const lambda = toLambdaFunction(ctx, `queue-${id}`, props.consumer);
1384
1531
  const source = new SqsEventSource(id, lambda, {
1385
1532
  queueArn: queue2.arn,
1386
- onFailure: getGlobalOnFailure(ctx)
1533
+ batchSize: props.batchSize,
1534
+ maxConcurrency: props.maxConcurrency,
1535
+ maxBatchingWindow: props.maxBatchingWindow
1387
1536
  });
1388
1537
  stack.add(queue2, lambda, source);
1389
1538
  bind((lambda2) => {
@@ -1404,6 +1553,7 @@ var Table = class extends Resource {
1404
1553
  this.props = props;
1405
1554
  this.name = formatName(this.props.name || logicalId);
1406
1555
  this.indexes = { ...this.props.indexes || {} };
1556
+ this.tag("name", this.name);
1407
1557
  }
1408
1558
  name;
1409
1559
  indexes;
@@ -1436,7 +1586,13 @@ var Table = class extends Resource {
1436
1586
  "dynamodb:Query",
1437
1587
  "dynamodb:Scan"
1438
1588
  ],
1439
- resources: [this.arn]
1589
+ resources: [
1590
+ formatArn({
1591
+ service: "dynamodb",
1592
+ resource: "table",
1593
+ resourceName: this.name
1594
+ })
1595
+ ]
1440
1596
  };
1441
1597
  }
1442
1598
  attributeDefinitions() {
@@ -1670,6 +1826,7 @@ var Bucket = class extends Resource {
1670
1826
  super("AWS::S3::Bucket", logicalId);
1671
1827
  this.props = props;
1672
1828
  this.name = formatName(this.props.name || logicalId);
1829
+ this.tag("name", this.name);
1673
1830
  }
1674
1831
  name;
1675
1832
  get arn() {
@@ -1686,7 +1843,13 @@ var Bucket = class extends Resource {
1686
1843
  "s3:GetQueueUrl",
1687
1844
  "s3:GetQueueAttributes"
1688
1845
  ],
1689
- resources: [this.arn]
1846
+ resources: [
1847
+ formatArn({
1848
+ service: "s3",
1849
+ resource: "bucket",
1850
+ resourceName: this.name
1851
+ })
1852
+ ]
1690
1853
  };
1691
1854
  }
1692
1855
  properties() {
@@ -1739,6 +1902,7 @@ var Topic = class extends Resource {
1739
1902
  super("AWS::SNS::Topic", logicalId);
1740
1903
  this.props = props;
1741
1904
  this.name = formatName(this.props.name || logicalId);
1905
+ this.tag("name", this.name);
1742
1906
  }
1743
1907
  name;
1744
1908
  get arn() {
@@ -1747,7 +1911,13 @@ var Topic = class extends Resource {
1747
1911
  get permissions() {
1748
1912
  return {
1749
1913
  actions: ["sns:Publish"],
1750
- resources: [this.arn]
1914
+ resources: [
1915
+ formatArn({
1916
+ service: "sns",
1917
+ resource: "topic",
1918
+ resourceName: this.name
1919
+ })
1920
+ ]
1751
1921
  };
1752
1922
  }
1753
1923
  properties() {
@@ -1980,6 +2150,7 @@ var GraphQLApi = class extends Resource {
1980
2150
  super("AWS::AppSync::GraphQLApi", logicalId);
1981
2151
  this.props = props;
1982
2152
  this.name = formatName(this.props.name || logicalId);
2153
+ this.tag("name", this.name);
1983
2154
  }
1984
2155
  name;
1985
2156
  lambdaAuthProviders = [];
@@ -2632,7 +2803,7 @@ var domainPlugin = definePlugin({
2632
2803
  name: DomainNameSchema.optional(),
2633
2804
  /** The DNS record type. */
2634
2805
  type: z15.enum(["A", "AAAA", "CAA", "CNAME", "DS", "MX", "NAPTR", "NS", "PTR", "SOA", "SPF", "SRV", "TXT"]),
2635
- /** The resource record cache time to live (TTL) */
2806
+ /** The resource record cache time to live (TTL). */
2636
2807
  ttl: DurationSchema,
2637
2808
  /** One or more values that correspond with the value that you specified for the Type property. */
2638
2809
  records: z15.string().array()
@@ -2744,6 +2915,12 @@ var Vpc = class extends Resource {
2744
2915
  get id() {
2745
2916
  return ref(this.logicalId);
2746
2917
  }
2918
+ get defaultNetworkAcl() {
2919
+ return getAtt(this.logicalId, "DefaultNetworkAcl");
2920
+ }
2921
+ get defaultSecurityGroup() {
2922
+ return getAtt(this.logicalId, "DefaultSecurityGroup");
2923
+ }
2747
2924
  properties() {
2748
2925
  return {
2749
2926
  CidrBlock: this.props.cidrBlock.ip
@@ -2755,6 +2932,7 @@ var RouteTable = class extends Resource {
2755
2932
  super("AWS::EC2::RouteTable", logicalId);
2756
2933
  this.props = props;
2757
2934
  this.name = formatName(props.name || logicalId);
2935
+ this.tag("name", this.name);
2758
2936
  }
2759
2937
  name;
2760
2938
  get id() {
@@ -2762,11 +2940,7 @@ var RouteTable = class extends Resource {
2762
2940
  }
2763
2941
  properties() {
2764
2942
  return {
2765
- VpcId: this.props.vpcId,
2766
- Tags: [{
2767
- Key: "name",
2768
- Value: this.name
2769
- }]
2943
+ VpcId: this.props.vpcId
2770
2944
  };
2771
2945
  }
2772
2946
  };
@@ -2919,6 +3093,7 @@ var vpcPlugin = definePlugin({
2919
3093
  routeTableId: publicRouteTable.id,
2920
3094
  destination: Peer.anyIpv4()
2921
3095
  }).dependsOn(gateway, publicRouteTable);
3096
+ bootstrap2.export("vpc-security-group-id", vpc.defaultSecurityGroup);
2922
3097
  bootstrap2.export(`vpc-id`, vpc.id);
2923
3098
  bootstrap2.add(
2924
3099
  vpc,
@@ -2961,7 +3136,9 @@ var SecurityGroup = class extends Resource {
2961
3136
  constructor(logicalId, props) {
2962
3137
  super("AWS::EC2::SecurityGroup", logicalId);
2963
3138
  this.props = props;
3139
+ this.name = formatName(props.name ?? logicalId);
2964
3140
  }
3141
+ name;
2965
3142
  ingress = [];
2966
3143
  egress = [];
2967
3144
  get id() {
@@ -2986,7 +3163,7 @@ var SecurityGroup = class extends Resource {
2986
3163
  properties() {
2987
3164
  return {
2988
3165
  VpcId: this.props.vpcId,
2989
- GroupName: this.logicalId,
3166
+ GroupName: this.name,
2990
3167
  GroupDescription: this.props.description,
2991
3168
  SecurityGroupIngress: this.ingress.map((rule) => ({
2992
3169
  Description: rule.description || "",
@@ -3397,6 +3574,7 @@ var Collection = class extends Resource {
3397
3574
  super("AWS::OpenSearchServerless::Collection", logicalId);
3398
3575
  this.props = props;
3399
3576
  this.name = this.props.name || logicalId;
3577
+ this.tag("name", this.name);
3400
3578
  }
3401
3579
  name;
3402
3580
  get id() {
@@ -3408,6 +3586,18 @@ var Collection = class extends Resource {
3408
3586
  get endpoint() {
3409
3587
  return getAtt(this.logicalId, "CollectionEndpoint");
3410
3588
  }
3589
+ get permissions() {
3590
+ return {
3591
+ actions: ["aoss:APIAccessAll"],
3592
+ resources: [
3593
+ formatArn({
3594
+ service: "aoss",
3595
+ resource: "collection",
3596
+ resourceName: this.name
3597
+ })
3598
+ ]
3599
+ };
3600
+ }
3411
3601
  properties() {
3412
3602
  return {
3413
3603
  Name: this.name,
@@ -3432,10 +3622,155 @@ var searchPlugin = definePlugin({
3432
3622
  type: "search"
3433
3623
  });
3434
3624
  bind((lambda) => {
3435
- lambda.addPermissions({
3436
- actions: ["aoss:APIAccessAll"],
3437
- resources: [collection.arn]
3438
- });
3625
+ lambda.addPermissions(collection.permissions);
3626
+ });
3627
+ }
3628
+ }
3629
+ });
3630
+
3631
+ // src/plugins/cache.ts
3632
+ import { z as z19 } from "zod";
3633
+
3634
+ // src/formation/resource/memorydb/cluster.ts
3635
+ var Cluster = class extends Resource {
3636
+ constructor(logicalId, props) {
3637
+ super("AWS::MemoryDB::Cluster", logicalId);
3638
+ this.props = props;
3639
+ this.name = formatName(this.props.name || logicalId);
3640
+ this.tag("name", this.name);
3641
+ }
3642
+ name;
3643
+ get status() {
3644
+ return this.getAtt("Status");
3645
+ }
3646
+ get arn() {
3647
+ return this.getAtt("ARN");
3648
+ }
3649
+ get address() {
3650
+ return this.getAtt("ClusterEndpoint.Address");
3651
+ }
3652
+ get port() {
3653
+ return this.getAtt("ClusterEndpoint.Port");
3654
+ }
3655
+ properties() {
3656
+ return {
3657
+ ClusterName: this.name,
3658
+ ClusterEndpoint: {
3659
+ Port: this.props.port
3660
+ },
3661
+ Port: this.props.port,
3662
+ ...this.attr("Description", this.props.description),
3663
+ ACLName: this.props.aclName,
3664
+ EngineVersion: this.props.engine ?? "7.0",
3665
+ ...this.attr("SubnetGroupName", this.props.subnetGroupName),
3666
+ ...this.attr("SecurityGroupIds", this.props.securityGroupIds),
3667
+ NodeType: "db." + this.props.type,
3668
+ NumReplicasPerShard: this.props.replicasPerShard ?? 1,
3669
+ NumShards: this.props.shards ?? 1,
3670
+ TLSEnabled: this.props.tls ?? false,
3671
+ DataTiering: this.props.dataTiering ? "true" : "false",
3672
+ AutoMinorVersionUpgrade: this.props.autoMinorVersionUpgrade ?? true,
3673
+ MaintenanceWindow: this.props.maintenanceWindow ?? "Sat:02:00-Sat:05:00"
3674
+ };
3675
+ }
3676
+ };
3677
+
3678
+ // src/formation/resource/memorydb/subnet-group.ts
3679
+ var SubnetGroup = class extends Resource {
3680
+ constructor(logicalId, props) {
3681
+ super("AWS::MemoryDB::SubnetGroup", logicalId);
3682
+ this.props = props;
3683
+ this.name = formatName(this.props.name || logicalId);
3684
+ }
3685
+ name;
3686
+ get arn() {
3687
+ return getAtt(this.logicalId, "Arn");
3688
+ }
3689
+ properties() {
3690
+ return {
3691
+ SubnetGroupName: this.name,
3692
+ SubnetIds: this.props.subnetIds,
3693
+ ...this.attr("Description", this.props.description)
3694
+ };
3695
+ }
3696
+ };
3697
+
3698
+ // src/plugins/cache.ts
3699
+ var TypeSchema = z19.enum([
3700
+ "t4g.small",
3701
+ "t4g.medium",
3702
+ "r6g.large",
3703
+ "r6g.xlarge",
3704
+ "r6g.2xlarge",
3705
+ "r6g.4xlarge",
3706
+ "r6g.8xlarge",
3707
+ "r6g.12xlarge",
3708
+ "r6g.16xlarge",
3709
+ "r6gd.xlarge",
3710
+ "r6gd.2xlarge",
3711
+ "r6gd.4xlarge",
3712
+ "r6gd.8xlarge"
3713
+ ]);
3714
+ var PortSchema = z19.number().int().min(1).max(5e4);
3715
+ var ShardsSchema = z19.number().int().min(0).max(100);
3716
+ var ReplicasPerShardSchema = z19.number().int().min(0).max(5);
3717
+ var EngineSchema = z19.enum(["7.0", "6.2"]);
3718
+ var cachePlugin = definePlugin({
3719
+ name: "cache",
3720
+ schema: z19.object({
3721
+ stacks: z19.object({
3722
+ /** Define the caches in your stack.
3723
+ * For access to the cache put your functions inside the global VPC.
3724
+ * @example
3725
+ * {
3726
+ * caches: {
3727
+ * CACHE_NAME: {
3728
+ * type: 't4g.small'
3729
+ * }
3730
+ * }
3731
+ * }
3732
+ */
3733
+ caches: z19.record(
3734
+ ResourceIdSchema,
3735
+ z19.object({
3736
+ type: TypeSchema.default("t4g.small"),
3737
+ port: PortSchema.default(6379),
3738
+ shards: ShardsSchema.default(1),
3739
+ replicasPerShard: ReplicasPerShardSchema.default(1),
3740
+ engine: EngineSchema.default("7.0"),
3741
+ dataTiering: z19.boolean().default(false)
3742
+ })
3743
+ ).optional()
3744
+ }).array()
3745
+ }),
3746
+ onStack({ config, stack, stackConfig, bootstrap: bootstrap2, bind }) {
3747
+ for (const [id, props] of Object.entries(stackConfig.caches || {})) {
3748
+ const name = `${config.name}-${stack.name}-${id}`;
3749
+ const subnetGroup = new SubnetGroup(id, {
3750
+ name,
3751
+ subnetIds: [
3752
+ bootstrap2.import(`private-subnet-1`),
3753
+ bootstrap2.import(`private-subnet-2`)
3754
+ ]
3755
+ });
3756
+ const securityGroup = new SecurityGroup(id, {
3757
+ name,
3758
+ vpcId: bootstrap2.import(`vpc-id`),
3759
+ description: name
3760
+ });
3761
+ const port = Port.tcp(props.port);
3762
+ securityGroup.addIngressRule(Peer.anyIpv4(), port);
3763
+ securityGroup.addIngressRule(Peer.anyIpv6(), port);
3764
+ const cluster = new Cluster(id, {
3765
+ name,
3766
+ aclName: "open-access",
3767
+ securityGroupIds: [securityGroup.id],
3768
+ subnetGroupName: subnetGroup.name,
3769
+ ...props
3770
+ }).dependsOn(subnetGroup, securityGroup);
3771
+ stack.add(subnetGroup, securityGroup, cluster);
3772
+ bind((lambda) => {
3773
+ lambda.addEnvironment(`CACHE_${stack.name}_${id}_HOST`, cluster.address).addEnvironment(`CACHE_${stack.name}_${id}_PORT`, props.port.toString());
3439
3774
  });
3440
3775
  }
3441
3776
  }
@@ -3446,6 +3781,7 @@ var defaultPlugins = [
3446
3781
  extendPlugin,
3447
3782
  vpcPlugin,
3448
3783
  functionPlugin,
3784
+ cachePlugin,
3449
3785
  cronPlugin,
3450
3786
  queuePlugin,
3451
3787
  tablePlugin,
@@ -3627,7 +3963,7 @@ var toApp = async (config, filters) => {
3627
3963
  config.stacks.filter((stack) => filters.includes(stack.name))
3628
3964
  );
3629
3965
  for (const stackConfig of filterdStacks) {
3630
- const { stack } = toStack({
3966
+ const { stack, bindings: bindings2 } = toStack({
3631
3967
  config,
3632
3968
  stackConfig,
3633
3969
  bootstrap: bootstrap2,
@@ -3636,7 +3972,7 @@ var toApp = async (config, filters) => {
3636
3972
  app
3637
3973
  });
3638
3974
  app.add(stack);
3639
- stacks.push({ stack, config: stackConfig });
3975
+ stacks.push({ stack, config: stackConfig, bindings: bindings2 });
3640
3976
  }
3641
3977
  for (const plugin of plugins) {
3642
3978
  for (const stack of app.stacks) {
@@ -3658,23 +3994,31 @@ var toApp = async (config, filters) => {
3658
3994
  bind2(fn);
3659
3995
  }
3660
3996
  }
3661
- let dependencyTree = createDependencyTree(stacks);
3997
+ for (const entry of stacks) {
3998
+ for (const dep of entry.config.depends || []) {
3999
+ const depStack = stacks.find((entry2) => entry2.config.name === dep.name);
4000
+ if (!depStack) {
4001
+ throw new Error(`Stack dependency not found: ${dep.name}`);
4002
+ }
4003
+ const functions2 = entry.stack.find(Function);
4004
+ for (const bind2 of depStack.bindings) {
4005
+ for (const fn of functions2) {
4006
+ bind2(fn);
4007
+ }
4008
+ }
4009
+ }
4010
+ }
4011
+ const deploymentLine = createDeploymentLine(stacks);
3662
4012
  if (bootstrap2.size > 0) {
3663
- dependencyTree = [{
3664
- stack: bootstrap2,
3665
- children: dependencyTree
3666
- }];
4013
+ deploymentLine.unshift([bootstrap2]);
3667
4014
  }
3668
4015
  if (usEastBootstrap.size > 0) {
3669
- dependencyTree = [{
3670
- stack: usEastBootstrap,
3671
- children: dependencyTree
3672
- }];
4016
+ deploymentLine.unshift([usEastBootstrap]);
3673
4017
  }
3674
4018
  return {
3675
4019
  app,
3676
4020
  plugins,
3677
- dependencyTree
4021
+ deploymentLine
3678
4022
  };
3679
4023
  };
3680
4024
 
@@ -3698,17 +4042,17 @@ var getCredentials = (profile) => {
3698
4042
  };
3699
4043
 
3700
4044
  // src/schema/app.ts
3701
- import { z as z22 } from "zod";
4045
+ import { z as z23 } from "zod";
3702
4046
 
3703
4047
  // src/schema/stack.ts
3704
- import { z as z19 } from "zod";
3705
- var StackSchema = z19.object({
4048
+ import { z as z20 } from "zod";
4049
+ var StackSchema = z20.object({
3706
4050
  name: ResourceIdSchema,
3707
- depends: z19.array(z19.lazy(() => StackSchema)).optional()
4051
+ depends: z20.array(z20.lazy(() => StackSchema)).optional()
3708
4052
  });
3709
4053
 
3710
4054
  // src/schema/region.ts
3711
- import { z as z20 } from "zod";
4055
+ import { z as z21 } from "zod";
3712
4056
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
3713
4057
  var AF = ["af-south-1"];
3714
4058
  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"];
@@ -3725,47 +4069,49 @@ var regions = [
3725
4069
  ...ME,
3726
4070
  ...SA
3727
4071
  ];
3728
- var RegionSchema = z20.enum(regions);
4072
+ var RegionSchema = z21.enum(regions);
3729
4073
 
3730
4074
  // src/schema/plugin.ts
3731
- import { z as z21 } from "zod";
3732
- var PluginSchema = z21.object({
3733
- name: z21.string(),
3734
- schema: z21.custom().optional(),
4075
+ import { z as z22 } from "zod";
4076
+ var PluginSchema = z22.object({
4077
+ name: z22.string(),
4078
+ schema: z22.custom().optional(),
3735
4079
  // depends: z.array(z.lazy(() => PluginSchema)).optional(),
3736
- onApp: z21.function().returns(z21.void()).optional(),
3737
- onStack: z21.function().returns(z21.any()).optional(),
3738
- onResource: z21.function().returns(z21.any()).optional()
4080
+ onApp: z22.function().returns(z22.void()).optional(),
4081
+ onStack: z22.function().returns(z22.any()).optional(),
4082
+ onResource: z22.function().returns(z22.any()).optional()
3739
4083
  // bind: z.function().optional(),
3740
4084
  });
3741
4085
 
3742
4086
  // src/schema/app.ts
3743
- var AppSchema = z22.object({
4087
+ var AppSchema = z23.object({
3744
4088
  /** App name */
3745
4089
  name: ResourceIdSchema,
3746
4090
  /** The AWS region to deploy to. */
3747
4091
  region: RegionSchema,
3748
4092
  /** The AWS profile to deploy to. */
3749
- profile: z22.string(),
4093
+ profile: z23.string(),
3750
4094
  /** The deployment stage.
3751
4095
  * @default 'prod'
3752
4096
  */
3753
- stage: z22.string().regex(/[a-z]+/).default("prod"),
4097
+ stage: z23.string().regex(/[a-z]+/).default("prod"),
3754
4098
  /** Default properties. */
3755
- defaults: z22.object({}).default({}),
4099
+ defaults: z23.object({}).default({}),
3756
4100
  /** The application stacks. */
3757
- stacks: z22.array(StackSchema).min(1).refine((stacks) => {
4101
+ stacks: z23.array(StackSchema).min(1).refine((stacks) => {
3758
4102
  const unique = new Set(stacks.map((stack) => stack.name));
3759
4103
  return unique.size === stacks.length;
3760
4104
  }, "Must be an array of unique stacks"),
3761
4105
  /** Custom plugins. */
3762
- plugins: z22.array(PluginSchema).optional()
4106
+ plugins: z23.array(PluginSchema).optional()
3763
4107
  });
3764
4108
 
3765
4109
  // src/util/import.ts
3766
- import { transformFile } from "@swc/core";
4110
+ import { rollup as rollup2 } from "rollup";
4111
+ import { swc as swc2 } from "rollup-plugin-swc3";
4112
+ import replace from "rollup-plugin-replace";
3767
4113
  import { dirname, join as join2 } from "path";
3768
- import { lstat as lstat2, mkdir, writeFile } from "fs/promises";
4114
+ import { mkdir, writeFile } from "fs/promises";
3769
4115
 
3770
4116
  // src/util/path.ts
3771
4117
  import { lstat } from "fs/promises";
@@ -3812,54 +4158,25 @@ var fileExist = async (file) => {
3812
4158
  };
3813
4159
 
3814
4160
  // src/util/import.ts
3815
- var resolveFileNameExtension = async (path) => {
3816
- const options = [
3817
- "",
3818
- ".ts",
3819
- ".js",
3820
- "/index.ts",
3821
- "/index.js"
3822
- ];
3823
- for (const option of options) {
3824
- const file = path.replace(/\.js$/, "") + option;
3825
- let stat;
3826
- try {
3827
- stat = await lstat2(file);
3828
- } catch (error) {
3829
- continue;
3830
- }
3831
- if (stat.isFile()) {
3832
- return file;
3833
- }
3834
- }
3835
- throw new Error(`Failed to load file: ${path}`);
3836
- };
3837
- var resolveDir = (path) => {
3838
- return dirname(path).replace(directories.root + "/", "");
3839
- };
3840
4161
  var importFile = async (path) => {
3841
- const load = async (file) => {
3842
- debug("Load file:", style.info(file));
3843
- let { code: code2 } = await transformFile(file, {
3844
- isModule: true
3845
- });
3846
- const path2 = dirname(file);
3847
- const dir = resolveDir(file);
3848
- code2 = code2.replaceAll("__dirname", `"${dir}"`);
3849
- const matches = code2.match(/(import|export)\s*{\s*[a-z0-9\_\,\s\*]+\s*}\s*from\s*('|")(\.\.?[\/a-z0-9\_\-\.]+)('|");?/ig);
3850
- if (!matches)
3851
- return code2;
3852
- await Promise.all(matches?.map(async (match) => {
3853
- const parts = /('|")(\.\.?[\/a-z0-9\_\-\.]+)('|")/ig.exec(match);
3854
- const from = parts[2];
3855
- const file2 = await resolveFileNameExtension(join2(path2, from));
3856
- const result = await load(file2);
3857
- code2 = code2.replace(match, result);
3858
- }));
3859
- return code2;
3860
- };
3861
- const code = await load(path);
4162
+ const bundle = await rollup2({
4163
+ input: path,
4164
+ plugins: [
4165
+ replace({
4166
+ __dirname: (id) => `'${dirname(id)}'`
4167
+ }),
4168
+ swc2({
4169
+ minify: false
4170
+ })
4171
+ ]
4172
+ });
3862
4173
  const outputFile = join2(directories.cache, "config.js");
4174
+ const result = await bundle.generate({
4175
+ format: "esm",
4176
+ exports: "default"
4177
+ });
4178
+ const output = result.output[0];
4179
+ const code = output.code;
3863
4180
  await mkdir(directories.cache, { recursive: true });
3864
4181
  await writeFile(outputFile, code);
3865
4182
  debug("Save config file:", style.info(outputFile));
@@ -4161,7 +4478,7 @@ var Renderer = class {
4161
4478
  flushing = false;
4162
4479
  screen = [];
4163
4480
  width() {
4164
- return this.output.columns;
4481
+ return this.output.columns - 1;
4165
4482
  }
4166
4483
  height() {
4167
4484
  return this.output.rows;
@@ -4999,12 +5316,73 @@ var assetPublisher = (config, app) => {
4999
5316
  };
5000
5317
  };
5001
5318
 
5319
+ // src/cli/ui/complex/deployer.ts
5320
+ var stacksDeployer = (deploymentLine) => {
5321
+ const stackNames = deploymentLine.map((line) => line.map((stack) => stack.name)).flat();
5322
+ const stackNameSize = Math.max(...stackNames.map((name) => name.length));
5323
+ return (term) => {
5324
+ const ui = {};
5325
+ term.out.gap();
5326
+ for (const i in deploymentLine) {
5327
+ const line = flexLine(
5328
+ term,
5329
+ [" "],
5330
+ [
5331
+ " ",
5332
+ style.placeholder(Number(i) + 1),
5333
+ style.placeholder(" \u2500\u2500")
5334
+ ]
5335
+ );
5336
+ term.out.write(line);
5337
+ term.out.write(br());
5338
+ for (const stack of deploymentLine[i]) {
5339
+ const icon = new Signal(" ");
5340
+ const name = new Signal(style.label.dim(stack.name));
5341
+ const status2 = new Signal(style.info.dim("waiting"));
5342
+ let stopSpinner;
5343
+ term.out.write([
5344
+ icon,
5345
+ " ",
5346
+ name,
5347
+ " ".repeat(stackNameSize - stack.name.length),
5348
+ " ",
5349
+ style.placeholder(symbol.pointerSmall),
5350
+ " ",
5351
+ status2,
5352
+ br()
5353
+ ]);
5354
+ ui[stack.name] = {
5355
+ start: (value) => {
5356
+ const [spinner, stop] = createSpinner();
5357
+ name.set(style.label(stack.name));
5358
+ icon.set(spinner);
5359
+ status2.set(style.warning(value));
5360
+ stopSpinner = stop;
5361
+ },
5362
+ done(value) {
5363
+ stopSpinner();
5364
+ icon.set(style.success(symbol.success));
5365
+ status2.set(style.success(value));
5366
+ },
5367
+ fail(value) {
5368
+ stopSpinner();
5369
+ icon.set(style.error(symbol.error));
5370
+ status2.set(style.error(value));
5371
+ }
5372
+ };
5373
+ }
5374
+ }
5375
+ term.out.gap();
5376
+ return ui;
5377
+ };
5378
+ };
5379
+
5002
5380
  // src/cli/command/deploy.ts
5003
5381
  var deploy = (program2) => {
5004
5382
  program2.command("deploy").argument("[stacks...]", "Optionally filter stacks to deploy").description("Deploy your app to AWS").action(async (filters) => {
5005
5383
  await layout(async (config, write) => {
5006
5384
  await write(bootstrapDeployer(config));
5007
- const { app, dependencyTree } = await toApp(config, filters);
5385
+ const { app, deploymentLine } = await toApp(config, filters);
5008
5386
  const stackNames = app.stacks.map((stack) => stack.name);
5009
5387
  const formattedFilter = stackNames.map((i) => style.info(i)).join(style.placeholder(", "));
5010
5388
  debug("Stacks to deploy", formattedFilter);
@@ -5018,26 +5396,21 @@ var deploy = (program2) => {
5018
5396
  await write(assetBuilder(app));
5019
5397
  await write(assetPublisher(config, app));
5020
5398
  await write(templateBuilder(app));
5021
- const statuses = {};
5022
- for (const stack of app) {
5023
- statuses[stack.name] = new Signal(style.info("waiting"));
5024
- }
5025
5399
  const doneDeploying = write(loadingDialog("Deploying stacks to AWS..."));
5026
- write(stackTree(dependencyTree, statuses));
5027
5400
  const client = new StackClient(app, config.account, config.region, config.credentials);
5028
- const deploymentLine = createDeploymentLine(dependencyTree);
5029
- for (const stacks of deploymentLine) {
5030
- const results = await Promise.allSettled(stacks.map(async (stack) => {
5031
- const signal = statuses[stack.name];
5032
- signal.set(style.warning("deploying"));
5401
+ const ui = write(stacksDeployer(deploymentLine));
5402
+ for (const line of deploymentLine) {
5403
+ const results = await Promise.allSettled(line.map(async (stack) => {
5404
+ const item = ui[stack.name];
5405
+ item.start("deploying");
5033
5406
  try {
5034
5407
  await client.deploy(stack);
5035
5408
  } catch (error) {
5036
5409
  debugError(error);
5037
- signal.set(style.error("failed"));
5410
+ item.fail("failed");
5038
5411
  throw error;
5039
5412
  }
5040
- signal.set(style.success("deployed"));
5413
+ item.done("deployed");
5041
5414
  }));
5042
5415
  for (const result of results) {
5043
5416
  if (result.status === "rejected") {