@awsless/awsless 0.0.653 → 0.0.655

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
@@ -939,7 +939,7 @@ var debug = (...parts) => {
939
939
  };
940
940
 
941
941
  // src/config/app.ts
942
- import { z as z28 } from "zod";
942
+ import { z as z29 } from "zod";
943
943
 
944
944
  // src/feature/alert/schema.ts
945
945
  import { kebabCase } from "change-case";
@@ -1304,39 +1304,50 @@ var LayerSchema = z17.record(
1304
1304
  ).optional().describe("Define the lambda layers in your stack.");
1305
1305
 
1306
1306
  // src/feature/on-failure/schema.ts
1307
- var OnFailureDefaultSchema = FunctionSchema.optional().describe(
1307
+ import { z as z18 } from "zod";
1308
+ var NotifySchema = z18.union([
1309
+ //
1310
+ EmailSchema.transform((v) => [v]),
1311
+ EmailSchema.array()
1312
+ ]).describe("Receive an email notification when consuming failure entries goes wrong.");
1313
+ var OnFailureDefaultSchema = z18.object({
1314
+ consumer: FunctionSchema,
1315
+ notify: NotifySchema.optional()
1316
+ }).optional().describe(
1308
1317
  [
1309
1318
  "Defining a onFailure handler will add a global onFailure handler for the following resources:",
1310
- "- CloudWatch Scheduler",
1311
- "- Async lambda functions",
1312
- "- SQS queues",
1313
- "- DynamoDB streams"
1319
+ "- Tasks",
1320
+ "- Crons",
1321
+ "- Queues",
1322
+ "- Topics",
1323
+ "- Pubsub",
1324
+ "- Table streams"
1314
1325
  ].join("\n")
1315
1326
  );
1316
1327
 
1317
1328
  // src/feature/on-log/schema.ts
1318
- import { z as z18 } from "zod";
1319
- var FilterSchema = z18.enum(["trace", "debug", "info", "warn", "error", "fatal"]).array().describe("The log level that will gets delivered to the consumer.");
1320
- var OnLogDefaultSchema = z18.union([
1329
+ import { z as z19 } from "zod";
1330
+ var FilterSchema = z19.enum(["trace", "debug", "info", "warn", "error", "fatal"]).array().describe("The log level that will gets delivered to the consumer.");
1331
+ var OnLogDefaultSchema = z19.union([
1321
1332
  FunctionSchema.transform((consumer) => ({
1322
1333
  consumer,
1323
1334
  filter: ["error", "fatal"]
1324
1335
  })),
1325
- z18.object({
1336
+ z19.object({
1326
1337
  consumer: FunctionSchema,
1327
1338
  filter: FilterSchema
1328
1339
  })
1329
1340
  ]).optional().describe("Define a subscription on all Lambda functions logs.");
1330
1341
 
1331
1342
  // src/feature/pubsub/schema.ts
1332
- import { z as z19 } from "zod";
1343
+ import { z as z20 } from "zod";
1333
1344
  var DomainSchema = ResourceIdSchema.describe("The domain id to link your Pubsub API with.");
1334
- var PubSubDefaultSchema = z19.record(
1345
+ var PubSubDefaultSchema = z20.record(
1335
1346
  ResourceIdSchema,
1336
- z19.object({
1347
+ z20.object({
1337
1348
  auth: FunctionSchema,
1338
1349
  domain: DomainSchema.optional(),
1339
- subDomain: z19.string().optional()
1350
+ subDomain: z20.string().optional()
1340
1351
  // auth: z.union([
1341
1352
  // ResourceIdSchema,
1342
1353
  // z.object({
@@ -1352,11 +1363,11 @@ var PubSubDefaultSchema = z19.record(
1352
1363
  // .optional(),
1353
1364
  })
1354
1365
  ).optional().describe("Define the pubsub subscriber in your stack.");
1355
- var PubSubSchema = z19.record(
1366
+ var PubSubSchema = z20.record(
1356
1367
  ResourceIdSchema,
1357
- z19.object({
1358
- sql: z19.string().describe("The SQL statement used to query the IOT topic."),
1359
- sqlVersion: z19.enum(["2015-10-08", "2016-03-23", "beta"]).default("2016-03-23").describe("The version of the SQL rules engine to use when evaluating the rule."),
1368
+ z20.object({
1369
+ sql: z20.string().describe("The SQL statement used to query the IOT topic."),
1370
+ sqlVersion: z20.enum(["2015-10-08", "2016-03-23", "beta"]).default("2016-03-23").describe("The version of the SQL rules engine to use when evaluating the rule."),
1360
1371
  consumer: FunctionSchema.describe("The consuming lambda function properties.")
1361
1372
  })
1362
1373
  ).optional().describe("Define the pubsub subscriber in your stack.");
@@ -1364,7 +1375,7 @@ var PubSubSchema = z19.record(
1364
1375
  // src/feature/queue/schema.ts
1365
1376
  import { days as days2, hours, minutes as minutes2, seconds as seconds2 } from "@awsless/duration";
1366
1377
  import { kibibytes } from "@awsless/size";
1367
- import { z as z20 } from "zod";
1378
+ import { z as z21 } from "zod";
1368
1379
  var RetentionPeriodSchema = DurationSchema.refine(
1369
1380
  durationMin(minutes2(1)),
1370
1381
  "Minimum retention period is 1 minute"
@@ -1392,10 +1403,10 @@ var ReceiveMessageWaitTimeSchema = DurationSchema.refine(
1392
1403
  var MaxMessageSizeSchema = SizeSchema.refine(sizeMin(kibibytes(1)), "Minimum max message size is 1 KB").refine(sizeMax(kibibytes(256)), "Maximum max message size is 256 KB").describe(
1393
1404
  "The limit of how many bytes that a message can contain before Amazon SQS rejects it. You can specify an size from 1 KB to 256 KB."
1394
1405
  );
1395
- var BatchSizeSchema = z20.number().int().min(1, "Minimum batch size is 1").max(1e4, "Maximum batch size is 10000").describe(
1406
+ var BatchSizeSchema = z21.number().int().min(1, "Minimum batch size is 1").max(1e4, "Maximum batch size is 10000").describe(
1396
1407
  "The maximum number of records in each batch that Lambda pulls from your queue and sends to your function. 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). You can specify an integer from 1 to 10000."
1397
1408
  );
1398
- var MaxConcurrencySchema = z20.number().int().min(2, "Minimum max concurrency is 2").max(1e3, "Maximum max concurrency is 1000").describe(
1409
+ var MaxConcurrencySchema = z21.number().int().min(2, "Minimum max concurrency is 2").max(1e3, "Maximum max concurrency is 1000").describe(
1399
1410
  "Limits the number of concurrent instances that the queue worker can invoke. You can specify an integer from 2 to 1000."
1400
1411
  );
1401
1412
  var MaxBatchingWindow = DurationSchema.refine(
@@ -1404,7 +1415,10 @@ var MaxBatchingWindow = DurationSchema.refine(
1404
1415
  ).describe(
1405
1416
  "The maximum amount of time, that Lambda spends gathering records before invoking the function. You can specify an duration from 0 seconds to 5 minutes."
1406
1417
  );
1407
- var QueueDefaultSchema = z20.object({
1418
+ var RetryAttemptsSchema2 = z21.number().int().min(0).max(999).describe(
1419
+ "The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 999."
1420
+ );
1421
+ var QueueDefaultSchema = z21.object({
1408
1422
  retentionPeriod: RetentionPeriodSchema.default("7 days"),
1409
1423
  visibilityTimeout: VisibilityTimeoutSchema.default("30 seconds"),
1410
1424
  deliveryDelay: DeliveryDelaySchema.default("0 seconds"),
@@ -1412,9 +1426,10 @@ var QueueDefaultSchema = z20.object({
1412
1426
  maxMessageSize: MaxMessageSizeSchema.default("256 KB"),
1413
1427
  batchSize: BatchSizeSchema.default(10),
1414
1428
  maxConcurrency: MaxConcurrencySchema.optional(),
1415
- maxBatchingWindow: MaxBatchingWindow.optional()
1429
+ maxBatchingWindow: MaxBatchingWindow.optional(),
1430
+ retryAttempts: RetryAttemptsSchema2.default(2)
1416
1431
  }).default({});
1417
- var QueueSchema = z20.object({
1432
+ var QueueSchema = z21.object({
1418
1433
  consumer: FunctionSchema.optional().describe("The consuming lambda function properties."),
1419
1434
  retentionPeriod: RetentionPeriodSchema.optional(),
1420
1435
  visibilityTimeout: VisibilityTimeoutSchema.optional(),
@@ -1423,11 +1438,12 @@ var QueueSchema = z20.object({
1423
1438
  maxMessageSize: MaxMessageSizeSchema.optional(),
1424
1439
  batchSize: BatchSizeSchema.optional(),
1425
1440
  maxConcurrency: MaxConcurrencySchema.optional(),
1426
- maxBatchingWindow: MaxBatchingWindow.optional()
1441
+ maxBatchingWindow: MaxBatchingWindow.optional(),
1442
+ retryAttempts: RetryAttemptsSchema2.optional()
1427
1443
  });
1428
- var QueuesSchema = z20.record(
1444
+ var QueuesSchema = z21.record(
1429
1445
  ResourceIdSchema,
1430
- z20.union([
1446
+ z21.union([
1431
1447
  LocalFileSchema.transform((consumer) => ({
1432
1448
  consumer
1433
1449
  })).pipe(QueueSchema),
@@ -1436,26 +1452,26 @@ var QueuesSchema = z20.record(
1436
1452
  ).optional().describe("Define the queues in your stack.");
1437
1453
 
1438
1454
  // src/feature/rest/schema.ts
1439
- import { z as z22 } from "zod";
1455
+ import { z as z23 } from "zod";
1440
1456
 
1441
1457
  // src/config/schema/route.ts
1442
- import { z as z21 } from "zod";
1443
- var RouteSchema = z21.union([
1444
- z21.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS|ANY)(\s\/[a-z0-9\+\_\-\/\{\}]*)$/gi, "Invalid route"),
1445
- z21.literal("$default")
1458
+ import { z as z22 } from "zod";
1459
+ var RouteSchema = z22.union([
1460
+ z22.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS|ANY)(\s\/[a-z0-9\+\_\-\/\{\}]*)$/gi, "Invalid route"),
1461
+ z22.literal("$default")
1446
1462
  ]);
1447
1463
 
1448
1464
  // src/feature/rest/schema.ts
1449
- var RestDefaultSchema = z22.record(
1465
+ var RestDefaultSchema = z23.record(
1450
1466
  ResourceIdSchema,
1451
- z22.object({
1467
+ z23.object({
1452
1468
  domain: ResourceIdSchema.describe("The domain id to link your API with.").optional(),
1453
- subDomain: z22.string().optional()
1469
+ subDomain: z23.string().optional()
1454
1470
  })
1455
1471
  ).optional().describe("Define your global REST API's.");
1456
- var RestSchema = z22.record(
1472
+ var RestSchema = z23.record(
1457
1473
  ResourceIdSchema,
1458
- z22.record(
1474
+ z23.record(
1459
1475
  RouteSchema.describe(
1460
1476
  [
1461
1477
  "The REST API route that is comprised by the http method and http path.",
@@ -1469,19 +1485,19 @@ var RestSchema = z22.record(
1469
1485
 
1470
1486
  // src/feature/rpc/schema.ts
1471
1487
  import { minutes as minutes4, seconds as seconds3 } from "@awsless/duration";
1472
- import { z as z24 } from "zod";
1488
+ import { z as z25 } from "zod";
1473
1489
 
1474
1490
  // src/feature/router/schema.ts
1475
1491
  import { days as days3, minutes as minutes3, parse as parse3 } from "@awsless/duration";
1476
- import { z as z23 } from "zod";
1477
- var ErrorResponsePathSchema = z23.string().describe(
1492
+ import { z as z24 } from "zod";
1493
+ var ErrorResponsePathSchema = z24.string().describe(
1478
1494
  [
1479
1495
  "The path to the custom error page that you want to return to the viewer when your origin returns the HTTP status code specified.",
1480
1496
  "- We recommend that you store custom error pages in an Amazon S3 bucket.",
1481
1497
  "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."
1482
1498
  ].join("\n")
1483
1499
  );
1484
- var StatusCodeSchema = z23.number().int().positive().optional().describe(
1500
+ var StatusCodeSchema = z24.number().int().positive().optional().describe(
1485
1501
  [
1486
1502
  "The HTTP status code that you want CloudFront to return to the viewer along with the custom error page.",
1487
1503
  "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:",
@@ -1494,26 +1510,26 @@ var StatusCodeSchema = z23.number().int().positive().optional().describe(
1494
1510
  var MinTTLSchema = DurationSchema.describe(
1495
1511
  "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."
1496
1512
  );
1497
- var ErrorResponseSchema = z23.union([
1513
+ var ErrorResponseSchema = z24.union([
1498
1514
  ErrorResponsePathSchema,
1499
- z23.object({
1515
+ z24.object({
1500
1516
  path: ErrorResponsePathSchema,
1501
1517
  statusCode: StatusCodeSchema.optional(),
1502
1518
  minTTL: MinTTLSchema.optional()
1503
1519
  })
1504
1520
  ]).optional();
1505
- var RouteSchema2 = z23.string().regex(/^\//, "Route must start with a slash (/)");
1506
- var VisibilitySchema = z23.boolean().default(false).describe("Whether to enable CloudWatch metrics for the WAF rule.");
1507
- var WafSettingsSchema = z23.object({
1508
- rateLimiter: z23.object({
1509
- limit: z23.number().min(10).max(2e9).default(10).describe(
1521
+ var RouteSchema2 = z24.string().regex(/^\//, "Route must start with a slash (/)");
1522
+ var VisibilitySchema = z24.boolean().default(false).describe("Whether to enable CloudWatch metrics for the WAF rule.");
1523
+ var WafSettingsSchema = z24.object({
1524
+ rateLimiter: z24.object({
1525
+ limit: z24.number().min(10).max(2e9).default(10).describe(
1510
1526
  "The limit on requests during the specified evaluation window for a single aggregation instance for the rate-based rule."
1511
1527
  ),
1512
- window: z23.union([
1513
- z23.literal("1 minute"),
1514
- z23.literal("2 minutes"),
1515
- z23.literal("5 minutes"),
1516
- z23.literal("10 minutes")
1528
+ window: z24.union([
1529
+ z24.literal("1 minute"),
1530
+ z24.literal("2 minutes"),
1531
+ z24.literal("5 minutes"),
1532
+ z24.literal("10 minutes")
1517
1533
  ]).default("5 minutes").transform((v) => parse3(v)).describe(
1518
1534
  "The amount of time, in seconds, that AWS WAF should include in its request counts, looking back from the current time."
1519
1535
  ),
@@ -1521,18 +1537,18 @@ var WafSettingsSchema = z23.object({
1521
1537
  }).optional().describe(
1522
1538
  "A rate-based rule counts incoming requests and rate limits requests when they are coming at too fast a rate."
1523
1539
  ),
1524
- ddosProtection: z23.object({
1525
- sensitivity: z23.object({
1526
- challenge: z23.enum(["low", "medium", "high"]).default("low").transform((v) => v.toUpperCase()).describe("The sensitivity level for challenge requests."),
1527
- block: z23.enum(["low", "medium", "high"]).default("low").transform((v) => v.toUpperCase()).describe("The sensitivity level for block requests.")
1540
+ ddosProtection: z24.object({
1541
+ sensitivity: z24.object({
1542
+ challenge: z24.enum(["low", "medium", "high"]).default("low").transform((v) => v.toUpperCase()).describe("The sensitivity level for challenge requests."),
1543
+ block: z24.enum(["low", "medium", "high"]).default("low").transform((v) => v.toUpperCase()).describe("The sensitivity level for block requests.")
1528
1544
  }),
1529
- exemptUriRegex: z23.string().default("^$"),
1545
+ exemptUriRegex: z24.string().default("^$"),
1530
1546
  visibility: VisibilitySchema
1531
1547
  }).optional().describe(
1532
1548
  "Provides protection against DDoS attacks targeting the application layer, also known as Layer 7 attacks. Uses 50 WCU."
1533
1549
  ),
1534
- botProtection: z23.object({
1535
- inspectionLevel: z23.enum(["common", "targeted"]).default("common").transform((v) => v.toUpperCase()),
1550
+ botProtection: z24.object({
1551
+ inspectionLevel: z24.enum(["common", "targeted"]).default("common").transform((v) => v.toUpperCase()),
1536
1552
  visibility: VisibilitySchema
1537
1553
  }).optional().describe(
1538
1554
  "Provides protection against automated bots that can consume excess resources, skew business metrics, cause downtime, or perform malicious activities. Bot Control provides additional visibility through Amazon CloudWatch and generates labels that you can use to control bot traffic to your applications. Uses 50 WCU."
@@ -1546,14 +1562,14 @@ var WafSettingsSchema = z23.object({
1546
1562
  }).describe(
1547
1563
  "WAF settings for the router. Each rule consumes Web ACL capacity units (WCUs). The total WCUs for a web ACL can't exceed 5000. Using over 1500 WCUs affects your costs."
1548
1564
  );
1549
- var RouterDefaultSchema = z23.record(
1565
+ var RouterDefaultSchema = z24.record(
1550
1566
  ResourceIdSchema,
1551
- z23.object({
1567
+ z24.object({
1552
1568
  domain: ResourceIdSchema.describe("The domain id to link your Router.").optional(),
1553
- subDomain: z23.string().optional(),
1569
+ subDomain: z24.string().optional(),
1554
1570
  waf: WafSettingsSchema.optional(),
1555
- geoRestrictions: z23.array(z23.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
1556
- errors: z23.object({
1571
+ geoRestrictions: z24.array(z24.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
1572
+ errors: z24.object({
1557
1573
  400: ErrorResponseSchema.describe("Customize a `400 Bad Request` response."),
1558
1574
  403: ErrorResponseSchema.describe("Customize a `403 Forbidden` response."),
1559
1575
  404: ErrorResponseSchema.describe("Customize a `404 Not Found` response."),
@@ -1566,19 +1582,22 @@ var RouterDefaultSchema = z23.record(
1566
1582
  503: ErrorResponseSchema.describe("Customize a `503 Service Unavailable` response."),
1567
1583
  504: ErrorResponseSchema.describe("Customize a `504 Gateway Timeout` response.")
1568
1584
  }).optional().describe("Customize the error responses for specific HTTP status codes."),
1569
- cors: z23.object({
1570
- override: z23.boolean().default(false),
1585
+ cors: z24.object({
1586
+ override: z24.boolean().default(false),
1571
1587
  maxAge: DurationSchema.default("365 days"),
1572
- exposeHeaders: z23.string().array().optional(),
1573
- credentials: z23.boolean().default(false),
1574
- headers: z23.string().array().default(["*"]),
1575
- origins: z23.string().array().default(["*"]),
1576
- methods: z23.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
1588
+ exposeHeaders: z24.string().array().optional(),
1589
+ credentials: z24.boolean().default(false),
1590
+ headers: z24.string().array().default(["*"]),
1591
+ origins: z24.string().array().default(["*"]),
1592
+ methods: z24.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
1577
1593
  }).optional().describe("Specify the cors headers."),
1578
- basicAuth: z23.object({
1579
- username: z23.string().describe("Basic auth username."),
1580
- password: z23.string().describe("Basic auth password.")
1581
- }).optional().describe("Enable basic authentication for the site."),
1594
+ passwordAuth: z24.object({
1595
+ password: z24.string().describe("Password.")
1596
+ }).optional().describe("Enable password authentication for the router."),
1597
+ basicAuth: z24.object({
1598
+ username: z24.string().describe("Basic auth username."),
1599
+ password: z24.string().describe("Basic auth password.")
1600
+ }).optional().describe("Enable basic authentication for the router."),
1582
1601
  // security: z
1583
1602
  // .object({
1584
1603
  // contentSecurityPolicy: z.object({
@@ -1624,10 +1643,10 @@ var RouterDefaultSchema = z23.record(
1624
1643
  // })
1625
1644
  // .optional()
1626
1645
  // .describe('Specify the security policy.'),
1627
- cache: z23.object({
1628
- cookies: z23.string().array().optional().describe("Specifies the cookies that CloudFront includes in the cache key."),
1629
- headers: z23.string().array().optional().describe("Specifies the headers that CloudFront includes in the cache key."),
1630
- queries: z23.string().array().optional().describe("Specifies the query values that CloudFront includes in the cache key.")
1646
+ cache: z24.object({
1647
+ cookies: z24.string().array().optional().describe("Specifies the cookies that CloudFront includes in the cache key."),
1648
+ headers: z24.string().array().optional().describe("Specifies the headers that CloudFront includes in the cache key."),
1649
+ queries: z24.string().array().optional().describe("Specifies the query values that CloudFront includes in the cache key.")
1631
1650
  }).optional().describe(
1632
1651
  "Specifies the cookies, headers, and query values that CloudFront includes in the cache key."
1633
1652
  )
@@ -1642,9 +1661,9 @@ var TimeoutSchema2 = DurationSchema.refine(durationMin(seconds3(10)), "Minimum t
1642
1661
  "The timeouts of all inner RPC functions will be capped at 80% of this timeout."
1643
1662
  ].join(" ")
1644
1663
  );
1645
- var RpcDefaultSchema = z24.record(
1664
+ var RpcDefaultSchema = z25.record(
1646
1665
  ResourceIdSchema,
1647
- z24.object({
1666
+ z25.object({
1648
1667
  // domain: ResourceIdSchema.describe('The domain id to link your RPC API with.').optional(),
1649
1668
  // subDomain: z.string().optional(),
1650
1669
  //
@@ -1655,18 +1674,18 @@ var RpcDefaultSchema = z24.record(
1655
1674
  timeout: TimeoutSchema2.default("1 minutes")
1656
1675
  })
1657
1676
  ).describe(`Define the global RPC API's.`).optional();
1658
- var RpcSchema = z24.record(
1677
+ var RpcSchema = z25.record(
1659
1678
  ResourceIdSchema,
1660
- z24.record(
1661
- z24.string(),
1662
- z24.union([
1679
+ z25.record(
1680
+ z25.string(),
1681
+ z25.union([
1663
1682
  FunctionSchema.transform((f) => ({
1664
1683
  function: f,
1665
1684
  lock: false
1666
1685
  })),
1667
- z24.object({
1686
+ z25.object({
1668
1687
  function: FunctionSchema.describe("The RPC function to execute."),
1669
- lock: z24.boolean().describe(
1688
+ lock: z25.boolean().describe(
1670
1689
  [
1671
1690
  "Specify if the function should be locked on the `lockKey` returned from the auth function.",
1672
1691
  "An example would be returning the user ID as `lockKey`."
@@ -1680,8 +1699,8 @@ var RpcSchema = z24.record(
1680
1699
  // src/feature/instance/schema.ts
1681
1700
  import { days as days4, toDays as toDays2 } from "@awsless/duration";
1682
1701
  import { toMebibytes } from "@awsless/size";
1683
- import { z as z25 } from "zod";
1684
- var CpuSchema = z25.union([z25.literal(0.25), z25.literal(0.5), z25.literal(1), z25.literal(2), z25.literal(4), z25.literal(8), z25.literal(16)]).transform((v) => `${v} vCPU`).describe(
1702
+ import { z as z26 } from "zod";
1703
+ var CpuSchema = z26.union([z26.literal(0.25), z26.literal(0.5), z26.literal(1), z26.literal(2), z26.literal(4), z26.literal(8), z26.literal(16)]).transform((v) => `${v} vCPU`).describe(
1685
1704
  "The number of virtual CPU units (vCPU) used by the instance. Valid values: 0.25, 0.5, 1, 2, 4, 8, 16 vCPU."
1686
1705
  );
1687
1706
  var validMemorySize = [
@@ -1721,10 +1740,10 @@ var MemorySizeSchema2 = SizeSchema.refine(
1721
1740
  (s) => validMemorySize.includes(toMebibytes(s)),
1722
1741
  `Invalid memory size. Allowed sizes: ${validMemorySize.join(", ")} MiB`
1723
1742
  ).describe("The amount of memory (in MiB) used by the instance. Valid memory values depend on the CPU configuration.");
1724
- var HealthCheckSchema = z25.object({
1725
- path: z25.string().describe("The path that the container runs to determine if it is healthy."),
1743
+ var HealthCheckSchema = z26.object({
1744
+ path: z26.string().describe("The path that the container runs to determine if it is healthy."),
1726
1745
  interval: DurationSchema.describe("The time period in seconds between each health check execution."),
1727
- retries: z25.number().int().min(1).max(10).describe(
1746
+ retries: z26.number().int().min(1).max(10).describe(
1728
1747
  "The number of times to retry a failed health check before the container is considered unhealthy."
1729
1748
  ),
1730
1749
  startPeriod: DurationSchema.describe(
@@ -1734,22 +1753,22 @@ var HealthCheckSchema = z25.object({
1734
1753
  "The time period in seconds to wait for a health check to succeed before it is considered a failure."
1735
1754
  )
1736
1755
  }).describe("The health check command and associated configuration parameters for the container.");
1737
- var EnvironmentSchema2 = z25.record(z25.string(), z25.string()).optional().describe("Environment variable key-value pairs.");
1738
- var ArchitectureSchema3 = z25.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the instance supports.");
1739
- var ActionSchema2 = z25.string();
1740
- var ActionsSchema2 = z25.union([ActionSchema2.transform((v) => [v]), ActionSchema2.array()]);
1741
- var ArnSchema2 = z25.string().startsWith("arn:");
1742
- var WildcardSchema2 = z25.literal("*");
1743
- var ResourceSchema2 = z25.union([ArnSchema2, WildcardSchema2]);
1744
- var ResourcesSchema2 = z25.union([ResourceSchema2.transform((v) => [v]), ResourceSchema2.array()]);
1745
- var PermissionSchema2 = z25.object({
1746
- effect: z25.enum(["allow", "deny"]).default("allow"),
1756
+ var EnvironmentSchema2 = z26.record(z26.string(), z26.string()).optional().describe("Environment variable key-value pairs.");
1757
+ var ArchitectureSchema3 = z26.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the instance supports.");
1758
+ var ActionSchema2 = z26.string();
1759
+ var ActionsSchema2 = z26.union([ActionSchema2.transform((v) => [v]), ActionSchema2.array()]);
1760
+ var ArnSchema2 = z26.string().startsWith("arn:");
1761
+ var WildcardSchema2 = z26.literal("*");
1762
+ var ResourceSchema2 = z26.union([ArnSchema2, WildcardSchema2]);
1763
+ var ResourcesSchema2 = z26.union([ResourceSchema2.transform((v) => [v]), ResourceSchema2.array()]);
1764
+ var PermissionSchema2 = z26.object({
1765
+ effect: z26.enum(["allow", "deny"]).default("allow"),
1747
1766
  actions: ActionsSchema2,
1748
1767
  resources: ResourcesSchema2
1749
1768
  });
1750
- var PermissionsSchema2 = z25.union([PermissionSchema2.transform((v) => [v]), PermissionSchema2.array()]).describe("Add IAM permissions to your instance.");
1751
- var DescriptionSchema2 = z25.string().describe("A description of the instance.");
1752
- var ImageSchema = z25.string().optional().describe("The URL of the container image to use.");
1769
+ var PermissionsSchema2 = z26.union([PermissionSchema2.transform((v) => [v]), PermissionSchema2.array()]).describe("Add IAM permissions to your instance.");
1770
+ var DescriptionSchema2 = z26.string().describe("A description of the instance.");
1771
+ var ImageSchema = z26.string().optional().describe("The URL of the container image to use.");
1753
1772
  var validLogRetentionDays2 = [
1754
1773
  ...[1, 3, 5, 7, 14, 30, 60, 90, 120, 150],
1755
1774
  ...[180, 365, 400, 545, 731, 1096, 1827, 2192],
@@ -1764,23 +1783,23 @@ var LogRetentionSchema2 = DurationSchema.refine(
1764
1783
  },
1765
1784
  `Invalid log retention. Valid days are: ${validLogRetentionDays2.map((days8) => `${days8}`).join(", ")}`
1766
1785
  ).describe("The log retention duration.");
1767
- var LogSchema2 = z25.union([
1768
- z25.boolean().transform((enabled) => ({ retention: enabled ? days4(7) : days4(0) })),
1786
+ var LogSchema2 = z26.union([
1787
+ z26.boolean().transform((enabled) => ({ retention: enabled ? days4(7) : days4(0) })),
1769
1788
  LogRetentionSchema2.transform((retention) => ({ retention })),
1770
- z25.object({
1789
+ z26.object({
1771
1790
  retention: LogRetentionSchema2.optional()
1772
1791
  })
1773
1792
  ]).describe("Enable logging to a CloudWatch log group. Providing a duration value will set the log retention time.");
1774
- var FileCodeSchema2 = z25.object({
1793
+ var FileCodeSchema2 = z26.object({
1775
1794
  file: LocalFileSchema.describe("The file path of the instance code.")
1776
1795
  });
1777
- var CodeSchema2 = z25.union([
1796
+ var CodeSchema2 = z26.union([
1778
1797
  LocalFileSchema.transform((file) => ({
1779
1798
  file
1780
1799
  })).pipe(FileCodeSchema2),
1781
1800
  FileCodeSchema2
1782
1801
  ]).describe("Specify the code of your instance.");
1783
- var ISchema = z25.object({
1802
+ var ISchema = z26.object({
1784
1803
  code: CodeSchema2,
1785
1804
  description: DescriptionSchema2.optional(),
1786
1805
  image: ImageSchema.optional(),
@@ -1793,14 +1812,14 @@ var ISchema = z25.object({
1793
1812
  healthCheck: HealthCheckSchema.optional()
1794
1813
  // restartPolicy: RestartPolicySchema.optional(),
1795
1814
  });
1796
- var InstanceSchema = z25.union([
1815
+ var InstanceSchema = z26.union([
1797
1816
  LocalFileSchema.transform((code) => ({
1798
1817
  code
1799
1818
  })).pipe(ISchema),
1800
1819
  ISchema
1801
1820
  ]);
1802
- var InstancesSchema = z25.record(ResourceIdSchema, InstanceSchema).optional().describe("Define the instances in your stack.");
1803
- var InstanceDefaultSchema = z25.object({
1821
+ var InstancesSchema = z26.record(ResourceIdSchema, InstanceSchema).optional().describe("Define the instances in your stack.");
1822
+ var InstanceDefaultSchema = z26.object({
1804
1823
  image: ImageSchema.optional(),
1805
1824
  cpu: CpuSchema.default(0.25),
1806
1825
  memorySize: MemorySizeSchema2.default("512 MB"),
@@ -1816,15 +1835,15 @@ var InstanceDefaultSchema = z25.object({
1816
1835
 
1817
1836
  // src/feature/topic/schema.ts
1818
1837
  import { kebabCase as kebabCase3 } from "change-case";
1819
- import { z as z26 } from "zod";
1820
- var TopicNameSchema = z26.string().min(3).max(256).regex(/^[a-z0-9\-]+$/i, "Invalid topic name").transform((value) => kebabCase3(value)).describe("Define event topic name.");
1821
- var TopicsDefaultSchema = z26.array(TopicNameSchema).refine((topics) => {
1838
+ import { z as z27 } from "zod";
1839
+ var TopicNameSchema = z27.string().min(3).max(256).regex(/^[a-z0-9\-]+$/i, "Invalid topic name").transform((value) => kebabCase3(value)).describe("Define event topic name.");
1840
+ var TopicsDefaultSchema = z27.array(TopicNameSchema).refine((topics) => {
1822
1841
  return topics.length === new Set(topics).size;
1823
1842
  }, "Must be a list of unique topic names").optional().describe("Define the event topics for your app.");
1824
- var SubscribersSchema = z26.record(TopicNameSchema, FunctionSchema).optional().describe("Define the event topics to subscribe too in your stack.");
1843
+ var SubscribersSchema = z27.record(TopicNameSchema, FunctionSchema).optional().describe("Define the event topics to subscribe too in your stack.");
1825
1844
 
1826
1845
  // src/config/schema/region.ts
1827
- import { z as z27 } from "zod";
1846
+ import { z as z28 } from "zod";
1828
1847
  var US = ["us-east-2", "us-east-1", "us-west-1", "us-west-2"];
1829
1848
  var AF = ["af-south-1"];
1830
1849
  var AP = [
@@ -1853,16 +1872,16 @@ var EU = [
1853
1872
  var ME = ["me-south-1", "me-central-1"];
1854
1873
  var SA = ["sa-east-1"];
1855
1874
  var regions = [...US, ...AF, ...AP, ...CA, ...EU, ...ME, ...SA];
1856
- var RegionSchema = z27.enum(regions);
1875
+ var RegionSchema = z28.enum(regions);
1857
1876
 
1858
1877
  // src/config/app.ts
1859
- var AppSchema = z28.object({
1860
- $schema: z28.string().optional(),
1878
+ var AppSchema = z29.object({
1879
+ $schema: z29.string().optional(),
1861
1880
  name: ResourceIdSchema.describe("App name."),
1862
1881
  region: RegionSchema.describe("The AWS region to deploy to."),
1863
- profile: z28.string().describe("The AWS profile to deploy to."),
1864
- protect: z28.boolean().default(false).describe("Protect your app & stacks from being deleted."),
1865
- removal: z28.enum(["remove", "retain"]).default("remove").describe(
1882
+ profile: z29.string().describe("The AWS profile to deploy to."),
1883
+ protect: z29.boolean().default(false).describe("Protect your app & stacks from being deleted."),
1884
+ removal: z29.enum(["remove", "retain"]).default("remove").describe(
1866
1885
  [
1867
1886
  "Configure how your resources are handled when they have to be removed.",
1868
1887
  "",
@@ -1876,7 +1895,7 @@ var AppSchema = z28.object({
1876
1895
  // .default('prod')
1877
1896
  // .describe('The deployment stage.'),
1878
1897
  // onFailure: OnFailureSchema,
1879
- defaults: z28.object({
1898
+ defaults: z29.object({
1880
1899
  onFailure: OnFailureDefaultSchema,
1881
1900
  onLog: OnLogDefaultSchema,
1882
1901
  auth: AuthDefaultSchema,
@@ -1900,11 +1919,11 @@ var AppSchema = z28.object({
1900
1919
  });
1901
1920
 
1902
1921
  // src/config/stack.ts
1903
- import { z as z44 } from "zod";
1922
+ import { z as z45 } from "zod";
1904
1923
 
1905
1924
  // src/feature/cache/schema.ts
1906
1925
  import { gibibytes as gibibytes2 } from "@awsless/size";
1907
- import { z as z29 } from "zod";
1926
+ import { z as z30 } from "zod";
1908
1927
  var StorageSchema = SizeSchema.refine(sizeMin(gibibytes2(1)), "Minimum storage size is 1 GB").refine(
1909
1928
  sizeMax(gibibytes2(5e3)),
1910
1929
  "Maximum storage size is 5000 GB"
@@ -1915,31 +1934,31 @@ var MinimumStorageSchema = StorageSchema.describe(
1915
1934
  var MaximumStorageSchema = StorageSchema.describe(
1916
1935
  "The upper limit for data storage the cache is set to use. You can specify a size value from 1 GB to 5000 GB."
1917
1936
  );
1918
- var EcpuSchema = z29.number().int().min(1e3).max(15e6);
1937
+ var EcpuSchema = z30.number().int().min(1e3).max(15e6);
1919
1938
  var MinimumEcpuSchema = EcpuSchema.describe(
1920
1939
  "The minimum number of ECPUs the cache can consume per second. You can specify a integer from 1,000 to 15,000,000."
1921
1940
  );
1922
1941
  var MaximumEcpuSchema = EcpuSchema.describe(
1923
1942
  "The maximum number of ECPUs the cache can consume per second. You can specify a integer from 1,000 to 15,000,000."
1924
1943
  );
1925
- var CachesSchema = z29.record(
1944
+ var CachesSchema = z30.record(
1926
1945
  ResourceIdSchema,
1927
- z29.object({
1946
+ z30.object({
1928
1947
  minStorage: MinimumStorageSchema.optional(),
1929
1948
  maxStorage: MaximumStorageSchema.optional(),
1930
1949
  minECPU: MinimumEcpuSchema.optional(),
1931
1950
  maxECPU: MaximumEcpuSchema.optional(),
1932
- snapshotRetentionLimit: z29.number().int().positive().default(1)
1951
+ snapshotRetentionLimit: z30.number().int().positive().default(1)
1933
1952
  })
1934
1953
  ).optional().describe("Define the caches in your stack. For access to the cache put your functions inside the global VPC.");
1935
1954
 
1936
1955
  // src/feature/command/schema.ts
1937
- import { z as z30 } from "zod";
1938
- var CommandSchema = z30.union([
1939
- z30.object({
1956
+ import { z as z31 } from "zod";
1957
+ var CommandSchema = z31.union([
1958
+ z31.object({
1940
1959
  file: LocalFileSchema,
1941
- handler: z30.string().default("default").describe("The name of the handler that needs to run"),
1942
- description: z30.string().optional().describe("A description of the command")
1960
+ handler: z31.string().default("default").describe("The name of the handler that needs to run"),
1961
+ description: z31.string().optional().describe("A description of the command")
1943
1962
  // options: z.record(ResourceIdSchema, OptionSchema).optional(),
1944
1963
  // arguments: z.record(ResourceIdSchema, ArgumentSchema).optional(),
1945
1964
  }),
@@ -1949,22 +1968,22 @@ var CommandSchema = z30.union([
1949
1968
  description: void 0
1950
1969
  }))
1951
1970
  ]);
1952
- var CommandsSchema = z30.record(ResourceIdSchema, CommandSchema).optional().describe("Define the custom commands for your stack.");
1971
+ var CommandsSchema = z31.record(ResourceIdSchema, CommandSchema).optional().describe("Define the custom commands for your stack.");
1953
1972
 
1954
1973
  // src/feature/config/schema.ts
1955
- import { z as z31 } from "zod";
1956
- var ConfigNameSchema = z31.string().regex(/[a-z0-9\-]/g, "Invalid config name");
1957
- var ConfigsSchema = z31.array(ConfigNameSchema).optional().describe("Define the config values for your stack.");
1974
+ import { z as z32 } from "zod";
1975
+ var ConfigNameSchema = z32.string().regex(/[a-z0-9\-]/g, "Invalid config name");
1976
+ var ConfigsSchema = z32.array(ConfigNameSchema).optional().describe("Define the config values for your stack.");
1958
1977
 
1959
1978
  // src/feature/cron/schema/index.ts
1960
- import { z as z33 } from "zod";
1979
+ import { z as z34 } from "zod";
1961
1980
 
1962
1981
  // src/feature/cron/schema/schedule.ts
1963
- import { z as z32 } from "zod";
1982
+ import { z as z33 } from "zod";
1964
1983
  import { awsCronExpressionValidator } from "aws-cron-expression-validator";
1965
- var RateExpressionSchema = z32.custom(
1984
+ var RateExpressionSchema = z33.custom(
1966
1985
  (value) => {
1967
- return z32.string().regex(/^[0-9]+ (seconds?|minutes?|hours?|days?)$/).refine((rate) => {
1986
+ return z33.string().regex(/^[0-9]+ (seconds?|minutes?|hours?|days?)$/).refine((rate) => {
1968
1987
  const [str] = rate.split(" ");
1969
1988
  const number = parseInt(str);
1970
1989
  return number > 0;
@@ -1980,9 +1999,9 @@ var RateExpressionSchema = z32.custom(
1980
1999
  }
1981
2000
  return `rate(${rate})`;
1982
2001
  });
1983
- var CronExpressionSchema = z32.custom(
2002
+ var CronExpressionSchema = z33.custom(
1984
2003
  (value) => {
1985
- return z32.string().safeParse(value).success;
2004
+ return z33.string().safeParse(value).success;
1986
2005
  },
1987
2006
  { message: "Invalid cron expression" }
1988
2007
  ).superRefine((value, ctx) => {
@@ -1991,12 +2010,12 @@ var CronExpressionSchema = z32.custom(
1991
2010
  } catch (error) {
1992
2011
  if (error instanceof Error) {
1993
2012
  ctx.addIssue({
1994
- code: z32.ZodIssueCode.custom,
2013
+ code: z33.ZodIssueCode.custom,
1995
2014
  message: `Invalid cron expression: ${error.message}`
1996
2015
  });
1997
2016
  } else {
1998
2017
  ctx.addIssue({
1999
- code: z32.ZodIssueCode.custom,
2018
+ code: z33.ZodIssueCode.custom,
2000
2019
  message: "Invalid cron expression"
2001
2020
  });
2002
2021
  }
@@ -2007,28 +2026,28 @@ var CronExpressionSchema = z32.custom(
2007
2026
  var ScheduleExpressionSchema = RateExpressionSchema.or(CronExpressionSchema);
2008
2027
 
2009
2028
  // src/feature/cron/schema/index.ts
2010
- var CronsSchema = z33.record(
2029
+ var CronsSchema = z34.record(
2011
2030
  ResourceIdSchema,
2012
- z33.object({
2013
- enabled: z33.boolean().default(true).describe("If the cron is enabled."),
2031
+ z34.object({
2032
+ enabled: z34.boolean().default(true).describe("If the cron is enabled."),
2014
2033
  consumer: FunctionSchema.describe("The consuming lambda function properties."),
2015
2034
  schedule: ScheduleExpressionSchema.describe(
2016
2035
  'The scheduling expression.\n\nexample: "0 20 * * ? *"\nexample: "5 minutes"'
2017
2036
  ),
2018
- payload: z33.unknown().optional().describe("The JSON payload that will be passed to the consumer.")
2037
+ payload: z34.unknown().optional().describe("The JSON payload that will be passed to the consumer.")
2019
2038
  })
2020
2039
  ).optional().describe(`Define the cron jobs in your stack.`);
2021
2040
 
2022
2041
  // src/feature/search/schema.ts
2023
2042
  import { gibibytes as gibibytes3 } from "@awsless/size";
2024
- import { z as z34 } from "zod";
2025
- var VersionSchema = z34.union([
2043
+ import { z as z35 } from "zod";
2044
+ var VersionSchema = z35.union([
2026
2045
  //
2027
- z34.enum(["2.13", "2.11", "2.9", "2.7", "2.5", "2.3", "1.3"]),
2028
- z34.string()
2046
+ z35.enum(["2.13", "2.11", "2.9", "2.7", "2.5", "2.3", "1.3"]),
2047
+ z35.string()
2029
2048
  ]).describe("Specify the OpenSearch engine version.");
2030
- var TypeSchema = z34.union([
2031
- z34.enum([
2049
+ var TypeSchema = z35.union([
2050
+ z35.enum([
2032
2051
  "t3.small",
2033
2052
  "t3.medium",
2034
2053
  "m3.medium",
@@ -2102,13 +2121,13 @@ var TypeSchema = z34.union([
2102
2121
  "r6gd.12xlarge",
2103
2122
  "r6gd.16xlarge"
2104
2123
  ]),
2105
- z34.string()
2124
+ z35.string()
2106
2125
  ]).describe("Instance type of data nodes in the cluster.");
2107
- var CountSchema = z34.number().int().min(1).describe("Number of instances in the cluster.");
2126
+ var CountSchema = z35.number().int().min(1).describe("Number of instances in the cluster.");
2108
2127
  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.");
2109
- var SearchsSchema = z34.record(
2128
+ var SearchsSchema = z35.record(
2110
2129
  ResourceIdSchema,
2111
- z34.object({
2130
+ z35.object({
2112
2131
  type: TypeSchema.default("t3.small"),
2113
2132
  count: CountSchema.default(1),
2114
2133
  version: VersionSchema.default("2.13"),
@@ -2119,12 +2138,12 @@ var SearchsSchema = z34.record(
2119
2138
  ).optional().describe("Define the search instances in your stack. Backed by OpenSearch.");
2120
2139
 
2121
2140
  // src/feature/site/schema.ts
2122
- import { z as z36 } from "zod";
2141
+ import { z as z37 } from "zod";
2123
2142
 
2124
2143
  // src/config/schema/local-entry.ts
2125
2144
  import { stat as stat3 } from "fs/promises";
2126
- import { z as z35 } from "zod";
2127
- var LocalEntrySchema = z35.union([
2145
+ import { z as z36 } from "zod";
2146
+ var LocalEntrySchema = z36.union([
2128
2147
  RelativePathSchema.refine(async (path) => {
2129
2148
  try {
2130
2149
  const s = await stat3(path);
@@ -2133,7 +2152,7 @@ var LocalEntrySchema = z35.union([
2133
2152
  return false;
2134
2153
  }
2135
2154
  }, `File or directory doesn't exist`),
2136
- z35.object({
2155
+ z36.object({
2137
2156
  nocheck: RelativePathSchema.describe(
2138
2157
  "Specifies a local file or directory without checking if the file or directory exists."
2139
2158
  )
@@ -2141,21 +2160,21 @@ var LocalEntrySchema = z35.union([
2141
2160
  ]);
2142
2161
 
2143
2162
  // src/feature/site/schema.ts
2144
- var SitesSchema = z36.record(
2163
+ var SitesSchema = z37.record(
2145
2164
  ResourceIdSchema,
2146
- z36.object({
2165
+ z37.object({
2147
2166
  router: ResourceIdSchema.describe("The router id to link your site with."),
2148
2167
  path: RouteSchema2.describe("The path inside the router to link your site to."),
2149
- build: z36.object({
2150
- command: z36.string().describe(
2168
+ build: z37.object({
2169
+ command: z37.string().describe(
2151
2170
  `Specifies the files and directories to generate the cache key for your custom build command.`
2152
2171
  ),
2153
- cacheKey: z36.union([LocalEntrySchema.transform((v) => [v]), LocalEntrySchema.array()]).describe(
2172
+ cacheKey: z37.union([LocalEntrySchema.transform((v) => [v]), LocalEntrySchema.array()]).describe(
2154
2173
  `Specifies the files and directories to generate the cache key for your custom build command.`
2155
2174
  ),
2156
- configs: z36.string().array().optional().describe("Define the config values for your build command.")
2175
+ configs: z37.string().array().optional().describe("Define the config values for your build command.")
2157
2176
  }).optional().describe(`Specifies the build process for sites that need a build step.`),
2158
- static: z36.union([LocalDirectorySchema, z36.boolean()]).optional().describe(
2177
+ static: z37.union([LocalDirectorySchema, z37.boolean()]).optional().describe(
2159
2178
  "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."
2160
2179
  ),
2161
2180
  ssr: FunctionSchema.optional().describe("Specifies the file that will render the site on the server.")
@@ -2163,21 +2182,21 @@ var SitesSchema = z36.record(
2163
2182
  ).optional().describe("Define the sites in your stack.");
2164
2183
 
2165
2184
  // src/feature/store/schema.ts
2166
- import { z as z37 } from "zod";
2167
- var StoresSchema = z37.union([
2168
- z37.array(ResourceIdSchema).transform((list3) => {
2185
+ import { z as z38 } from "zod";
2186
+ var StoresSchema = z38.union([
2187
+ z38.array(ResourceIdSchema).transform((list3) => {
2169
2188
  const stores = {};
2170
2189
  for (const key of list3) {
2171
2190
  stores[key] = {};
2172
2191
  }
2173
2192
  return stores;
2174
2193
  }),
2175
- z37.record(
2194
+ z38.record(
2176
2195
  ResourceIdSchema,
2177
- z37.object({
2196
+ z38.object({
2178
2197
  static: LocalDirectorySchema.optional().describe("Specifies the path to the static files directory."),
2179
- versioning: z37.boolean().default(false).describe("Enable versioning of your store."),
2180
- events: z37.object({
2198
+ versioning: z38.boolean().default(false).describe("Enable versioning of your store."),
2199
+ events: z38.object({
2181
2200
  // create
2182
2201
  "created:*": FunctionSchema.optional().describe(
2183
2202
  "Subscribe to notifications regardless of the API that was used to create an object."
@@ -2210,30 +2229,30 @@ var StoresSchema = z37.union([
2210
2229
  ]).optional().describe("Define the stores in your stack.");
2211
2230
 
2212
2231
  // src/feature/icon/schema.ts
2213
- import { z as z38 } from "zod";
2232
+ import { z as z39 } from "zod";
2214
2233
  var staticOriginSchema = LocalDirectorySchema.describe(
2215
2234
  "Specifies the path to a local image directory that will be uploaded in S3."
2216
2235
  );
2217
2236
  var functionOriginSchema = FunctionSchema.describe(
2218
2237
  "Specifies the file that will be called when an image isn't found in the (cache) bucket."
2219
2238
  );
2220
- var IconsSchema = z38.record(
2239
+ var IconsSchema = z39.record(
2221
2240
  ResourceIdSchema,
2222
- z38.object({
2241
+ z39.object({
2223
2242
  // domain: ResourceIdSchema.describe('The domain id to link your site with.').optional(),
2224
2243
  // subDomain: z.string().optional(),
2225
2244
  router: ResourceIdSchema.describe("The router id to link your icon proxy."),
2226
2245
  path: RouteSchema2.describe("The path inside the router to link your icon proxy to."),
2227
2246
  log: LogSchema.optional(),
2228
2247
  cacheDuration: DurationSchema.optional().describe("The cache duration of the cached icons."),
2229
- preserveIds: z38.boolean().optional().default(false).describe("Preserve the IDs of the icons."),
2230
- symbols: z38.boolean().optional().default(false).describe(`Convert the SVG's to SVG symbols.`),
2231
- origin: z38.union([
2232
- z38.object({
2248
+ preserveIds: z39.boolean().optional().default(false).describe("Preserve the IDs of the icons."),
2249
+ symbols: z39.boolean().optional().default(false).describe(`Convert the SVG's to SVG symbols.`),
2250
+ origin: z39.union([
2251
+ z39.object({
2233
2252
  static: staticOriginSchema,
2234
2253
  function: functionOriginSchema.optional()
2235
2254
  }),
2236
- z38.object({
2255
+ z39.object({
2237
2256
  static: staticOriginSchema.optional(),
2238
2257
  function: functionOriginSchema
2239
2258
  })
@@ -2260,13 +2279,13 @@ var IconsSchema = z38.record(
2260
2279
  ).optional().describe("Define an svg icon proxy in your stack. Store, optimize, and deliver svg icons at scale.");
2261
2280
 
2262
2281
  // src/feature/image/schema.ts
2263
- import { z as z39 } from "zod";
2264
- var transformationOptionsSchema = z39.object({
2265
- width: z39.number().int().positive().optional(),
2266
- height: z39.number().int().positive().optional(),
2267
- fit: z39.enum(["cover", "contain", "fill", "inside", "outside"]).optional(),
2268
- position: z39.enum(["top", "right top", "right", "right bottom", "bottom", "left bottom", "left", "left top", "center"]).optional(),
2269
- quality: z39.number().int().min(1).max(100).optional()
2282
+ import { z as z40 } from "zod";
2283
+ var transformationOptionsSchema = z40.object({
2284
+ width: z40.number().int().positive().optional(),
2285
+ height: z40.number().int().positive().optional(),
2286
+ fit: z40.enum(["cover", "contain", "fill", "inside", "outside"]).optional(),
2287
+ position: z40.enum(["top", "right top", "right", "right bottom", "bottom", "left bottom", "left", "left top", "center"]).optional(),
2288
+ quality: z40.number().int().min(1).max(100).optional()
2270
2289
  });
2271
2290
  var staticOriginSchema2 = LocalDirectorySchema.describe(
2272
2291
  "Specifies the path to a local image directory that will be uploaded in S3."
@@ -2274,38 +2293,38 @@ var staticOriginSchema2 = LocalDirectorySchema.describe(
2274
2293
  var functionOriginSchema2 = FunctionSchema.describe(
2275
2294
  "Specifies the file that will be called when an image isn't found in the (cache) bucket."
2276
2295
  );
2277
- var ImagesSchema = z39.record(
2296
+ var ImagesSchema = z40.record(
2278
2297
  ResourceIdSchema,
2279
- z39.object({
2298
+ z40.object({
2280
2299
  // domain: ResourceIdSchema.describe('The domain id to link your site with.').optional(),
2281
2300
  // subDomain: z.string().optional(),
2282
2301
  router: ResourceIdSchema.describe("The router id to link your image proxy."),
2283
2302
  path: RouteSchema2.describe("The path inside the router to link your image proxy to."),
2284
2303
  log: LogSchema.optional(),
2285
2304
  cacheDuration: DurationSchema.optional().describe("Cache duration of the cached images."),
2286
- presets: z39.record(z39.string(), transformationOptionsSchema).describe("Named presets for image transformations"),
2287
- extensions: z39.object({
2288
- jpg: z39.object({
2289
- mozjpeg: z39.boolean().optional(),
2290
- progressive: z39.boolean().optional()
2305
+ presets: z40.record(z40.string(), transformationOptionsSchema).describe("Named presets for image transformations"),
2306
+ extensions: z40.object({
2307
+ jpg: z40.object({
2308
+ mozjpeg: z40.boolean().optional(),
2309
+ progressive: z40.boolean().optional()
2291
2310
  }).optional(),
2292
- webp: z39.object({
2293
- effort: z39.number().int().min(1).max(10).default(7).optional(),
2294
- lossless: z39.boolean().optional(),
2295
- nearLossless: z39.boolean().optional()
2311
+ webp: z40.object({
2312
+ effort: z40.number().int().min(1).max(10).default(7).optional(),
2313
+ lossless: z40.boolean().optional(),
2314
+ nearLossless: z40.boolean().optional()
2296
2315
  }).optional(),
2297
- png: z39.object({
2298
- compressionLevel: z39.number().int().min(0).max(9).default(6).optional()
2316
+ png: z40.object({
2317
+ compressionLevel: z40.number().int().min(0).max(9).default(6).optional()
2299
2318
  }).optional()
2300
2319
  }).refine((data) => {
2301
2320
  return Object.keys(data).length > 0;
2302
2321
  }, "At least one extension must be defined.").describe("Specify the allowed extensions."),
2303
- origin: z39.union([
2304
- z39.object({
2322
+ origin: z40.union([
2323
+ z40.object({
2305
2324
  static: staticOriginSchema2,
2306
2325
  function: functionOriginSchema2.optional()
2307
2326
  }),
2308
- z39.object({
2327
+ z40.object({
2309
2328
  static: staticOriginSchema2.optional(),
2310
2329
  function: functionOriginSchema2
2311
2330
  })
@@ -2320,7 +2339,7 @@ var ImagesSchema = z39.record(
2320
2339
  ).optional().describe("Define an image proxy in your stack. Store, transform, optimize, and deliver images at scale.");
2321
2340
 
2322
2341
  // src/feature/metric/schema.ts
2323
- import { z as z40 } from "zod";
2342
+ import { z as z41 } from "zod";
2324
2343
  var ops = {
2325
2344
  ">": "GreaterThanThreshold",
2326
2345
  ">=": "GreaterThanOrEqualToThreshold",
@@ -2334,15 +2353,15 @@ var stats = {
2334
2353
  min: "Minimum",
2335
2354
  max: "Maximum"
2336
2355
  };
2337
- var WhereSchema = z40.union([
2338
- z40.string().regex(/(count|avg|sum|min|max) (>|>=|<|<=) (\d)/, "Invalid where query").transform((where) => {
2356
+ var WhereSchema = z41.union([
2357
+ z41.string().regex(/(count|avg|sum|min|max) (>|>=|<|<=) (\d)/, "Invalid where query").transform((where) => {
2339
2358
  const [stat4, op, value] = where.split(" ");
2340
2359
  return { stat: stat4, op, value: parseFloat(value) };
2341
2360
  }),
2342
- z40.object({
2343
- stat: z40.enum(["count", "avg", "sum", "min", "max"]),
2344
- op: z40.enum([">", ">=", "<", "<="]),
2345
- value: z40.number()
2361
+ z41.object({
2362
+ stat: z41.enum(["count", "avg", "sum", "min", "max"]),
2363
+ op: z41.enum([">", ">=", "<", "<="]),
2364
+ value: z41.number()
2346
2365
  })
2347
2366
  ]).transform((where) => {
2348
2367
  return {
@@ -2351,39 +2370,39 @@ var WhereSchema = z40.union([
2351
2370
  value: where.value
2352
2371
  };
2353
2372
  });
2354
- var AlarmSchema = z40.object({
2355
- description: z40.string().optional(),
2373
+ var AlarmSchema = z41.object({
2374
+ description: z41.string().optional(),
2356
2375
  where: WhereSchema,
2357
2376
  period: DurationSchema,
2358
- minDataPoints: z40.number().int().default(1),
2359
- trigger: z40.union([EmailSchema.transform((v) => [v]), EmailSchema.array(), FunctionSchema])
2377
+ minDataPoints: z41.number().int().default(1),
2378
+ trigger: z41.union([EmailSchema.transform((v) => [v]), EmailSchema.array(), FunctionSchema])
2360
2379
  });
2361
- var MetricsSchema = z40.record(
2380
+ var MetricsSchema = z41.record(
2362
2381
  ResourceIdSchema,
2363
- z40.object({
2364
- type: z40.enum(["number", "size", "duration"]),
2382
+ z41.object({
2383
+ type: z41.enum(["number", "size", "duration"]),
2365
2384
  alarms: AlarmSchema.array().optional()
2366
2385
  })
2367
2386
  ).optional().describe("Define the metrics in your stack.");
2368
2387
 
2369
2388
  // src/feature/table/schema.ts
2370
2389
  import { minutes as minutes5, seconds as seconds4 } from "@awsless/duration";
2371
- import { z as z41 } from "zod";
2372
- var KeySchema = z41.string().min(1).max(255);
2373
- var TablesSchema = z41.record(
2390
+ import { z as z42 } from "zod";
2391
+ var KeySchema = z42.string().min(1).max(255);
2392
+ var TablesSchema = z42.record(
2374
2393
  ResourceIdSchema,
2375
- z41.object({
2394
+ z42.object({
2376
2395
  hash: KeySchema.describe(
2377
2396
  "Specifies the name of the partition / hash key that makes up the primary key for the table."
2378
2397
  ),
2379
2398
  sort: KeySchema.optional().describe(
2380
2399
  "Specifies the name of the range / sort key that makes up the primary key for the table."
2381
2400
  ),
2382
- fields: z41.record(z41.string(), z41.enum(["string", "number", "binary"])).optional().describe(
2401
+ fields: z42.record(z42.string(), z42.enum(["string", "number", "binary"])).optional().describe(
2383
2402
  'A list of attributes that describe the key schema for the table and indexes. If no attribute field is defined we default to "string".'
2384
2403
  ),
2385
- class: z41.enum(["standard", "standard-infrequent-access"]).default("standard").describe("The table class of the table."),
2386
- pointInTimeRecovery: z41.boolean().default(false).describe("Indicates whether point in time recovery is enabled on the table."),
2404
+ class: z42.enum(["standard", "standard-infrequent-access"]).default("standard").describe("The table class of the table."),
2405
+ pointInTimeRecovery: z42.boolean().default(false).describe("Indicates whether point in time recovery is enabled on the table."),
2387
2406
  ttl: KeySchema.optional().describe(
2388
2407
  [
2389
2408
  "The name of the TTL attribute used to store the expiration time for items in the table.",
@@ -2391,8 +2410,8 @@ var TablesSchema = z41.record(
2391
2410
  ].join("\n")
2392
2411
  ),
2393
2412
  // deletionProtection: DeletionProtectionSchema.optional(),
2394
- stream: z41.object({
2395
- type: z41.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]).describe(
2413
+ stream: z42.object({
2414
+ type: z42.enum(["keys-only", "new-image", "old-image", "new-and-old-images"]).describe(
2396
2415
  [
2397
2416
  "When an item in the table is modified, you can determines what information is written to the stream for this table.",
2398
2417
  "Valid values are:",
@@ -2402,7 +2421,7 @@ var TablesSchema = z41.record(
2402
2421
  "- new-and-old-images - Both the new and the old item images of the item are written to the stream."
2403
2422
  ].join("\n")
2404
2423
  ),
2405
- batchSize: z41.number().min(1).max(1e4).default(1).describe(
2424
+ batchSize: z42.number().min(1).max(1e4).default(1).describe(
2406
2425
  [
2407
2426
  "The maximum number of records in each batch that Lambda pulls from your stream and sends to your function.",
2408
2427
  "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).",
@@ -2418,29 +2437,26 @@ var TablesSchema = z41.record(
2418
2437
  "You can specify a duration from 1 seconds to 5 minutes."
2419
2438
  ].join("\n")
2420
2439
  ),
2421
- // maxRecordAge: DurationSchema.refine(
2422
- // durationMin(seconds(1)),
2423
- // 'Minimum record age duration is 1 second'
2424
- // )
2425
- // .refine(durationMax(minutes(5)), 'Maximum batch window duration is 5 minutes')
2426
- // .optional()
2427
- // .describe(
2428
- // [
2429
- // 'Discard records after the specified number of retries.',
2430
- // 'The default value is -1, which sets the maximum number of retries to infinite.',
2431
- // 'When maxRetryAttempts is infinite, Lambda retries failed records until the record expires in the event source.',
2432
- // 'You can specify a number from -1 to 10000.',
2433
- // ].join('\n')
2434
- // ),
2435
- retryAttempts: z41.number().min(-1).max(1e4).default(-1).describe(
2440
+ maxRecordAge: DurationSchema.refine(
2441
+ durationMin(seconds4(1)),
2442
+ "Minimum record age duration is 1 second"
2443
+ ).refine(durationMax(minutes5(1)), "Maximum record age duration is 1 minute").default("60 seconds").describe(
2444
+ [
2445
+ "Discard records older than the specified age.",
2446
+ "The maximum valid value for maximum record age is 60s.",
2447
+ "The default value is 60s"
2448
+ ].join("\n")
2449
+ ),
2450
+ retryAttempts: z42.number().min(-1).max(1e4).default(2).describe(
2436
2451
  [
2437
2452
  "Discard records after the specified number of retries.",
2438
- "The default value is -1, which sets the maximum number of retries to infinite.",
2453
+ "-1 will sets the maximum number of retries to infinite.",
2439
2454
  "When maxRetryAttempts is infinite, Lambda retries failed records until the record expires in the event source.",
2440
- "You can specify a number from -1 to 10000."
2455
+ "You can specify a number from -1 to 10000.",
2456
+ "The default value is 2"
2441
2457
  ].join("\n")
2442
2458
  ),
2443
- concurrencyPerShard: z41.number().min(1).max(10).default(1).describe(
2459
+ concurrencyPerShard: z42.number().min(1).max(10).default(1).describe(
2444
2460
  [
2445
2461
  "The number of batches to process concurrently from each shard.",
2446
2462
  "You can specify a number from 1 to 10."
@@ -2450,16 +2466,16 @@ var TablesSchema = z41.record(
2450
2466
  }).optional().describe(
2451
2467
  "The settings for the DynamoDB table stream, which capture changes to items stored in the table."
2452
2468
  ),
2453
- indexes: z41.record(
2454
- z41.string(),
2455
- z41.object({
2456
- hash: z41.union([KeySchema.transform((v) => [v]), KeySchema.array()]).describe(
2469
+ indexes: z42.record(
2470
+ z42.string(),
2471
+ z42.object({
2472
+ hash: z42.union([KeySchema.transform((v) => [v]), KeySchema.array()]).describe(
2457
2473
  "Specifies the name of the partition / hash key that makes up the primary key for the global secondary index."
2458
2474
  ),
2459
- sort: z41.union([KeySchema.transform((v) => [v]), KeySchema.array()]).optional().describe(
2475
+ sort: z42.union([KeySchema.transform((v) => [v]), KeySchema.array()]).optional().describe(
2460
2476
  "Specifies the name of the range / sort key that makes up the primary key for the global secondary index."
2461
2477
  ),
2462
- projection: z41.enum(["all", "keys-only"]).default("all").describe(
2478
+ projection: z42.enum(["all", "keys-only"]).default("all").describe(
2463
2479
  [
2464
2480
  "The set of attributes that are projected into the index:",
2465
2481
  "- all - All of the table attributes are projected into the index.",
@@ -2473,11 +2489,11 @@ var TablesSchema = z41.record(
2473
2489
  ).optional().describe("Define the tables in your stack.");
2474
2490
 
2475
2491
  // src/feature/task/schema.ts
2476
- import { z as z42 } from "zod";
2477
- var RetryAttemptsSchema2 = z42.number().int().min(0).max(2).describe(
2492
+ import { z as z43 } from "zod";
2493
+ var RetryAttemptsSchema3 = z43.number().int().min(0).max(2).describe(
2478
2494
  "The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 2."
2479
2495
  );
2480
- var TaskSchema = z42.union([
2496
+ var TaskSchema = z43.union([
2481
2497
  LocalFileSchema.transform((file) => ({
2482
2498
  consumer: {
2483
2499
  code: {
@@ -2488,20 +2504,20 @@ var TaskSchema = z42.union([
2488
2504
  },
2489
2505
  retryAttempts: void 0
2490
2506
  })),
2491
- z42.object({
2507
+ z43.object({
2492
2508
  consumer: FunctionSchema,
2493
- retryAttempts: RetryAttemptsSchema2.optional()
2509
+ retryAttempts: RetryAttemptsSchema3.optional()
2494
2510
  })
2495
2511
  ]);
2496
- var TasksSchema = z42.record(ResourceIdSchema, TaskSchema).optional().describe("Define the tasks in your stack.");
2512
+ var TasksSchema = z43.record(ResourceIdSchema, TaskSchema).optional().describe("Define the tasks in your stack.");
2497
2513
 
2498
2514
  // src/feature/test/schema.ts
2499
- import { z as z43 } from "zod";
2500
- var TestsSchema = z43.union([
2515
+ import { z as z44 } from "zod";
2516
+ var TestsSchema = z44.union([
2501
2517
  //
2502
2518
  LocalDirectorySchema.transform((v) => [v]),
2503
2519
  LocalDirectorySchema.array(),
2504
- z43.literal(false)
2520
+ z44.literal(false)
2505
2521
  ]).describe("Define the location of your tests for your stack.").optional();
2506
2522
 
2507
2523
  // src/config/stack.ts
@@ -2509,8 +2525,8 @@ var DependsSchema = ResourceIdSchema.array().optional().describe("Define the sta
2509
2525
  var NameSchema = ResourceIdSchema.refine((name) => !["base", "hostedzones"].includes(name), {
2510
2526
  message: `Stack name can't be a reserved name.`
2511
2527
  }).describe("Stack name.");
2512
- var StackSchema = z44.object({
2513
- $schema: z44.string().optional(),
2528
+ var StackSchema = z45.object({
2529
+ $schema: z45.string().optional(),
2514
2530
  name: NameSchema,
2515
2531
  depends: DependsSchema,
2516
2532
  commands: CommandsSchema,
@@ -2547,37 +2563,37 @@ import { basename, dirname as dirname2, extname, join as join4 } from "path";
2547
2563
 
2548
2564
  // src/config/stage-patch.ts
2549
2565
  import jsonPatch from "fast-json-patch";
2550
- import { z as z45 } from "zod";
2551
- var AddOperationSchema = z45.object({
2552
- op: z45.literal("add"),
2553
- path: z45.string(),
2554
- value: z45.unknown()
2566
+ import { z as z46 } from "zod";
2567
+ var AddOperationSchema = z46.object({
2568
+ op: z46.literal("add"),
2569
+ path: z46.string(),
2570
+ value: z46.unknown()
2555
2571
  }).strict();
2556
- var RemoveOperationSchema = z45.object({
2557
- op: z45.literal("remove"),
2558
- path: z45.string()
2572
+ var RemoveOperationSchema = z46.object({
2573
+ op: z46.literal("remove"),
2574
+ path: z46.string()
2559
2575
  }).strict();
2560
- var ReplaceOperationSchema = z45.object({
2561
- op: z45.literal("replace"),
2562
- path: z45.string(),
2563
- value: z45.unknown()
2576
+ var ReplaceOperationSchema = z46.object({
2577
+ op: z46.literal("replace"),
2578
+ path: z46.string(),
2579
+ value: z46.unknown()
2564
2580
  }).strict();
2565
- var MoveOperationSchema = z45.object({
2566
- op: z45.literal("move"),
2567
- from: z45.string(),
2568
- path: z45.string()
2581
+ var MoveOperationSchema = z46.object({
2582
+ op: z46.literal("move"),
2583
+ from: z46.string(),
2584
+ path: z46.string()
2569
2585
  }).strict();
2570
- var CopyOperationSchema = z45.object({
2571
- op: z45.literal("copy"),
2572
- from: z45.string(),
2573
- path: z45.string()
2586
+ var CopyOperationSchema = z46.object({
2587
+ op: z46.literal("copy"),
2588
+ from: z46.string(),
2589
+ path: z46.string()
2574
2590
  }).strict();
2575
- var TestOperationSchema = z45.object({
2576
- op: z45.literal("test"),
2577
- path: z45.string(),
2578
- value: z45.unknown()
2591
+ var TestOperationSchema = z46.object({
2592
+ op: z46.literal("test"),
2593
+ path: z46.string(),
2594
+ value: z46.unknown()
2579
2595
  }).strict();
2580
- var JsonPatchOperationSchema = z45.discriminatedUnion("op", [
2596
+ var JsonPatchOperationSchema = z46.discriminatedUnion("op", [
2581
2597
  AddOperationSchema,
2582
2598
  RemoveOperationSchema,
2583
2599
  ReplaceOperationSchema,
@@ -2585,8 +2601,8 @@ var JsonPatchOperationSchema = z45.discriminatedUnion("op", [
2585
2601
  CopyOperationSchema,
2586
2602
  TestOperationSchema
2587
2603
  ]);
2588
- var StagePatchSchema = z45.object({
2589
- $schema: z45.string().optional(),
2604
+ var StagePatchSchema = z46.object({
2605
+ $schema: z46.string().optional(),
2590
2606
  operations: JsonPatchOperationSchema.array()
2591
2607
  }).strict();
2592
2608
  var applyStagePatch = (source, patch, file) => {
@@ -2602,13 +2618,13 @@ var applyStagePatch = (source, patch, file) => {
2602
2618
  };
2603
2619
 
2604
2620
  // src/config/load/validate.ts
2605
- import { z as z46 } from "zod";
2621
+ import { z as z47 } from "zod";
2606
2622
  var validateConfig = async (schema, file, data) => {
2607
2623
  try {
2608
2624
  const result = await schema.parseAsync(data);
2609
2625
  return result;
2610
2626
  } catch (error) {
2611
- if (error instanceof z46.ZodError) {
2627
+ if (error instanceof z47.ZodError) {
2612
2628
  throw new ConfigError(file, error, data);
2613
2629
  }
2614
2630
  throw error;
@@ -3419,7 +3435,7 @@ var formatByteSize = (size) => {
3419
3435
 
3420
3436
  // src/feature/on-failure/util.ts
3421
3437
  var getGlobalOnFailure = (ctx) => {
3422
- return ctx.shared.get("on-failure", "queue-arn");
3438
+ return ctx.shared.get("on-failure", "bucket-arn");
3423
3439
  };
3424
3440
 
3425
3441
  // src/feature/function/build/zip.ts
@@ -3967,8 +3983,15 @@ var createAsyncLambdaFunction = (group, ctx, ns, id, local) => {
3967
3983
  }
3968
3984
  );
3969
3985
  result.addPermission({
3970
- actions: ["sqs:SendMessage", "sqs:GetQueueUrl"],
3971
- resources: [onFailure]
3986
+ actions: ["s3:PutObject", "s3:ListBucket"],
3987
+ resources: [onFailure, $interpolate`${onFailure}/*`],
3988
+ conditions: {
3989
+ StringEquals: {
3990
+ // This will protect anyone from taking our bucket name,
3991
+ // and us sending our failed items to the wrong s3 bucket
3992
+ "s3:ResourceAccount": ctx.accountId
3993
+ }
3994
+ }
3972
3995
  });
3973
3996
  return result;
3974
3997
  };
@@ -4448,146 +4471,509 @@ var onLogFeature = defineFeature({
4448
4471
  });
4449
4472
 
4450
4473
  // src/feature/on-failure/index.ts
4451
- import { Group as Group8 } from "@terraforge/core";
4474
+ import { Group as Group9 } from "@terraforge/core";
4475
+ import { aws as aws10 } from "@terraforge/aws";
4476
+
4477
+ // src/feature/function/prebuild.ts
4478
+ import { days as days5, seconds as seconds5, toDays as toDays5, toSeconds as toSeconds3 } from "@awsless/duration";
4479
+ import { mebibytes as mebibytes2, toMebibytes as toMebibytes3 } from "@awsless/size";
4452
4480
  import { aws as aws9 } from "@terraforge/aws";
4453
- import { days as days5, toSeconds as toSeconds3 } from "@awsless/duration";
4454
- var onFailureFeature = defineFeature({
4455
- name: "on-failure",
4456
- onApp(ctx) {
4457
- const group = new Group8(ctx.base, "on-failure", "main");
4458
- const deadletter = new aws9.sqs.Queue(group, "deadletter", {
4459
- name: formatGlobalResourceName({
4460
- appName: ctx.app.name,
4461
- resourceType: "on-failure",
4462
- resourceName: "deadletter"
4463
- }),
4464
- messageRetentionSeconds: toSeconds3(days5(14))
4481
+ import { Output as Output4, findInputDeps as findInputDeps2, resolveInputs as resolveInputs2 } from "@terraforge/core";
4482
+ import { pascalCase as pascalCase2 } from "change-case";
4483
+ var createPrebuildLambdaFunction = (group, ctx, ns, id, props) => {
4484
+ let name;
4485
+ let roleName;
4486
+ if ("stack" in ctx) {
4487
+ name = formatLocalResourceName({
4488
+ appName: ctx.app.name,
4489
+ stackName: ctx.stack.name,
4490
+ resourceType: ns,
4491
+ resourceName: id
4465
4492
  });
4466
- const queue2 = new aws9.sqs.Queue(group, "on-failure", {
4467
- name: formatGlobalResourceName({
4468
- appName: ctx.app.name,
4469
- resourceType: "on-failure",
4470
- resourceName: "failure"
4471
- }),
4472
- redrivePolicy: deadletter.arn.pipe((deadLetterTargetArn) => {
4473
- return JSON.stringify({
4474
- deadLetterTargetArn,
4475
- maxReceiveCount: 100
4476
- });
4477
- })
4493
+ roleName = formatLocalResourceName({
4494
+ appName: ctx.app.name,
4495
+ stackName: ctx.stack.name,
4496
+ resourceType: ns,
4497
+ resourceName: id,
4498
+ postfix: ctx.appId
4478
4499
  });
4479
- ctx.shared.set("on-failure", "queue-arn", queue2.arn);
4480
- if (!ctx.appConfig.defaults.onFailure) {
4481
- return;
4482
- }
4483
- const result = createLambdaFunction(group, ctx, "on-failure", "consumer", ctx.appConfig.defaults.onFailure);
4484
- new aws9.lambda.EventSourceMapping(
4485
- group,
4486
- "on-failure",
4487
- {
4488
- functionName: result.lambda.functionName,
4489
- eventSourceArn: queue2.arn,
4490
- batchSize: 10
4491
- },
4492
- {
4493
- dependsOn: [result.policy]
4494
- }
4495
- );
4496
- result.addPermission({
4497
- actions: [
4498
- "sqs:SendMessage",
4499
- "sqs:DeleteMessage",
4500
- "sqs:ReceiveMessage",
4501
- "sqs:GetQueueUrl",
4502
- "sqs:GetQueueAttributes"
4503
- ],
4504
- resources: [queue2.arn]
4500
+ } else {
4501
+ name = formatGlobalResourceName({
4502
+ appName: ctx.appConfig.name,
4503
+ resourceType: ns,
4504
+ resourceName: id
4505
4505
  });
4506
- result.addPermission({
4507
- effect: "deny",
4508
- actions: ["lambda:InvokeFunction", "lambda:InvokeAsync", "sqs:SendMessage", "sns:Publish"],
4509
- resources: ["*"]
4506
+ roleName = formatGlobalResourceName({
4507
+ appName: ctx.appConfig.name,
4508
+ resourceType: ns,
4509
+ resourceName: id,
4510
+ postfix: ctx.appId
4510
4511
  });
4511
4512
  }
4512
- });
4513
-
4514
- // src/feature/pubsub/index.ts
4515
- import { Group as Group9 } from "@terraforge/core";
4516
- import { aws as aws10 } from "@terraforge/aws";
4517
- import { constantCase as constantCase5 } from "change-case";
4518
-
4519
- // src/feature/domain/util.ts
4520
- var getDomainNameById = (config2, id) => {
4521
- const domains = config2.defaults.domains ?? {};
4522
- if (id in domains) {
4523
- if (domains[id]) {
4524
- return domains[id].domain;
4525
- }
4526
- }
4527
- throw new TypeError(`No domain registered with id: ${id}`);
4528
- };
4529
- var formatFullDomainName = (config2, id, subDomain) => {
4530
- const domain2 = getDomainNameById(config2, id);
4531
- if (subDomain) {
4532
- return `${subDomain.replace(/\.$/, "")}.${domain2}`;
4533
- }
4534
- return domain2;
4535
- };
4536
-
4537
- // src/feature/pubsub/index.ts
4538
- import { minutes as minutes7, toSeconds as toSeconds4 } from "@awsless/duration";
4539
- var pubsubFeature = defineFeature({
4540
- name: "pubsub",
4541
- onApp(ctx) {
4542
- ctx.addGlobalPermission({
4543
- actions: ["iot:Publish"],
4544
- resources: [
4545
- // `arn:aws:iot:${ctx.appConfig.region}:${ctx.accountId}:topic/*`,
4546
- `arn:aws:iot:${ctx.appConfig.region}:${ctx.accountId}:topic/${ctx.app.name}/pubsub/*`
4547
- ]
4548
- });
4549
- for (const [id, props] of Object.entries(ctx.appConfig.defaults.pubsub ?? {})) {
4550
- const group = new Group9(ctx.base, "pubsub", id);
4551
- const { lambda } = createLambdaFunction(group, ctx, "pubsub-authorizer", id, props.auth);
4552
- const name = formatGlobalResourceName({
4553
- appName: ctx.app.name,
4554
- resourceType: "pubsub",
4555
- resourceName: id
4556
- });
4557
- const authorizer = new aws10.iot.Authorizer(group, "authorizer", {
4558
- name,
4559
- authorizerFunctionArn: lambda.arn,
4560
- status: "ACTIVE",
4561
- signingDisabled: true,
4562
- enableCachingForHttp: false
4563
- });
4564
- new aws10.lambda.Permission(group, "permission", {
4565
- functionName: lambda.functionName,
4566
- action: "lambda:InvokeFunction",
4567
- principal: "iot.amazonaws.com",
4568
- sourceArn: authorizer.arn
4569
- });
4570
- ctx.bind(`PUBSUB_${constantCase5(id)}_AUTHORIZER`, name);
4571
- const endpoint = aws10.iot.getEndpoint(group, "endpoint", {
4572
- endpointType: "iot:Data-ATS"
4573
- });
4574
- if (props.domain) {
4575
- const domainName = formatFullDomainName(ctx.appConfig, props.domain, props.subDomain);
4576
- new aws10.iot.DomainConfiguration(group, "domain", {
4577
- name,
4578
- domainName,
4579
- serverCertificateArns: [ctx.shared.entry("domain", `certificate-arn`, props.domain)],
4580
- authorizerConfig: {
4581
- defaultAuthorizerName: authorizer.name
4513
+ const code = new aws9.s3.BucketObject(group, "code", {
4514
+ bucket: ctx.shared.get("function", "bucket-name"),
4515
+ key: `/lambda/${name}.zip`,
4516
+ source: props.bundleFile,
4517
+ sourceHash: $hash(props.bundleFile)
4518
+ // body: Asset.fromFile(props.bundleFile),
4519
+ });
4520
+ const role = new aws9.iam.Role(group, "role", {
4521
+ name: roleName,
4522
+ assumeRolePolicy: JSON.stringify({
4523
+ Version: "2012-10-17",
4524
+ Statement: [
4525
+ {
4526
+ Effect: "Allow",
4527
+ Action: "sts:AssumeRole",
4528
+ Principal: {
4529
+ Service: ["lambda.amazonaws.com"]
4582
4530
  }
4583
- // validationCertificate: ctx.shared.get(`global-certificate-${props.domain}-arn`),
4584
- });
4585
- new aws10.route53.Record(group, "record", {
4586
- zoneId: ctx.shared.entry("domain", `zone-id`, props.domain),
4587
- name: domainName,
4588
- type: "CNAME",
4589
- ttl: toSeconds4(minutes7(5)),
4590
- records: [endpoint.endpointAddress]
4531
+ }
4532
+ ]
4533
+ })
4534
+ });
4535
+ const statements = [];
4536
+ const statementDeps = /* @__PURE__ */ new Set();
4537
+ const addPermission = (...permissions) => {
4538
+ statements.push(...permissions);
4539
+ for (const dep of findInputDeps2(permissions)) {
4540
+ statementDeps.add(dep);
4541
+ }
4542
+ };
4543
+ ctx.onPermission((statement) => {
4544
+ addPermission(statement);
4545
+ });
4546
+ const policy = new aws9.iam.RolePolicy(group, "policy", {
4547
+ role: role.name,
4548
+ name: "lambda-policy",
4549
+ policy: new Output4(statementDeps, async (resolve) => {
4550
+ const list3 = await resolveInputs2(statements);
4551
+ resolve(
4552
+ JSON.stringify({
4553
+ Version: "2012-10-17",
4554
+ Statement: list3.map((statement) => ({
4555
+ Effect: pascalCase2(statement.effect ?? "allow"),
4556
+ Action: statement.actions,
4557
+ Resource: statement.resources
4558
+ }))
4559
+ })
4560
+ );
4561
+ })
4562
+ });
4563
+ const variables = {};
4564
+ const logFormats = {
4565
+ text: "Text",
4566
+ json: "JSON"
4567
+ };
4568
+ const lambda = new aws9.lambda.Function(group, `function`, {
4569
+ functionName: name,
4570
+ role: role.arn,
4571
+ // code,
4572
+ // runtime: props.runtime === 'container' ? undefined : props.runtime,
4573
+ runtime: props.runtime,
4574
+ handler: props.handler,
4575
+ timeout: toSeconds3(props.timeout ?? seconds5(10)),
4576
+ memorySize: toMebibytes3(props.memorySize ?? mebibytes2(128)),
4577
+ architectures: [props.architecture ?? "arm64"],
4578
+ layers: props.layers?.map((id2) => ctx.shared.entry("layer", "arn", id2)),
4579
+ s3Bucket: code.bucket,
4580
+ s3ObjectVersion: code.versionId,
4581
+ s3Key: code.key.pipe((name2) => {
4582
+ if (name2.startsWith("/")) {
4583
+ return name2.substring(1);
4584
+ }
4585
+ return name2;
4586
+ }),
4587
+ sourceCodeHash: $hash(props.bundleFile),
4588
+ environment: {
4589
+ variables
4590
+ },
4591
+ loggingConfig: {
4592
+ logGroup: `/aws/lambda/${name}`,
4593
+ logFormat: logFormats[props.log && "format" in props.log && props.log.format || "json"],
4594
+ applicationLogLevel: props.log && "format" in props.log && props.log.format === "json" ? props.log.level?.toUpperCase() : void 0,
4595
+ systemLogLevel: props.log && "format" in props.log && props.log.format === "json" ? props.log.system?.toUpperCase() : void 0
4596
+ }
4597
+ });
4598
+ ctx.onEnv((name2, value) => {
4599
+ variables[name2] = value;
4600
+ });
4601
+ variables.APP = ctx.appConfig.name;
4602
+ variables.APP_ID = ctx.appId;
4603
+ variables.AWS_ACCOUNT_ID = ctx.accountId;
4604
+ if ("stackConfig" in ctx) {
4605
+ variables.STACK = ctx.stackConfig.name;
4606
+ }
4607
+ if (props.log?.retention && props.log?.retention?.value > 0n) {
4608
+ const logGroup = new aws9.cloudwatch.LogGroup(group, "log", {
4609
+ name: `/aws/lambda/${name}`,
4610
+ retentionInDays: toDays5(props.log.retention ?? days5(7))
4611
+ });
4612
+ addPermission({
4613
+ actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
4614
+ resources: [logGroup.arn.pipe((arn) => `${arn}:*`)]
4615
+ });
4616
+ const onLogArn = getGlobalOnLog(ctx);
4617
+ if (onLogArn && ctx.appConfig.defaults.onLog) {
4618
+ const logFilter = ctx.appConfig.defaults.onLog.filter;
4619
+ new aws9.cloudwatch.LogSubscriptionFilter(group, `on-log`, {
4620
+ name: "log-subscription",
4621
+ destinationArn: onLogArn,
4622
+ logGroupName: logGroup.name,
4623
+ filterPattern: formatFilterPattern(logFilter)
4624
+ });
4625
+ }
4626
+ }
4627
+ if (props.warm) {
4628
+ const rule = new aws9.cloudwatch.EventRule(group, "warm", {
4629
+ name: `${name}--warm`,
4630
+ description: "Lambda Warmer",
4631
+ scheduleExpression: "rate(5 minutes)",
4632
+ isEnabled: true
4633
+ });
4634
+ new aws9.cloudwatch.EventTarget(group, "warm", {
4635
+ rule: rule.name,
4636
+ targetId: "warmer",
4637
+ arn: lambda.arn,
4638
+ input: JSON.stringify({
4639
+ warmer: true,
4640
+ concurrency: props.warm
4641
+ })
4642
+ });
4643
+ new aws9.lambda.Permission(group, `warm`, {
4644
+ action: "lambda:InvokeFunction",
4645
+ principal: "events.amazonaws.com",
4646
+ functionName: lambda.functionName,
4647
+ sourceArn: rule.arn
4648
+ });
4649
+ }
4650
+ return {
4651
+ name,
4652
+ lambda,
4653
+ policy,
4654
+ code,
4655
+ setEnvironment(name2, value) {
4656
+ variables[name2] = value;
4657
+ },
4658
+ addPermission(statement) {
4659
+ addPermission(statement);
4660
+ }
4661
+ };
4662
+ };
4663
+
4664
+ // src/feature/on-failure/index.ts
4665
+ import { join as join10 } from "node:path";
4666
+ import { mebibytes as mebibytes3 } from "@awsless/size";
4667
+ import { days as days6, toSeconds as toSeconds4 } from "@awsless/duration";
4668
+ var onFailureFeature = defineFeature({
4669
+ name: "on-failure",
4670
+ onApp(ctx) {
4671
+ const group = new Group9(ctx.base, "on-failure", "main");
4672
+ const deadletter = new aws10.sqs.Queue(group, "deadletter", {
4673
+ name: formatGlobalResourceName({
4674
+ appName: ctx.app.name,
4675
+ resourceType: "on-failure",
4676
+ resourceName: "deadletter"
4677
+ }),
4678
+ messageRetentionSeconds: toSeconds4(days6(14))
4679
+ });
4680
+ const queue2 = new aws10.sqs.Queue(group, "on-failure", {
4681
+ name: formatGlobalResourceName({
4682
+ appName: ctx.app.name,
4683
+ resourceType: "on-failure",
4684
+ resourceName: "failure"
4685
+ }),
4686
+ redrivePolicy: deadletter.arn.pipe((deadLetterTargetArn) => {
4687
+ return JSON.stringify({
4688
+ deadLetterTargetArn,
4689
+ maxReceiveCount: 3
4690
+ });
4691
+ })
4692
+ });
4693
+ ctx.shared.set("on-failure", "queue-arn", queue2.arn);
4694
+ const bucket = new aws10.s3.Bucket(group, "bucket", {
4695
+ bucket: formatGlobalResourceName({
4696
+ appName: ctx.app.name,
4697
+ resourceType: "on-failure",
4698
+ resourceName: "failure",
4699
+ postfix: ctx.appId
4700
+ }),
4701
+ lifecycleRule: [
4702
+ {
4703
+ id: "ttl",
4704
+ enabled: true,
4705
+ expiration: {
4706
+ days: 14
4707
+ }
4708
+ }
4709
+ ]
4710
+ });
4711
+ ctx.shared.set("on-failure", "bucket-arn", bucket.arn);
4712
+ const props = ctx.appConfig.defaults.onFailure;
4713
+ if (props) {
4714
+ if (props.notify) {
4715
+ const topic = new aws10.sns.Topic(group, "deadletter-topic", {
4716
+ name: formatGlobalResourceName({
4717
+ appName: ctx.app.name,
4718
+ resourceType: "on-failure",
4719
+ resourceName: "deadletter"
4720
+ })
4721
+ });
4722
+ for (const email of props.notify) {
4723
+ new aws10.sns.TopicSubscription(group, email, {
4724
+ topicArn: topic.arn,
4725
+ protocol: "email",
4726
+ endpoint: email
4727
+ });
4728
+ }
4729
+ const role = new aws10.iam.Role(group, "deadletter-topic-role", {
4730
+ name: formatGlobalResourceName({
4731
+ appName: ctx.app.name,
4732
+ resourceType: "on-failure",
4733
+ resourceName: "pipe"
4734
+ }),
4735
+ description: `${ctx.app.name} on-failure deadletter notification pipe`,
4736
+ assumeRolePolicy: JSON.stringify({
4737
+ Version: "2012-10-17",
4738
+ Statement: [
4739
+ {
4740
+ Effect: "Allow",
4741
+ Action: "sts:AssumeRole",
4742
+ Principal: {
4743
+ Service: ["pipes.amazonaws.com"]
4744
+ }
4745
+ }
4746
+ ]
4747
+ }),
4748
+ inlinePolicy: [
4749
+ {
4750
+ name: "deadletter-topic",
4751
+ policy: topic.arn.pipe(
4752
+ (topicArn) => deadletter.arn.pipe(
4753
+ (queueArn) => JSON.stringify({
4754
+ Version: "2012-10-17",
4755
+ Statement: [
4756
+ {
4757
+ Effect: "Allow",
4758
+ Action: [
4759
+ "sqs:ReceiveMessage",
4760
+ "sqs:DeleteMessage",
4761
+ "sqs:GetQueueAttributes",
4762
+ "sqs:ChangeMessageVisibility"
4763
+ ],
4764
+ Resource: queueArn
4765
+ },
4766
+ {
4767
+ Effect: "Allow",
4768
+ Action: ["sns:Publish"],
4769
+ Resource: topicArn
4770
+ }
4771
+ ]
4772
+ })
4773
+ )
4774
+ )
4775
+ }
4776
+ ]
4777
+ });
4778
+ new aws10.pipes.Pipe(group, "deadletter-topic-pipe", {
4779
+ name: formatGlobalResourceName({
4780
+ appName: ctx.app.name,
4781
+ resourceType: "on-failure",
4782
+ resourceName: "notify"
4783
+ }),
4784
+ roleArn: role.arn,
4785
+ source: deadletter.arn,
4786
+ target: topic.arn,
4787
+ sourceParameters: {
4788
+ sqsQueueParameters: {
4789
+ batchSize: 1
4790
+ }
4791
+ },
4792
+ targetParameters: {
4793
+ inputTemplate: [
4794
+ `Awsless on-failure DLQ message`,
4795
+ `App: ${ctx.app.name}`,
4796
+ `Sent: <$.attributes.SentTimestamp>`,
4797
+ "",
4798
+ `Body:
4799
+ <$.body>`
4800
+ ].join("\n")
4801
+ }
4802
+ });
4803
+ }
4804
+ const consumer = createLambdaFunction(group, ctx, "on-failure", "consumer", props.consumer);
4805
+ consumer.addPermission({
4806
+ effect: "deny",
4807
+ actions: [
4808
+ //
4809
+ "lambda:InvokeFunction",
4810
+ "lambda:InvokeAsync",
4811
+ "sqs:SendMessage",
4812
+ "sns:Publish"
4813
+ ],
4814
+ resources: ["*"]
4815
+ });
4816
+ const prebuild = createPrebuildLambdaFunction(group, ctx, "on-failure", "normalizer", {
4817
+ bundleFile: join10(__dirname, "/prebuild/on-failure/bundle.zip"),
4818
+ bundleHash: join10(__dirname, "/prebuild/on-failure/HASH"),
4819
+ memorySize: mebibytes3(256),
4820
+ timeout: props.consumer.timeout,
4821
+ handler: "index.default",
4822
+ runtime: "nodejs24.x",
4823
+ log: {
4824
+ format: "json",
4825
+ level: "warn",
4826
+ retention: days6(3),
4827
+ system: "warn"
4828
+ }
4829
+ });
4830
+ prebuild.setEnvironment("CONSUMER", consumer.name);
4831
+ prebuild.addPermission({
4832
+ actions: ["lambda:InvokeFunction"],
4833
+ resources: [consumer.lambda.arn]
4834
+ });
4835
+ prebuild.addPermission({
4836
+ actions: ["s3:GetObject", "s3:DeleteObject"],
4837
+ resources: [bucket.arn, $interpolate`${bucket.arn}/*`]
4838
+ });
4839
+ prebuild.addPermission({
4840
+ actions: ["sqs:SendMessage"],
4841
+ resources: [deadletter.arn]
4842
+ });
4843
+ new aws10.lambda.FunctionEventInvokeConfig(
4844
+ group,
4845
+ "async",
4846
+ {
4847
+ functionName: prebuild.lambda.arn,
4848
+ maximumRetryAttempts: 2,
4849
+ destinationConfig: {
4850
+ onFailure: {
4851
+ destination: deadletter.arn
4852
+ }
4853
+ }
4854
+ },
4855
+ {
4856
+ dependsOn: [prebuild.policy]
4857
+ }
4858
+ );
4859
+ prebuild.addPermission({
4860
+ actions: [
4861
+ "sqs:SendMessage",
4862
+ "sqs:DeleteMessage",
4863
+ "sqs:ReceiveMessage",
4864
+ "sqs:GetQueueUrl",
4865
+ "sqs:GetQueueAttributes"
4866
+ ],
4867
+ resources: [queue2.arn]
4868
+ });
4869
+ new aws10.lambda.EventSourceMapping(
4870
+ group,
4871
+ "on-failure",
4872
+ {
4873
+ functionName: prebuild.lambda.functionName,
4874
+ eventSourceArn: queue2.arn,
4875
+ batchSize: 10
4876
+ },
4877
+ {
4878
+ dependsOn: [prebuild.policy]
4879
+ }
4880
+ );
4881
+ new aws10.lambda.Permission(group, "permission", {
4882
+ action: "lambda:InvokeFunction",
4883
+ principal: "s3.amazonaws.com",
4884
+ functionName: prebuild.lambda.functionName,
4885
+ sourceArn: bucket.arn
4886
+ });
4887
+ new aws10.s3.BucketNotification(group, "notification", {
4888
+ bucket: bucket.bucket,
4889
+ lambdaFunction: [
4890
+ {
4891
+ lambdaFunctionArn: prebuild.lambda.arn,
4892
+ events: ["s3:ObjectCreated:*"]
4893
+ }
4894
+ ]
4895
+ });
4896
+ }
4897
+ }
4898
+ });
4899
+
4900
+ // src/feature/pubsub/index.ts
4901
+ import { Group as Group10 } from "@terraforge/core";
4902
+ import { aws as aws11 } from "@terraforge/aws";
4903
+ import { constantCase as constantCase5 } from "change-case";
4904
+
4905
+ // src/feature/domain/util.ts
4906
+ var getDomainNameById = (config2, id) => {
4907
+ const domains = config2.defaults.domains ?? {};
4908
+ if (id in domains) {
4909
+ if (domains[id]) {
4910
+ return domains[id].domain;
4911
+ }
4912
+ }
4913
+ throw new TypeError(`No domain registered with id: ${id}`);
4914
+ };
4915
+ var formatFullDomainName = (config2, id, subDomain) => {
4916
+ const domain2 = getDomainNameById(config2, id);
4917
+ if (subDomain) {
4918
+ return `${subDomain.replace(/\.$/, "")}.${domain2}`;
4919
+ }
4920
+ return domain2;
4921
+ };
4922
+
4923
+ // src/feature/pubsub/index.ts
4924
+ import { minutes as minutes7, toSeconds as toSeconds5 } from "@awsless/duration";
4925
+ var pubsubFeature = defineFeature({
4926
+ name: "pubsub",
4927
+ onApp(ctx) {
4928
+ ctx.addGlobalPermission({
4929
+ actions: ["iot:Publish"],
4930
+ resources: [
4931
+ // `arn:aws:iot:${ctx.appConfig.region}:${ctx.accountId}:topic/*`,
4932
+ `arn:aws:iot:${ctx.appConfig.region}:${ctx.accountId}:topic/${ctx.app.name}/pubsub/*`
4933
+ ]
4934
+ });
4935
+ for (const [id, props] of Object.entries(ctx.appConfig.defaults.pubsub ?? {})) {
4936
+ const group = new Group10(ctx.base, "pubsub", id);
4937
+ const { lambda } = createLambdaFunction(group, ctx, "pubsub-authorizer", id, props.auth);
4938
+ const name = formatGlobalResourceName({
4939
+ appName: ctx.app.name,
4940
+ resourceType: "pubsub",
4941
+ resourceName: id
4942
+ });
4943
+ const authorizer = new aws11.iot.Authorizer(group, "authorizer", {
4944
+ name,
4945
+ authorizerFunctionArn: lambda.arn,
4946
+ status: "ACTIVE",
4947
+ signingDisabled: true,
4948
+ enableCachingForHttp: false
4949
+ });
4950
+ new aws11.lambda.Permission(group, "permission", {
4951
+ functionName: lambda.functionName,
4952
+ action: "lambda:InvokeFunction",
4953
+ principal: "iot.amazonaws.com",
4954
+ sourceArn: authorizer.arn
4955
+ });
4956
+ ctx.bind(`PUBSUB_${constantCase5(id)}_AUTHORIZER`, name);
4957
+ const endpoint = aws11.iot.getEndpoint(group, "endpoint", {
4958
+ endpointType: "iot:Data-ATS"
4959
+ });
4960
+ if (props.domain) {
4961
+ const domainName = formatFullDomainName(ctx.appConfig, props.domain, props.subDomain);
4962
+ new aws11.iot.DomainConfiguration(group, "domain", {
4963
+ name,
4964
+ domainName,
4965
+ serverCertificateArns: [ctx.shared.entry("domain", `certificate-arn`, props.domain)],
4966
+ authorizerConfig: {
4967
+ defaultAuthorizerName: authorizer.name
4968
+ }
4969
+ // validationCertificate: ctx.shared.get(`global-certificate-${props.domain}-arn`),
4970
+ });
4971
+ new aws11.route53.Record(group, "record", {
4972
+ zoneId: ctx.shared.entry("domain", `zone-id`, props.domain),
4973
+ name: domainName,
4974
+ type: "CNAME",
4975
+ ttl: toSeconds5(minutes7(5)),
4976
+ records: [endpoint.endpointAddress]
4591
4977
  });
4592
4978
  ctx.bind(`PUBSUB_${constantCase5(id)}_ENDPOINT`, domainName);
4593
4979
  } else {
@@ -4597,7 +4983,7 @@ var pubsubFeature = defineFeature({
4597
4983
  },
4598
4984
  onStack(ctx) {
4599
4985
  for (const [id, props] of Object.entries(ctx.stackConfig.pubsub ?? {})) {
4600
- const group = new Group9(ctx.stack, "pubsub", id);
4986
+ const group = new Group10(ctx.stack, "pubsub", id);
4601
4987
  const { lambda } = createAsyncLambdaFunction(group, ctx, `pubsub`, id, props.consumer);
4602
4988
  const name = formatLocalResourceName({
4603
4989
  appName: ctx.app.name,
@@ -4605,14 +4991,14 @@ var pubsubFeature = defineFeature({
4605
4991
  resourceType: "pubsub",
4606
4992
  resourceName: id
4607
4993
  });
4608
- const topic = new aws10.iot.TopicRule(group, "rule", {
4994
+ const topic = new aws11.iot.TopicRule(group, "rule", {
4609
4995
  name: name.replaceAll("-", "_"),
4610
4996
  enabled: true,
4611
4997
  sql: props.sql,
4612
4998
  sqlVersion: props.sqlVersion,
4613
4999
  lambda: [{ functionArn: lambda.arn }]
4614
5000
  });
4615
- new aws10.lambda.Permission(group, "permission", {
5001
+ new aws11.lambda.Permission(group, "permission", {
4616
5002
  action: "lambda:InvokeFunction",
4617
5003
  principal: "iot.amazonaws.com",
4618
5004
  functionName: lambda.functionName,
@@ -4623,12 +5009,12 @@ var pubsubFeature = defineFeature({
4623
5009
  });
4624
5010
 
4625
5011
  // src/feature/queue/index.ts
4626
- import { Group as Group10 } from "@terraforge/core";
4627
- import { aws as aws11 } from "@terraforge/aws";
5012
+ import { Group as Group11 } from "@terraforge/core";
5013
+ import { aws as aws12 } from "@terraforge/aws";
4628
5014
  import { camelCase as camelCase5, constantCase as constantCase6 } from "change-case";
4629
5015
  import deepmerge3 from "deepmerge";
4630
5016
  import { relative as relative5 } from "path";
4631
- import { seconds as seconds5, toSeconds as toSeconds5 } from "@awsless/duration";
5017
+ import { seconds as seconds6, toSeconds as toSeconds6 } from "@awsless/duration";
4632
5018
  import { toBytes } from "@awsless/size";
4633
5019
  var typeGenCode4 = `
4634
5020
  import { SendMessageOptions, SendMessageBatchOptions, BatchItem } from '@awsless/sqs'
@@ -4688,42 +5074,44 @@ var queueFeature = defineFeature({
4688
5074
  gen.addInterface("QueueMockResponse", mockResponses);
4689
5075
  await ctx.write("queue.d.ts", gen, true);
4690
5076
  },
5077
+ onApp(ctx) {
5078
+ },
4691
5079
  onStack(ctx) {
4692
5080
  for (const [id, local] of Object.entries(ctx.stackConfig.queues || {})) {
4693
5081
  const props = deepmerge3(ctx.appConfig.defaults.queue, typeof local === "object" ? local : {});
4694
- const group = new Group10(ctx.stack, "queue", id);
5082
+ const group = new Group11(ctx.stack, "queue", id);
4695
5083
  const name = formatLocalResourceName({
4696
5084
  appName: ctx.app.name,
4697
5085
  stackName: ctx.stack.name,
4698
5086
  resourceType: "queue",
4699
5087
  resourceName: id
4700
5088
  });
4701
- const onFailure = getGlobalOnFailure(ctx);
4702
- const queue2 = new aws11.sqs.Queue(group, "queue", {
5089
+ const onFailure = ctx.shared.get("on-failure", "queue-arn");
5090
+ const queue2 = new aws12.sqs.Queue(group, "queue", {
4703
5091
  name,
4704
- delaySeconds: toSeconds5(props.deliveryDelay),
4705
- visibilityTimeoutSeconds: toSeconds5(props.visibilityTimeout),
4706
- receiveWaitTimeSeconds: toSeconds5(props.receiveMessageWaitTime ?? seconds5(0)),
4707
- messageRetentionSeconds: toSeconds5(props.retentionPeriod),
5092
+ delaySeconds: toSeconds6(props.deliveryDelay),
5093
+ visibilityTimeoutSeconds: toSeconds6(props.visibilityTimeout),
5094
+ receiveWaitTimeSeconds: toSeconds6(props.receiveMessageWaitTime ?? seconds6(0)),
5095
+ messageRetentionSeconds: toSeconds6(props.retentionPeriod),
4708
5096
  maxMessageSize: toBytes(props.maxMessageSize),
4709
5097
  redrivePolicy: onFailure.pipe(
4710
5098
  (arn) => JSON.stringify({
4711
5099
  deadLetterTargetArn: arn,
4712
- maxReceiveCount: 100
5100
+ maxReceiveCount: props.retryAttempts + 1
4713
5101
  })
4714
5102
  )
4715
5103
  });
4716
5104
  if (local.consumer) {
4717
5105
  const lambdaConsumer = createLambdaFunction(group, ctx, `queue`, id, local.consumer);
4718
5106
  lambdaConsumer.setEnvironment("THROW_EXPECTED_ERRORS", "1");
4719
- new aws11.lambda.EventSourceMapping(
5107
+ new aws12.lambda.EventSourceMapping(
4720
5108
  group,
4721
5109
  "event",
4722
5110
  {
4723
5111
  functionName: lambdaConsumer.lambda.functionName,
4724
5112
  eventSourceArn: queue2.arn,
4725
5113
  batchSize: props.batchSize,
4726
- maximumBatchingWindowInSeconds: props.maxBatchingWindow && toSeconds5(props.maxBatchingWindow),
5114
+ maximumBatchingWindowInSeconds: props.maxBatchingWindow && toSeconds6(props.maxBatchingWindow),
4727
5115
  scalingConfig: {
4728
5116
  maximumConcurrency: props.maxConcurrency
4729
5117
  }
@@ -4759,24 +5147,24 @@ var queueFeature = defineFeature({
4759
5147
  });
4760
5148
 
4761
5149
  // src/feature/rest/index.ts
4762
- import { Group as Group11 } from "@terraforge/core";
4763
- import { aws as aws12 } from "@terraforge/aws";
5150
+ import { Group as Group12 } from "@terraforge/core";
5151
+ import { aws as aws13 } from "@terraforge/aws";
4764
5152
  import { constantCase as constantCase7 } from "change-case";
4765
5153
  var restFeature = defineFeature({
4766
5154
  name: "rest",
4767
5155
  onApp(ctx) {
4768
5156
  for (const [id, props] of Object.entries(ctx.appConfig.defaults?.rest ?? {})) {
4769
- const group = new Group11(ctx.base, "rest", id);
5157
+ const group = new Group12(ctx.base, "rest", id);
4770
5158
  const name = formatGlobalResourceName({
4771
5159
  appName: ctx.app.name,
4772
5160
  resourceType: "rest",
4773
5161
  resourceName: id
4774
5162
  });
4775
- const api = new aws12.apigatewayv2.Api(group, "api", {
5163
+ const api = new aws13.apigatewayv2.Api(group, "api", {
4776
5164
  name,
4777
5165
  protocolType: "HTTP"
4778
5166
  });
4779
- const stage = new aws12.apigatewayv2.Stage(group, "stage", {
5167
+ const stage = new aws13.apigatewayv2.Stage(group, "stage", {
4780
5168
  name: "v1",
4781
5169
  apiId: api.id,
4782
5170
  autoDeploy: true
@@ -4786,7 +5174,7 @@ var restFeature = defineFeature({
4786
5174
  const domainName = formatFullDomainName(ctx.appConfig, props.domain, props.subDomain);
4787
5175
  const zoneId = ctx.shared.entry("domain", `zone-id`, props.domain);
4788
5176
  const certificateArn = ctx.shared.entry("domain", `certificate-arn`, props.domain);
4789
- const domain2 = new aws12.apigatewayv2.DomainName(group, "domain", {
5177
+ const domain2 = new aws13.apigatewayv2.DomainName(group, "domain", {
4790
5178
  domainName,
4791
5179
  domainNameConfiguration: {
4792
5180
  certificateArn,
@@ -4794,12 +5182,12 @@ var restFeature = defineFeature({
4794
5182
  securityPolicy: "TLS_1_2"
4795
5183
  }
4796
5184
  });
4797
- const mapping = new aws12.apigatewayv2.ApiMapping(group, "mapping", {
5185
+ const mapping = new aws13.apigatewayv2.ApiMapping(group, "mapping", {
4798
5186
  apiId: api.id,
4799
5187
  domainName: domain2.domainName,
4800
5188
  stage: stage.name
4801
5189
  });
4802
- new aws12.route53.Record(
5190
+ new aws13.route53.Record(
4803
5191
  group,
4804
5192
  "record",
4805
5193
  {
@@ -4827,21 +5215,21 @@ var restFeature = defineFeature({
4827
5215
  },
4828
5216
  onStack(ctx) {
4829
5217
  for (const [id, routes] of Object.entries(ctx.stackConfig.rest ?? {})) {
4830
- const restGroup = new Group11(ctx.stack, "rest", id);
5218
+ const restGroup = new Group12(ctx.stack, "rest", id);
4831
5219
  for (const [routeKey, props] of Object.entries(routes)) {
4832
- const group = new Group11(restGroup, "route", routeKey);
5220
+ const group = new Group12(restGroup, "route", routeKey);
4833
5221
  const apiId = ctx.shared.entry("rest", "id", id);
4834
5222
  const routeId = shortId(routeKey);
4835
5223
  const { lambda } = createLambdaFunction(group, ctx, "rest", `${id}-${routeId}`, {
4836
5224
  ...props,
4837
5225
  description: `${id} ${routeKey}`
4838
5226
  });
4839
- const permission = new aws12.lambda.Permission(group, "permission", {
5227
+ const permission = new aws13.lambda.Permission(group, "permission", {
4840
5228
  action: "lambda:InvokeFunction",
4841
5229
  principal: "apigateway.amazonaws.com",
4842
5230
  functionName: lambda.functionName
4843
5231
  });
4844
- const integration = new aws12.apigatewayv2.Integration(group, "integration", {
5232
+ const integration = new aws13.apigatewayv2.Integration(group, "integration", {
4845
5233
  apiId,
4846
5234
  description: `${id} ${routeKey}`,
4847
5235
  integrationType: "AWS_PROXY",
@@ -4851,7 +5239,7 @@ var restFeature = defineFeature({
4851
5239
  return `arn:aws:apigateway:${ctx.appConfig.region}:lambda:path/2015-03-31/functions/${arn}/invocations`;
4852
5240
  })
4853
5241
  });
4854
- new aws12.apigatewayv2.Route(
5242
+ new aws13.apigatewayv2.Route(
4855
5243
  group,
4856
5244
  "route",
4857
5245
  {
@@ -4872,200 +5260,11 @@ var restFeature = defineFeature({
4872
5260
  import { camelCase as camelCase6, constantCase as constantCase8, kebabCase as kebabCase6 } from "change-case";
4873
5261
  import { Group as Group13 } from "@terraforge/core";
4874
5262
  import { aws as aws14 } from "@terraforge/aws";
4875
- import { mebibytes as mebibytes3 } from "@awsless/size";
4876
- import { dirname as dirname5, join as join10, relative as relative6 } from "path";
5263
+ import { mebibytes as mebibytes4 } from "@awsless/size";
5264
+ import { dirname as dirname5, join as join11, relative as relative6 } from "path";
4877
5265
  import { fileURLToPath } from "node:url";
4878
-
4879
- // src/feature/function/prebuild.ts
4880
- import { days as days6, seconds as seconds6, toDays as toDays5, toSeconds as toSeconds6 } from "@awsless/duration";
4881
- import { mebibytes as mebibytes2, toMebibytes as toMebibytes3 } from "@awsless/size";
4882
- import { aws as aws13 } from "@terraforge/aws";
4883
- import { Output as Output4, findInputDeps as findInputDeps2, resolveInputs as resolveInputs2 } from "@terraforge/core";
4884
- import { pascalCase as pascalCase2 } from "change-case";
4885
- var createPrebuildLambdaFunction = (group, ctx, ns, id, props) => {
4886
- let name;
4887
- let roleName;
4888
- if ("stack" in ctx) {
4889
- name = formatLocalResourceName({
4890
- appName: ctx.app.name,
4891
- stackName: ctx.stack.name,
4892
- resourceType: ns,
4893
- resourceName: id
4894
- });
4895
- roleName = formatLocalResourceName({
4896
- appName: ctx.app.name,
4897
- stackName: ctx.stack.name,
4898
- resourceType: ns,
4899
- resourceName: id,
4900
- postfix: ctx.appId
4901
- });
4902
- } else {
4903
- name = formatGlobalResourceName({
4904
- appName: ctx.appConfig.name,
4905
- resourceType: ns,
4906
- resourceName: id
4907
- });
4908
- roleName = formatGlobalResourceName({
4909
- appName: ctx.appConfig.name,
4910
- resourceType: ns,
4911
- resourceName: id,
4912
- postfix: ctx.appId
4913
- });
4914
- }
4915
- const code = new aws13.s3.BucketObject(group, "code", {
4916
- bucket: ctx.shared.get("function", "bucket-name"),
4917
- key: `/lambda/${name}.zip`,
4918
- source: props.bundleFile,
4919
- sourceHash: $hash(props.bundleFile)
4920
- // body: Asset.fromFile(props.bundleFile),
4921
- });
4922
- const role = new aws13.iam.Role(group, "role", {
4923
- name: roleName,
4924
- assumeRolePolicy: JSON.stringify({
4925
- Version: "2012-10-17",
4926
- Statement: [
4927
- {
4928
- Effect: "Allow",
4929
- Action: "sts:AssumeRole",
4930
- Principal: {
4931
- Service: ["lambda.amazonaws.com"]
4932
- }
4933
- }
4934
- ]
4935
- })
4936
- });
4937
- const statements = [];
4938
- const statementDeps = /* @__PURE__ */ new Set();
4939
- const addPermission = (...permissions) => {
4940
- statements.push(...permissions);
4941
- for (const dep of findInputDeps2(permissions)) {
4942
- statementDeps.add(dep);
4943
- }
4944
- };
4945
- ctx.onPermission((statement) => {
4946
- addPermission(statement);
4947
- });
4948
- const policy = new aws13.iam.RolePolicy(group, "policy", {
4949
- role: role.name,
4950
- name: "lambda-policy",
4951
- policy: new Output4(statementDeps, async (resolve) => {
4952
- const list3 = await resolveInputs2(statements);
4953
- resolve(
4954
- JSON.stringify({
4955
- Version: "2012-10-17",
4956
- Statement: list3.map((statement) => ({
4957
- Effect: pascalCase2(statement.effect ?? "allow"),
4958
- Action: statement.actions,
4959
- Resource: statement.resources
4960
- }))
4961
- })
4962
- );
4963
- })
4964
- });
4965
- const variables = {};
4966
- const logFormats = {
4967
- text: "Text",
4968
- json: "JSON"
4969
- };
4970
- const lambda = new aws13.lambda.Function(group, `function`, {
4971
- functionName: name,
4972
- role: role.arn,
4973
- // code,
4974
- // runtime: props.runtime === 'container' ? undefined : props.runtime,
4975
- runtime: props.runtime,
4976
- handler: props.handler,
4977
- timeout: toSeconds6(props.timeout ?? seconds6(10)),
4978
- memorySize: toMebibytes3(props.memorySize ?? mebibytes2(128)),
4979
- architectures: [props.architecture ?? "arm64"],
4980
- layers: props.layers?.map((id2) => ctx.shared.entry("layer", "arn", id2)),
4981
- s3Bucket: code.bucket,
4982
- s3ObjectVersion: code.versionId,
4983
- s3Key: code.key.pipe((name2) => {
4984
- if (name2.startsWith("/")) {
4985
- return name2.substring(1);
4986
- }
4987
- return name2;
4988
- }),
4989
- sourceCodeHash: $hash(props.bundleFile),
4990
- environment: {
4991
- variables
4992
- },
4993
- loggingConfig: {
4994
- logGroup: `/aws/lambda/${name}`,
4995
- logFormat: logFormats[props.log && "format" in props.log && props.log.format || "json"],
4996
- applicationLogLevel: props.log && "format" in props.log && props.log.format === "json" ? props.log.level?.toUpperCase() : void 0,
4997
- systemLogLevel: props.log && "format" in props.log && props.log.format === "json" ? props.log.system?.toUpperCase() : void 0
4998
- }
4999
- });
5000
- ctx.onEnv((name2, value) => {
5001
- variables[name2] = value;
5002
- });
5003
- variables.APP = ctx.appConfig.name;
5004
- variables.APP_ID = ctx.appId;
5005
- variables.AWS_ACCOUNT_ID = ctx.accountId;
5006
- if ("stackConfig" in ctx) {
5007
- variables.STACK = ctx.stackConfig.name;
5008
- }
5009
- if (props.log?.retention && props.log?.retention?.value > 0n) {
5010
- const logGroup = new aws13.cloudwatch.LogGroup(group, "log", {
5011
- name: `/aws/lambda/${name}`,
5012
- retentionInDays: toDays5(props.log.retention ?? days6(7))
5013
- });
5014
- addPermission({
5015
- actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
5016
- resources: [logGroup.arn.pipe((arn) => `${arn}:*`)]
5017
- });
5018
- const onLogArn = getGlobalOnLog(ctx);
5019
- if (onLogArn && ctx.appConfig.defaults.onLog) {
5020
- const logFilter = ctx.appConfig.defaults.onLog.filter;
5021
- new aws13.cloudwatch.LogSubscriptionFilter(group, `on-log`, {
5022
- name: "log-subscription",
5023
- destinationArn: onLogArn,
5024
- logGroupName: logGroup.name,
5025
- filterPattern: formatFilterPattern(logFilter)
5026
- });
5027
- }
5028
- }
5029
- if (props.warm) {
5030
- const rule = new aws13.cloudwatch.EventRule(group, "warm", {
5031
- name: `${name}--warm`,
5032
- description: "Lambda Warmer",
5033
- scheduleExpression: "rate(5 minutes)",
5034
- isEnabled: true
5035
- });
5036
- new aws13.cloudwatch.EventTarget(group, "warm", {
5037
- rule: rule.name,
5038
- targetId: "warmer",
5039
- arn: lambda.arn,
5040
- input: JSON.stringify({
5041
- warmer: true,
5042
- concurrency: props.warm
5043
- })
5044
- });
5045
- new aws13.lambda.Permission(group, `warm`, {
5046
- action: "lambda:InvokeFunction",
5047
- principal: "events.amazonaws.com",
5048
- functionName: lambda.functionName,
5049
- sourceArn: rule.arn
5050
- });
5051
- }
5052
- return {
5053
- name,
5054
- lambda,
5055
- policy,
5056
- code,
5057
- setEnvironment(name2, value) {
5058
- variables[name2] = value;
5059
- },
5060
- addPermission(statement) {
5061
- addPermission(statement);
5062
- }
5063
- };
5064
- };
5065
-
5066
- // src/feature/rpc/index.ts
5067
5266
  import { toSeconds as toSeconds7 } from "@awsless/duration";
5068
- var __dirname = dirname5(fileURLToPath(import.meta.url));
5267
+ var __dirname2 = dirname5(fileURLToPath(import.meta.url));
5069
5268
  var rpcFeature = defineFeature({
5070
5269
  name: "rpc",
5071
5270
  async onTypeGen(ctx) {
@@ -5125,9 +5324,9 @@ var rpcFeature = defineFeature({
5125
5324
  for (const [id, props] of Object.entries(ctx.appConfig.defaults.rpc ?? {})) {
5126
5325
  const group = new Group13(ctx.base, "rpc", id);
5127
5326
  const result = createPrebuildLambdaFunction(group, ctx, "rpc", id, {
5128
- bundleFile: join10(__dirname, "/prebuild/rpc/bundle.zip"),
5129
- bundleHash: join10(__dirname, "/prebuild/rpc/HASH"),
5130
- memorySize: mebibytes3(256),
5327
+ bundleFile: join11(__dirname2, "/prebuild/rpc/bundle.zip"),
5328
+ bundleHash: join11(__dirname2, "/prebuild/rpc/HASH"),
5329
+ memorySize: mebibytes4(256),
5131
5330
  timeout: props.timeout,
5132
5331
  handler: "index.default",
5133
5332
  runtime: "nodejs22.x",
@@ -5394,7 +5593,7 @@ var searchFeature = defineFeature({
5394
5593
  import { Group as Group15 } from "@terraforge/core";
5395
5594
  import { aws as aws16 } from "@terraforge/aws";
5396
5595
  import { glob as glob2 } from "glob";
5397
- import { dirname as dirname6, join as join11 } from "path";
5596
+ import { dirname as dirname6, join as join12 } from "path";
5398
5597
 
5399
5598
  // src/feature/site/util.ts
5400
5599
  import { contentType, lookup } from "mime-types";
@@ -5440,7 +5639,7 @@ var siteFeature = defineFeature({
5440
5639
  return build3(fingerprint, async (write) => {
5441
5640
  const credentialProvider = await getCredentials(ctx.appConfig.profile);
5442
5641
  const credentials = await credentialProvider();
5443
- const cwd = join11(directories.root, dirname6(ctx.stackConfig.file));
5642
+ const cwd = join12(directories.root, dirname6(ctx.stackConfig.file));
5444
5643
  const env = {
5445
5644
  ...process.env,
5446
5645
  // Pass the app config name
@@ -5585,20 +5784,20 @@ var siteFeature = defineFeature({
5585
5784
  });
5586
5785
  const staticRoutes = {};
5587
5786
  for (const file of files) {
5588
- const prefixedFile = join11("/", file);
5787
+ const prefixedFile = join12("/", file);
5589
5788
  const object = new aws16.s3.BucketObject(group, prefixedFile, {
5590
5789
  bucket: bucket.bucket,
5591
5790
  key: prefixedFile,
5592
5791
  cacheControl: getCacheControl(file),
5593
5792
  contentType: getContentType(file),
5594
- source: join11(props.static, file),
5595
- sourceHash: $hash(join11(props.static, file))
5793
+ source: join12(props.static, file),
5794
+ sourceHash: $hash(join12(props.static, file))
5596
5795
  });
5597
5796
  versions.push(object.key);
5598
5797
  versions.push(object.sourceHash);
5599
5798
  const strippedHtmlFile = file.endsWith("index.html") ? file.slice(0, -11) : file.endsWith(".html") ? file.slice(0, -5) : file;
5600
5799
  const urlFriendlyFile = strippedHtmlFile.endsWith("/") ? strippedHtmlFile.slice(0, -1) : strippedHtmlFile;
5601
- const routeFileKey = join11(props.path, urlFriendlyFile);
5800
+ const routeFileKey = join12(props.path, urlFriendlyFile);
5602
5801
  staticRoutes[routeFileKey] = {
5603
5802
  type: "s3",
5604
5803
  domainName: bucket.bucketRegionalDomainName,
@@ -5641,7 +5840,7 @@ var getContentType2 = (file) => {
5641
5840
  };
5642
5841
 
5643
5842
  // src/feature/store/index.ts
5644
- import { join as join12 } from "path";
5843
+ import { join as join13 } from "path";
5645
5844
  var typeGenCode6 = `
5646
5845
  import { Body, PutObjectProps, BodyStream } from '@awsless/s3'
5647
5846
 
@@ -5697,7 +5896,14 @@ var storeFeature = defineFeature({
5697
5896
  //
5698
5897
  `arn:aws:s3:::${name}`,
5699
5898
  `arn:aws:s3:::${name}/*`
5700
- ]
5899
+ ],
5900
+ conditions: {
5901
+ StringEquals: {
5902
+ // This will protect anyone from taking our bucket name,
5903
+ // and us sending our items to the wrong s3 bucket
5904
+ "s3:ResourceAccount": ctx.accountId
5905
+ }
5906
+ }
5701
5907
  });
5702
5908
  },
5703
5909
  onStack(ctx) {
@@ -5746,8 +5952,8 @@ var storeFeature = defineFeature({
5746
5952
  key: file,
5747
5953
  cacheControl: getCacheControl2(file),
5748
5954
  contentType: getContentType2(file),
5749
- source: join12(props.static, file),
5750
- sourceHash: $hash(join12(props.static, file))
5955
+ source: join13(props.static, file),
5956
+ sourceHash: $hash(join13(props.static, file))
5751
5957
  });
5752
5958
  }
5753
5959
  }
@@ -5800,7 +6006,14 @@ var storeFeature = defineFeature({
5800
6006
  //
5801
6007
  bucket.arn,
5802
6008
  bucket.arn.pipe((arn) => `${arn}/*`)
5803
- ]
6009
+ ],
6010
+ conditions: {
6011
+ StringEquals: {
6012
+ // This will protect anyone from taking our bucket name,
6013
+ // and us sending our items to the wrong s3 bucket
6014
+ "s3:ResourceAccount": ctx.accountId
6015
+ }
6016
+ }
5804
6017
  });
5805
6018
  }
5806
6019
  }
@@ -5939,7 +6152,7 @@ var tableFeature = defineFeature({
5939
6152
  functionName: result.lambda.functionName,
5940
6153
  eventSourceArn: table.streamArn,
5941
6154
  // tumblingWindowInSeconds
5942
- // maximumRecordAgeInSeconds: props.stream.
6155
+ maximumRecordAgeInSeconds: toSeconds8(props.stream.maxRecordAge),
5943
6156
  // bisectBatchOnFunctionError: true,
5944
6157
  batchSize: props.stream.batchSize,
5945
6158
  maximumBatchingWindowInSeconds: props.stream.batchWindow ? toSeconds8(props.stream.batchWindow) : void 0,
@@ -5955,6 +6168,17 @@ var tableFeature = defineFeature({
5955
6168
  },
5956
6169
  { dependsOn: [result.policy] }
5957
6170
  );
6171
+ result.addPermission({
6172
+ actions: ["s3:PutObject", "s3:ListBucket"],
6173
+ resources: [onFailure, $interpolate`${onFailure}/*`],
6174
+ conditions: {
6175
+ StringEquals: {
6176
+ // This will protect anyone from taking our bucket name,
6177
+ // and us sending our failed items to the wrong s3 bucket
6178
+ "s3:ResourceAccount": ctx.accountId
6179
+ }
6180
+ }
6181
+ });
5958
6182
  result.addPermission({
5959
6183
  actions: [
5960
6184
  "dynamodb:ListStreams",
@@ -5964,10 +6188,6 @@ var tableFeature = defineFeature({
5964
6188
  ],
5965
6189
  resources: [table.streamArn]
5966
6190
  });
5967
- result.addPermission({
5968
- actions: ["sqs:SendMessage", "sqs:GetQueueUrl"],
5969
- resources: [onFailure]
5970
- });
5971
6191
  }
5972
6192
  ctx.addStackPermission({
5973
6193
  actions: [
@@ -6497,12 +6717,12 @@ var layerFeature = defineFeature({
6497
6717
  // src/feature/image/index.ts
6498
6718
  import { Group as Group23 } from "@terraforge/core";
6499
6719
  import { aws as aws24 } from "@terraforge/aws";
6500
- import { join as join13, dirname as dirname7 } from "path";
6501
- import { mebibytes as mebibytes4 } from "@awsless/size";
6720
+ import { join as join14, dirname as dirname7 } from "path";
6721
+ import { mebibytes as mebibytes5 } from "@awsless/size";
6502
6722
  import { seconds as seconds7, toDays as toDays6 } from "@awsless/duration";
6503
6723
  import { fileURLToPath as fileURLToPath2 } from "url";
6504
6724
  import { glob as glob4 } from "glob";
6505
- var __dirname2 = dirname7(fileURLToPath2(import.meta.url));
6725
+ var __dirname3 = dirname7(fileURLToPath2(import.meta.url));
6506
6726
  var imageFeature = defineFeature({
6507
6727
  name: "image",
6508
6728
  onApp(ctx) {
@@ -6513,7 +6733,7 @@ var imageFeature = defineFeature({
6513
6733
  return;
6514
6734
  }
6515
6735
  const group = new Group23(ctx.base, "image", "layer");
6516
- const path = join13(__dirname2, "/layers/sharp-arm.zip");
6736
+ const path = join14(__dirname3, "/layers/sharp-arm.zip");
6517
6737
  const layerId = formatGlobalResourceName({
6518
6738
  appName: ctx.appConfig.name,
6519
6739
  resourceType: "layer",
@@ -6602,9 +6822,9 @@ var imageFeature = defineFeature({
6602
6822
  resourceName: "sharp"
6603
6823
  });
6604
6824
  const serverLambda = createPrebuildLambdaFunction(group, ctx, "image", id, {
6605
- bundleFile: join13(__dirname2, "/prebuild/image/bundle.zip"),
6606
- bundleHash: join13(__dirname2, "/prebuild/image/HASH"),
6607
- memorySize: mebibytes4(512),
6825
+ bundleFile: join14(__dirname3, "/prebuild/image/bundle.zip"),
6826
+ bundleHash: join14(__dirname3, "/prebuild/image/HASH"),
6827
+ memorySize: mebibytes5(512),
6608
6828
  timeout: seconds7(10),
6609
6829
  handler: "index.default",
6610
6830
  runtime: "nodejs22.x",
@@ -6678,8 +6898,8 @@ var imageFeature = defineFeature({
6678
6898
  new aws24.s3.BucketObject(group, `static-${file}`, {
6679
6899
  bucket: s3Origin.bucket,
6680
6900
  key: file,
6681
- source: join13(props.origin.static, file),
6682
- sourceHash: $hash(join13(props.origin.static, file))
6901
+ source: join14(props.origin.static, file),
6902
+ sourceHash: $hash(join14(props.origin.static, file))
6683
6903
  });
6684
6904
  }
6685
6905
  }
@@ -6694,12 +6914,12 @@ var imageFeature = defineFeature({
6694
6914
  // src/feature/icon/index.ts
6695
6915
  import { Group as Group24 } from "@terraforge/core";
6696
6916
  import { aws as aws25 } from "@terraforge/aws";
6697
- import { join as join14, dirname as dirname8 } from "path";
6698
- import { mebibytes as mebibytes5 } from "@awsless/size";
6917
+ import { join as join15, dirname as dirname8 } from "path";
6918
+ import { mebibytes as mebibytes6 } from "@awsless/size";
6699
6919
  import { seconds as seconds8, toDays as toDays7 } from "@awsless/duration";
6700
6920
  import { fileURLToPath as fileURLToPath3 } from "url";
6701
6921
  import { glob as glob5 } from "glob";
6702
- var __dirname3 = dirname8(fileURLToPath3(import.meta.url));
6922
+ var __dirname4 = dirname8(fileURLToPath3(import.meta.url));
6703
6923
  var iconFeature = defineFeature({
6704
6924
  name: "icon",
6705
6925
  onStack(ctx) {
@@ -6748,9 +6968,9 @@ var iconFeature = defineFeature({
6748
6968
  } : {}
6749
6969
  });
6750
6970
  const serverLambda = createPrebuildLambdaFunction(group, ctx, "icon", id, {
6751
- bundleFile: join14(__dirname3, "/prebuild/icon/bundle.zip"),
6752
- bundleHash: join14(__dirname3, "/prebuild/icon/HASH"),
6753
- memorySize: mebibytes5(512),
6971
+ bundleFile: join15(__dirname4, "/prebuild/icon/bundle.zip"),
6972
+ bundleHash: join15(__dirname4, "/prebuild/icon/HASH"),
6973
+ memorySize: mebibytes6(512),
6754
6974
  timeout: seconds8(10),
6755
6975
  handler: "index.default",
6756
6976
  runtime: "nodejs22.x",
@@ -6826,8 +7046,8 @@ var iconFeature = defineFeature({
6826
7046
  new aws25.s3.BucketObject(group, `static-${file}`, {
6827
7047
  bucket: s3Origin.bucket,
6828
7048
  key: file,
6829
- source: join14(props.origin.static, file),
6830
- sourceHash: $hash(join14(props.origin.static, file))
7049
+ source: join15(props.origin.static, file),
7050
+ sourceHash: $hash(join15(props.origin.static, file))
6831
7051
  });
6832
7052
  }
6833
7053
  }
@@ -6851,14 +7071,14 @@ import { aws as aws26 } from "@terraforge/aws";
6851
7071
  import { Group as Group25, Output as Output6, findInputDeps as findInputDeps3, resolveInputs as resolveInputs3 } from "@terraforge/core";
6852
7072
  import { constantCase as constantCase12, pascalCase as pascalCase3 } from "change-case";
6853
7073
  import deepmerge4 from "deepmerge";
6854
- import { join as join16 } from "path";
7074
+ import { join as join17 } from "path";
6855
7075
 
6856
7076
  // src/feature/instance/build/executable.ts
6857
7077
  import { createHash as createHash3 } from "crypto";
6858
7078
  import { readFile as readFile4 } from "fs/promises";
6859
- import { join as join15 } from "path";
7079
+ import { join as join16 } from "path";
6860
7080
  var buildExecutable = async (input, outputPath, architecture) => {
6861
- const filePath = join15(outputPath, "program");
7081
+ const filePath = join16(outputPath, "program");
6862
7082
  const target = architecture === "x86_64" ? "bun-linux-x64" : "bun-linux-arm64";
6863
7083
  let result;
6864
7084
  try {
@@ -7102,7 +7322,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
7102
7322
  healthCheck: props.healthCheck ? {
7103
7323
  command: [
7104
7324
  "CMD-SHELL",
7105
- `curl -f http://${join16("localhost", props.healthCheck.path)} || exit 1`
7325
+ `curl -f http://${join17("localhost", props.healthCheck.path)} || exit 1`
7106
7326
  ],
7107
7327
  interval: toSeconds9(props.healthCheck.interval),
7108
7328
  retries: props.healthCheck.retries,
@@ -7387,7 +7607,13 @@ import { camelCase as camelCase8, constantCase as constantCase14 } from "change-
7387
7607
  var getViewerRequestFunctionCode = (props) => {
7388
7608
  return CODE([
7389
7609
  props.blockDirectAccess ? BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT : "",
7390
- props.basicAuth ? BASIC_AUTH_CHECK(props.basicAuth.username, props.basicAuth.password) : ""
7610
+ props.passwordAuth ?? props.basicAuth ? AUTH_WRAPPER(
7611
+ [
7612
+ //
7613
+ props.basicAuth ? BASIC_AUTH_CHECK(props.basicAuth.username, props.basicAuth.password) : "",
7614
+ props.passwordAuth ? PASSWORD_AUTH_CHECK(props.passwordAuth.password) : ""
7615
+ ].join("\n")
7616
+ ) : ""
7391
7617
  ]);
7392
7618
  };
7393
7619
  var BLOCK_DIRECT_ACCESS_TO_CLOUDFRONT = `
@@ -7398,13 +7624,36 @@ if (headers.host && headers.host.value.includes('cloudfront.net')) {
7398
7624
  };
7399
7625
  }`;
7400
7626
  var BASIC_AUTH_CHECK = (username, password) => `
7401
- const auth = headers.authorization && headers.authorization.value;
7402
- if (!auth || !auth.startsWith('Basic ') || auth.slice(6) !== '${Buffer.from(`${username}:${password}`).toString("base64")}') {
7627
+ authMethods.push('Basic realm="Protected"');
7628
+
7629
+ if(!isAuthorized) {
7630
+ if(authHeader && authHeader.startsWith('Basic ') && authHeader.slice(6) === '${Buffer.from(`${username}:${password}`).toString("base64")}') {
7631
+ isAuthorized = true;
7632
+ }
7633
+ }
7634
+ `;
7635
+ var PASSWORD_AUTH_CHECK = (password) => `
7636
+ authMethods.push('Password realm="Protected"');
7637
+
7638
+ if(!isAuthorized) {
7639
+ if(authHeader && authHeader.startsWith('Password ') && authHeader.slice(9) === '${password}') {
7640
+ isAuthorized = true;
7641
+ }
7642
+ }
7643
+ `;
7644
+ var AUTH_WRAPPER = (code) => `
7645
+ const authHeader = headers.authorization && headers.authorization.value;
7646
+ const authMethods = [];
7647
+ let isAuthorized = false;
7648
+
7649
+ ${code}
7650
+
7651
+ if (!isAuthorized) {
7403
7652
  return {
7404
7653
  statusCode: 401,
7405
7654
  headers: {
7406
7655
  'www-authenticate': {
7407
- value: 'Basic realm="Protected"'
7656
+ value: authMethods.join(', ')
7408
7657
  }
7409
7658
  }
7410
7659
  };
@@ -7723,7 +7972,8 @@ var routerFeature = defineFeature({
7723
7972
  keyValueStoreAssociations: [routeStore.arn],
7724
7973
  code: getViewerRequestFunctionCode({
7725
7974
  blockDirectAccess: !!props.domain,
7726
- basicAuth: props.basicAuth
7975
+ basicAuth: props.basicAuth,
7976
+ passwordAuth: props.passwordAuth
7727
7977
  })
7728
7978
  });
7729
7979
  const wafSettingsConfig = props.waf;
@@ -9085,20 +9335,20 @@ import wildstring4 from "wildstring";
9085
9335
  // src/cli/ui/complex/run-tests.ts
9086
9336
  import { log as log18 } from "@awsless/clui";
9087
9337
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
9088
- import { join as join18 } from "path";
9338
+ import { join as join19 } from "path";
9089
9339
  import wildstring3 from "wildstring";
9090
9340
  import { parse as parse4, stringify } from "@awsless/json";
9091
9341
  import { generateFolderHash, loadWorkspace as loadWorkspace2 } from "@awsless/ts-file-cache";
9092
9342
 
9093
9343
  // src/test/start.ts
9094
- import { dirname as dirname9, join as join17 } from "path";
9344
+ import { dirname as dirname9, join as join18 } from "path";
9095
9345
  import { fileURLToPath as fileURLToPath4 } from "url";
9096
9346
  import { configDefaults } from "vitest/config";
9097
9347
  import { startVitest } from "vitest/node";
9098
9348
  var NullReporter = class {
9099
9349
  };
9100
9350
  var startTest = async (props) => {
9101
- const __dirname4 = dirname9(fileURLToPath4(import.meta.url));
9351
+ const __dirname5 = dirname9(fileURLToPath4(import.meta.url));
9102
9352
  const startTime = process.hrtime.bigint();
9103
9353
  process.noDeprecation = true;
9104
9354
  const vitest = await startVitest(
@@ -9129,7 +9379,7 @@ var startTest = async (props) => {
9129
9379
  // },
9130
9380
  setupFiles: [
9131
9381
  //
9132
- join17(__dirname4, "test-global-setup.js")
9382
+ join18(__dirname5, "test-global-setup.js")
9133
9383
  ]
9134
9384
  // globalSetup: [
9135
9385
  // //
@@ -9323,7 +9573,7 @@ var logTestErrors = (event) => {
9323
9573
  };
9324
9574
  var runTest = async (stack, dir, filters, workspace, opts) => {
9325
9575
  await mkdir4(directories.test, { recursive: true });
9326
- const file = join18(directories.test, `${stack}.json`);
9576
+ const file = join19(directories.test, `${stack}.json`);
9327
9577
  const fingerprint = await generateFolderHash(workspace, dir);
9328
9578
  if (!process.env.NO_CACHE) {
9329
9579
  const exists = await fileExist(file);
@@ -10008,7 +10258,7 @@ import { log as log25 } from "@awsless/clui";
10008
10258
 
10009
10259
  // src/type-gen/generate.ts
10010
10260
  import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
10011
- import { dirname as dirname10, join as join19, relative as relative8 } from "path";
10261
+ import { dirname as dirname10, join as join20, relative as relative8 } from "path";
10012
10262
  var generateTypes = async (props) => {
10013
10263
  const files = [];
10014
10264
  await Promise.all(
@@ -10017,7 +10267,7 @@ var generateTypes = async (props) => {
10017
10267
  ...props,
10018
10268
  async write(file, data, include = false) {
10019
10269
  const code = data?.toString("utf8");
10020
- const path = join19(directories.types, file);
10270
+ const path = join20(directories.types, file);
10021
10271
  if (code) {
10022
10272
  if (include) {
10023
10273
  files.push(relative8(directories.root, path));
@@ -10031,7 +10281,7 @@ var generateTypes = async (props) => {
10031
10281
  );
10032
10282
  if (files.length) {
10033
10283
  const code = files.map((file) => `/// <reference path='${file}' />`).join("\n");
10034
- await writeFile4(join19(directories.root, `awsless.d.ts`), code);
10284
+ await writeFile4(join20(directories.root, `awsless.d.ts`), code);
10035
10285
  }
10036
10286
  };
10037
10287