@awsless/awsless 0.0.547 → 0.0.549

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
@@ -609,7 +609,7 @@ var debug = (...parts) => {
609
609
  };
610
610
 
611
611
  // src/config/app.ts
612
- import { z as z25 } from "zod";
612
+ import { z as z26 } from "zod";
613
613
 
614
614
  // src/feature/alert/schema.ts
615
615
  import { kebabCase } from "change-case";
@@ -969,7 +969,13 @@ var LayerSchema = z16.record(
969
969
 
970
970
  // src/feature/on-failure/schema.ts
971
971
  var OnFailureDefaultSchema = FunctionSchema.optional().describe(
972
- "Defining a onFailure handler will add a global onFailure handler for the following resources:\n- Async lambda functions\n- SQS queues\n- DynamoDB streams"
972
+ [
973
+ "Defining a onFailure handler will add a global onFailure handler for the following resources:",
974
+ "- CloudWatch Scheduler",
975
+ "- Async lambda functions",
976
+ "- SQS queues",
977
+ "- DynamoDB streams"
978
+ ].join("\n")
973
979
  );
974
980
 
975
981
  // src/feature/on-log/schema.ts
@@ -1285,8 +1291,17 @@ var InstanceDefaultSchema = z23.object({
1285
1291
  }))
1286
1292
  }).default({});
1287
1293
 
1288
- // src/config/schema/region.ts
1294
+ // src/feature/topic/schema.ts
1295
+ import { kebabCase as kebabCase3 } from "change-case";
1289
1296
  import { z as z24 } from "zod";
1297
+ var TopicNameSchema = z24.string().min(3).max(256).regex(/^[a-z0-9\-]+$/i, "Invalid topic name").transform((value) => kebabCase3(value)).describe("Define event topic name.");
1298
+ var TopicsDefaultSchema = z24.array(TopicNameSchema).refine((topics) => {
1299
+ return topics.length === new Set(topics).size;
1300
+ }, "Must be a list of unique topic names").optional().describe("Define the event topics for your app.");
1301
+ var SubscribersSchema = z24.record(TopicNameSchema, FunctionSchema).optional().describe("Define the event topics to subscribe too in your stack.");
1302
+
1303
+ // src/config/schema/region.ts
1304
+ import { z as z25 } from "zod";
1290
1305
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1291
1306
  var AF = ["af-south-1"];
1292
1307
  var AP = [
@@ -1315,16 +1330,16 @@ var EU = [
1315
1330
  var ME = ["me-south-1", "me-central-1"];
1316
1331
  var SA = ["sa-east-1"];
1317
1332
  var regions = [...US, ...AF, ...AP, ...CA, ...EU, ...ME, ...SA];
1318
- var RegionSchema = z24.enum(regions);
1333
+ var RegionSchema = z25.enum(regions);
1319
1334
 
1320
1335
  // src/config/app.ts
1321
- var AppSchema = z25.object({
1322
- $schema: z25.string().optional(),
1336
+ var AppSchema = z26.object({
1337
+ $schema: z26.string().optional(),
1323
1338
  name: ResourceIdSchema.describe("App name."),
1324
1339
  region: RegionSchema.describe("The AWS region to deploy to."),
1325
- profile: z25.string().describe("The AWS profile to deploy to."),
1326
- protect: z25.boolean().default(false).describe("Protect your app & stacks from being deleted."),
1327
- removal: z25.enum(["remove", "retain"]).default("remove").describe(
1340
+ profile: z26.string().describe("The AWS profile to deploy to."),
1341
+ protect: z26.boolean().default(false).describe("Protect your app & stacks from being deleted."),
1342
+ removal: z26.enum(["remove", "retain"]).default("remove").describe(
1328
1343
  [
1329
1344
  "Configure how your resources are handled when they have to be removed.",
1330
1345
  "",
@@ -1338,7 +1353,7 @@ var AppSchema = z25.object({
1338
1353
  // .default('prod')
1339
1354
  // .describe('The deployment stage.'),
1340
1355
  // onFailure: OnFailureSchema,
1341
- defaults: z25.object({
1356
+ defaults: z26.object({
1342
1357
  onFailure: OnFailureDefaultSchema,
1343
1358
  onLog: OnLogDefaultSchema,
1344
1359
  auth: AuthDefaultSchema,
@@ -1354,17 +1369,18 @@ var AppSchema = z25.object({
1354
1369
  // table: TableDefaultSchema,
1355
1370
  // store: StoreDefaultSchema,
1356
1371
  alerts: AlertsDefaultSchema,
1372
+ topics: TopicsDefaultSchema,
1357
1373
  layers: LayerSchema
1358
1374
  // dataRetention: z.boolean().describe('Configure how your resources are handled on delete.').default(false),
1359
1375
  }).default({}).describe("Default properties")
1360
1376
  });
1361
1377
 
1362
1378
  // src/config/stack.ts
1363
- import { z as z41 } from "zod";
1379
+ import { z as z42 } from "zod";
1364
1380
 
1365
1381
  // src/feature/cache/schema.ts
1366
1382
  import { gibibytes as gibibytes2 } from "@awsless/size";
1367
- import { z as z26 } from "zod";
1383
+ import { z as z27 } from "zod";
1368
1384
  var StorageSchema = SizeSchema.refine(sizeMin(gibibytes2(1)), "Minimum storage size is 1 GB").refine(
1369
1385
  sizeMax(gibibytes2(5e3)),
1370
1386
  "Maximum storage size is 5000 GB"
@@ -1375,31 +1391,31 @@ var MinimumStorageSchema = StorageSchema.describe(
1375
1391
  var MaximumStorageSchema = StorageSchema.describe(
1376
1392
  "The upper limit for data storage the cache is set to use. You can specify a size value from 1 GB to 5000 GB."
1377
1393
  );
1378
- var EcpuSchema = z26.number().int().min(1e3).max(15e6);
1394
+ var EcpuSchema = z27.number().int().min(1e3).max(15e6);
1379
1395
  var MinimumEcpuSchema = EcpuSchema.describe(
1380
1396
  "The minimum number of ECPUs the cache can consume per second. You can specify a integer from 1,000 to 15,000,000."
1381
1397
  );
1382
1398
  var MaximumEcpuSchema = EcpuSchema.describe(
1383
1399
  "The maximum number of ECPUs the cache can consume per second. You can specify a integer from 1,000 to 15,000,000."
1384
1400
  );
1385
- var CachesSchema = z26.record(
1401
+ var CachesSchema = z27.record(
1386
1402
  ResourceIdSchema,
1387
- z26.object({
1403
+ z27.object({
1388
1404
  minStorage: MinimumStorageSchema.optional(),
1389
1405
  maxStorage: MaximumStorageSchema.optional(),
1390
1406
  minECPU: MinimumEcpuSchema.optional(),
1391
1407
  maxECPU: MaximumEcpuSchema.optional(),
1392
- snapshotRetentionLimit: z26.number().int().positive().default(1)
1408
+ snapshotRetentionLimit: z27.number().int().positive().default(1)
1393
1409
  })
1394
1410
  ).optional().describe("Define the caches in your stack. For access to the cache put your functions inside the global VPC.");
1395
1411
 
1396
1412
  // src/feature/command/schema.ts
1397
- import { z as z27 } from "zod";
1398
- var CommandSchema = z27.union([
1399
- z27.object({
1413
+ import { z as z28 } from "zod";
1414
+ var CommandSchema = z28.union([
1415
+ z28.object({
1400
1416
  file: LocalFileSchema,
1401
- handler: z27.string().default("default").describe("The name of the handler that needs to run"),
1402
- description: z27.string().optional().describe("A description of the command")
1417
+ handler: z28.string().default("default").describe("The name of the handler that needs to run"),
1418
+ description: z28.string().optional().describe("A description of the command")
1403
1419
  // options: z.record(ResourceIdSchema, OptionSchema).optional(),
1404
1420
  // arguments: z.record(ResourceIdSchema, ArgumentSchema).optional(),
1405
1421
  }),
@@ -1409,22 +1425,22 @@ var CommandSchema = z27.union([
1409
1425
  description: void 0
1410
1426
  }))
1411
1427
  ]);
1412
- var CommandsSchema = z27.record(ResourceIdSchema, CommandSchema).optional().describe("Define the custom commands for your stack.");
1428
+ var CommandsSchema = z28.record(ResourceIdSchema, CommandSchema).optional().describe("Define the custom commands for your stack.");
1413
1429
 
1414
1430
  // src/feature/config/schema.ts
1415
- import { z as z28 } from "zod";
1416
- var ConfigNameSchema = z28.string().regex(/[a-z0-9\-]/g, "Invalid config name");
1417
- var ConfigsSchema = z28.array(ConfigNameSchema).optional().describe("Define the config values for your stack.");
1431
+ import { z as z29 } from "zod";
1432
+ var ConfigNameSchema = z29.string().regex(/[a-z0-9\-]/g, "Invalid config name");
1433
+ var ConfigsSchema = z29.array(ConfigNameSchema).optional().describe("Define the config values for your stack.");
1418
1434
 
1419
1435
  // src/feature/cron/schema/index.ts
1420
- import { z as z30 } from "zod";
1436
+ import { z as z31 } from "zod";
1421
1437
 
1422
1438
  // src/feature/cron/schema/schedule.ts
1423
- import { z as z29 } from "zod";
1439
+ import { z as z30 } from "zod";
1424
1440
  import { awsCronExpressionValidator } from "aws-cron-expression-validator";
1425
- var RateExpressionSchema = z29.custom(
1441
+ var RateExpressionSchema = z30.custom(
1426
1442
  (value) => {
1427
- return z29.string().regex(/^[0-9]+ (seconds?|minutes?|hours?|days?)$/).refine((rate) => {
1443
+ return z30.string().regex(/^[0-9]+ (seconds?|minutes?|hours?|days?)$/).refine((rate) => {
1428
1444
  const [str] = rate.split(" ");
1429
1445
  const number = parseInt(str);
1430
1446
  return number > 0;
@@ -1440,9 +1456,9 @@ var RateExpressionSchema = z29.custom(
1440
1456
  }
1441
1457
  return `rate(${rate})`;
1442
1458
  });
1443
- var CronExpressionSchema = z29.custom(
1459
+ var CronExpressionSchema = z30.custom(
1444
1460
  (value) => {
1445
- return z29.string().safeParse(value).success;
1461
+ return z30.string().safeParse(value).success;
1446
1462
  },
1447
1463
  { message: "Invalid cron expression" }
1448
1464
  ).superRefine((value, ctx) => {
@@ -1451,12 +1467,12 @@ var CronExpressionSchema = z29.custom(
1451
1467
  } catch (error) {
1452
1468
  if (error instanceof Error) {
1453
1469
  ctx.addIssue({
1454
- code: z29.ZodIssueCode.custom,
1470
+ code: z30.ZodIssueCode.custom,
1455
1471
  message: `Invalid cron expression: ${error.message}`
1456
1472
  });
1457
1473
  } else {
1458
1474
  ctx.addIssue({
1459
- code: z29.ZodIssueCode.custom,
1475
+ code: z30.ZodIssueCode.custom,
1460
1476
  message: "Invalid cron expression"
1461
1477
  });
1462
1478
  }
@@ -1467,28 +1483,28 @@ var CronExpressionSchema = z29.custom(
1467
1483
  var ScheduleExpressionSchema = RateExpressionSchema.or(CronExpressionSchema);
1468
1484
 
1469
1485
  // src/feature/cron/schema/index.ts
1470
- var CronsSchema = z30.record(
1486
+ var CronsSchema = z31.record(
1471
1487
  ResourceIdSchema,
1472
- z30.object({
1473
- enabled: z30.boolean().default(true).describe("If the cron is enabled."),
1488
+ z31.object({
1489
+ enabled: z31.boolean().default(true).describe("If the cron is enabled."),
1474
1490
  consumer: FunctionSchema.describe("The consuming lambda function properties."),
1475
1491
  schedule: ScheduleExpressionSchema.describe(
1476
1492
  'The scheduling expression.\n\nexample: "0 20 * * ? *"\nexample: "5 minutes"'
1477
1493
  ),
1478
- payload: z30.unknown().optional().describe("The JSON payload that will be passed to the consumer.")
1494
+ payload: z31.unknown().optional().describe("The JSON payload that will be passed to the consumer.")
1479
1495
  })
1480
1496
  ).optional().describe(`Define the cron jobs in your stack.`);
1481
1497
 
1482
1498
  // src/feature/search/schema.ts
1483
1499
  import { gibibytes as gibibytes3 } from "@awsless/size";
1484
- import { z as z31 } from "zod";
1485
- var VersionSchema = z31.union([
1500
+ import { z as z32 } from "zod";
1501
+ var VersionSchema = z32.union([
1486
1502
  //
1487
- z31.enum(["2.13", "2.11", "2.9", "2.7", "2.5", "2.3", "1.3"]),
1488
- z31.string()
1503
+ z32.enum(["2.13", "2.11", "2.9", "2.7", "2.5", "2.3", "1.3"]),
1504
+ z32.string()
1489
1505
  ]).describe("Specify the OpenSearch engine version.");
1490
- var TypeSchema = z31.union([
1491
- z31.enum([
1506
+ var TypeSchema = z32.union([
1507
+ z32.enum([
1492
1508
  "t3.small",
1493
1509
  "t3.medium",
1494
1510
  "m3.medium",
@@ -1562,13 +1578,13 @@ var TypeSchema = z31.union([
1562
1578
  "r6gd.12xlarge",
1563
1579
  "r6gd.16xlarge"
1564
1580
  ]),
1565
- z31.string()
1581
+ z32.string()
1566
1582
  ]).describe("Instance type of data nodes in the cluster.");
1567
- var CountSchema = z31.number().int().min(1).describe("Number of instances in the cluster.");
1583
+ var CountSchema = z32.number().int().min(1).describe("Number of instances in the cluster.");
1568
1584
  var StorageSizeSchema = SizeSchema.refine(sizeMin(gibibytes3(10)), "Minimum storage size is 10 GB").refine(sizeMax(gibibytes3(100)), "Maximum storage size is 100 GB").describe("The size of the function's /tmp directory. You can specify a size value from 512 MB to 10 GiB.");
1569
- var SearchsSchema = z31.record(
1585
+ var SearchsSchema = z32.record(
1570
1586
  ResourceIdSchema,
1571
- z31.object({
1587
+ z32.object({
1572
1588
  type: TypeSchema.default("t3.small"),
1573
1589
  count: CountSchema.default(1),
1574
1590
  version: VersionSchema.default("2.13"),
@@ -1579,12 +1595,12 @@ var SearchsSchema = z31.record(
1579
1595
  ).optional().describe("Define the search instances in your stack. Backed by OpenSearch.");
1580
1596
 
1581
1597
  // src/feature/site/schema.ts
1582
- import { z as z33 } from "zod";
1598
+ import { z as z34 } from "zod";
1583
1599
 
1584
1600
  // src/config/schema/local-entry.ts
1585
1601
  import { stat as stat3 } from "fs/promises";
1586
- import { z as z32 } from "zod";
1587
- var LocalEntrySchema = z32.union([
1602
+ import { z as z33 } from "zod";
1603
+ var LocalEntrySchema = z33.union([
1588
1604
  RelativePathSchema.refine(async (path) => {
1589
1605
  try {
1590
1606
  const s = await stat3(path);
@@ -1593,7 +1609,7 @@ var LocalEntrySchema = z32.union([
1593
1609
  return false;
1594
1610
  }
1595
1611
  }, `File or directory doesn't exist`),
1596
- z32.object({
1612
+ z33.object({
1597
1613
  nocheck: RelativePathSchema.describe(
1598
1614
  "Specifies a local file or directory without checking if the file or directory exists."
1599
1615
  )
@@ -1601,14 +1617,14 @@ var LocalEntrySchema = z32.union([
1601
1617
  ]);
1602
1618
 
1603
1619
  // src/feature/site/schema.ts
1604
- var ErrorResponsePathSchema = z33.string().describe(
1620
+ var ErrorResponsePathSchema = z34.string().describe(
1605
1621
  [
1606
1622
  "The path to the custom error page that you want to return to the viewer when your origin returns the HTTP status code specified.",
1607
1623
  "- We recommend that you store custom error pages in an Amazon S3 bucket.",
1608
1624
  "If you store custom error pages on an HTTP server and the server starts to return 5xx errors, CloudFront can't get the files that you want to return to viewers because the origin server is unavailable."
1609
1625
  ].join("\n")
1610
1626
  );
1611
- var StatusCodeSchema = z33.number().int().positive().optional().describe(
1627
+ var StatusCodeSchema = z34.number().int().positive().optional().describe(
1612
1628
  [
1613
1629
  "The HTTP status code that you want CloudFront to return to the viewer along with the custom error page.",
1614
1630
  "There are a variety of reasons that you might want CloudFront to return a status code different from the status code that your origin returned to CloudFront, for example:",
@@ -1621,19 +1637,19 @@ var StatusCodeSchema = z33.number().int().positive().optional().describe(
1621
1637
  var MinTTLSchema = DurationSchema.describe(
1622
1638
  "The minimum amount of time, that you want to cache the error response. When this time period has elapsed, CloudFront queries your origin to see whether the problem that caused the error has been resolved and the requested object is now available."
1623
1639
  );
1624
- var ErrorResponseSchema = z33.union([
1640
+ var ErrorResponseSchema = z34.union([
1625
1641
  ErrorResponsePathSchema,
1626
- z33.object({
1642
+ z34.object({
1627
1643
  path: ErrorResponsePathSchema,
1628
1644
  statusCode: StatusCodeSchema.optional(),
1629
1645
  minTTL: MinTTLSchema.optional()
1630
1646
  })
1631
1647
  ]).optional();
1632
- var SitesSchema = z33.record(
1648
+ var SitesSchema = z34.record(
1633
1649
  ResourceIdSchema,
1634
- z33.object({
1650
+ z34.object({
1635
1651
  domain: ResourceIdSchema.describe("The domain id to link your site with.").optional(),
1636
- subDomain: z33.string().optional(),
1652
+ subDomain: z34.string().optional(),
1637
1653
  // bind: z
1638
1654
  // .object({
1639
1655
  // auth: z.array(ResourceIdSchema),
@@ -1642,16 +1658,16 @@ var SitesSchema = z33.record(
1642
1658
  // // rest: z.array(ResourceIdSchema),
1643
1659
  // })
1644
1660
  // .optional(),
1645
- build: z33.object({
1646
- command: z33.string().describe(
1661
+ build: z34.object({
1662
+ command: z34.string().describe(
1647
1663
  `Specifies the files and directories to generate the cache key for your custom build command.`
1648
1664
  ),
1649
- cacheKey: z33.union([LocalEntrySchema.transform((v) => [v]), LocalEntrySchema.array()]).describe(
1665
+ cacheKey: z34.union([LocalEntrySchema.transform((v) => [v]), LocalEntrySchema.array()]).describe(
1650
1666
  `Specifies the files and directories to generate the cache key for your custom build command.`
1651
1667
  ),
1652
- configs: z33.string().array().describe("Define the config values for your build command.")
1668
+ configs: z34.string().array().describe("Define the config values for your build command.")
1653
1669
  }).optional().describe(`Specifies the build process for sites that need a build step.`),
1654
- static: z33.union([LocalDirectorySchema, z33.boolean()]).optional().describe(
1670
+ static: z34.union([LocalDirectorySchema, z34.boolean()]).optional().describe(
1655
1671
  "Specifies the path to the static files directory. Additionally you can also pass `true` when you don't have local static files, but still want to make an S3 bucket."
1656
1672
  ),
1657
1673
  ssr: FunctionSchema.optional().describe("Specifies the file that will render the site on the server."),
@@ -1672,7 +1688,7 @@ var SitesSchema = z33.record(
1672
1688
  // build: z.string().optional(),
1673
1689
  // }),
1674
1690
  // ]),
1675
- geoRestrictions: z33.array(z33.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
1691
+ geoRestrictions: z34.array(z34.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
1676
1692
  // forwardHost: z
1677
1693
  // .boolean()
1678
1694
  // .default(false)
@@ -1683,7 +1699,7 @@ var SitesSchema = z33.record(
1683
1699
  // 'Keep in mind that this requires an extra CloudFront Function.',
1684
1700
  // ].join('\n')
1685
1701
  // ),
1686
- errors: z33.object({
1702
+ errors: z34.object({
1687
1703
  400: ErrorResponseSchema.describe("Customize a `400 Bad Request` response."),
1688
1704
  403: ErrorResponseSchema.describe("Customize a `403 Forbidden` response."),
1689
1705
  404: ErrorResponseSchema.describe("Customize a `404 Not Found` response."),
@@ -1696,20 +1712,20 @@ var SitesSchema = z33.record(
1696
1712
  503: ErrorResponseSchema.describe("Customize a `503 Service Unavailable` response."),
1697
1713
  504: ErrorResponseSchema.describe("Customize a `504 Gateway Timeout` response.")
1698
1714
  }).optional().describe("Customize the error responses for specific HTTP status codes."),
1699
- cors: z33.object({
1700
- override: z33.boolean().default(false),
1715
+ cors: z34.object({
1716
+ override: z34.boolean().default(false),
1701
1717
  maxAge: DurationSchema.default("365 days"),
1702
- exposeHeaders: z33.string().array().optional(),
1703
- credentials: z33.boolean().default(false),
1704
- headers: z33.string().array().default(["*"]),
1705
- origins: z33.string().array().default(["*"]),
1706
- methods: z33.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
1718
+ exposeHeaders: z34.string().array().optional(),
1719
+ credentials: z34.boolean().default(false),
1720
+ headers: z34.string().array().default(["*"]),
1721
+ origins: z34.string().array().default(["*"]),
1722
+ methods: z34.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
1707
1723
  }).optional().describe("Specify the cors headers."),
1708
- auth: z33.object({
1709
- username: z33.string().describe("Basic auth username"),
1710
- password: z33.string().describe("Basic auth password")
1724
+ auth: z34.object({
1725
+ username: z34.string().describe("Basic auth username"),
1726
+ password: z34.string().describe("Basic auth password")
1711
1727
  }).optional().describe("Enable basic authentication for the site"),
1712
- security: z33.object({
1728
+ security: z34.object({
1713
1729
  // contentSecurityPolicy: z.object({
1714
1730
  // override: z.boolean().default(false),
1715
1731
  // policy: z.string(),
@@ -1751,10 +1767,10 @@ var SitesSchema = z33.record(
1751
1767
  // reportUri?: string
1752
1768
  // }
1753
1769
  }).optional().describe("Specify the security policy."),
1754
- cache: z33.object({
1755
- cookies: z33.string().array().optional().describe("Specifies the cookies that CloudFront includes in the cache key."),
1756
- headers: z33.string().array().optional().describe("Specifies the headers that CloudFront includes in the cache key."),
1757
- queries: z33.string().array().optional().describe("Specifies the query values that CloudFront includes in the cache key.")
1770
+ cache: z34.object({
1771
+ cookies: z34.string().array().optional().describe("Specifies the cookies that CloudFront includes in the cache key."),
1772
+ headers: z34.string().array().optional().describe("Specifies the headers that CloudFront includes in the cache key."),
1773
+ queries: z34.string().array().optional().describe("Specifies the query values that CloudFront includes in the cache key.")
1758
1774
  }).optional().describe(
1759
1775
  "Specifies the cookies, headers, and query values that CloudFront includes in the cache key."
1760
1776
  )
@@ -1762,22 +1778,22 @@ var SitesSchema = z33.record(
1762
1778
  ).optional().describe("Define the sites in your stack.");
1763
1779
 
1764
1780
  // src/feature/store/schema.ts
1765
- import { z as z34 } from "zod";
1766
- var StoresSchema = z34.union([
1767
- z34.array(ResourceIdSchema).transform((list3) => {
1781
+ import { z as z35 } from "zod";
1782
+ var StoresSchema = z35.union([
1783
+ z35.array(ResourceIdSchema).transform((list3) => {
1768
1784
  const stores = {};
1769
1785
  for (const key of list3) {
1770
1786
  stores[key] = {};
1771
1787
  }
1772
1788
  return stores;
1773
1789
  }),
1774
- z34.record(
1790
+ z35.record(
1775
1791
  ResourceIdSchema,
1776
- z34.object({
1792
+ z35.object({
1777
1793
  // cors: CorsSchema,
1778
1794
  // deletionProtection: DeletionProtectionSchema.optional(),
1779
- versioning: z34.boolean().default(false).describe("Enable versioning of your store."),
1780
- events: z34.object({
1795
+ versioning: z35.boolean().default(false).describe("Enable versioning of your store."),
1796
+ events: z35.object({
1781
1797
  // create
1782
1798
  "created:*": FunctionSchema.optional().describe(
1783
1799
  "Subscribe to notifications regardless of the API that was used to create an object."
@@ -1810,58 +1826,58 @@ var StoresSchema = z34.union([
1810
1826
  ]).optional().describe("Define the stores in your stack.");
1811
1827
 
1812
1828
  // src/feature/icon/schema.ts
1813
- import { z as z35 } from "zod";
1829
+ import { z as z36 } from "zod";
1814
1830
  var staticOriginSchema = LocalDirectorySchema.describe(
1815
1831
  "Specifies the path to a local image directory that will be uploaded in S3."
1816
1832
  );
1817
1833
  var functionOriginSchema = FunctionSchema.describe(
1818
1834
  "Specifies the file that will be called when an image isn't found in the (cache) bucket."
1819
1835
  );
1820
- var IconsSchema = z35.record(
1836
+ var IconsSchema = z36.record(
1821
1837
  ResourceIdSchema,
1822
- z35.object({
1838
+ z36.object({
1823
1839
  domain: ResourceIdSchema.describe("The domain id to link your site with.").optional(),
1824
- subDomain: z35.string().optional(),
1840
+ subDomain: z36.string().optional(),
1825
1841
  log: LogSchema.optional(),
1826
1842
  cacheDuration: DurationSchema.optional().describe("The cache duration of the cached icons."),
1827
- preserveId: z35.boolean().optional().default(false).describe("Preserve the IDs of the icons."),
1828
- symbols: z35.boolean().optional().default(false).describe("Use SVG symbols for icons."),
1829
- origin: z35.union([
1830
- z35.object({
1843
+ preserveId: z36.boolean().optional().default(false).describe("Preserve the IDs of the icons."),
1844
+ symbols: z36.boolean().optional().default(false).describe("Use SVG symbols for icons."),
1845
+ origin: z36.union([
1846
+ z36.object({
1831
1847
  static: staticOriginSchema,
1832
1848
  function: functionOriginSchema.optional()
1833
1849
  }),
1834
- z35.object({
1850
+ z36.object({
1835
1851
  static: staticOriginSchema.optional(),
1836
1852
  function: functionOriginSchema
1837
1853
  }),
1838
- z35.object({
1854
+ z36.object({
1839
1855
  static: staticOriginSchema,
1840
1856
  function: functionOriginSchema
1841
1857
  })
1842
1858
  ]).describe(
1843
1859
  "Image transformation will be applied from a base image. Base images orginates from a local directory that will be uploaded to S3 or from a lambda function."
1844
1860
  ),
1845
- cors: z35.object({
1846
- override: z35.boolean().default(true),
1861
+ cors: z36.object({
1862
+ override: z36.boolean().default(true),
1847
1863
  maxAge: DurationSchema.default("365 days"),
1848
- exposeHeaders: z35.string().array().optional(),
1849
- credentials: z35.boolean().default(false),
1850
- headers: z35.string().array().default(["*"]),
1851
- origins: z35.string().array().default(["*"])
1864
+ exposeHeaders: z36.string().array().optional(),
1865
+ credentials: z36.boolean().default(false),
1866
+ headers: z36.string().array().default(["*"]),
1867
+ origins: z36.string().array().default(["*"])
1852
1868
  }).optional().describe("Specify the cors headers.")
1853
1869
  // version: z.number().int().min(1).optional().describe('Version of the icon configuration.'),
1854
1870
  })
1855
1871
  ).optional().describe("Define an icon proxy in your stack. Store, optimize, and deliver icons at scale.");
1856
1872
 
1857
1873
  // src/feature/image/schema.ts
1858
- import { z as z36 } from "zod";
1859
- var transformationOptionsSchema = z36.object({
1860
- width: z36.number().int().positive().optional(),
1861
- height: z36.number().int().positive().optional(),
1862
- fit: z36.enum(["cover", "contain", "fill", "inside", "outside"]).optional(),
1863
- position: z36.enum(["top", "right top", "right", "right bottom", "bottom", "left bottom", "left", "left top", "center"]).optional(),
1864
- quality: z36.number().int().min(1).max(100).optional()
1874
+ import { z as z37 } from "zod";
1875
+ var transformationOptionsSchema = z37.object({
1876
+ width: z37.number().int().positive().optional(),
1877
+ height: z37.number().int().positive().optional(),
1878
+ fit: z37.enum(["cover", "contain", "fill", "inside", "outside"]).optional(),
1879
+ position: z37.enum(["top", "right top", "right", "right bottom", "bottom", "left bottom", "left", "left top", "center"]).optional(),
1880
+ quality: z37.number().int().min(1).max(100).optional()
1865
1881
  });
1866
1882
  var staticOriginSchema2 = LocalDirectorySchema.describe(
1867
1883
  "Specifies the path to a local image directory that will be uploaded in S3."
@@ -1869,68 +1885,115 @@ var staticOriginSchema2 = LocalDirectorySchema.describe(
1869
1885
  var functionOriginSchema2 = FunctionSchema.describe(
1870
1886
  "Specifies the file that will be called when an image isn't found in the (cache) bucket."
1871
1887
  );
1872
- var ImagesSchema = z36.record(
1888
+ var ImagesSchema = z37.record(
1873
1889
  ResourceIdSchema,
1874
- z36.object({
1890
+ z37.object({
1875
1891
  domain: ResourceIdSchema.describe("The domain id to link your site with.").optional(),
1876
- subDomain: z36.string().optional(),
1892
+ subDomain: z37.string().optional(),
1877
1893
  log: LogSchema.optional(),
1878
1894
  cacheDuration: DurationSchema.optional().describe("Cache duration of the cached images."),
1879
- presets: z36.record(z36.string(), transformationOptionsSchema).describe("Named presets for image transformations"),
1880
- extensions: z36.object({
1881
- jpeg: z36.object({
1882
- mozjpeg: z36.boolean().optional(),
1883
- progressive: z36.boolean().optional()
1895
+ presets: z37.record(z37.string(), transformationOptionsSchema).describe("Named presets for image transformations"),
1896
+ extensions: z37.object({
1897
+ jpeg: z37.object({
1898
+ mozjpeg: z37.boolean().optional(),
1899
+ progressive: z37.boolean().optional()
1884
1900
  }).optional(),
1885
- webp: z36.object({
1886
- effort: z36.number().int().min(1).max(10).default(7).optional(),
1887
- lossless: z36.boolean().optional(),
1888
- nearLossless: z36.boolean().optional()
1901
+ webp: z37.object({
1902
+ effort: z37.number().int().min(1).max(10).default(7).optional(),
1903
+ lossless: z37.boolean().optional(),
1904
+ nearLossless: z37.boolean().optional()
1889
1905
  }).optional(),
1890
- png: z36.object({
1891
- compressionLevel: z36.number().int().min(0).max(9).default(6).optional()
1906
+ png: z37.object({
1907
+ compressionLevel: z37.number().int().min(0).max(9).default(6).optional()
1892
1908
  }).optional()
1893
1909
  }).refine((data) => {
1894
1910
  return Object.keys(data).length > 0;
1895
1911
  }, "At least one extension must be defined.").describe("Specify the allowed extensions."),
1896
- origin: z36.union([
1897
- z36.object({
1912
+ origin: z37.union([
1913
+ z37.object({
1898
1914
  static: staticOriginSchema2,
1899
1915
  function: functionOriginSchema2.optional()
1900
1916
  }),
1901
- z36.object({
1917
+ z37.object({
1902
1918
  static: staticOriginSchema2.optional(),
1903
1919
  function: functionOriginSchema2
1904
1920
  }),
1905
- z36.object({
1921
+ z37.object({
1906
1922
  static: staticOriginSchema2,
1907
1923
  function: functionOriginSchema2
1908
1924
  })
1909
1925
  ]).describe(
1910
1926
  "Specify the origin of your images. Image transformation will be applied from a base image. Base images can be loaded from a S3 bucket (that is synced from a local directory) or dynamicly from a lambda function."
1911
1927
  ),
1912
- version: z36.number().int().min(1).optional().describe("Version of the image configuration.")
1928
+ version: z37.number().int().min(1).optional().describe("Version of the image configuration.")
1913
1929
  })
1914
1930
  ).optional().describe("Define an image proxy in your stack. Store, transform, optimize, and deliver images at scale.");
1915
1931
 
1932
+ // src/feature/metric/schema.ts
1933
+ import { z as z38 } from "zod";
1934
+ var ops = {
1935
+ ">": "GreaterThanThreshold",
1936
+ ">=": "GreaterThanOrEqualToThreshold",
1937
+ "<": "LessThanThreshold",
1938
+ "<=": "LessThanOrEqualToThreshold"
1939
+ };
1940
+ var stats = {
1941
+ count: "SampleCount",
1942
+ avg: "Average",
1943
+ sum: "Sum",
1944
+ min: "Minimum",
1945
+ max: "Maximum"
1946
+ };
1947
+ var WhereSchema = z38.union([
1948
+ z38.string().regex(/(count|avg|sum|min|max) (>|>=|<|<=) (\d)/, "Invalid where query").transform((where) => {
1949
+ const [stat5, op, value] = where.split(" ");
1950
+ return { stat: stat5, op, value: parseFloat(value) };
1951
+ }),
1952
+ z38.object({
1953
+ stat: z38.enum(["count", "avg", "sum", "min", "max"]),
1954
+ op: z38.enum([">", ">=", "<", "<="]),
1955
+ value: z38.number()
1956
+ })
1957
+ ]).transform((where) => {
1958
+ return {
1959
+ stat: stats[where.stat],
1960
+ op: ops[where.op],
1961
+ value: where.value
1962
+ };
1963
+ });
1964
+ var AlarmSchema = z38.object({
1965
+ description: z38.string().optional(),
1966
+ where: WhereSchema,
1967
+ period: DurationSchema,
1968
+ minDataPoints: z38.number().int().default(1),
1969
+ trigger: z38.union([EmailSchema.transform((v) => [v]), EmailSchema.array(), FunctionSchema])
1970
+ });
1971
+ var MetricsSchema = z38.record(
1972
+ ResourceIdSchema,
1973
+ z38.object({
1974
+ type: z38.enum(["number", "size", "duration"]),
1975
+ alarms: AlarmSchema.array().optional()
1976
+ })
1977
+ ).optional().describe("Define the metrics in your stack.");
1978
+
1916
1979
  // src/feature/table/schema.ts
1917
1980
  import { minutes as minutes4, seconds as seconds4 } from "@awsless/duration";
1918
- import { z as z37 } from "zod";
1919
- var KeySchema = z37.string().min(1).max(255);
1920
- var TablesSchema = z37.record(
1981
+ import { z as z39 } from "zod";
1982
+ var KeySchema = z39.string().min(1).max(255);
1983
+ var TablesSchema = z39.record(
1921
1984
  ResourceIdSchema,
1922
- z37.object({
1985
+ z39.object({
1923
1986
  hash: KeySchema.describe(
1924
1987
  "Specifies the name of the partition / hash key that makes up the primary key for the table."
1925
1988
  ),
1926
1989
  sort: KeySchema.optional().describe(
1927
1990
  "Specifies the name of the range / sort key that makes up the primary key for the table."
1928
1991
  ),
1929
- fields: z37.record(z37.string(), z37.enum(["string", "number", "binary"])).optional().describe(
1992
+ fields: z39.record(z39.string(), z39.enum(["string", "number", "binary"])).optional().describe(
1930
1993
  'A list of attributes that describe the key schema for the table and indexes. If no attribute field is defined we default to "string".'
1931
1994
  ),
1932
- class: z37.enum(["standard", "standard-infrequent-access"]).default("standard").describe("The table class of the table."),
1933
- pointInTimeRecovery: z37.boolean().default(false).describe("Indicates whether point in time recovery is enabled on the table."),
1995
+ class: z39.enum(["standard", "standard-infrequent-access"]).default("standard").describe("The table class of the table."),
1996
+ pointInTimeRecovery: z39.boolean().default(false).describe("Indicates whether point in time recovery is enabled on the table."),
1934
1997
  ttl: KeySchema.optional().describe(
1935
1998
  [
1936
1999
  "The name of the TTL attribute used to store the expiration time for items in the table.",
@@ -1938,8 +2001,8 @@ var TablesSchema = z37.record(
1938
2001
  ].join("\n")
1939
2002
  ),
1940
2003
  // deletionProtection: DeletionProtectionSchema.optional(),
1941
- stream: z37.object({
1942
- type: z37.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]).describe(
2004
+ stream: z39.object({
2005
+ type: z39.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]).describe(
1943
2006
  [
1944
2007
  "When an item in the table is modified, you can determines what information is written to the stream for this table.",
1945
2008
  "Valid values are:",
@@ -1949,7 +2012,7 @@ var TablesSchema = z37.record(
1949
2012
  "- new-and-old-images - Both the new and the old item images of the item are written to the stream."
1950
2013
  ].join("\n")
1951
2014
  ),
1952
- batchSize: z37.number().min(1).max(1e4).default(1).describe(
2015
+ batchSize: z39.number().min(1).max(1e4).default(1).describe(
1953
2016
  [
1954
2017
  "The maximum number of records in each batch that Lambda pulls from your stream and sends to your function.",
1955
2018
  "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).",
@@ -1979,7 +2042,7 @@ var TablesSchema = z37.record(
1979
2042
  // 'You can specify a number from -1 to 10000.',
1980
2043
  // ].join('\n')
1981
2044
  // ),
1982
- retryAttempts: z37.number().min(-1).max(1e4).default(-1).describe(
2045
+ retryAttempts: z39.number().min(-1).max(1e4).default(-1).describe(
1983
2046
  [
1984
2047
  "Discard records after the specified number of retries.",
1985
2048
  "The default value is -1, which sets the maximum number of retries to infinite.",
@@ -1987,7 +2050,7 @@ var TablesSchema = z37.record(
1987
2050
  "You can specify a number from -1 to 10000."
1988
2051
  ].join("\n")
1989
2052
  ),
1990
- concurrencyPerShard: z37.number().min(1).max(10).default(1).describe(
2053
+ concurrencyPerShard: z39.number().min(1).max(10).default(1).describe(
1991
2054
  [
1992
2055
  "The number of batches to process concurrently from each shard.",
1993
2056
  "You can specify a number from 1 to 10."
@@ -1997,16 +2060,16 @@ var TablesSchema = z37.record(
1997
2060
  }).optional().describe(
1998
2061
  "The settings for the DynamoDB table stream, which capture changes to items stored in the table."
1999
2062
  ),
2000
- indexes: z37.record(
2001
- z37.string(),
2002
- z37.object({
2063
+ indexes: z39.record(
2064
+ z39.string(),
2065
+ z39.object({
2003
2066
  hash: KeySchema.describe(
2004
2067
  "Specifies the name of the partition / hash key that makes up the primary key for the global secondary index."
2005
2068
  ),
2006
2069
  sort: KeySchema.optional().describe(
2007
2070
  "Specifies the name of the range / sort key that makes up the primary key for the global secondary index."
2008
2071
  ),
2009
- projection: z37.enum(["all", "keys-only"]).default("all").describe(
2072
+ projection: z39.enum(["all", "keys-only"]).default("all").describe(
2010
2073
  [
2011
2074
  "The set of attributes that are projected into the index:",
2012
2075
  "- all - All of the table attributes are projected into the index.",
@@ -2020,11 +2083,11 @@ var TablesSchema = z37.record(
2020
2083
  ).optional().describe("Define the tables in your stack.");
2021
2084
 
2022
2085
  // src/feature/task/schema.ts
2023
- import { z as z38 } from "zod";
2024
- var RetryAttemptsSchema2 = z38.number().int().min(0).max(2).describe(
2086
+ import { z as z40 } from "zod";
2087
+ var RetryAttemptsSchema2 = z40.number().int().min(0).max(2).describe(
2025
2088
  "The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 2."
2026
2089
  );
2027
- var TaskSchema = z38.union([
2090
+ var TaskSchema = z40.union([
2028
2091
  LocalFileSchema.transform((file) => ({
2029
2092
  consumer: {
2030
2093
  code: {
@@ -2035,33 +2098,24 @@ var TaskSchema = z38.union([
2035
2098
  },
2036
2099
  retryAttempts: void 0
2037
2100
  })),
2038
- z38.object({
2101
+ z40.object({
2039
2102
  consumer: FunctionSchema,
2040
2103
  retryAttempts: RetryAttemptsSchema2.optional()
2041
2104
  })
2042
2105
  ]);
2043
- var TasksSchema = z38.record(ResourceIdSchema, TaskSchema).optional().describe("Define the tasks in your stack.");
2106
+ var TasksSchema = z40.record(ResourceIdSchema, TaskSchema).optional().describe("Define the tasks in your stack.");
2044
2107
 
2045
2108
  // src/feature/test/schema.ts
2046
- import { z as z39 } from "zod";
2047
- var TestsSchema = z39.union([LocalDirectorySchema.transform((v) => [v]), LocalDirectorySchema.array()]).describe("Define the location of your tests for your stack.").optional();
2048
-
2049
- // src/feature/topic/schema.ts
2050
- import { kebabCase as kebabCase3 } from "change-case";
2051
- import { z as z40 } from "zod";
2052
- var TopicNameSchema = z40.string().min(3).max(256).regex(/^[a-z0-9\-]+$/i, "Invalid topic name").transform((value) => kebabCase3(value)).describe("Define event topic name.");
2053
- var TopicsSchema = z40.array(TopicNameSchema).refine((topics) => {
2054
- return topics.length === new Set(topics).size;
2055
- }, "Must be a list of unique topic names").optional().describe("Define the event topics to publish too in your stack.");
2056
- var SubscribersSchema = z40.record(TopicNameSchema, FunctionSchema).optional().describe("Define the event topics to subscribe too in your stack.");
2109
+ import { z as z41 } from "zod";
2110
+ var TestsSchema = z41.union([LocalDirectorySchema.transform((v) => [v]), LocalDirectorySchema.array()]).describe("Define the location of your tests for your stack.").optional();
2057
2111
 
2058
2112
  // src/config/stack.ts
2059
2113
  var DependsSchema = ResourceIdSchema.array().optional().describe("Define the stacks that this stack is depended on.");
2060
2114
  var NameSchema = ResourceIdSchema.refine((name) => !["base", "hostedzones"].includes(name), {
2061
2115
  message: `Stack name can't be a reserved name.`
2062
2116
  }).describe("Stack name.");
2063
- var StackSchema = z41.object({
2064
- $schema: z41.string().optional(),
2117
+ var StackSchema = z42.object({
2118
+ $schema: z42.string().optional(),
2065
2119
  name: NameSchema,
2066
2120
  depends: DependsSchema,
2067
2121
  commands: CommandsSchema,
@@ -2074,7 +2128,7 @@ var StackSchema = z41.object({
2074
2128
  configs: ConfigsSchema,
2075
2129
  crons: CronsSchema,
2076
2130
  caches: CachesSchema,
2077
- topics: TopicsSchema,
2131
+ // topics: TopicsSchema,
2078
2132
  subscribers: SubscribersSchema,
2079
2133
  functions: FunctionsSchema,
2080
2134
  instances: InstancesSchema,
@@ -2088,7 +2142,8 @@ var StackSchema = z41.object({
2088
2142
  sites: SitesSchema,
2089
2143
  tests: TestsSchema,
2090
2144
  images: ImagesSchema,
2091
- icons: IconsSchema
2145
+ icons: IconsSchema,
2146
+ metrics: MetricsSchema
2092
2147
  });
2093
2148
 
2094
2149
  // src/config/load/read.ts
@@ -2130,13 +2185,13 @@ var readConfigWithStage = async (file, stage) => {
2130
2185
  };
2131
2186
 
2132
2187
  // src/config/load/validate.ts
2133
- import { z as z42 } from "zod";
2188
+ import { z as z43 } from "zod";
2134
2189
  var validateConfig = async (schema, file, data) => {
2135
2190
  try {
2136
2191
  const result = await schema.parseAsync(data);
2137
2192
  return result;
2138
2193
  } catch (error) {
2139
- if (error instanceof z42.ZodError) {
2194
+ if (error instanceof z43.ZodError) {
2140
2195
  throw new ConfigError(file, error, data);
2141
2196
  }
2142
2197
  throw error;
@@ -2889,7 +2944,7 @@ var formatByteSize = (size) => {
2889
2944
 
2890
2945
  // src/feature/on-failure/util.ts
2891
2946
  var getGlobalOnFailure = (ctx) => {
2892
- return ctx.appConfig.defaults.onFailure ? ctx.shared.get("on-failure", "queue-arn") : void 0;
2947
+ return ctx.shared.get("on-failure", "queue-arn");
2893
2948
  };
2894
2949
 
2895
2950
  // src/feature/function/build/typescript/bundle.ts
@@ -3226,7 +3281,8 @@ var createLambdaFunction = (parentGroup, ctx, ns, id, local) => {
3226
3281
  Statement: list3.map((statement) => ({
3227
3282
  Effect: pascalCase(statement.effect ?? "allow"),
3228
3283
  Action: statement.actions,
3229
- Resource: statement.resources
3284
+ Resource: statement.resources,
3285
+ Condition: statement.conditions
3230
3286
  }))
3231
3287
  })
3232
3288
  );
@@ -3432,19 +3488,17 @@ var createAsyncLambdaFunction = (group, ctx, ns, id, local) => {
3432
3488
  functionName: result.lambda.arn,
3433
3489
  maximumRetryAttempts: props.retryAttempts,
3434
3490
  destinationConfig: {
3435
- onFailure: onFailure ? { destination: onFailure } : void 0
3491
+ onFailure: { destination: onFailure }
3436
3492
  }
3437
3493
  },
3438
3494
  {
3439
3495
  dependsOn: [result.policy]
3440
3496
  }
3441
3497
  );
3442
- if (onFailure) {
3443
- result.addPermission({
3444
- actions: ["sqs:SendMessage", "sqs:GetQueueUrl"],
3445
- resources: [onFailure]
3446
- });
3447
- }
3498
+ result.addPermission({
3499
+ actions: ["sqs:SendMessage", "sqs:GetQueueUrl"],
3500
+ resources: [onFailure]
3501
+ });
3448
3502
  return result;
3449
3503
  };
3450
3504
 
@@ -3796,7 +3850,7 @@ var functionFeature = defineFeature({
3796
3850
  // forceDelete: true,
3797
3851
  });
3798
3852
  ctx.shared.set("function", "bucket-name", bucket.bucket);
3799
- const warmGroup = new $6.aws.scheduler.ScheduleGroup(ctx.base, "warm", {
3853
+ const warmGroup = new $6.aws.scheduler.ScheduleGroup(group, "warm", {
3800
3854
  name: formatGlobalResourceName({
3801
3855
  appName: ctx.app.name,
3802
3856
  resourceType: "function",
@@ -3859,9 +3913,6 @@ var onFailureFeature = defineFeature({
3859
3913
  // }
3860
3914
  // },
3861
3915
  onApp(ctx) {
3862
- if (!ctx.appConfig.defaults.onFailure) {
3863
- return;
3864
- }
3865
3916
  const group = new Group8(ctx.base, "on-failure", "main");
3866
3917
  const queue2 = new $8.aws.sqs.Queue(group, "on-failure", {
3867
3918
  name: formatGlobalResourceName({
@@ -3870,8 +3921,10 @@ var onFailureFeature = defineFeature({
3870
3921
  resourceName: "failure"
3871
3922
  })
3872
3923
  });
3873
- ctx.addEnv("ON_FAILURE_QUEUE_ARN", queue2.arn);
3874
3924
  ctx.shared.set("on-failure", "queue-arn", queue2.arn);
3925
+ if (!ctx.appConfig.defaults.onFailure) {
3926
+ return;
3927
+ }
3875
3928
  const result = createLambdaFunction(group, ctx, "on-failure", "consumer", ctx.appConfig.defaults.onFailure);
3876
3929
  new $8.aws.lambda.EventSourceMapping(
3877
3930
  group,
@@ -3896,31 +3949,6 @@ var onFailureFeature = defineFeature({
3896
3949
  resources: [queue2.arn]
3897
3950
  });
3898
3951
  }
3899
- // onStack(ctx) {
3900
- // const onFailure = ctx.stackConfig.onFailure
3901
- // if (!onFailure) {
3902
- // return
3903
- // }
3904
- // const queueArn = ctx.shared.get<aws.ARN>('on-failure-queue-arn')
3905
- // const group = new Node(ctx.stack, 'on-failure', 'failure')
3906
- // const { lambda, policy } = createLambdaFunction(group, ctx, 'on-failure', 'failure', onFailure)
3907
- // const source = new aws.lambda.EventSourceMapping(group, 'on-failure', {
3908
- // functionArn: lambda.arn,
3909
- // sourceArn: queueArn,
3910
- // batchSize: 10,
3911
- // })
3912
- // source.dependsOn(policy)
3913
- // policy.addStatement({
3914
- // actions: [
3915
- // 'sqs:SendMessage',
3916
- // 'sqs:DeleteMessage',
3917
- // 'sqs:ReceiveMessage',
3918
- // 'sqs:GetQueueUrl',
3919
- // 'sqs:GetQueueAttributes',
3920
- // ],
3921
- // resources: [queueArn],
3922
- // })
3923
- // },
3924
3952
  });
3925
3953
 
3926
3954
  // src/feature/pubsub/index.ts
@@ -4111,7 +4139,7 @@ var queueFeature = defineFeature({
4111
4139
  receiveWaitTimeSeconds: toSeconds3(props.receiveMessageWaitTime ?? seconds5(0)),
4112
4140
  messageRetentionSeconds: toSeconds3(props.retentionPeriod),
4113
4141
  maxMessageSize: toBytes(props.maxMessageSize),
4114
- redrivePolicy: onFailure && onFailure.pipe(
4142
+ redrivePolicy: onFailure.pipe(
4115
4143
  (arn) => JSON.stringify({
4116
4144
  deadLetterTargetArn: arn,
4117
4145
  maxReceiveCount: 100
@@ -5678,7 +5706,9 @@ var tableFeature = defineFeature({
5678
5706
  functionResponseTypes: ["ReportBatchItemFailures"],
5679
5707
  startingPosition: "LATEST",
5680
5708
  destinationConfig: {
5681
- onFailure: onFailure ? { destinationArn: onFailure } : void 0
5709
+ onFailure: {
5710
+ destinationArn: onFailure
5711
+ }
5682
5712
  }
5683
5713
  },
5684
5714
  { dependsOn: [result.policy] }
@@ -5692,12 +5722,10 @@ var tableFeature = defineFeature({
5692
5722
  ],
5693
5723
  resources: [table.streamArn]
5694
5724
  });
5695
- if (onFailure) {
5696
- result.addPermission({
5697
- actions: ["sqs:SendMessage", "sqs:GetQueueUrl"],
5698
- resources: [onFailure]
5699
- });
5700
- }
5725
+ result.addPermission({
5726
+ actions: ["sqs:SendMessage", "sqs:GetQueueUrl"],
5727
+ resources: [onFailure]
5728
+ });
5701
5729
  }
5702
5730
  ctx.addStackPermission({
5703
5731
  actions: [
@@ -5891,17 +5919,15 @@ var topicFeature = defineFeature({
5891
5919
  const resources2 = new TypeObject(1);
5892
5920
  const mocks = new TypeObject(1);
5893
5921
  const mockResponses = new TypeObject(1);
5894
- for (const stack of ctx.stackConfigs) {
5895
- for (const topic of stack.topics || []) {
5896
- const name = formatGlobalResourceName({
5897
- appName: ctx.appConfig.name,
5898
- resourceType: "topic",
5899
- resourceName: topic
5900
- });
5901
- mockResponses.addType(topic, "Mock");
5902
- resources2.addType(topic, `Publish<'${name}'>`);
5903
- mocks.addType(topic, `MockBuilder`);
5904
- }
5922
+ for (const topic of ctx.appConfig.defaults.topics ?? []) {
5923
+ const name = formatGlobalResourceName({
5924
+ appName: ctx.appConfig.name,
5925
+ resourceType: "topic",
5926
+ resourceName: topic
5927
+ });
5928
+ mockResponses.addType(topic, "Mock");
5929
+ resources2.addType(topic, `Publish<'${name}'>`);
5930
+ mocks.addType(topic, `MockBuilder`);
5905
5931
  }
5906
5932
  gen.addCode(typeGenCode7);
5907
5933
  gen.addInterface("TopicResources", resources2);
@@ -5910,40 +5936,29 @@ var topicFeature = defineFeature({
5910
5936
  await ctx.write("topic.d.ts", gen, true);
5911
5937
  },
5912
5938
  onValidate(ctx) {
5913
- const unique = [];
5914
- for (const stack of ctx.stackConfigs) {
5915
- for (const topic of stack.topics ?? []) {
5916
- if (unique.includes(topic)) {
5917
- throw new FileError(stack.file, `Duplicate topic "${topic}"`);
5918
- } else {
5919
- unique.push(topic);
5920
- }
5921
- }
5922
- }
5939
+ const topics = ctx.appConfig.defaults.topics ?? [];
5923
5940
  for (const stack of ctx.stackConfigs) {
5924
5941
  for (const topic of Object.keys(stack.subscribers ?? {})) {
5925
- if (!unique.includes(topic)) {
5926
- throw new FileError(stack.file, `Subscription to a undefined topic "${topic}"`);
5942
+ if (!topics.includes(topic)) {
5943
+ throw new FileError(stack.file, `Subscription to a non existent topic "${topic}"`);
5927
5944
  }
5928
5945
  }
5929
5946
  }
5930
5947
  },
5931
5948
  onApp(ctx) {
5932
- for (const stack of ctx.stackConfigs) {
5933
- for (const id of stack.topics ?? []) {
5934
- const group = new Group19(ctx.base, "topic", id);
5935
- const name = formatGlobalResourceName({
5936
- appName: ctx.appConfig.name,
5937
- resourceType: "topic",
5938
- resourceName: id
5939
- });
5940
- const topic = new $19.aws.sns.Topic(group, "topic", {
5941
- name
5942
- });
5943
- ctx.shared.add("topic", `arn`, id, topic.arn);
5944
- }
5949
+ for (const id of ctx.appConfig.defaults.topics ?? []) {
5950
+ const group = new Group19(ctx.base, "topic", id);
5951
+ const name = formatGlobalResourceName({
5952
+ appName: ctx.appConfig.name,
5953
+ resourceType: "topic",
5954
+ resourceName: id
5955
+ });
5956
+ const topic = new $19.aws.sns.Topic(group, "topic", {
5957
+ name
5958
+ });
5959
+ ctx.shared.add("topic", `arn`, id, topic.arn);
5945
5960
  }
5946
- ctx.addAppPermission({
5961
+ ctx.addGlobalPermission({
5947
5962
  actions: ["sns:Publish"],
5948
5963
  resources: [
5949
5964
  `arn:aws:sns:${ctx.appConfig.region}:${ctx.accountId}:${formatGlobalResourceName({
@@ -5955,12 +5970,6 @@ var topicFeature = defineFeature({
5955
5970
  });
5956
5971
  },
5957
5972
  onStack(ctx) {
5958
- for (const id of ctx.stackConfig.topics ?? []) {
5959
- ctx.addStackPermission({
5960
- actions: ["sns:Publish"],
5961
- resources: [ctx.shared.entry("topic", "arn", id)]
5962
- });
5963
- }
5964
5973
  for (const [id, props] of Object.entries(ctx.stackConfig.subscribers ?? {})) {
5965
5974
  const group = new Group19(ctx.stack, "topic", id);
5966
5975
  const topicArn = ctx.shared.entry("topic", "arn", id);
@@ -6107,7 +6116,7 @@ var alertFeature = defineFeature({
6107
6116
  name
6108
6117
  });
6109
6118
  for (const email of emails) {
6110
- new $21.aws.sns.TopicSubscription(group, id, {
6119
+ new $21.aws.sns.TopicSubscription(group, email, {
6111
6120
  topicArn: topic.arn,
6112
6121
  protocol: "email",
6113
6122
  endpoint: email
@@ -7214,6 +7223,133 @@ var instanceFeature = defineFeature({
7214
7223
  }
7215
7224
  });
7216
7225
 
7226
+ // src/feature/metric/index.ts
7227
+ import { $ as $27, Group as Group27 } from "@awsless/formation";
7228
+ import { kebabCase as kebabCase8, constantCase as constantCase15 } from "change-case";
7229
+ import { toSeconds as toSeconds11 } from "@awsless/duration";
7230
+ var typeGenCode9 = `
7231
+ import { type PutDataProps, putData, batchPutData } from '@awsless/cloudwatch'
7232
+
7233
+ type PutResponse = ReturnType<typeof putData>
7234
+ type Batch = typeof batchPutData
7235
+
7236
+ type MetricBase<NS extends string, N extends string> = {
7237
+ readonly namespace: NS
7238
+ readonly name: N
7239
+ }
7240
+
7241
+ type NumberMetric = {
7242
+ readonly unit: 'number'
7243
+ put(value: number | number[], options?: PutDataProps): PutResponse
7244
+ }
7245
+
7246
+ type DurationMetric = {
7247
+ readonly unit: 'duration'
7248
+ put(value: Duration | Duration[], options?: PutDataProps): PutResponse
7249
+ }
7250
+
7251
+ type SizeMetric = {
7252
+ readonly unit: 'size'
7253
+ put(value: Size | Size[], options?: PutDataProps): PutResponse
7254
+ }
7255
+ `;
7256
+ var metricFeature = defineFeature({
7257
+ name: "metric",
7258
+ async onTypeGen(ctx) {
7259
+ const gen = new TypeFile("@awsless/awsless");
7260
+ const resources2 = new TypeObject(1);
7261
+ for (const stack of ctx.stackConfigs ?? []) {
7262
+ const namespace = `awsless/${kebabCase8(ctx.appConfig.name)}/${kebabCase8(stack.name)}`;
7263
+ const stackResources = new TypeObject(2);
7264
+ for (const [id, metric] of Object.entries(stack.metrics ?? {})) {
7265
+ const name = kebabCase8(id);
7266
+ const types2 = {
7267
+ number: "NumberMetric",
7268
+ duration: "DurationMetric",
7269
+ size: "SizeMetric"
7270
+ };
7271
+ stackResources.addType(id, `MetricBase<'${namespace}', '${name}'> & ${types2[metric.type]}`);
7272
+ }
7273
+ resources2.addType(stack.name, stackResources);
7274
+ }
7275
+ resources2.addType("batch", "Batch");
7276
+ gen.addCode(typeGenCode9);
7277
+ gen.addInterface("MetricResources", resources2);
7278
+ await ctx.write("metric.d.ts", gen, true);
7279
+ },
7280
+ onStack(ctx) {
7281
+ const namespace = `awsless/${kebabCase8(ctx.app.name)}/${kebabCase8(ctx.stack.name)}`;
7282
+ ctx.addStackPermission({
7283
+ actions: ["cloudwatch:PutMetricData"],
7284
+ resources: ["*"],
7285
+ conditions: {
7286
+ StringEquals: {
7287
+ // Luckily we can limit access to only the namespace.
7288
+ "cloudwatch:namespace": namespace
7289
+ }
7290
+ }
7291
+ });
7292
+ for (const [id, props] of Object.entries(ctx.stackConfig.metrics ?? {})) {
7293
+ const group = new Group27(ctx.stack, "metric", id);
7294
+ ctx.addEnv(`METRIC_${constantCase15(id)}`, props.type);
7295
+ for (const alarmId in props.alarms ?? []) {
7296
+ const alarmGroup = new Group27(group, "alarm", alarmId);
7297
+ const alarmName = kebabCase8(`${id}-${alarmId}`);
7298
+ const alarmProps = props.alarms[alarmId];
7299
+ let alarmAction;
7300
+ let alarmLambda;
7301
+ if (Array.isArray(alarmProps.trigger)) {
7302
+ const topic = new $27.aws.sns.Topic(alarmGroup, "alarm-trigger", {
7303
+ name: formatLocalResourceName({
7304
+ appName: ctx.app.name,
7305
+ stackName: ctx.stack.name,
7306
+ resourceType: "metric",
7307
+ resourceName: alarmName
7308
+ })
7309
+ });
7310
+ alarmAction = topic.arn;
7311
+ for (const email of alarmProps.trigger) {
7312
+ new $27.aws.sns.TopicSubscription(alarmGroup, email, {
7313
+ topicArn: topic.arn,
7314
+ protocol: "email",
7315
+ endpoint: email
7316
+ });
7317
+ }
7318
+ } else {
7319
+ const { lambda } = createLambdaFunction(alarmGroup, ctx, "metric", alarmName, alarmProps.trigger);
7320
+ alarmLambda = lambda;
7321
+ alarmAction = lambda.arn;
7322
+ }
7323
+ const alarm = new $27.aws.cloudwatch.MetricAlarm(alarmGroup, "alarm", {
7324
+ namespace,
7325
+ metricName: kebabCase8(id),
7326
+ alarmName: formatLocalResourceName({
7327
+ appName: ctx.app.name,
7328
+ stackName: ctx.stack.name,
7329
+ resourceType: "metric",
7330
+ resourceName: alarmName
7331
+ }),
7332
+ alarmDescription: alarmProps.description,
7333
+ statistic: alarmProps.where.stat,
7334
+ threshold: alarmProps.where.value,
7335
+ period: toSeconds11(alarmProps.period),
7336
+ evaluationPeriods: alarmProps.minDataPoints,
7337
+ comparisonOperator: alarmProps.where.op,
7338
+ alarmActions: [alarmAction]
7339
+ });
7340
+ if (alarmLambda) {
7341
+ new $27.aws.lambda.Permission(alarmGroup, "permission", {
7342
+ action: "lambda:InvokeFunction",
7343
+ principal: "lambda.alarms.cloudwatch.amazonaws.com",
7344
+ functionName: alarmLambda.functionName,
7345
+ sourceArn: alarm.arn
7346
+ });
7347
+ }
7348
+ }
7349
+ }
7350
+ }
7351
+ });
7352
+
7217
7353
  // src/feature/index.ts
7218
7354
  var features = [
7219
7355
  // 1
@@ -7233,6 +7369,7 @@ var features = [
7233
7369
  configFeature,
7234
7370
  searchFeature,
7235
7371
  pubsubFeature,
7372
+ metricFeature,
7236
7373
  // streamFeature,
7237
7374
  tableFeature,
7238
7375
  topicFeature,
@@ -8609,7 +8746,7 @@ var auth = (program2) => {
8609
8746
 
8610
8747
  // src/cli/command/bind.ts
8611
8748
  import { log as log17 } from "@awsless/clui";
8612
- import { constantCase as constantCase15 } from "change-case";
8749
+ import { constantCase as constantCase16 } from "change-case";
8613
8750
  import { spawn } from "child_process";
8614
8751
  var bind = (program2) => {
8615
8752
  program2.command("bind").argument("[command...]", "The command to execute").option("--config <string...>", "List of config values that will be accessable", (v) => v.split(",")).description(`Bind your site environment variables to a command`).action(async (commands9 = [], opts) => {
@@ -8638,10 +8775,10 @@ var bind = (program2) => {
8638
8775
  const configList = opts.config ?? [];
8639
8776
  const configs = {};
8640
8777
  for (const name of configList) {
8641
- configs[`CONFIG_${constantCase15(name)}`] = name;
8778
+ configs[`CONFIG_${constantCase16(name)}`] = name;
8642
8779
  }
8643
8780
  if (configList.length ?? 0 > 0) {
8644
- log17.note("Bind Config", configList.map((v) => color.label(constantCase15(v))).join("\n"));
8781
+ log17.note("Bind Config", configList.map((v) => color.label(constantCase16(v))).join("\n"));
8645
8782
  }
8646
8783
  if (commands9.length === 0) {
8647
8784
  return "No command to execute.";
@@ -8769,7 +8906,7 @@ var resources = (program2) => {
8769
8906
  const accountId = await getAccountId(credentials, region);
8770
8907
  const { app } = createApp({ appConfig, stackConfigs, accountId });
8771
8908
  const formatResource = (stack, urn) => {
8772
- return urn.replace(stack.urn + ":", "").replace(/\{([a-z0-9\-\s\/\._]+)\}/gi, (_, v) => {
8909
+ return urn.replace(stack.urn + ":", "").replace(/\{([a-z0-9\-\s\/\.\@\_]+)\}/gi, (_, v) => {
8773
8910
  return `${color.dim("{")}${color.warning(v)}${color.dim("}")}`;
8774
8911
  }).replaceAll(":", color.dim(":"));
8775
8912
  };