@awsless/cli 0.0.31 → 0.0.33
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/app.json +1 -1
- package/dist/app.stage.json +1 -1
- package/dist/bin.js +1440 -824
- package/dist/build-json-schema.js +336 -343
- package/dist/prebuild/icon/bundle.zip +0 -0
- package/dist/prebuild/image/bundle.zip +0 -0
- package/dist/prebuild/on-error-log/bundle.zip +0 -0
- package/dist/prebuild/on-failure/bundle.zip +0 -0
- package/dist/prebuild/pubsub-publisher/HASH +1 -0
- package/dist/prebuild/pubsub-publisher/bundle.zip +0 -0
- package/dist/prebuild/pubsub-server/HASH +1 -0
- package/dist/prebuild/pubsub-server/index.mjs +236 -0
- package/dist/prebuild/rpc/bundle.zip +0 -0
- package/dist/prebuild.js +24 -2
- package/dist/stack.json +1 -1
- package/dist/stack.stage.json +1 -1
- package/package.json +16 -15
package/dist/bin.js
CHANGED
|
@@ -1179,7 +1179,7 @@ var LogRetentionSchema = DurationSchema.refine(
|
|
|
1179
1179
|
(duration) => {
|
|
1180
1180
|
return validLogRetentionDays.includes(toDays(duration));
|
|
1181
1181
|
},
|
|
1182
|
-
`Invalid log retention. Valid days are: ${validLogRetentionDays.map((
|
|
1182
|
+
`Invalid log retention. Valid days are: ${validLogRetentionDays.map((days13) => `${days13}`).join(", ")}`
|
|
1183
1183
|
).describe("The log retention duration.");
|
|
1184
1184
|
var LogSchema = z15.union([
|
|
1185
1185
|
z15.boolean().transform((enabled) => ({ retention: enabled ? days(7) : days(0) })),
|
|
@@ -1359,140 +1359,159 @@ var OnFailureDefaultSchema = z19.union([
|
|
|
1359
1359
|
);
|
|
1360
1360
|
|
|
1361
1361
|
// src/feature/pubsub/schema.ts
|
|
1362
|
+
import { days as days4 } from "@awsless/duration";
|
|
1363
|
+
import { z as z22 } from "zod";
|
|
1364
|
+
|
|
1365
|
+
// src/feature/instance/schema.ts
|
|
1366
|
+
import { days as days2, toDays as toDays2 } from "@awsless/duration";
|
|
1367
|
+
import { toMebibytes } from "@awsless/size";
|
|
1362
1368
|
import { z as z20 } from "zod";
|
|
1363
|
-
var
|
|
1364
|
-
|
|
1365
|
-
ResourceIdSchema,
|
|
1366
|
-
z20.object({
|
|
1367
|
-
auth: FunctionSchema,
|
|
1368
|
-
domain: DomainSchema.optional(),
|
|
1369
|
-
subDomain: z20.string().optional()
|
|
1370
|
-
// auth: z.union([
|
|
1371
|
-
// ResourceIdSchema,
|
|
1372
|
-
// z.object({
|
|
1373
|
-
// authorizer: FunctionSchema,
|
|
1374
|
-
// // ttl: AuthorizerTtl.default('1 hour'),
|
|
1375
|
-
// }),
|
|
1376
|
-
// ]),
|
|
1377
|
-
// policy: z
|
|
1378
|
-
// .object({
|
|
1379
|
-
// publish: z.array(z.string()).optional(),
|
|
1380
|
-
// subscribe: z.array(z.string()).optional(),
|
|
1381
|
-
// })
|
|
1382
|
-
// .optional(),
|
|
1383
|
-
})
|
|
1384
|
-
).optional().describe("Define the pubsub subscriber in your stack.");
|
|
1385
|
-
var RetryAttemptsSchema2 = z20.number().int().min(0).max(2).describe(
|
|
1386
|
-
"The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 2."
|
|
1369
|
+
var CpuSchema = z20.union([z20.literal(0.25), z20.literal(0.5), z20.literal(1), z20.literal(2), z20.literal(4), z20.literal(8), z20.literal(16)]).transform((v) => `${v} vCPU`).describe(
|
|
1370
|
+
"The number of virtual CPU units (vCPU) used by the instance. Valid values: 0.25, 0.5, 1, 2, 4, 8, 16 vCPU."
|
|
1387
1371
|
);
|
|
1388
|
-
var
|
|
1389
|
-
|
|
1372
|
+
var validMemorySize = [
|
|
1373
|
+
// 0.25 vCPU
|
|
1374
|
+
512,
|
|
1375
|
+
1024,
|
|
1376
|
+
2048,
|
|
1377
|
+
// 0.5 vCPU
|
|
1378
|
+
1024,
|
|
1379
|
+
2048,
|
|
1380
|
+
3072,
|
|
1381
|
+
4096,
|
|
1382
|
+
// 1 vCPU
|
|
1383
|
+
2048,
|
|
1384
|
+
3072,
|
|
1385
|
+
4096,
|
|
1386
|
+
5120,
|
|
1387
|
+
6144,
|
|
1388
|
+
7168,
|
|
1389
|
+
8192,
|
|
1390
|
+
// 2 vCPU
|
|
1391
|
+
4096,
|
|
1392
|
+
5120,
|
|
1393
|
+
6144,
|
|
1394
|
+
7168,
|
|
1395
|
+
8192,
|
|
1396
|
+
9216,
|
|
1397
|
+
10240,
|
|
1398
|
+
11264,
|
|
1399
|
+
12288,
|
|
1400
|
+
13312,
|
|
1401
|
+
14336,
|
|
1402
|
+
15360,
|
|
1403
|
+
16384
|
|
1404
|
+
];
|
|
1405
|
+
var MemorySizeSchema2 = SizeSchema.refine(
|
|
1406
|
+
(s) => validMemorySize.includes(toMebibytes(s)),
|
|
1407
|
+
`Invalid memory size. Allowed sizes: ${validMemorySize.join(", ")} MiB`
|
|
1408
|
+
).describe("The amount of memory (in MiB) used by the instance. Valid memory values depend on the CPU configuration.");
|
|
1409
|
+
var HealthCheckSchema = z20.object({
|
|
1410
|
+
path: z20.string().describe("The path that the container runs to determine if it is healthy."),
|
|
1411
|
+
interval: DurationSchema.describe("The time period in seconds between each health check execution."),
|
|
1412
|
+
retries: z20.number().int().min(1).max(10).describe(
|
|
1413
|
+
"The number of times to retry a failed health check before the container is considered unhealthy."
|
|
1414
|
+
),
|
|
1415
|
+
startPeriod: DurationSchema.describe(
|
|
1416
|
+
"The optional grace period to provide containers time to bootstrap before failed health checks count towards the maximum number of retries."
|
|
1417
|
+
),
|
|
1418
|
+
timeout: DurationSchema.describe(
|
|
1419
|
+
"The time period in seconds to wait for a health check to succeed before it is considered a failure."
|
|
1420
|
+
)
|
|
1421
|
+
}).describe("The health check command and associated configuration parameters for the container.");
|
|
1422
|
+
var EnvironmentSchema2 = z20.record(z20.string(), z20.string()).optional().describe("Environment variable key-value pairs.");
|
|
1423
|
+
var ArchitectureSchema3 = z20.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the instance supports.");
|
|
1424
|
+
var ActionSchema2 = z20.string();
|
|
1425
|
+
var ActionsSchema2 = z20.union([ActionSchema2.transform((v) => [v]), ActionSchema2.array()]);
|
|
1426
|
+
var ArnSchema2 = z20.string().startsWith("arn:");
|
|
1427
|
+
var WildcardSchema2 = z20.literal("*");
|
|
1428
|
+
var ResourceSchema2 = z20.union([ArnSchema2, WildcardSchema2]);
|
|
1429
|
+
var ResourcesSchema2 = z20.union([ResourceSchema2.transform((v) => [v]), ResourceSchema2.array()]);
|
|
1430
|
+
var PermissionSchema2 = z20.object({
|
|
1431
|
+
effect: z20.enum(["allow", "deny"]).default("allow"),
|
|
1432
|
+
actions: ActionsSchema2,
|
|
1433
|
+
resources: ResourcesSchema2
|
|
1434
|
+
});
|
|
1435
|
+
var PermissionsSchema2 = z20.union([PermissionSchema2.transform((v) => [v]), PermissionSchema2.array()]).describe("Add IAM permissions to your instance.");
|
|
1436
|
+
var DescriptionSchema2 = z20.string().describe("A description of the instance.");
|
|
1437
|
+
var ImageSchema = z20.string().optional().describe("The URL of the container image to use. Default: public.ecr.aws/aws-cli/aws-cli:{architecture}");
|
|
1438
|
+
var validLogRetentionDays2 = [
|
|
1439
|
+
...[1, 3, 5, 7, 14, 30, 60, 90, 120, 150],
|
|
1440
|
+
...[180, 365, 400, 545, 731, 1096, 1827, 2192],
|
|
1441
|
+
...[2557, 2922, 3288, 3653]
|
|
1442
|
+
];
|
|
1443
|
+
var LogRetentionSchema2 = DurationSchema.refine(
|
|
1444
|
+
durationMin(days2(0)),
|
|
1445
|
+
"Minimum log retention is 0 day, which will disable logging."
|
|
1446
|
+
).refine(
|
|
1447
|
+
(duration) => {
|
|
1448
|
+
return validLogRetentionDays2.includes(toDays2(duration));
|
|
1449
|
+
},
|
|
1450
|
+
`Invalid log retention. Valid days are: ${validLogRetentionDays2.map((days13) => `${days13}`).join(", ")}`
|
|
1451
|
+
).describe("The log retention duration.");
|
|
1452
|
+
var LogSchema2 = z20.union([
|
|
1453
|
+
z20.boolean().transform((enabled) => ({ retention: enabled ? days2(7) : days2(0) })),
|
|
1454
|
+
LogRetentionSchema2.transform((retention) => ({ retention })),
|
|
1390
1455
|
z20.object({
|
|
1391
|
-
|
|
1392
|
-
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."),
|
|
1393
|
-
consumer: FunctionSchema.describe("The consuming lambda function properties."),
|
|
1394
|
-
retryAttempts: RetryAttemptsSchema2.default(2)
|
|
1456
|
+
retention: LogRetentionSchema2.optional()
|
|
1395
1457
|
})
|
|
1396
|
-
).
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
import { days as days2, hours, minutes as minutes2, seconds as seconds2 } from "@awsless/duration";
|
|
1400
|
-
import { kibibytes } from "@awsless/size";
|
|
1401
|
-
import { z as z21 } from "zod";
|
|
1402
|
-
var RetentionPeriodSchema = DurationSchema.refine(durationMin(minutes2(1)), "Minimum retention period is 1 minute").refine(durationMax(days2(14)), "Maximum retention period is 14 days").describe(
|
|
1403
|
-
"The number of seconds that Amazon SQS retains a message. You can specify a duration from 1 minute to 14 days."
|
|
1404
|
-
);
|
|
1405
|
-
var VisibilityTimeoutSchema = DurationSchema.refine(
|
|
1406
|
-
durationMax(hours(12)),
|
|
1407
|
-
"Maximum visibility timeout is 12 hours"
|
|
1408
|
-
).describe(
|
|
1409
|
-
"The length of time during which a message will be unavailable after a message is delivered from the queue. You can specify a duration from 0 to 12 hours."
|
|
1410
|
-
);
|
|
1411
|
-
var ReceiveMessageWaitTimeSchema = DurationSchema.refine(
|
|
1412
|
-
durationMin(seconds2(1)),
|
|
1413
|
-
"Minimum receive message wait time is 1 second"
|
|
1414
|
-
).refine(durationMax(seconds2(20)), "Maximum receive message wait time is 20 seconds").describe("Long-polling wait time. You can specify a duration from 1 to 20 seconds.");
|
|
1415
|
-
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("Message size limit. You can specify a size from 1 KB to 256 KB.");
|
|
1416
|
-
var BatchSizeSchema = z21.number().int().min(1, "Minimum batch size is 1").max(10, "FIFO queues support a maximum batch size of 10").describe("The maximum number of records per batch. FIFO queues are capped at 10.");
|
|
1417
|
-
var RetryAttemptsSchema3 = z21.number().int().min(0).max(999).describe(
|
|
1418
|
-
"The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 999."
|
|
1419
|
-
);
|
|
1420
|
-
var QueueDefaultSchema = z21.object({
|
|
1421
|
-
retentionPeriod: RetentionPeriodSchema.default("7 days"),
|
|
1422
|
-
visibilityTimeout: VisibilityTimeoutSchema.default("2 minutes"),
|
|
1423
|
-
receiveMessageWaitTime: ReceiveMessageWaitTimeSchema.optional(),
|
|
1424
|
-
maxMessageSize: MaxMessageSizeSchema.default("256 KB"),
|
|
1425
|
-
batchSize: BatchSizeSchema.default(10),
|
|
1426
|
-
retryAttempts: RetryAttemptsSchema3.default(2)
|
|
1427
|
-
}).default({});
|
|
1428
|
-
var QueueSchema = z21.object({
|
|
1429
|
-
consumer: FunctionSchema.optional().describe("The consuming lambda function properties."),
|
|
1430
|
-
retentionPeriod: RetentionPeriodSchema.optional(),
|
|
1431
|
-
visibilityTimeout: VisibilityTimeoutSchema.optional(),
|
|
1432
|
-
receiveMessageWaitTime: ReceiveMessageWaitTimeSchema.optional(),
|
|
1433
|
-
maxMessageSize: MaxMessageSizeSchema.optional(),
|
|
1434
|
-
batchSize: BatchSizeSchema.optional(),
|
|
1435
|
-
retryAttempts: RetryAttemptsSchema3.optional()
|
|
1458
|
+
]).describe("Enable logging to a CloudWatch log group. Providing a duration value will set the log retention time.");
|
|
1459
|
+
var FileCodeSchema2 = z20.object({
|
|
1460
|
+
file: LocalFileSchema.describe("The file path of the instance code.")
|
|
1436
1461
|
});
|
|
1437
|
-
var
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
)
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1462
|
+
var CodeSchema2 = z20.union([
|
|
1463
|
+
LocalFileSchema.transform((file) => ({
|
|
1464
|
+
file
|
|
1465
|
+
})).pipe(FileCodeSchema2),
|
|
1466
|
+
FileCodeSchema2
|
|
1467
|
+
]).describe("Specify the code of your instance.");
|
|
1468
|
+
var StartupCommandSchema = z20.union([z20.string().transform((v) => [v]), z20.string().array()]).describe("Optional shell commands to run before the instance program starts.");
|
|
1469
|
+
var ISchema = z20.object({
|
|
1470
|
+
code: CodeSchema2,
|
|
1471
|
+
description: DescriptionSchema2.optional(),
|
|
1472
|
+
image: ImageSchema.optional(),
|
|
1473
|
+
startupCommand: StartupCommandSchema.optional(),
|
|
1474
|
+
log: LogSchema2.optional(),
|
|
1475
|
+
cpu: CpuSchema.optional(),
|
|
1476
|
+
memorySize: MemorySizeSchema2.optional(),
|
|
1477
|
+
architecture: ArchitectureSchema3.optional(),
|
|
1478
|
+
environment: EnvironmentSchema2.optional(),
|
|
1479
|
+
permissions: PermissionsSchema2.optional(),
|
|
1480
|
+
healthCheck: HealthCheckSchema.optional()
|
|
1481
|
+
// restartPolicy: RestartPolicySchema.optional(),
|
|
1482
|
+
});
|
|
1483
|
+
var InstanceSchema = z20.union([
|
|
1484
|
+
LocalFileSchema.transform((code) => ({
|
|
1485
|
+
code
|
|
1486
|
+
})).pipe(ISchema),
|
|
1487
|
+
ISchema
|
|
1457
1488
|
]);
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
"The REST API route that is comprised by the http method and http path.",
|
|
1473
|
-
"The possible http methods are POST, GET,PUT, DELETE, HEAD, OPTIONS, ANY.",
|
|
1474
|
-
"Example: GET /posts/{id}"
|
|
1475
|
-
].join("\n")
|
|
1476
|
-
),
|
|
1477
|
-
FunctionSchema
|
|
1478
|
-
)
|
|
1479
|
-
).optional().describe("Define routes in your stack for your global REST API.");
|
|
1480
|
-
|
|
1481
|
-
// src/feature/rpc/schema.ts
|
|
1482
|
-
import { minutes as minutes4, seconds as seconds3 } from "@awsless/duration";
|
|
1483
|
-
import { z as z25 } from "zod";
|
|
1489
|
+
var InstancesSchema = z20.record(ResourceIdSchema, InstanceSchema).optional().describe("Define the instances in your stack.");
|
|
1490
|
+
var InstanceDefaultSchema = z20.object({
|
|
1491
|
+
image: ImageSchema.optional(),
|
|
1492
|
+
cpu: CpuSchema.default(0.25),
|
|
1493
|
+
memorySize: MemorySizeSchema2.default("512 MB"),
|
|
1494
|
+
architecture: ArchitectureSchema3.default("arm64"),
|
|
1495
|
+
environment: EnvironmentSchema2.optional(),
|
|
1496
|
+
permissions: PermissionsSchema2.optional(),
|
|
1497
|
+
healthCheck: HealthCheckSchema.optional(),
|
|
1498
|
+
// restartPolicy: RestartPolicySchema.default({ enabled: true }),
|
|
1499
|
+
log: LogSchema2.default(true).transform((log35) => ({
|
|
1500
|
+
retention: log35.retention ?? days2(7)
|
|
1501
|
+
}))
|
|
1502
|
+
}).default({});
|
|
1484
1503
|
|
|
1485
1504
|
// src/feature/router/schema.ts
|
|
1486
|
-
import { days as days3, minutes as
|
|
1487
|
-
import { z as
|
|
1488
|
-
var ErrorResponsePathSchema =
|
|
1505
|
+
import { days as days3, minutes as minutes2, parse as parse3 } from "@awsless/duration";
|
|
1506
|
+
import { z as z21 } from "zod";
|
|
1507
|
+
var ErrorResponsePathSchema = z21.string().describe(
|
|
1489
1508
|
[
|
|
1490
1509
|
"The path to the custom error page that you want to return to the viewer when your origin returns the HTTP status code specified.",
|
|
1491
1510
|
"- We recommend that you store custom error pages in an Amazon S3 bucket.",
|
|
1492
1511
|
"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."
|
|
1493
1512
|
].join("\n")
|
|
1494
1513
|
);
|
|
1495
|
-
var StatusCodeSchema =
|
|
1514
|
+
var StatusCodeSchema = z21.number().int().positive().optional().describe(
|
|
1496
1515
|
[
|
|
1497
1516
|
"The HTTP status code that you want CloudFront to return to the viewer along with the custom error page.",
|
|
1498
1517
|
"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:",
|
|
@@ -1505,26 +1524,26 @@ var StatusCodeSchema = z24.number().int().positive().optional().describe(
|
|
|
1505
1524
|
var MinTTLSchema = DurationSchema.describe(
|
|
1506
1525
|
"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."
|
|
1507
1526
|
);
|
|
1508
|
-
var ErrorResponseSchema =
|
|
1527
|
+
var ErrorResponseSchema = z21.union([
|
|
1509
1528
|
ErrorResponsePathSchema,
|
|
1510
|
-
|
|
1529
|
+
z21.object({
|
|
1511
1530
|
path: ErrorResponsePathSchema,
|
|
1512
1531
|
statusCode: StatusCodeSchema.optional(),
|
|
1513
1532
|
minTTL: MinTTLSchema.optional()
|
|
1514
1533
|
})
|
|
1515
1534
|
]).optional();
|
|
1516
|
-
var
|
|
1517
|
-
var VisibilitySchema =
|
|
1518
|
-
var WafSettingsSchema =
|
|
1519
|
-
rateLimiter:
|
|
1520
|
-
limit:
|
|
1535
|
+
var RouteSchema = z21.string().regex(/^\//, "Route must start with a slash (/)");
|
|
1536
|
+
var VisibilitySchema = z21.boolean().default(false).describe("Whether to enable CloudWatch metrics for the WAF rule.");
|
|
1537
|
+
var WafSettingsSchema = z21.object({
|
|
1538
|
+
rateLimiter: z21.object({
|
|
1539
|
+
limit: z21.number().min(10).max(2e9).default(10).describe(
|
|
1521
1540
|
"The limit on requests during the specified evaluation window for a single aggregation instance for the rate-based rule."
|
|
1522
1541
|
),
|
|
1523
|
-
window:
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1542
|
+
window: z21.union([
|
|
1543
|
+
z21.literal("1 minute"),
|
|
1544
|
+
z21.literal("2 minutes"),
|
|
1545
|
+
z21.literal("5 minutes"),
|
|
1546
|
+
z21.literal("10 minutes")
|
|
1528
1547
|
]).default("5 minutes").transform((v) => parse3(v)).describe(
|
|
1529
1548
|
"The amount of time, in seconds, that AWS WAF should include in its request counts, looking back from the current time."
|
|
1530
1549
|
),
|
|
@@ -1532,39 +1551,39 @@ var WafSettingsSchema = z24.object({
|
|
|
1532
1551
|
}).optional().describe(
|
|
1533
1552
|
"A rate-based rule counts incoming requests and rate limits requests when they are coming at too fast a rate."
|
|
1534
1553
|
),
|
|
1535
|
-
ddosProtection:
|
|
1536
|
-
sensitivity:
|
|
1537
|
-
challenge:
|
|
1538
|
-
block:
|
|
1554
|
+
ddosProtection: z21.object({
|
|
1555
|
+
sensitivity: z21.object({
|
|
1556
|
+
challenge: z21.enum(["low", "medium", "high"]).default("low").transform((v) => v.toUpperCase()).describe("The sensitivity level for challenge requests."),
|
|
1557
|
+
block: z21.enum(["low", "medium", "high"]).default("low").transform((v) => v.toUpperCase()).describe("The sensitivity level for block requests.")
|
|
1539
1558
|
}),
|
|
1540
|
-
exemptUriRegex:
|
|
1559
|
+
exemptUriRegex: z21.string().default("^$"),
|
|
1541
1560
|
visibility: VisibilitySchema
|
|
1542
1561
|
}).optional().describe(
|
|
1543
1562
|
"Provides protection against DDoS attacks targeting the application layer, also known as Layer 7 attacks. Uses 50 WCU."
|
|
1544
1563
|
),
|
|
1545
|
-
botProtection:
|
|
1546
|
-
inspectionLevel:
|
|
1564
|
+
botProtection: z21.object({
|
|
1565
|
+
inspectionLevel: z21.enum(["common", "targeted"]).default("common").transform((v) => v.toUpperCase()),
|
|
1547
1566
|
visibility: VisibilitySchema
|
|
1548
1567
|
}).optional().describe(
|
|
1549
1568
|
"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."
|
|
1550
1569
|
),
|
|
1551
|
-
captchaImmunityTime: DurationSchema.refine(durationMin(
|
|
1570
|
+
captchaImmunityTime: DurationSchema.refine(durationMin(minutes2(1)), "Minimum timeout duration is 1 minute").refine(durationMax(days3(3)), "Maximum timeout duration is 3 days").default("5 minutes").describe(
|
|
1552
1571
|
"The amount of time that a CAPTCHA timestamp is considered valid by AWS WAF. The default setting is 5 minutes."
|
|
1553
1572
|
),
|
|
1554
|
-
challengeImmunityTime: DurationSchema.refine(durationMin(
|
|
1573
|
+
challengeImmunityTime: DurationSchema.refine(durationMin(minutes2(1)), "Minimum timeout duration is 1 minute").refine(durationMax(days3(3)), "Maximum timeout duration is 3 days").default("5 minutes").describe(
|
|
1555
1574
|
"The amount of time that a challenge timestamp is considered valid by AWS WAF. The default setting is 5 minutes."
|
|
1556
1575
|
)
|
|
1557
1576
|
}).describe(
|
|
1558
1577
|
"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."
|
|
1559
1578
|
);
|
|
1560
|
-
var RouterDefaultSchema =
|
|
1579
|
+
var RouterDefaultSchema = z21.record(
|
|
1561
1580
|
ResourceIdSchema,
|
|
1562
|
-
|
|
1581
|
+
z21.object({
|
|
1563
1582
|
domain: ResourceIdSchema.describe("The domain id to link your Router.").optional(),
|
|
1564
|
-
subDomain:
|
|
1583
|
+
subDomain: z21.string().optional(),
|
|
1565
1584
|
waf: WafSettingsSchema.optional(),
|
|
1566
|
-
geoRestrictions:
|
|
1567
|
-
errors:
|
|
1585
|
+
geoRestrictions: z21.array(z21.string().length(2).toUpperCase()).default([]).describe("Specifies a blacklist of countries that should be blocked."),
|
|
1586
|
+
errors: z21.object({
|
|
1568
1587
|
400: ErrorResponseSchema.describe("Customize a `400 Bad Request` response."),
|
|
1569
1588
|
403: ErrorResponseSchema.describe("Customize a `403 Forbidden` response."),
|
|
1570
1589
|
404: ErrorResponseSchema.describe("Customize a `404 Not Found` response."),
|
|
@@ -1577,26 +1596,26 @@ var RouterDefaultSchema = z24.record(
|
|
|
1577
1596
|
503: ErrorResponseSchema.describe("Customize a `503 Service Unavailable` response."),
|
|
1578
1597
|
504: ErrorResponseSchema.describe("Customize a `504 Gateway Timeout` response.")
|
|
1579
1598
|
}).optional().describe("Customize the error responses for specific HTTP status codes."),
|
|
1580
|
-
cors:
|
|
1581
|
-
override:
|
|
1599
|
+
cors: z21.object({
|
|
1600
|
+
override: z21.boolean().default(false),
|
|
1582
1601
|
maxAge: DurationSchema.default("365 days"),
|
|
1583
|
-
exposeHeaders:
|
|
1584
|
-
credentials:
|
|
1585
|
-
headers:
|
|
1586
|
-
origins:
|
|
1587
|
-
methods:
|
|
1602
|
+
exposeHeaders: z21.string().array().optional(),
|
|
1603
|
+
credentials: z21.boolean().default(false),
|
|
1604
|
+
headers: z21.string().array().default(["*"]),
|
|
1605
|
+
origins: z21.string().array().default(["*"]),
|
|
1606
|
+
methods: z21.enum(["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "ALL"]).array().default(["ALL"])
|
|
1588
1607
|
}).optional().describe("Specify the cors headers."),
|
|
1589
|
-
passwordAuth:
|
|
1590
|
-
password:
|
|
1608
|
+
passwordAuth: z21.object({
|
|
1609
|
+
password: z21.string().describe("Password.")
|
|
1591
1610
|
}).optional().describe(
|
|
1592
1611
|
[
|
|
1593
1612
|
"Enable password authentication for the router.",
|
|
1594
1613
|
'You can authenicate by adding a "authorization" header with the value "Password [YOUR_PASSWORD]".'
|
|
1595
1614
|
].join("\n")
|
|
1596
1615
|
),
|
|
1597
|
-
basicAuth:
|
|
1598
|
-
username:
|
|
1599
|
-
password:
|
|
1616
|
+
basicAuth: z21.object({
|
|
1617
|
+
username: z21.string().describe("Basic auth username."),
|
|
1618
|
+
password: z21.string().describe("Basic auth password.")
|
|
1600
1619
|
}).optional().describe("Enable basic authentication for the router."),
|
|
1601
1620
|
// security: z
|
|
1602
1621
|
// .object({
|
|
@@ -1643,49 +1662,163 @@ var RouterDefaultSchema = z24.record(
|
|
|
1643
1662
|
// })
|
|
1644
1663
|
// .optional()
|
|
1645
1664
|
// .describe('Specify the security policy.'),
|
|
1646
|
-
cache:
|
|
1647
|
-
cookies:
|
|
1648
|
-
headers:
|
|
1649
|
-
queries:
|
|
1665
|
+
cache: z21.object({
|
|
1666
|
+
cookies: z21.string().array().optional().describe("Specifies the cookies that CloudFront includes in the cache key."),
|
|
1667
|
+
headers: z21.string().array().optional().describe("Specifies the headers that CloudFront includes in the cache key."),
|
|
1668
|
+
queries: z21.string().array().optional().describe("Specifies the query values that CloudFront includes in the cache key.")
|
|
1650
1669
|
}).optional().describe(
|
|
1651
1670
|
"Specifies the cookies, headers, and query values that CloudFront includes in the cache key."
|
|
1652
1671
|
)
|
|
1653
1672
|
})
|
|
1654
1673
|
).optional().describe(`Define the global Router. Backed by AWS CloudFront.`);
|
|
1655
1674
|
|
|
1656
|
-
// src/feature/
|
|
1657
|
-
var
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1675
|
+
// src/feature/pubsub/schema.ts
|
|
1676
|
+
var PubSubDefaultSchema = z22.record(
|
|
1677
|
+
ResourceIdSchema,
|
|
1678
|
+
z22.object({
|
|
1679
|
+
auth: FunctionSchema.describe(
|
|
1680
|
+
"The authorizer that validates the client auth token and returns the allowed topics."
|
|
1681
|
+
),
|
|
1682
|
+
router: ResourceIdSchema.describe("The router id to route pubsub traffic through."),
|
|
1683
|
+
path: RouteSchema.default("/ws").describe("The base path on the router that exposes the pubsub endpoint."),
|
|
1684
|
+
log: LogSchema2.default(true).transform((log35) => ({
|
|
1685
|
+
retention: log35.retention ?? days4(7)
|
|
1686
|
+
}))
|
|
1687
|
+
})
|
|
1688
|
+
).optional().describe("Define the pubsub API for your app. Backed by a websocket server on AWS Fargate.");
|
|
1689
|
+
var PubSubSchema = z22.record(
|
|
1690
|
+
ResourceIdSchema,
|
|
1691
|
+
z22.object({
|
|
1692
|
+
connected: FunctionSchema.optional().describe("Subscribe to the event when a client connects."),
|
|
1693
|
+
disconnected: FunctionSchema.optional().describe("Subscribe to the event when a client disconnects."),
|
|
1694
|
+
subscribed: FunctionSchema.optional().describe(
|
|
1695
|
+
"Subscribe to the event when a client subscribes to topics."
|
|
1696
|
+
),
|
|
1697
|
+
unsubscribed: FunctionSchema.optional().describe(
|
|
1698
|
+
"Subscribe to the event when a client unsubscribes from topics."
|
|
1699
|
+
)
|
|
1700
|
+
})
|
|
1701
|
+
).optional().describe("Define the pubsub event listeners in your stack.");
|
|
1702
|
+
var pubsubEventTypes = ["connected", "disconnected", "subscribed", "unsubscribed"];
|
|
1703
|
+
|
|
1704
|
+
// src/feature/queue/schema.ts
|
|
1705
|
+
import { days as days5, hours, minutes as minutes3, seconds as seconds2 } from "@awsless/duration";
|
|
1706
|
+
import { kibibytes } from "@awsless/size";
|
|
1707
|
+
import { z as z23 } from "zod";
|
|
1708
|
+
var RetentionPeriodSchema = DurationSchema.refine(durationMin(minutes3(1)), "Minimum retention period is 1 minute").refine(durationMax(days5(14)), "Maximum retention period is 14 days").describe(
|
|
1709
|
+
"The number of seconds that Amazon SQS retains a message. You can specify a duration from 1 minute to 14 days."
|
|
1710
|
+
);
|
|
1711
|
+
var VisibilityTimeoutSchema = DurationSchema.refine(
|
|
1712
|
+
durationMax(hours(12)),
|
|
1713
|
+
"Maximum visibility timeout is 12 hours"
|
|
1714
|
+
).describe(
|
|
1715
|
+
"The length of time during which a message will be unavailable after a message is delivered from the queue. You can specify a duration from 0 to 12 hours."
|
|
1716
|
+
);
|
|
1717
|
+
var ReceiveMessageWaitTimeSchema = DurationSchema.refine(
|
|
1718
|
+
durationMin(seconds2(1)),
|
|
1719
|
+
"Minimum receive message wait time is 1 second"
|
|
1720
|
+
).refine(durationMax(seconds2(20)), "Maximum receive message wait time is 20 seconds").describe("Long-polling wait time. You can specify a duration from 1 to 20 seconds.");
|
|
1721
|
+
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("Message size limit. You can specify a size from 1 KB to 256 KB.");
|
|
1722
|
+
var BatchSizeSchema = z23.number().int().min(1, "Minimum batch size is 1").max(10, "FIFO queues support a maximum batch size of 10").describe("The maximum number of records per batch. FIFO queues are capped at 10.");
|
|
1723
|
+
var RetryAttemptsSchema2 = z23.number().int().min(0).max(999).describe(
|
|
1724
|
+
"The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 999."
|
|
1725
|
+
);
|
|
1726
|
+
var QueueDefaultSchema = z23.object({
|
|
1727
|
+
retentionPeriod: RetentionPeriodSchema.default("7 days"),
|
|
1728
|
+
visibilityTimeout: VisibilityTimeoutSchema.default("2 minutes"),
|
|
1729
|
+
receiveMessageWaitTime: ReceiveMessageWaitTimeSchema.optional(),
|
|
1730
|
+
maxMessageSize: MaxMessageSizeSchema.default("256 KB"),
|
|
1731
|
+
batchSize: BatchSizeSchema.default(10),
|
|
1732
|
+
retryAttempts: RetryAttemptsSchema2.default(2)
|
|
1733
|
+
}).default({});
|
|
1734
|
+
var QueueSchema = z23.object({
|
|
1735
|
+
consumer: FunctionSchema.optional().describe("The consuming lambda function properties."),
|
|
1736
|
+
retentionPeriod: RetentionPeriodSchema.optional(),
|
|
1737
|
+
visibilityTimeout: VisibilityTimeoutSchema.optional(),
|
|
1738
|
+
receiveMessageWaitTime: ReceiveMessageWaitTimeSchema.optional(),
|
|
1739
|
+
maxMessageSize: MaxMessageSizeSchema.optional(),
|
|
1740
|
+
batchSize: BatchSizeSchema.optional(),
|
|
1741
|
+
retryAttempts: RetryAttemptsSchema2.optional()
|
|
1742
|
+
});
|
|
1743
|
+
var QueuesSchema = z23.record(
|
|
1744
|
+
ResourceIdSchema,
|
|
1745
|
+
z23.union([
|
|
1746
|
+
LocalFileSchema.transform((consumer) => ({
|
|
1747
|
+
consumer
|
|
1748
|
+
})).pipe(QueueSchema),
|
|
1749
|
+
QueueSchema
|
|
1750
|
+
])
|
|
1751
|
+
).optional().describe(
|
|
1752
|
+
"Define the queues in your stack. Queues are FIFO with required per-message groupId: messages with the same groupId are processed strictly in order; different groupIds parallelize."
|
|
1663
1753
|
);
|
|
1664
|
-
|
|
1754
|
+
|
|
1755
|
+
// src/feature/rest/schema.ts
|
|
1756
|
+
import { z as z25 } from "zod";
|
|
1757
|
+
|
|
1758
|
+
// src/config/schema/route.ts
|
|
1759
|
+
import { z as z24 } from "zod";
|
|
1760
|
+
var RouteSchema2 = z24.union([
|
|
1761
|
+
z24.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS|ANY)(\s\/[a-z0-9\+\_\-\/\{\}]*)$/gi, "Invalid route"),
|
|
1762
|
+
z24.literal("$default")
|
|
1763
|
+
]);
|
|
1764
|
+
|
|
1765
|
+
// src/feature/rest/schema.ts
|
|
1766
|
+
var RestDefaultSchema = z25.record(
|
|
1665
1767
|
ResourceIdSchema,
|
|
1666
1768
|
z25.object({
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
//
|
|
1670
|
-
router: ResourceIdSchema.describe("The router id to link your RPC API with."),
|
|
1671
|
-
path: RouteSchema2.describe("The path inside the router to link your RPC API to."),
|
|
1672
|
-
auth: FunctionSchema.optional().describe("The authentication handler for your RPC API."),
|
|
1673
|
-
log: LogSchema.optional(),
|
|
1674
|
-
timeout: TimeoutSchema2.default("1 minutes")
|
|
1769
|
+
domain: ResourceIdSchema.describe("The domain id to link your API with.").optional(),
|
|
1770
|
+
subDomain: z25.string().optional()
|
|
1675
1771
|
})
|
|
1676
|
-
).describe(
|
|
1677
|
-
var
|
|
1772
|
+
).optional().describe("Define your global REST API's.");
|
|
1773
|
+
var RestSchema = z25.record(
|
|
1678
1774
|
ResourceIdSchema,
|
|
1679
1775
|
z25.record(
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1776
|
+
RouteSchema2.describe(
|
|
1777
|
+
[
|
|
1778
|
+
"The REST API route that is comprised by the http method and http path.",
|
|
1779
|
+
"The possible http methods are POST, GET,PUT, DELETE, HEAD, OPTIONS, ANY.",
|
|
1780
|
+
"Example: GET /posts/{id}"
|
|
1781
|
+
].join("\n")
|
|
1782
|
+
),
|
|
1783
|
+
FunctionSchema
|
|
1784
|
+
)
|
|
1785
|
+
).optional().describe("Define routes in your stack for your global REST API.");
|
|
1786
|
+
|
|
1787
|
+
// src/feature/rpc/schema.ts
|
|
1788
|
+
import { minutes as minutes4, seconds as seconds3 } from "@awsless/duration";
|
|
1789
|
+
import { z as z26 } from "zod";
|
|
1790
|
+
var TimeoutSchema2 = DurationSchema.refine(durationMin(seconds3(10)), "Minimum timeout duration is 10 seconds").refine(durationMax(minutes4(5)), "Maximum timeout duration is 5 minutes").describe(
|
|
1791
|
+
[
|
|
1792
|
+
"The amount of time that the RPC lambda is allowed run before stopping it.",
|
|
1793
|
+
"You can specify a timeout from 10 second to 5 minutes.",
|
|
1794
|
+
"The timeouts of all inner RPC functions will be capped at 80% of this timeout."
|
|
1795
|
+
].join(" ")
|
|
1796
|
+
);
|
|
1797
|
+
var RpcDefaultSchema = z26.record(
|
|
1798
|
+
ResourceIdSchema,
|
|
1799
|
+
z26.object({
|
|
1800
|
+
// domain: ResourceIdSchema.describe('The domain id to link your RPC API with.').optional(),
|
|
1801
|
+
// subDomain: z.string().optional(),
|
|
1802
|
+
//
|
|
1803
|
+
router: ResourceIdSchema.describe("The router id to link your RPC API with."),
|
|
1804
|
+
path: RouteSchema.describe("The path inside the router to link your RPC API to."),
|
|
1805
|
+
auth: FunctionSchema.optional().describe("The authentication handler for your RPC API."),
|
|
1806
|
+
log: LogSchema.optional(),
|
|
1807
|
+
timeout: TimeoutSchema2.default("1 minutes")
|
|
1808
|
+
})
|
|
1809
|
+
).describe(`Define the global RPC API's.`).optional();
|
|
1810
|
+
var RpcSchema = z26.record(
|
|
1811
|
+
ResourceIdSchema,
|
|
1812
|
+
z26.record(
|
|
1813
|
+
z26.string(),
|
|
1814
|
+
z26.union([
|
|
1815
|
+
FunctionSchema.transform((f) => ({
|
|
1816
|
+
function: f,
|
|
1684
1817
|
lock: false
|
|
1685
1818
|
})),
|
|
1686
|
-
|
|
1819
|
+
z26.object({
|
|
1687
1820
|
function: FunctionSchema.describe("The RPC function to execute."),
|
|
1688
|
-
lock:
|
|
1821
|
+
lock: z26.boolean().describe(
|
|
1689
1822
|
[
|
|
1690
1823
|
"Specify if the function should be locked on the `lockKey` returned from the auth function.",
|
|
1691
1824
|
"An example would be returning the user ID as `lockKey`."
|
|
@@ -1697,136 +1830,10 @@ var RpcSchema = z25.record(
|
|
|
1697
1830
|
).describe("Define the schema in your stack for your global RPC API.").optional();
|
|
1698
1831
|
|
|
1699
1832
|
// src/feature/job/schema.ts
|
|
1700
|
-
import { days as
|
|
1701
|
-
import { toMebibytes } from "@awsless/size";
|
|
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("The number of virtual CPU units (vCPU) used by the job. Valid values: 0.25, 0.5, 1, 2, 4, 8, 16 vCPU.");
|
|
1704
|
-
var validMemorySize = [
|
|
1705
|
-
// 0.25 vCPU
|
|
1706
|
-
512,
|
|
1707
|
-
1024,
|
|
1708
|
-
2048,
|
|
1709
|
-
// 0.5 vCPU
|
|
1710
|
-
1024,
|
|
1711
|
-
2048,
|
|
1712
|
-
3072,
|
|
1713
|
-
4096,
|
|
1714
|
-
// 1 vCPU
|
|
1715
|
-
2048,
|
|
1716
|
-
3072,
|
|
1717
|
-
4096,
|
|
1718
|
-
5120,
|
|
1719
|
-
6144,
|
|
1720
|
-
7168,
|
|
1721
|
-
8192,
|
|
1722
|
-
// 2 vCPU
|
|
1723
|
-
4096,
|
|
1724
|
-
5120,
|
|
1725
|
-
6144,
|
|
1726
|
-
7168,
|
|
1727
|
-
8192,
|
|
1728
|
-
9216,
|
|
1729
|
-
10240,
|
|
1730
|
-
11264,
|
|
1731
|
-
12288,
|
|
1732
|
-
13312,
|
|
1733
|
-
14336,
|
|
1734
|
-
15360,
|
|
1735
|
-
16384
|
|
1736
|
-
];
|
|
1737
|
-
var MemorySizeSchema2 = SizeSchema.refine(
|
|
1738
|
-
(s) => validMemorySize.includes(toMebibytes(s)),
|
|
1739
|
-
`Invalid memory size. Allowed sizes: ${validMemorySize.join(", ")} MiB`
|
|
1740
|
-
).describe("The amount of memory (in MiB) used by the job. Valid memory values depend on the CPU configuration.");
|
|
1741
|
-
var EnvironmentSchema2 = z26.record(z26.string(), z26.string()).optional().describe("Environment variable key-value pairs.");
|
|
1742
|
-
var ArchitectureSchema3 = z26.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the job supports.");
|
|
1743
|
-
var ActionSchema2 = z26.string();
|
|
1744
|
-
var ActionsSchema2 = z26.union([ActionSchema2.transform((v) => [v]), ActionSchema2.array()]);
|
|
1745
|
-
var ArnSchema2 = z26.string().startsWith("arn:");
|
|
1746
|
-
var WildcardSchema2 = z26.literal("*");
|
|
1747
|
-
var ResourceSchema2 = z26.union([ArnSchema2, WildcardSchema2]);
|
|
1748
|
-
var ResourcesSchema2 = z26.union([ResourceSchema2.transform((v) => [v]), ResourceSchema2.array()]);
|
|
1749
|
-
var PermissionSchema2 = z26.object({
|
|
1750
|
-
effect: z26.enum(["allow", "deny"]).default("allow"),
|
|
1751
|
-
actions: ActionsSchema2,
|
|
1752
|
-
resources: ResourcesSchema2
|
|
1753
|
-
});
|
|
1754
|
-
var PermissionsSchema2 = z26.union([PermissionSchema2.transform((v) => [v]), PermissionSchema2.array()]).describe("Add IAM permissions to your job.");
|
|
1755
|
-
var validLogRetentionDays2 = [
|
|
1756
|
-
...[1, 3, 5, 7, 14, 30, 60, 90, 120, 150],
|
|
1757
|
-
...[180, 365, 400, 545, 731, 1096, 1827, 2192],
|
|
1758
|
-
...[2557, 2922, 3288, 3653]
|
|
1759
|
-
];
|
|
1760
|
-
var LogRetentionSchema2 = DurationSchema.refine(
|
|
1761
|
-
durationMin(days4(0)),
|
|
1762
|
-
"Minimum log retention is 0 day, which will disable logging."
|
|
1763
|
-
).refine(
|
|
1764
|
-
(duration) => {
|
|
1765
|
-
return validLogRetentionDays2.includes(toDays2(duration));
|
|
1766
|
-
},
|
|
1767
|
-
`Invalid log retention. Valid days are: ${validLogRetentionDays2.map((days12) => `${days12}`).join(", ")}`
|
|
1768
|
-
).describe("The log retention duration.");
|
|
1769
|
-
var LogSchema2 = z26.union([
|
|
1770
|
-
z26.boolean().transform((enabled) => ({ retention: enabled ? days4(7) : days4(0) })),
|
|
1771
|
-
LogRetentionSchema2.transform((retention) => ({ retention })),
|
|
1772
|
-
z26.object({
|
|
1773
|
-
retention: LogRetentionSchema2.optional()
|
|
1774
|
-
})
|
|
1775
|
-
]).describe("Enable logging to a CloudWatch log group. Providing a duration value will set the log retention time.");
|
|
1776
|
-
var FileCodeSchema2 = z26.object({
|
|
1777
|
-
file: LocalFileSchema.describe("The file path of the job code.")
|
|
1778
|
-
});
|
|
1779
|
-
var CodeSchema2 = z26.union([
|
|
1780
|
-
LocalFileSchema.transform((file) => ({
|
|
1781
|
-
file
|
|
1782
|
-
})).pipe(FileCodeSchema2),
|
|
1783
|
-
FileCodeSchema2
|
|
1784
|
-
]).describe("Specify the code of your job.");
|
|
1785
|
-
var TimeoutSchema3 = DurationSchema.describe("The maximum time the job is allowed to run before being stopped.");
|
|
1786
|
-
var ImageSchema = z26.string().describe("The URL of the container image to use. Default: public.ecr.aws/aws-cli/aws-cli:{architecture}");
|
|
1787
|
-
var PersistentStorageSchema = z26.boolean().describe("Mount persistent storage for the job at a fixed internal path.");
|
|
1788
|
-
var StartupCommandSchema = z26.union([z26.string().transform((v) => [v]), z26.string().array()]).describe("Optional shell commands to run before the job executable is downloaded and started.");
|
|
1789
|
-
var ASchema = z26.object({
|
|
1790
|
-
code: CodeSchema2,
|
|
1791
|
-
image: ImageSchema.optional(),
|
|
1792
|
-
persistentStorage: PersistentStorageSchema.optional(),
|
|
1793
|
-
startupCommand: StartupCommandSchema.optional(),
|
|
1794
|
-
log: LogSchema2.optional(),
|
|
1795
|
-
cpu: CpuSchema.optional(),
|
|
1796
|
-
memorySize: MemorySizeSchema2.optional(),
|
|
1797
|
-
architecture: ArchitectureSchema3.optional(),
|
|
1798
|
-
environment: EnvironmentSchema2.optional(),
|
|
1799
|
-
permissions: PermissionsSchema2.optional(),
|
|
1800
|
-
timeout: TimeoutSchema3.default("30 minutes").describe("The maximum time the job is allowed to run before being stopped. Default: 30 minutes.")
|
|
1801
|
-
});
|
|
1802
|
-
var JobSchema = z26.union([
|
|
1803
|
-
LocalFileSchema.transform((code) => ({
|
|
1804
|
-
code
|
|
1805
|
-
})).pipe(ASchema),
|
|
1806
|
-
ASchema
|
|
1807
|
-
]);
|
|
1808
|
-
var JobsSchema = z26.record(ResourceIdSchema, JobSchema).optional().describe("Define the jobs in your stack.");
|
|
1809
|
-
var JobDefaultSchema = z26.object({
|
|
1810
|
-
image: ImageSchema.optional(),
|
|
1811
|
-
persistentStorage: PersistentStorageSchema.optional(),
|
|
1812
|
-
cpu: CpuSchema.default(0.25),
|
|
1813
|
-
memorySize: MemorySizeSchema2.default("512 MB"),
|
|
1814
|
-
architecture: ArchitectureSchema3.default("arm64"),
|
|
1815
|
-
environment: EnvironmentSchema2.optional(),
|
|
1816
|
-
permissions: PermissionsSchema2.optional(),
|
|
1817
|
-
timeout: TimeoutSchema3.optional(),
|
|
1818
|
-
log: LogSchema2.default(true).transform((log35) => ({
|
|
1819
|
-
retention: log35.retention ?? days4(7)
|
|
1820
|
-
}))
|
|
1821
|
-
}).default({});
|
|
1822
|
-
|
|
1823
|
-
// src/feature/instance/schema.ts
|
|
1824
|
-
import { days as days5, toDays as toDays3 } from "@awsless/duration";
|
|
1833
|
+
import { days as days6, toDays as toDays3 } from "@awsless/duration";
|
|
1825
1834
|
import { toMebibytes as toMebibytes2 } from "@awsless/size";
|
|
1826
1835
|
import { z as z27 } from "zod";
|
|
1827
|
-
var CpuSchema2 = z27.union([z27.literal(0.25), z27.literal(0.5), z27.literal(1), z27.literal(2), z27.literal(4), z27.literal(8), z27.literal(16)]).transform((v) => `${v} vCPU`).describe(
|
|
1828
|
-
"The number of virtual CPU units (vCPU) used by the instance. Valid values: 0.25, 0.5, 1, 2, 4, 8, 16 vCPU."
|
|
1829
|
-
);
|
|
1836
|
+
var CpuSchema2 = z27.union([z27.literal(0.25), z27.literal(0.5), z27.literal(1), z27.literal(2), z27.literal(4), z27.literal(8), z27.literal(16)]).transform((v) => `${v} vCPU`).describe("The number of virtual CPU units (vCPU) used by the job. Valid values: 0.25, 0.5, 1, 2, 4, 8, 16 vCPU.");
|
|
1830
1837
|
var validMemorySize2 = [
|
|
1831
1838
|
// 0.25 vCPU
|
|
1832
1839
|
512,
|
|
@@ -1863,22 +1870,9 @@ var validMemorySize2 = [
|
|
|
1863
1870
|
var MemorySizeSchema3 = SizeSchema.refine(
|
|
1864
1871
|
(s) => validMemorySize2.includes(toMebibytes2(s)),
|
|
1865
1872
|
`Invalid memory size. Allowed sizes: ${validMemorySize2.join(", ")} MiB`
|
|
1866
|
-
).describe("The amount of memory (in MiB) used by the
|
|
1867
|
-
var HealthCheckSchema = z27.object({
|
|
1868
|
-
path: z27.string().describe("The path that the container runs to determine if it is healthy."),
|
|
1869
|
-
interval: DurationSchema.describe("The time period in seconds between each health check execution."),
|
|
1870
|
-
retries: z27.number().int().min(1).max(10).describe(
|
|
1871
|
-
"The number of times to retry a failed health check before the container is considered unhealthy."
|
|
1872
|
-
),
|
|
1873
|
-
startPeriod: DurationSchema.describe(
|
|
1874
|
-
"The optional grace period to provide containers time to bootstrap before failed health checks count towards the maximum number of retries."
|
|
1875
|
-
),
|
|
1876
|
-
timeout: DurationSchema.describe(
|
|
1877
|
-
"The time period in seconds to wait for a health check to succeed before it is considered a failure."
|
|
1878
|
-
)
|
|
1879
|
-
}).describe("The health check command and associated configuration parameters for the container.");
|
|
1873
|
+
).describe("The amount of memory (in MiB) used by the job. Valid memory values depend on the CPU configuration.");
|
|
1880
1874
|
var EnvironmentSchema3 = z27.record(z27.string(), z27.string()).optional().describe("Environment variable key-value pairs.");
|
|
1881
|
-
var ArchitectureSchema4 = z27.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the
|
|
1875
|
+
var ArchitectureSchema4 = z27.enum(["x86_64", "arm64"]).describe("The instruction set architecture that the job supports.");
|
|
1882
1876
|
var ActionSchema3 = z27.string();
|
|
1883
1877
|
var ActionsSchema3 = z27.union([ActionSchema3.transform((v) => [v]), ActionSchema3.array()]);
|
|
1884
1878
|
var ArnSchema3 = z27.string().startsWith("arn:");
|
|
@@ -1890,44 +1884,45 @@ var PermissionSchema3 = z27.object({
|
|
|
1890
1884
|
actions: ActionsSchema3,
|
|
1891
1885
|
resources: ResourcesSchema3
|
|
1892
1886
|
});
|
|
1893
|
-
var PermissionsSchema3 = z27.union([PermissionSchema3.transform((v) => [v]), PermissionSchema3.array()]).describe("Add IAM permissions to your
|
|
1894
|
-
var DescriptionSchema2 = z27.string().describe("A description of the instance.");
|
|
1895
|
-
var ImageSchema2 = z27.string().optional().describe("The URL of the container image to use. Default: public.ecr.aws/aws-cli/aws-cli:{architecture}");
|
|
1887
|
+
var PermissionsSchema3 = z27.union([PermissionSchema3.transform((v) => [v]), PermissionSchema3.array()]).describe("Add IAM permissions to your job.");
|
|
1896
1888
|
var validLogRetentionDays3 = [
|
|
1897
1889
|
...[1, 3, 5, 7, 14, 30, 60, 90, 120, 150],
|
|
1898
1890
|
...[180, 365, 400, 545, 731, 1096, 1827, 2192],
|
|
1899
1891
|
...[2557, 2922, 3288, 3653]
|
|
1900
1892
|
];
|
|
1901
1893
|
var LogRetentionSchema3 = DurationSchema.refine(
|
|
1902
|
-
durationMin(
|
|
1894
|
+
durationMin(days6(0)),
|
|
1903
1895
|
"Minimum log retention is 0 day, which will disable logging."
|
|
1904
1896
|
).refine(
|
|
1905
1897
|
(duration) => {
|
|
1906
1898
|
return validLogRetentionDays3.includes(toDays3(duration));
|
|
1907
1899
|
},
|
|
1908
|
-
`Invalid log retention. Valid days are: ${validLogRetentionDays3.map((
|
|
1900
|
+
`Invalid log retention. Valid days are: ${validLogRetentionDays3.map((days13) => `${days13}`).join(", ")}`
|
|
1909
1901
|
).describe("The log retention duration.");
|
|
1910
1902
|
var LogSchema3 = z27.union([
|
|
1911
|
-
z27.boolean().transform((enabled) => ({ retention: enabled ?
|
|
1903
|
+
z27.boolean().transform((enabled) => ({ retention: enabled ? days6(7) : days6(0) })),
|
|
1912
1904
|
LogRetentionSchema3.transform((retention) => ({ retention })),
|
|
1913
1905
|
z27.object({
|
|
1914
1906
|
retention: LogRetentionSchema3.optional()
|
|
1915
1907
|
})
|
|
1916
1908
|
]).describe("Enable logging to a CloudWatch log group. Providing a duration value will set the log retention time.");
|
|
1917
1909
|
var FileCodeSchema3 = z27.object({
|
|
1918
|
-
file: LocalFileSchema.describe("The file path of the
|
|
1910
|
+
file: LocalFileSchema.describe("The file path of the job code.")
|
|
1919
1911
|
});
|
|
1920
1912
|
var CodeSchema3 = z27.union([
|
|
1921
1913
|
LocalFileSchema.transform((file) => ({
|
|
1922
1914
|
file
|
|
1923
1915
|
})).pipe(FileCodeSchema3),
|
|
1924
1916
|
FileCodeSchema3
|
|
1925
|
-
]).describe("Specify the code of your
|
|
1926
|
-
var
|
|
1927
|
-
var
|
|
1917
|
+
]).describe("Specify the code of your job.");
|
|
1918
|
+
var TimeoutSchema3 = DurationSchema.describe("The maximum time the job is allowed to run before being stopped.");
|
|
1919
|
+
var ImageSchema2 = z27.string().describe("The URL of the container image to use. Default: public.ecr.aws/aws-cli/aws-cli:{architecture}");
|
|
1920
|
+
var PersistentStorageSchema = z27.boolean().describe("Mount persistent storage for the job at a fixed internal path.");
|
|
1921
|
+
var StartupCommandSchema2 = z27.union([z27.string().transform((v) => [v]), z27.string().array()]).describe("Optional shell commands to run before the job executable is downloaded and started.");
|
|
1922
|
+
var ASchema = z27.object({
|
|
1928
1923
|
code: CodeSchema3,
|
|
1929
|
-
description: DescriptionSchema2.optional(),
|
|
1930
1924
|
image: ImageSchema2.optional(),
|
|
1925
|
+
persistentStorage: PersistentStorageSchema.optional(),
|
|
1931
1926
|
startupCommand: StartupCommandSchema2.optional(),
|
|
1932
1927
|
log: LogSchema3.optional(),
|
|
1933
1928
|
cpu: CpuSchema2.optional(),
|
|
@@ -1935,27 +1930,26 @@ var ISchema = z27.object({
|
|
|
1935
1930
|
architecture: ArchitectureSchema4.optional(),
|
|
1936
1931
|
environment: EnvironmentSchema3.optional(),
|
|
1937
1932
|
permissions: PermissionsSchema3.optional(),
|
|
1938
|
-
|
|
1939
|
-
// restartPolicy: RestartPolicySchema.optional(),
|
|
1933
|
+
timeout: TimeoutSchema3.default("30 minutes").describe("The maximum time the job is allowed to run before being stopped. Default: 30 minutes.")
|
|
1940
1934
|
});
|
|
1941
|
-
var
|
|
1935
|
+
var JobSchema = z27.union([
|
|
1942
1936
|
LocalFileSchema.transform((code) => ({
|
|
1943
1937
|
code
|
|
1944
|
-
})).pipe(
|
|
1945
|
-
|
|
1938
|
+
})).pipe(ASchema),
|
|
1939
|
+
ASchema
|
|
1946
1940
|
]);
|
|
1947
|
-
var
|
|
1948
|
-
var
|
|
1941
|
+
var JobsSchema = z27.record(ResourceIdSchema, JobSchema).optional().describe("Define the jobs in your stack.");
|
|
1942
|
+
var JobDefaultSchema = z27.object({
|
|
1949
1943
|
image: ImageSchema2.optional(),
|
|
1944
|
+
persistentStorage: PersistentStorageSchema.optional(),
|
|
1950
1945
|
cpu: CpuSchema2.default(0.25),
|
|
1951
1946
|
memorySize: MemorySizeSchema3.default("512 MB"),
|
|
1952
1947
|
architecture: ArchitectureSchema4.default("arm64"),
|
|
1953
1948
|
environment: EnvironmentSchema3.optional(),
|
|
1954
1949
|
permissions: PermissionsSchema3.optional(),
|
|
1955
|
-
|
|
1956
|
-
// restartPolicy: RestartPolicySchema.default({ enabled: true }),
|
|
1950
|
+
timeout: TimeoutSchema3.optional(),
|
|
1957
1951
|
log: LogSchema3.default(true).transform((log35) => ({
|
|
1958
|
-
retention: log35.retention ??
|
|
1952
|
+
retention: log35.retention ?? days6(7)
|
|
1959
1953
|
}))
|
|
1960
1954
|
}).default({});
|
|
1961
1955
|
|
|
@@ -2153,7 +2147,7 @@ var CronExpressionSchema = z34.custom(
|
|
|
2153
2147
|
var ScheduleExpressionSchema = RateExpressionSchema.or(CronExpressionSchema);
|
|
2154
2148
|
|
|
2155
2149
|
// src/feature/cron/schema/index.ts
|
|
2156
|
-
var
|
|
2150
|
+
var RetryAttemptsSchema3 = z35.number().int().min(0).max(2).describe(
|
|
2157
2151
|
"The maximum number of times to retry when the function returns an error. You can specify a number from 0 to 2."
|
|
2158
2152
|
);
|
|
2159
2153
|
var CronsSchema = z35.record(
|
|
@@ -2165,7 +2159,7 @@ var CronsSchema = z35.record(
|
|
|
2165
2159
|
'The scheduling expression.\n\nexample: "0 20 * * ? *"\nexample: "5 minutes"'
|
|
2166
2160
|
),
|
|
2167
2161
|
payload: z35.unknown().optional().describe("The JSON payload that will be passed to the consumer."),
|
|
2168
|
-
retryAttempts:
|
|
2162
|
+
retryAttempts: RetryAttemptsSchema3.default(2)
|
|
2169
2163
|
})
|
|
2170
2164
|
).optional().describe(`Define the cron jobs in your stack.`);
|
|
2171
2165
|
|
|
@@ -2295,7 +2289,7 @@ var SitesSchema = z38.record(
|
|
|
2295
2289
|
ResourceIdSchema,
|
|
2296
2290
|
z38.object({
|
|
2297
2291
|
router: ResourceIdSchema.describe("The router id to link your site with."),
|
|
2298
|
-
path:
|
|
2292
|
+
path: RouteSchema.describe("The path inside the router to link your site to."),
|
|
2299
2293
|
build: z38.object({
|
|
2300
2294
|
command: z38.string().describe(
|
|
2301
2295
|
`Specifies the files and directories to generate the cache key for your custom build command.`
|
|
@@ -2313,11 +2307,11 @@ var SitesSchema = z38.record(
|
|
|
2313
2307
|
).optional().describe("Define the sites in your stack.");
|
|
2314
2308
|
|
|
2315
2309
|
// src/feature/store/schema.ts
|
|
2316
|
-
import { days as
|
|
2310
|
+
import { days as days7 } from "@awsless/duration";
|
|
2317
2311
|
import { z as z39 } from "zod";
|
|
2318
2312
|
var LifecycleRuleSchema = z39.object({
|
|
2319
2313
|
prefix: z39.string().optional().describe("Object-key prefix this rule applies to. Omit to apply bucket-wide."),
|
|
2320
|
-
expiration: DurationSchema.refine(durationMin(
|
|
2314
|
+
expiration: DurationSchema.refine(durationMin(days7(1)), "Minimum expiration is 1 day").describe(
|
|
2321
2315
|
"How long objects matching this rule live before S3 deletes them."
|
|
2322
2316
|
)
|
|
2323
2317
|
});
|
|
@@ -2381,7 +2375,7 @@ var IconsSchema = z40.record(
|
|
|
2381
2375
|
// domain: ResourceIdSchema.describe('The domain id to link your site with.').optional(),
|
|
2382
2376
|
// subDomain: z.string().optional(),
|
|
2383
2377
|
router: ResourceIdSchema.describe("The router id to link your icon proxy."),
|
|
2384
|
-
path:
|
|
2378
|
+
path: RouteSchema.describe("The path inside the router to link your icon proxy to."),
|
|
2385
2379
|
log: LogSchema.optional(),
|
|
2386
2380
|
cacheDuration: DurationSchema.optional().describe("The cache duration of the cached icons."),
|
|
2387
2381
|
preserveIds: z40.boolean().optional().default(false).describe("Preserve the IDs of the icons."),
|
|
@@ -2438,7 +2432,7 @@ var ImagesSchema = z41.record(
|
|
|
2438
2432
|
// domain: ResourceIdSchema.describe('The domain id to link your site with.').optional(),
|
|
2439
2433
|
// subDomain: z.string().optional(),
|
|
2440
2434
|
router: ResourceIdSchema.describe("The router id to link your image proxy."),
|
|
2441
|
-
path:
|
|
2435
|
+
path: RouteSchema.describe("The path inside the router to link your image proxy to."),
|
|
2442
2436
|
log: LogSchema.optional(),
|
|
2443
2437
|
cacheDuration: DurationSchema.optional().describe("Cache duration of the cached images."),
|
|
2444
2438
|
presets: z41.record(z41.string(), transformationOptionsSchema).describe("Named presets for image transformations"),
|
|
@@ -3690,13 +3684,15 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3690
3684
|
file,
|
|
3691
3685
|
nativeDir,
|
|
3692
3686
|
external,
|
|
3687
|
+
externalAwsSdk = true,
|
|
3688
|
+
codeSplitting = true,
|
|
3693
3689
|
importAsString: importAsStringList
|
|
3694
3690
|
}) => {
|
|
3695
3691
|
const bundle = await rolldown({
|
|
3696
3692
|
input: file,
|
|
3697
3693
|
platform: "node",
|
|
3698
3694
|
external: (importee) => {
|
|
3699
|
-
return importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk") || external?.includes(importee);
|
|
3695
|
+
return externalAwsSdk && (importee.startsWith("@aws-sdk") || importee.startsWith("aws-sdk")) || external?.includes(importee);
|
|
3700
3696
|
},
|
|
3701
3697
|
onwarn: (error) => {
|
|
3702
3698
|
debugError(error.message);
|
|
@@ -3725,6 +3721,7 @@ var bundleTypeScriptWithRolldown = async ({
|
|
|
3725
3721
|
exports: "auto",
|
|
3726
3722
|
entryFileNames: `index.${ext}`,
|
|
3727
3723
|
chunkFileNames: `[name].${ext}`,
|
|
3724
|
+
codeSplitting,
|
|
3728
3725
|
minify
|
|
3729
3726
|
});
|
|
3730
3727
|
const hash = createHash2("sha1");
|
|
@@ -4549,7 +4546,7 @@ var functionFeature = defineFeature({
|
|
|
4549
4546
|
});
|
|
4550
4547
|
|
|
4551
4548
|
// src/feature/function/prebuild.ts
|
|
4552
|
-
import { days as
|
|
4549
|
+
import { days as days8, seconds as seconds5, toDays as toDays6, toSeconds as toSeconds3 } from "@awsless/duration";
|
|
4553
4550
|
import { mebibytes as mebibytes2, toMebibytes as toMebibytes4 } from "@awsless/size";
|
|
4554
4551
|
import { aws as aws8 } from "@terraforge/aws";
|
|
4555
4552
|
import { Output as Output4, findInputDeps as findInputDeps2, resolveInputs as resolveInputs2 } from "@terraforge/core";
|
|
@@ -4614,6 +4611,28 @@ var createPrebuildLambdaFunction = (group, ctx, ns, id, props) => {
|
|
|
4614
4611
|
statementDeps.add(dep);
|
|
4615
4612
|
}
|
|
4616
4613
|
};
|
|
4614
|
+
if (props.vpc) {
|
|
4615
|
+
new aws8.iam.RolePolicy(group, "vpc-policy", {
|
|
4616
|
+
role: role.name,
|
|
4617
|
+
name: "lambda-vpc-policy",
|
|
4618
|
+
policy: JSON.stringify({
|
|
4619
|
+
Version: "2012-10-17",
|
|
4620
|
+
Statement: [
|
|
4621
|
+
{
|
|
4622
|
+
Effect: "Allow",
|
|
4623
|
+
Action: [
|
|
4624
|
+
"ec2:CreateNetworkInterface",
|
|
4625
|
+
"ec2:DescribeNetworkInterfaces",
|
|
4626
|
+
"ec2:DeleteNetworkInterface",
|
|
4627
|
+
"ec2:AssignPrivateIpAddresses",
|
|
4628
|
+
"ec2:UnassignPrivateIpAddresses"
|
|
4629
|
+
],
|
|
4630
|
+
Resource: ["*"]
|
|
4631
|
+
}
|
|
4632
|
+
]
|
|
4633
|
+
})
|
|
4634
|
+
});
|
|
4635
|
+
}
|
|
4617
4636
|
ctx.onPermission((statement) => {
|
|
4618
4637
|
addPermission(statement);
|
|
4619
4638
|
});
|
|
@@ -4662,6 +4681,11 @@ var createPrebuildLambdaFunction = (group, ctx, ns, id, props) => {
|
|
|
4662
4681
|
environment: {
|
|
4663
4682
|
variables
|
|
4664
4683
|
},
|
|
4684
|
+
vpcConfig: props.vpc ? {
|
|
4685
|
+
securityGroupIds: [ctx.shared.get("vpc", "security-group-id")],
|
|
4686
|
+
subnetIds: ctx.shared.get("vpc", "private-subnets"),
|
|
4687
|
+
ipv6AllowedForDualStack: true
|
|
4688
|
+
} : void 0,
|
|
4665
4689
|
loggingConfig: {
|
|
4666
4690
|
logGroup: `/aws/lambda/${name}`,
|
|
4667
4691
|
logFormat: logFormats[props.log && "format" in props.log && props.log.format || "json"],
|
|
@@ -4678,10 +4702,13 @@ var createPrebuildLambdaFunction = (group, ctx, ns, id, props) => {
|
|
|
4678
4702
|
if ("stackConfig" in ctx) {
|
|
4679
4703
|
variables.STACK = ctx.stackConfig.name;
|
|
4680
4704
|
}
|
|
4705
|
+
if (props.vpc) {
|
|
4706
|
+
variables.AWS_USE_DUALSTACK_ENDPOINT = "true";
|
|
4707
|
+
}
|
|
4681
4708
|
if (props.log?.retention && props.log?.retention?.value > 0n) {
|
|
4682
4709
|
const logGroup = new aws8.cloudwatch.LogGroup(group, "log", {
|
|
4683
4710
|
name: `/aws/lambda/${name}`,
|
|
4684
|
-
retentionInDays: toDays6(props.log.retention ??
|
|
4711
|
+
retentionInDays: toDays6(props.log.retention ?? days8(7))
|
|
4685
4712
|
});
|
|
4686
4713
|
addPermission({
|
|
4687
4714
|
actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
|
|
@@ -4738,7 +4765,7 @@ import { Group as Group8 } from "@terraforge/core";
|
|
|
4738
4765
|
import { aws as aws9 } from "@terraforge/aws";
|
|
4739
4766
|
import { join as join10 } from "path";
|
|
4740
4767
|
import { mebibytes as mebibytes3 } from "@awsless/size";
|
|
4741
|
-
import { days as
|
|
4768
|
+
import { days as days9, seconds as seconds6 } from "@awsless/duration";
|
|
4742
4769
|
var onErrorLogFeature = defineFeature({
|
|
4743
4770
|
name: "on-error-log",
|
|
4744
4771
|
onApp(ctx) {
|
|
@@ -4753,7 +4780,7 @@ var onErrorLogFeature = defineFeature({
|
|
|
4753
4780
|
log: {
|
|
4754
4781
|
format: "json",
|
|
4755
4782
|
level: "warn",
|
|
4756
|
-
retention:
|
|
4783
|
+
retention: days9(3),
|
|
4757
4784
|
system: "warn"
|
|
4758
4785
|
}
|
|
4759
4786
|
});
|
|
@@ -4810,7 +4837,7 @@ import { Group as Group9 } from "@terraforge/core";
|
|
|
4810
4837
|
import { aws as aws10 } from "@terraforge/aws";
|
|
4811
4838
|
import { join as join11 } from "path";
|
|
4812
4839
|
import { mebibytes as mebibytes4 } from "@awsless/size";
|
|
4813
|
-
import { days as
|
|
4840
|
+
import { days as days10, toSeconds as toSeconds4 } from "@awsless/duration";
|
|
4814
4841
|
var onFailureFeature = defineFeature({
|
|
4815
4842
|
name: "on-failure",
|
|
4816
4843
|
onApp(ctx) {
|
|
@@ -4821,7 +4848,7 @@ var onFailureFeature = defineFeature({
|
|
|
4821
4848
|
resourceType: "on-failure",
|
|
4822
4849
|
resourceName: "deadletter"
|
|
4823
4850
|
}),
|
|
4824
|
-
messageRetentionSeconds: toSeconds4(
|
|
4851
|
+
messageRetentionSeconds: toSeconds4(days10(14))
|
|
4825
4852
|
});
|
|
4826
4853
|
const queue2 = new aws10.sqs.Queue(group, "on-failure", {
|
|
4827
4854
|
name: formatGlobalResourceName({
|
|
@@ -4969,7 +4996,7 @@ var onFailureFeature = defineFeature({
|
|
|
4969
4996
|
log: {
|
|
4970
4997
|
format: "json",
|
|
4971
4998
|
level: "warn",
|
|
4972
|
-
retention:
|
|
4999
|
+
retention: days10(3),
|
|
4973
5000
|
system: "warn"
|
|
4974
5001
|
}
|
|
4975
5002
|
});
|
|
@@ -5044,9 +5071,14 @@ var onFailureFeature = defineFeature({
|
|
|
5044
5071
|
});
|
|
5045
5072
|
|
|
5046
5073
|
// src/feature/pubsub/index.ts
|
|
5047
|
-
import {
|
|
5048
|
-
import {
|
|
5074
|
+
import { seconds as seconds7 } from "@awsless/duration";
|
|
5075
|
+
import { mebibytes as mebibytes5 } from "@awsless/size";
|
|
5076
|
+
import { aws as aws12 } from "@terraforge/aws";
|
|
5077
|
+
import { Group as Group11 } from "@terraforge/core";
|
|
5049
5078
|
import { constantCase as constantCase5 } from "change-case";
|
|
5079
|
+
import { createHmac as createHmac2 } from "crypto";
|
|
5080
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
5081
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5050
5082
|
|
|
5051
5083
|
// src/feature/domain/util.ts
|
|
5052
5084
|
var getDomainNameById = (config2, id) => {
|
|
@@ -5066,103 +5098,739 @@ var formatFullDomainName = (config2, id, subDomain) => {
|
|
|
5066
5098
|
return domain2;
|
|
5067
5099
|
};
|
|
5068
5100
|
|
|
5069
|
-
// src/feature/pubsub/
|
|
5070
|
-
import {
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5101
|
+
// src/feature/pubsub/util.ts
|
|
5102
|
+
import { toDays as toDays7 } from "@awsless/duration";
|
|
5103
|
+
import { stringify } from "@awsless/json";
|
|
5104
|
+
import { aws as aws11 } from "@terraforge/aws";
|
|
5105
|
+
import { Group as Group10, Output as Output5, findInputDeps as findInputDeps3, resolveInputs as resolveInputs3 } from "@terraforge/core";
|
|
5106
|
+
import { pascalCase as pascalCase3 } from "change-case";
|
|
5107
|
+
import { createHash as createHash4 } from "crypto";
|
|
5108
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
5109
|
+
import { fileURLToPath } from "url";
|
|
5110
|
+
import { dirname as dirname5, join as join13 } from "path";
|
|
5111
|
+
|
|
5112
|
+
// src/feature/instance/build/executable.ts
|
|
5113
|
+
import { createHash as createHash3 } from "crypto";
|
|
5114
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
5115
|
+
import { join as join12 } from "path";
|
|
5116
|
+
var buildExecutable = async (input, outputPath, architecture) => {
|
|
5117
|
+
const filePath = join12(outputPath, "program");
|
|
5118
|
+
const target = architecture === "x86_64" ? "bun-linux-x64" : "bun-linux-arm64";
|
|
5119
|
+
let result;
|
|
5120
|
+
try {
|
|
5121
|
+
result = await Bun.build({
|
|
5122
|
+
entrypoints: [input],
|
|
5123
|
+
compile: {
|
|
5124
|
+
target,
|
|
5125
|
+
outfile: filePath
|
|
5126
|
+
},
|
|
5127
|
+
target: "bun",
|
|
5128
|
+
loader: {
|
|
5129
|
+
".md": "text",
|
|
5130
|
+
".txt": "text",
|
|
5131
|
+
".html": "text",
|
|
5132
|
+
".css": "text",
|
|
5133
|
+
".yaml": "text",
|
|
5134
|
+
".yml": "text",
|
|
5135
|
+
".xml": "text",
|
|
5136
|
+
".csv": "text",
|
|
5137
|
+
".svg": "text",
|
|
5138
|
+
".png": "file",
|
|
5139
|
+
".jpg": "file",
|
|
5140
|
+
".jpeg": "file",
|
|
5141
|
+
".gif": "file",
|
|
5142
|
+
".webp": "file",
|
|
5143
|
+
".wasm": "file"
|
|
5144
|
+
}
|
|
5080
5145
|
});
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5146
|
+
} catch (error) {
|
|
5147
|
+
throw new ExpectedError(
|
|
5148
|
+
`Executable build failed: ${error instanceof Error ? error.message : JSON.stringify(error)}`
|
|
5149
|
+
);
|
|
5150
|
+
}
|
|
5151
|
+
if (!result.success) {
|
|
5152
|
+
throw new ExpectedError(`Executable build failed:
|
|
5153
|
+
${result.logs?.map((log35) => log35.message).join("\n")}`);
|
|
5154
|
+
}
|
|
5155
|
+
const file = await readFile4(filePath);
|
|
5156
|
+
return {
|
|
5157
|
+
hash: createHash3("sha1").update(file).update("x86_64").digest("hex"),
|
|
5158
|
+
file
|
|
5159
|
+
};
|
|
5160
|
+
};
|
|
5161
|
+
|
|
5162
|
+
// src/feature/pubsub/util.ts
|
|
5163
|
+
var __dirname2 = dirname5(fileURLToPath(import.meta.url));
|
|
5164
|
+
var WS_PORT = 3e3;
|
|
5165
|
+
var ARCHITECTURE = "arm64";
|
|
5166
|
+
var CPU = "0.25 vCPU";
|
|
5167
|
+
var MEMORY = "512";
|
|
5168
|
+
var MIN_CAPACITY = 1;
|
|
5169
|
+
var MAX_CAPACITY = 10;
|
|
5170
|
+
var createPubSubService = (parentGroup, ctx, id, props, inputs) => {
|
|
5171
|
+
const group = new Group10(parentGroup, "service", id);
|
|
5172
|
+
const name = formatGlobalResourceName({
|
|
5173
|
+
appName: ctx.app.name,
|
|
5174
|
+
resourceType: "pubsub",
|
|
5175
|
+
resourceName: id
|
|
5176
|
+
});
|
|
5177
|
+
const shortName = shortId(`${ctx.app.name}:pubsub:${id}:${ctx.appId}`);
|
|
5178
|
+
const image2 = "public.ecr.aws/aws-cli/aws-cli:arm64";
|
|
5179
|
+
const bundleFile = join13(__dirname2, "prebuild/pubsub-server/index.mjs");
|
|
5180
|
+
const bundleHash = join13(__dirname2, "prebuild/pubsub-server/HASH");
|
|
5181
|
+
ctx.registerBuild("pubsub", name, async (build3) => {
|
|
5182
|
+
const hash = await readFile5(bundleHash, "utf8");
|
|
5183
|
+
const fingerprint = `${hash.trim()}-${ARCHITECTURE}`;
|
|
5184
|
+
return build3(fingerprint, async (write) => {
|
|
5185
|
+
const temp = await createTempFolder(`pubsub--${name}`);
|
|
5186
|
+
const executable = await buildExecutable(bundleFile, temp.path, ARCHITECTURE);
|
|
5187
|
+
await Promise.all([
|
|
5188
|
+
//
|
|
5189
|
+
write("HASH", executable.hash),
|
|
5190
|
+
write("program", executable.file),
|
|
5191
|
+
temp.delete()
|
|
5192
|
+
]);
|
|
5193
|
+
return {
|
|
5194
|
+
size: formatByteSize(executable.file.byteLength)
|
|
5195
|
+
};
|
|
5196
|
+
});
|
|
5197
|
+
});
|
|
5198
|
+
const code = new aws11.s3.BucketObject(group, "code", {
|
|
5199
|
+
bucket: ctx.shared.get("pubsub", "bucket-name"),
|
|
5200
|
+
key: name,
|
|
5201
|
+
source: relativePath(getBuildPath("pubsub", name, "program")),
|
|
5202
|
+
sourceHash: $file(getBuildPath("pubsub", name, "HASH"))
|
|
5203
|
+
});
|
|
5204
|
+
const executionRole = new aws11.iam.Role(group, "execution-role", {
|
|
5205
|
+
name: shortId(`${shortName}:execution-role`),
|
|
5206
|
+
description: name,
|
|
5207
|
+
assumeRolePolicy: JSON.stringify({
|
|
5208
|
+
Version: "2012-10-17",
|
|
5209
|
+
Statement: [
|
|
5210
|
+
{
|
|
5211
|
+
Effect: "Allow",
|
|
5212
|
+
Action: "sts:AssumeRole",
|
|
5213
|
+
Principal: {
|
|
5214
|
+
Service: ["ecs-tasks.amazonaws.com"]
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
5217
|
+
]
|
|
5218
|
+
}),
|
|
5219
|
+
managedPolicyArns: ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
|
|
5220
|
+
});
|
|
5221
|
+
const role = new aws11.iam.Role(
|
|
5222
|
+
group,
|
|
5223
|
+
"task-role",
|
|
5224
|
+
{
|
|
5225
|
+
name: shortId(`${shortName}:task-role`),
|
|
5226
|
+
description: name,
|
|
5227
|
+
assumeRolePolicy: JSON.stringify({
|
|
5228
|
+
Version: "2012-10-17",
|
|
5229
|
+
Statement: [
|
|
5230
|
+
{
|
|
5231
|
+
Effect: "Allow",
|
|
5232
|
+
Action: "sts:AssumeRole",
|
|
5233
|
+
Principal: {
|
|
5234
|
+
Service: ["ecs-tasks.amazonaws.com"]
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
]
|
|
5238
|
+
}),
|
|
5239
|
+
inlinePolicy: [
|
|
5240
|
+
{
|
|
5241
|
+
name: "s3-code-access",
|
|
5242
|
+
policy: $resolve([code.bucket, code.key], (bucket, key) => {
|
|
5243
|
+
return JSON.stringify({
|
|
5244
|
+
Version: "2012-10-17",
|
|
5245
|
+
Statement: [
|
|
5246
|
+
{
|
|
5247
|
+
Effect: pascalCase3("allow"),
|
|
5248
|
+
Action: ["s3:getObject", "s3:HeadObject"],
|
|
5249
|
+
Resource: `arn:aws:s3:::${bucket}/${key}`
|
|
5250
|
+
}
|
|
5251
|
+
]
|
|
5252
|
+
});
|
|
5253
|
+
})
|
|
5254
|
+
}
|
|
5255
|
+
]
|
|
5256
|
+
},
|
|
5257
|
+
{
|
|
5258
|
+
dependsOn: [code]
|
|
5259
|
+
}
|
|
5260
|
+
);
|
|
5261
|
+
const statements = [];
|
|
5262
|
+
const statementDeps = /* @__PURE__ */ new Set();
|
|
5263
|
+
const policy = new aws11.iam.RolePolicy(group, "policy", {
|
|
5264
|
+
role: role.name,
|
|
5265
|
+
name: "task-policy",
|
|
5266
|
+
policy: new Output5(statementDeps, async (resolve2) => {
|
|
5267
|
+
const list3 = await resolveInputs3(statements);
|
|
5268
|
+
resolve2(
|
|
5269
|
+
JSON.stringify({
|
|
5270
|
+
Version: "2012-10-17",
|
|
5271
|
+
Statement: list3.map((statement) => ({
|
|
5272
|
+
Effect: pascalCase3(statement.effect ?? "allow"),
|
|
5273
|
+
Action: statement.actions,
|
|
5274
|
+
Resource: statement.resources
|
|
5275
|
+
}))
|
|
5276
|
+
})
|
|
5277
|
+
);
|
|
5278
|
+
})
|
|
5279
|
+
});
|
|
5280
|
+
const addPermission = (...permissions) => {
|
|
5281
|
+
statements.push(...permissions);
|
|
5282
|
+
for (const dep of findInputDeps3(permissions)) {
|
|
5283
|
+
statementDeps.add(dep);
|
|
5284
|
+
}
|
|
5285
|
+
};
|
|
5286
|
+
ctx.onPermission((statement) => {
|
|
5287
|
+
addPermission(statement);
|
|
5288
|
+
});
|
|
5289
|
+
let logGroup;
|
|
5290
|
+
if (props.log.retention && props.log.retention.value > 0n) {
|
|
5291
|
+
logGroup = new aws11.cloudwatch.LogGroup(group, "log", {
|
|
5292
|
+
name: `/aws/ecs/${name}`,
|
|
5293
|
+
retentionInDays: toDays7(props.log.retention)
|
|
5294
|
+
});
|
|
5295
|
+
if (ctx.shared.has("on-error-log", "subscriber-arn")) {
|
|
5296
|
+
new aws11.cloudwatch.LogSubscriptionFilter(group, "on-error-log", {
|
|
5297
|
+
name: "error-log-subscription",
|
|
5298
|
+
destinationArn: ctx.shared.get("on-error-log", "subscriber-arn"),
|
|
5299
|
+
logGroupName: logGroup.name,
|
|
5300
|
+
filterPattern
|
|
5301
|
+
});
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
const tags = {
|
|
5305
|
+
APP: ctx.appConfig.name,
|
|
5306
|
+
APP_ID: ctx.appId
|
|
5307
|
+
};
|
|
5308
|
+
const variables = {};
|
|
5309
|
+
const variableDeps = /* @__PURE__ */ new Set();
|
|
5310
|
+
const task2 = new aws11.ecs.TaskDefinition(
|
|
5311
|
+
group,
|
|
5312
|
+
"task",
|
|
5313
|
+
{
|
|
5314
|
+
family: name,
|
|
5315
|
+
networkMode: "awsvpc",
|
|
5316
|
+
cpu: CPU,
|
|
5317
|
+
memory: MEMORY,
|
|
5318
|
+
requiresCompatibilities: ["FARGATE"],
|
|
5319
|
+
executionRoleArn: executionRole.arn,
|
|
5320
|
+
taskRoleArn: role.arn,
|
|
5321
|
+
runtimePlatform: {
|
|
5322
|
+
cpuArchitecture: "ARM64",
|
|
5323
|
+
operatingSystemFamily: "LINUX"
|
|
5324
|
+
},
|
|
5325
|
+
trackLatest: true,
|
|
5326
|
+
containerDefinitions: new Output5(variableDeps, async (resolve2) => {
|
|
5327
|
+
const data = await resolveInputs3(variables);
|
|
5328
|
+
const { s3Bucket, s3Key } = await resolveInputs3({
|
|
5329
|
+
s3Bucket: code.bucket,
|
|
5330
|
+
s3Key: code.key
|
|
5331
|
+
});
|
|
5332
|
+
resolve2(
|
|
5333
|
+
JSON.stringify([
|
|
5334
|
+
{
|
|
5335
|
+
name: `container-${id}`,
|
|
5336
|
+
essential: true,
|
|
5337
|
+
image: image2,
|
|
5338
|
+
protocol: "tcp",
|
|
5339
|
+
workingDirectory: "/usr/app",
|
|
5340
|
+
entryPoint: ["sh", "-c"],
|
|
5341
|
+
command: [
|
|
5342
|
+
[
|
|
5343
|
+
`aws s3 cp s3://${s3Bucket}/${s3Key} /usr/app/program`,
|
|
5344
|
+
`chmod +x /usr/app/program`,
|
|
5345
|
+
`exec /usr/app/program`
|
|
5346
|
+
].join(" && ")
|
|
5347
|
+
],
|
|
5348
|
+
environment: Object.entries(data).map(([name2, value]) => ({
|
|
5349
|
+
name: name2,
|
|
5350
|
+
value
|
|
5351
|
+
})),
|
|
5352
|
+
portMappings: [
|
|
5353
|
+
{
|
|
5354
|
+
name: "ws",
|
|
5355
|
+
protocol: "tcp",
|
|
5356
|
+
appProtocol: "http",
|
|
5357
|
+
containerPort: WS_PORT,
|
|
5358
|
+
hostPort: WS_PORT
|
|
5359
|
+
}
|
|
5360
|
+
],
|
|
5361
|
+
restartPolicy: {
|
|
5362
|
+
enabled: true,
|
|
5363
|
+
restartAttemptPeriod: 60
|
|
5364
|
+
},
|
|
5365
|
+
...logGroup && {
|
|
5366
|
+
logConfiguration: {
|
|
5367
|
+
logDriver: "awslogs",
|
|
5368
|
+
options: {
|
|
5369
|
+
"awslogs-group": `/aws/ecs/${name}`,
|
|
5370
|
+
"awslogs-region": ctx.appConfig.region,
|
|
5371
|
+
"awslogs-stream-prefix": "ecs",
|
|
5372
|
+
mode: "non-blocking"
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
])
|
|
5378
|
+
);
|
|
5379
|
+
}),
|
|
5380
|
+
tags
|
|
5381
|
+
},
|
|
5382
|
+
{
|
|
5383
|
+
replaceOnChanges: [
|
|
5384
|
+
"containerDefinitions",
|
|
5385
|
+
"cpu",
|
|
5386
|
+
"memory",
|
|
5387
|
+
"runtimePlatform",
|
|
5388
|
+
"executionRoleArn",
|
|
5389
|
+
"taskRoleArn"
|
|
5390
|
+
],
|
|
5391
|
+
dependsOn: [code]
|
|
5392
|
+
}
|
|
5393
|
+
);
|
|
5394
|
+
const service = new aws11.ecs.Service(
|
|
5395
|
+
group,
|
|
5396
|
+
"service",
|
|
5397
|
+
{
|
|
5398
|
+
name,
|
|
5399
|
+
cluster: inputs.clusterArn,
|
|
5400
|
+
taskDefinition: task2.arn,
|
|
5401
|
+
launchType: "FARGATE",
|
|
5402
|
+
networkConfiguration: {
|
|
5403
|
+
subnets: ctx.shared.get("vpc", "public-subnets"),
|
|
5404
|
+
securityGroups: [inputs.securityGroupId],
|
|
5405
|
+
assignPublicIp: true
|
|
5406
|
+
// https://stackoverflow.com/questions/76398247/cannotpullcontainererror-pull-image-manifest-has-been-retried-5-times-failed
|
|
5407
|
+
},
|
|
5408
|
+
loadBalancer: [
|
|
5409
|
+
{
|
|
5410
|
+
containerName: `container-${id}`,
|
|
5411
|
+
containerPort: WS_PORT,
|
|
5412
|
+
targetGroupArn: inputs.targetGroupArn
|
|
5413
|
+
}
|
|
5414
|
+
],
|
|
5415
|
+
healthCheckGracePeriodSeconds: 30,
|
|
5416
|
+
forceNewDeployment: true,
|
|
5417
|
+
forceDelete: true,
|
|
5418
|
+
tags,
|
|
5419
|
+
// ------------------------------------------------------------
|
|
5420
|
+
// Zero-downtime deploys: spin up the new tasks before the old
|
|
5421
|
+
// ones are drained.
|
|
5422
|
+
// The desired count is intentionally not set, so that deploys
|
|
5423
|
+
// never reset the capacity the autoscaler picked.
|
|
5424
|
+
schedulingStrategy: "REPLICA",
|
|
5425
|
+
deploymentMaximumPercent: 200,
|
|
5426
|
+
deploymentMinimumHealthyPercent: 100,
|
|
5427
|
+
deploymentCircuitBreaker: {
|
|
5428
|
+
enable: true,
|
|
5429
|
+
rollback: true
|
|
5430
|
+
},
|
|
5431
|
+
// ------------------------------------------------------------
|
|
5432
|
+
// Tag hygiene: let ECS manage and propagate runtime tags automatically.
|
|
5433
|
+
enableEcsManagedTags: true,
|
|
5434
|
+
propagateTags: "SERVICE"
|
|
5435
|
+
},
|
|
5436
|
+
{
|
|
5437
|
+
replaceOnChanges: ["cluster"]
|
|
5438
|
+
}
|
|
5439
|
+
);
|
|
5440
|
+
const target = new aws11.appautoscaling.Target(
|
|
5441
|
+
group,
|
|
5442
|
+
"autoscaling-target",
|
|
5443
|
+
{
|
|
5444
|
+
serviceNamespace: "ecs",
|
|
5445
|
+
scalableDimension: "ecs:service:DesiredCount",
|
|
5446
|
+
minCapacity: MIN_CAPACITY,
|
|
5447
|
+
maxCapacity: MAX_CAPACITY,
|
|
5448
|
+
resourceId: $resolve([inputs.clusterName, service.name], (clusterName, serviceName) => {
|
|
5449
|
+
return `service/${clusterName}/${serviceName}`;
|
|
5450
|
+
}),
|
|
5451
|
+
tags
|
|
5452
|
+
},
|
|
5453
|
+
{
|
|
5454
|
+
dependsOn: [service]
|
|
5455
|
+
}
|
|
5456
|
+
);
|
|
5457
|
+
new aws11.appautoscaling.Policy(
|
|
5458
|
+
group,
|
|
5459
|
+
"autoscaling-policy",
|
|
5460
|
+
{
|
|
5461
|
+
name: `${name}-cpu`,
|
|
5462
|
+
policyType: "TargetTrackingScaling",
|
|
5463
|
+
serviceNamespace: target.serviceNamespace,
|
|
5464
|
+
scalableDimension: target.scalableDimension,
|
|
5465
|
+
resourceId: target.resourceId,
|
|
5466
|
+
targetTrackingScalingPolicyConfiguration: {
|
|
5467
|
+
predefinedMetricSpecification: {
|
|
5468
|
+
predefinedMetricType: "ECSServiceAverageCPUUtilization"
|
|
5469
|
+
},
|
|
5470
|
+
targetValue: 70,
|
|
5471
|
+
scaleInCooldown: 300,
|
|
5472
|
+
scaleOutCooldown: 60
|
|
5473
|
+
}
|
|
5474
|
+
},
|
|
5475
|
+
{
|
|
5476
|
+
dependsOn: [target]
|
|
5477
|
+
}
|
|
5478
|
+
);
|
|
5479
|
+
ctx.onEnv((name2, value) => {
|
|
5480
|
+
variables[name2] = value;
|
|
5481
|
+
for (const dep of findInputDeps3([value])) {
|
|
5482
|
+
variableDeps.add(dep);
|
|
5483
|
+
}
|
|
5484
|
+
});
|
|
5485
|
+
variables.APP = ctx.appConfig.name;
|
|
5486
|
+
variables.APP_ID = ctx.appId;
|
|
5487
|
+
variables.AWS_ACCOUNT_ID = ctx.accountId;
|
|
5488
|
+
variables.CODE_HASH = code.sourceHash;
|
|
5489
|
+
variables.PUBSUB_CONFIG_HASH = createHash4("sha1").update(stringify(props)).digest("hex");
|
|
5490
|
+
for (const [key, value] of Object.entries(inputs.environment)) {
|
|
5491
|
+
variables[key] = value;
|
|
5492
|
+
for (const dep of findInputDeps3([value])) {
|
|
5493
|
+
variableDeps.add(dep);
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
return { name, task: task2, service, policy, code, group, addPermission };
|
|
5497
|
+
};
|
|
5498
|
+
|
|
5499
|
+
// src/feature/pubsub/index.ts
|
|
5500
|
+
var __dirname3 = dirname6(fileURLToPath2(import.meta.url));
|
|
5501
|
+
var typeGenCode4 = `
|
|
5502
|
+
import type { Mock } from 'vitest'
|
|
5503
|
+
|
|
5504
|
+
type Publish = (topic: string, event: string, payload?: unknown) => Promise<void>
|
|
5505
|
+
type PubSubInstance = {
|
|
5506
|
+
readonly publish: Publish
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
type MockHandle = (payload: { topic: string; event: string; payload?: unknown }) => void
|
|
5510
|
+
type MockBuilder = (handle?: MockHandle) => void
|
|
5511
|
+
type MockObject = Mock<[unknown], unknown>
|
|
5512
|
+
`;
|
|
5513
|
+
var pubsubFeature = defineFeature({
|
|
5514
|
+
name: "pubsub",
|
|
5515
|
+
async onTypeGen(ctx) {
|
|
5516
|
+
const gen = new TypeFile("awsless");
|
|
5517
|
+
const resources2 = new TypeObject(1);
|
|
5518
|
+
const mocks = new TypeObject(1);
|
|
5519
|
+
const mockResponses = new TypeObject(1);
|
|
5520
|
+
for (const id of Object.keys(ctx.appConfig.defaults.pubsub ?? {})) {
|
|
5521
|
+
resources2.addType(id, `PubSubInstance`);
|
|
5522
|
+
mocks.addType(id, `MockBuilder`);
|
|
5523
|
+
mockResponses.addType(id, `MockObject`);
|
|
5524
|
+
}
|
|
5525
|
+
gen.addCode(typeGenCode4);
|
|
5526
|
+
gen.addInterface("PubSubResources", resources2);
|
|
5527
|
+
gen.addInterface("PubSubMock", mocks);
|
|
5528
|
+
gen.addInterface("PubSubMockResponse", mockResponses);
|
|
5529
|
+
await ctx.write("pubsub.d.ts", gen, true);
|
|
5530
|
+
},
|
|
5531
|
+
onValidate(ctx) {
|
|
5532
|
+
const pubsubs = ctx.appConfig.defaults.pubsub ?? {};
|
|
5533
|
+
for (const [id, props] of Object.entries(pubsubs)) {
|
|
5534
|
+
if (!(props.router in (ctx.appConfig.defaults.router ?? {}))) {
|
|
5535
|
+
throw new FileError("app.json", `The pubsub "${id}" points to a non existent router "${props.router}"`);
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
for (const stack of ctx.stackConfigs) {
|
|
5539
|
+
for (const id of Object.keys(stack.pubsub ?? {})) {
|
|
5540
|
+
if (!(id in pubsubs)) {
|
|
5541
|
+
throw new FileError(stack.file, `Listening to a non existent pubsub "${id}"`);
|
|
5542
|
+
}
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
},
|
|
5546
|
+
onBefore(ctx) {
|
|
5547
|
+
const found = Object.keys(ctx.appConfig.defaults.pubsub ?? {}).length > 0;
|
|
5548
|
+
if (!found) {
|
|
5549
|
+
return;
|
|
5550
|
+
}
|
|
5551
|
+
const group = new Group11(ctx.base, "pubsub", "asset");
|
|
5552
|
+
const bucket = new aws12.s3.Bucket(group, "bucket", {
|
|
5553
|
+
bucket: formatGlobalResourceName({
|
|
5554
|
+
appName: ctx.app.name,
|
|
5555
|
+
resourceType: "pubsub",
|
|
5556
|
+
resourceName: "assets",
|
|
5557
|
+
postfix: ctx.appId
|
|
5558
|
+
}),
|
|
5559
|
+
forceDestroy: true
|
|
5560
|
+
});
|
|
5561
|
+
ctx.shared.set("pubsub", "bucket-name", bucket.bucket);
|
|
5562
|
+
},
|
|
5563
|
+
onApp(ctx) {
|
|
5564
|
+
const pubsubs = Object.entries(ctx.appConfig.defaults.pubsub ?? {});
|
|
5565
|
+
if (pubsubs.length === 0) {
|
|
5566
|
+
return;
|
|
5567
|
+
}
|
|
5568
|
+
const clusterGroup = new Group11(ctx.base, "pubsub", "cluster");
|
|
5569
|
+
const cluster = new aws12.ecs.Cluster(
|
|
5570
|
+
clusterGroup,
|
|
5571
|
+
"cluster",
|
|
5572
|
+
{
|
|
5573
|
+
name: `${ctx.app.name}-pubsub`
|
|
5574
|
+
},
|
|
5575
|
+
{
|
|
5576
|
+
replaceOnChanges: ["name"]
|
|
5577
|
+
}
|
|
5578
|
+
);
|
|
5579
|
+
for (const [id, props] of pubsubs) {
|
|
5580
|
+
const group = new Group11(ctx.base, "pubsub", id);
|
|
5581
|
+
const name = formatGlobalResourceName({
|
|
5582
|
+
appName: ctx.app.name,
|
|
5583
|
+
resourceType: "pubsub",
|
|
5584
|
+
resourceName: id
|
|
5585
|
+
});
|
|
5586
|
+
const vpcId = ctx.shared.get("vpc", "id");
|
|
5587
|
+
const auth2 = createLambdaFunction(group, ctx, "pubsub-auth", id, props.auth);
|
|
5588
|
+
const topicName = formatGlobalResourceName({
|
|
5589
|
+
appName: ctx.app.name,
|
|
5590
|
+
resourceType: "pubsub-events",
|
|
5591
|
+
resourceName: id
|
|
5592
|
+
});
|
|
5593
|
+
const topic = new aws12.sns.Topic(group, "events", {
|
|
5594
|
+
name: topicName
|
|
5595
|
+
});
|
|
5596
|
+
ctx.shared.add("pubsub", "events-topic-arn", id, topic.arn);
|
|
5597
|
+
const cacheName = formatGlobalResourceName({
|
|
5598
|
+
appName: ctx.app.name,
|
|
5599
|
+
resourceType: "pubsub-cache",
|
|
5600
|
+
resourceName: id,
|
|
5601
|
+
seperator: "-"
|
|
5602
|
+
});
|
|
5603
|
+
const cacheSecurityGroup = new aws12.security.Group(group, "cache-security", {
|
|
5604
|
+
name: cacheName,
|
|
5605
|
+
vpcId,
|
|
5606
|
+
description: cacheName
|
|
5607
|
+
});
|
|
5608
|
+
const cache = new aws12.elasticache.ServerlessCache(
|
|
5609
|
+
group,
|
|
5610
|
+
"cache",
|
|
5611
|
+
{
|
|
5612
|
+
name: cacheName,
|
|
5613
|
+
engine: "valkey",
|
|
5614
|
+
majorEngineVersion: "8",
|
|
5615
|
+
securityGroupIds: [cacheSecurityGroup.id],
|
|
5616
|
+
subnetIds: ctx.shared.get("vpc", "private-subnets")
|
|
5617
|
+
},
|
|
5618
|
+
{
|
|
5619
|
+
import: ctx.import ? cacheName : void 0
|
|
5620
|
+
}
|
|
5621
|
+
);
|
|
5622
|
+
const redisHost = cache.endpoint.pipe((v) => v.at(0).address);
|
|
5623
|
+
const redisPort = cache.endpoint.pipe((v) => v.at(0).port);
|
|
5624
|
+
new aws12.vpc.SecurityGroupIngressRule(group, "cache-rule-ip-v4", {
|
|
5625
|
+
securityGroupId: cacheSecurityGroup.id,
|
|
5626
|
+
description: redisPort.pipe((port) => `Allow ipv4 on port: ${port}`),
|
|
5627
|
+
ipProtocol: "tcp",
|
|
5628
|
+
cidrIpv4: "0.0.0.0/0",
|
|
5629
|
+
fromPort: redisPort,
|
|
5630
|
+
toPort: redisPort
|
|
5631
|
+
});
|
|
5632
|
+
new aws12.vpc.SecurityGroupIngressRule(group, "cache-rule-ip-v6", {
|
|
5633
|
+
securityGroupId: cacheSecurityGroup.id,
|
|
5634
|
+
description: redisPort.pipe((port) => `Allow ipv6 on port: ${port}`),
|
|
5635
|
+
ipProtocol: "tcp",
|
|
5636
|
+
cidrIpv6: "::/0",
|
|
5637
|
+
fromPort: redisPort,
|
|
5638
|
+
toPort: redisPort
|
|
5639
|
+
});
|
|
5640
|
+
const channel = `pubsub:${id}`;
|
|
5641
|
+
const cloudfrontPrefixList = aws12.ec2.getManagedPrefixList(group, "cloudfront-prefix-list", {
|
|
5642
|
+
name: "com.amazonaws.global.cloudfront.origin-facing"
|
|
5643
|
+
});
|
|
5644
|
+
const lbSecurityGroup = new aws12.security.Group(group, "lb-security", {
|
|
5645
|
+
name: `${name}-lb`,
|
|
5646
|
+
vpcId,
|
|
5647
|
+
description: `${name}-lb`
|
|
5648
|
+
});
|
|
5649
|
+
new aws12.vpc.SecurityGroupIngressRule(group, "lb-ingress", {
|
|
5650
|
+
securityGroupId: lbSecurityGroup.id,
|
|
5651
|
+
description: "Allow http traffic from CloudFront",
|
|
5652
|
+
ipProtocol: "tcp",
|
|
5653
|
+
prefixListId: cloudfrontPrefixList.id,
|
|
5654
|
+
fromPort: 80,
|
|
5655
|
+
toPort: 80
|
|
5656
|
+
});
|
|
5657
|
+
new aws12.vpc.SecurityGroupEgressRule(group, "lb-egress", {
|
|
5658
|
+
securityGroupId: lbSecurityGroup.id,
|
|
5659
|
+
description: "Allow all outbound traffic",
|
|
5660
|
+
ipProtocol: "-1",
|
|
5661
|
+
cidrIpv4: "0.0.0.0/0"
|
|
5662
|
+
});
|
|
5663
|
+
const taskSecurityGroup = new aws12.security.Group(group, "task-security", {
|
|
5664
|
+
name: `${name}-task`,
|
|
5665
|
+
vpcId,
|
|
5666
|
+
description: `${name}-task`
|
|
5667
|
+
});
|
|
5668
|
+
new aws12.vpc.SecurityGroupIngressRule(group, "task-ingress", {
|
|
5669
|
+
securityGroupId: taskSecurityGroup.id,
|
|
5670
|
+
description: "Allow websocket traffic from the load balancer",
|
|
5671
|
+
ipProtocol: "tcp",
|
|
5672
|
+
referencedSecurityGroupId: lbSecurityGroup.id,
|
|
5673
|
+
fromPort: WS_PORT,
|
|
5674
|
+
toPort: WS_PORT
|
|
5675
|
+
});
|
|
5676
|
+
new aws12.vpc.SecurityGroupEgressRule(group, "task-egress", {
|
|
5677
|
+
securityGroupId: taskSecurityGroup.id,
|
|
5678
|
+
description: "Allow all outbound traffic",
|
|
5679
|
+
ipProtocol: "-1",
|
|
5680
|
+
cidrIpv4: "0.0.0.0/0"
|
|
5681
|
+
});
|
|
5682
|
+
const lb = new aws12.Lb(group, "lb", {
|
|
5683
|
+
name: shortId(`${name}:lb:${ctx.appId}`),
|
|
5684
|
+
internal: false,
|
|
5685
|
+
loadBalancerType: "application",
|
|
5686
|
+
subnets: ctx.shared.get("vpc", "public-subnets"),
|
|
5687
|
+
securityGroups: [lbSecurityGroup.id],
|
|
5688
|
+
idleTimeout: 120
|
|
5689
|
+
});
|
|
5690
|
+
const targetGroup = new aws12.lb.TargetGroup(group, "target", {
|
|
5691
|
+
name: shortId(`${name}:target:${ctx.appId}`),
|
|
5692
|
+
targetType: "ip",
|
|
5693
|
+
port: WS_PORT,
|
|
5694
|
+
protocol: "HTTP",
|
|
5695
|
+
vpcId,
|
|
5696
|
+
deregistrationDelay: "30",
|
|
5697
|
+
healthCheck: {
|
|
5698
|
+
enabled: true,
|
|
5699
|
+
path: "/health",
|
|
5700
|
+
interval: 10,
|
|
5701
|
+
timeout: 5,
|
|
5702
|
+
healthyThreshold: 2,
|
|
5703
|
+
unhealthyThreshold: 2,
|
|
5704
|
+
matcher: "200"
|
|
5705
|
+
}
|
|
5706
|
+
});
|
|
5707
|
+
new aws12.lb.Listener(group, "listener", {
|
|
5708
|
+
loadBalancerArn: lb.arn,
|
|
5709
|
+
port: 80,
|
|
5710
|
+
protocol: "HTTP",
|
|
5711
|
+
defaultAction: [
|
|
5712
|
+
{
|
|
5713
|
+
type: "forward",
|
|
5714
|
+
targetGroupArn: targetGroup.arn
|
|
5715
|
+
}
|
|
5716
|
+
]
|
|
5101
5717
|
});
|
|
5102
|
-
ctx.
|
|
5103
|
-
const
|
|
5104
|
-
|
|
5718
|
+
const secret = createHmac2("sha1", ctx.appId).update(name).digest("hex");
|
|
5719
|
+
const service = createPubSubService(group, ctx, id, props, {
|
|
5720
|
+
clusterName: cluster.name,
|
|
5721
|
+
clusterArn: cluster.arn,
|
|
5722
|
+
targetGroupArn: targetGroup.arn,
|
|
5723
|
+
securityGroupId: taskSecurityGroup.id,
|
|
5724
|
+
environment: {
|
|
5725
|
+
AUTH: auth2.name,
|
|
5726
|
+
EVENTS_TOPIC: topicName,
|
|
5727
|
+
PORT: WS_PORT.toString(),
|
|
5728
|
+
REDIS_HOST: redisHost,
|
|
5729
|
+
REDIS_PORT: redisPort.pipe((port) => port.toString()),
|
|
5730
|
+
CHANNEL: channel,
|
|
5731
|
+
ORIGIN_SECRET: secret
|
|
5732
|
+
}
|
|
5733
|
+
});
|
|
5734
|
+
service.addPermission(
|
|
5735
|
+
{
|
|
5736
|
+
actions: ["lambda:InvokeFunction"],
|
|
5737
|
+
resources: [auth2.lambda.arn]
|
|
5738
|
+
},
|
|
5739
|
+
{
|
|
5740
|
+
actions: ["sns:Publish"],
|
|
5741
|
+
resources: [topic.arn]
|
|
5742
|
+
}
|
|
5743
|
+
);
|
|
5744
|
+
const publisher = createPrebuildLambdaFunction(group, ctx, "pubsub-publisher", id, {
|
|
5745
|
+
bundleFile: join14(__dirname3, "/prebuild/pubsub-publisher/bundle.zip"),
|
|
5746
|
+
bundleHash: join14(__dirname3, "/prebuild/pubsub-publisher/HASH"),
|
|
5747
|
+
memorySize: mebibytes5(256),
|
|
5748
|
+
timeout: seconds7(10),
|
|
5749
|
+
handler: "index.default",
|
|
5750
|
+
runtime: "nodejs24.x",
|
|
5751
|
+
vpc: true,
|
|
5752
|
+
log: props.log
|
|
5105
5753
|
});
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
records: [endpoint.endpointAddress]
|
|
5123
|
-
});
|
|
5124
|
-
ctx.bind(`PUBSUB_${constantCase5(id)}_ENDPOINT`, domainName);
|
|
5125
|
-
} else {
|
|
5126
|
-
ctx.bind(`PUBSUB_${constantCase5(id)}_ENDPOINT`, endpoint.endpointAddress);
|
|
5754
|
+
publisher.setEnvironment("REDIS_HOST", redisHost);
|
|
5755
|
+
publisher.setEnvironment(
|
|
5756
|
+
"REDIS_PORT",
|
|
5757
|
+
redisPort.pipe((port) => port.toString())
|
|
5758
|
+
);
|
|
5759
|
+
publisher.setEnvironment("CHANNEL", channel);
|
|
5760
|
+
ctx.addGlobalPermission({
|
|
5761
|
+
actions: ["lambda:InvokeFunction"],
|
|
5762
|
+
resources: [publisher.lambda.arn]
|
|
5763
|
+
});
|
|
5764
|
+
const routerProps = ctx.appConfig.defaults.router?.[props.router];
|
|
5765
|
+
if (!routerProps?.domain) {
|
|
5766
|
+
throw new FileError(
|
|
5767
|
+
"app.json",
|
|
5768
|
+
`The pubsub "${id}" requires the "${props.router}" router to have a domain configured.`
|
|
5769
|
+
);
|
|
5127
5770
|
}
|
|
5771
|
+
const addRoutes = ctx.shared.entry("router", "addRoutes", props.router);
|
|
5772
|
+
addRoutes(group, `pubsub-${id}`, {
|
|
5773
|
+
[`${props.path}/*`]: {
|
|
5774
|
+
type: "url",
|
|
5775
|
+
domainName: lb.dnsName,
|
|
5776
|
+
readTimeout: 60,
|
|
5777
|
+
customHeaders: {
|
|
5778
|
+
"x-origin-secret": secret
|
|
5779
|
+
},
|
|
5780
|
+
rewrite: {
|
|
5781
|
+
regex: `^${props.path}/(.*)$`,
|
|
5782
|
+
to: "/$1"
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
});
|
|
5786
|
+
const domainName = formatFullDomainName(ctx.appConfig, routerProps.domain, routerProps.subDomain);
|
|
5787
|
+
ctx.bind(`PUBSUB_${constantCase5(id)}_ENDPOINT`, `wss://${domainName}${props.path}/ws`);
|
|
5788
|
+
ctx.bind(`PUBSUB_${constantCase5(id)}_PUBLISHER`, publisher.name);
|
|
5128
5789
|
}
|
|
5129
5790
|
},
|
|
5130
5791
|
onStack(ctx) {
|
|
5131
5792
|
for (const [id, props] of Object.entries(ctx.stackConfig.pubsub ?? {})) {
|
|
5132
|
-
const group = new
|
|
5133
|
-
const
|
|
5134
|
-
const
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5793
|
+
const group = new Group11(ctx.stack, "pubsub", id);
|
|
5794
|
+
const topicArn = ctx.shared.entry("pubsub", "events-topic-arn", id);
|
|
5795
|
+
for (const event of pubsubEventTypes) {
|
|
5796
|
+
const consumer = props[event];
|
|
5797
|
+
if (!consumer) {
|
|
5798
|
+
continue;
|
|
5799
|
+
}
|
|
5800
|
+
const eventGroup = new Group11(group, "event", event);
|
|
5801
|
+
const { lambda } = createAsyncLambdaFunction(eventGroup, ctx, `pubsub`, `${id}-${event}`, {
|
|
5802
|
+
consumer,
|
|
5803
|
+
retryAttempts: 2
|
|
5804
|
+
});
|
|
5805
|
+
new aws12.sns.TopicSubscription(eventGroup, "subscription", {
|
|
5806
|
+
topicArn,
|
|
5807
|
+
protocol: "lambda",
|
|
5808
|
+
endpoint: lambda.arn,
|
|
5809
|
+
filterPolicyScope: "MessageAttributes",
|
|
5810
|
+
filterPolicy: JSON.stringify({
|
|
5811
|
+
event: [event]
|
|
5812
|
+
})
|
|
5813
|
+
});
|
|
5814
|
+
new aws12.lambda.Permission(eventGroup, "permission", {
|
|
5815
|
+
action: "lambda:InvokeFunction",
|
|
5816
|
+
principal: "sns.amazonaws.com",
|
|
5817
|
+
functionName: lambda.functionName,
|
|
5818
|
+
sourceArn: topicArn
|
|
5819
|
+
});
|
|
5820
|
+
}
|
|
5153
5821
|
}
|
|
5154
5822
|
}
|
|
5155
5823
|
});
|
|
5156
5824
|
|
|
5157
5825
|
// src/feature/queue/index.ts
|
|
5158
|
-
import { Group as
|
|
5159
|
-
import { aws as
|
|
5826
|
+
import { Group as Group12 } from "@terraforge/core";
|
|
5827
|
+
import { aws as aws13 } from "@terraforge/aws";
|
|
5160
5828
|
import { camelCase as camelCase5, constantCase as constantCase6 } from "change-case";
|
|
5161
5829
|
import deepmerge3 from "deepmerge";
|
|
5162
5830
|
import { relative as relative5 } from "path";
|
|
5163
|
-
import { seconds as
|
|
5831
|
+
import { seconds as seconds8, toSeconds as toSeconds5 } from "@awsless/duration";
|
|
5164
5832
|
import { toBytes } from "@awsless/size";
|
|
5165
|
-
var
|
|
5833
|
+
var typeGenCode5 = `
|
|
5166
5834
|
import {
|
|
5167
5835
|
SendMessageOptions,
|
|
5168
5836
|
SendMessageBatchOptions,
|
|
@@ -5220,7 +5888,7 @@ var queueFeature = defineFeature({
|
|
|
5220
5888
|
resources2.addType(stack.name, resource);
|
|
5221
5889
|
mockResponses.addType(stack.name, mockResponse);
|
|
5222
5890
|
}
|
|
5223
|
-
gen.addCode(
|
|
5891
|
+
gen.addCode(typeGenCode5);
|
|
5224
5892
|
gen.addInterface("QueueResources", resources2);
|
|
5225
5893
|
gen.addInterface("QueueMock", mocks);
|
|
5226
5894
|
gen.addInterface("QueueMockResponse", mockResponses);
|
|
@@ -5229,18 +5897,18 @@ var queueFeature = defineFeature({
|
|
|
5229
5897
|
onStack(ctx) {
|
|
5230
5898
|
for (const [id, local] of Object.entries(ctx.stackConfig.queues || {})) {
|
|
5231
5899
|
const props = deepmerge3(ctx.appConfig.defaults.queue, typeof local === "object" ? local : {});
|
|
5232
|
-
const group = new
|
|
5900
|
+
const group = new Group12(ctx.stack, "queue", id);
|
|
5233
5901
|
const baseName = formatLocalResourceName({
|
|
5234
5902
|
appName: ctx.app.name,
|
|
5235
5903
|
stackName: ctx.stack.name,
|
|
5236
5904
|
resourceType: "queue",
|
|
5237
5905
|
resourceName: id
|
|
5238
5906
|
});
|
|
5239
|
-
const queue2 = new
|
|
5907
|
+
const queue2 = new aws13.sqs.Queue(group, "queue", {
|
|
5240
5908
|
name: `${baseName}.fifo`,
|
|
5241
|
-
visibilityTimeoutSeconds:
|
|
5242
|
-
receiveWaitTimeSeconds:
|
|
5243
|
-
messageRetentionSeconds:
|
|
5909
|
+
visibilityTimeoutSeconds: toSeconds5(props.visibilityTimeout),
|
|
5910
|
+
receiveWaitTimeSeconds: toSeconds5(props.receiveMessageWaitTime ?? seconds8(0)),
|
|
5911
|
+
messageRetentionSeconds: toSeconds5(props.retentionPeriod),
|
|
5244
5912
|
maxMessageSize: toBytes(props.maxMessageSize),
|
|
5245
5913
|
fifoQueue: true,
|
|
5246
5914
|
deduplicationScope: "messageGroup",
|
|
@@ -5255,7 +5923,7 @@ var queueFeature = defineFeature({
|
|
|
5255
5923
|
if (local.consumer) {
|
|
5256
5924
|
const lambdaConsumer = createLambdaFunction(group, ctx, `queue`, id, local.consumer);
|
|
5257
5925
|
lambdaConsumer.setEnvironment("THROW_EXPECTED_ERRORS", "1");
|
|
5258
|
-
new
|
|
5926
|
+
new aws13.lambda.EventSourceMapping(
|
|
5259
5927
|
group,
|
|
5260
5928
|
"event",
|
|
5261
5929
|
{
|
|
@@ -5289,24 +5957,24 @@ var queueFeature = defineFeature({
|
|
|
5289
5957
|
});
|
|
5290
5958
|
|
|
5291
5959
|
// src/feature/rest/index.ts
|
|
5292
|
-
import { Group as
|
|
5293
|
-
import { aws as
|
|
5960
|
+
import { Group as Group13 } from "@terraforge/core";
|
|
5961
|
+
import { aws as aws14 } from "@terraforge/aws";
|
|
5294
5962
|
import { constantCase as constantCase7 } from "change-case";
|
|
5295
5963
|
var restFeature = defineFeature({
|
|
5296
5964
|
name: "rest",
|
|
5297
5965
|
onApp(ctx) {
|
|
5298
5966
|
for (const [id, props] of Object.entries(ctx.appConfig.defaults?.rest ?? {})) {
|
|
5299
|
-
const group = new
|
|
5967
|
+
const group = new Group13(ctx.base, "rest", id);
|
|
5300
5968
|
const name = formatGlobalResourceName({
|
|
5301
5969
|
appName: ctx.app.name,
|
|
5302
5970
|
resourceType: "rest",
|
|
5303
5971
|
resourceName: id
|
|
5304
5972
|
});
|
|
5305
|
-
const api = new
|
|
5973
|
+
const api = new aws14.apigatewayv2.Api(group, "api", {
|
|
5306
5974
|
name,
|
|
5307
5975
|
protocolType: "HTTP"
|
|
5308
5976
|
});
|
|
5309
|
-
const stage = new
|
|
5977
|
+
const stage = new aws14.apigatewayv2.Stage(group, "stage", {
|
|
5310
5978
|
name: "v1",
|
|
5311
5979
|
apiId: api.id,
|
|
5312
5980
|
autoDeploy: true
|
|
@@ -5316,7 +5984,7 @@ var restFeature = defineFeature({
|
|
|
5316
5984
|
const domainName = formatFullDomainName(ctx.appConfig, props.domain, props.subDomain);
|
|
5317
5985
|
const zoneId = ctx.shared.entry("domain", `zone-id`, props.domain);
|
|
5318
5986
|
const certificateArn = ctx.shared.entry("domain", `certificate-arn`, props.domain);
|
|
5319
|
-
const domain2 = new
|
|
5987
|
+
const domain2 = new aws14.apigatewayv2.DomainName(group, "domain", {
|
|
5320
5988
|
domainName,
|
|
5321
5989
|
domainNameConfiguration: {
|
|
5322
5990
|
certificateArn,
|
|
@@ -5324,12 +5992,12 @@ var restFeature = defineFeature({
|
|
|
5324
5992
|
securityPolicy: "TLS_1_2"
|
|
5325
5993
|
}
|
|
5326
5994
|
});
|
|
5327
|
-
const mapping = new
|
|
5995
|
+
const mapping = new aws14.apigatewayv2.ApiMapping(group, "mapping", {
|
|
5328
5996
|
apiId: api.id,
|
|
5329
5997
|
domainName: domain2.domainName,
|
|
5330
5998
|
stage: stage.name
|
|
5331
5999
|
});
|
|
5332
|
-
new
|
|
6000
|
+
new aws14.route53.Record(
|
|
5333
6001
|
group,
|
|
5334
6002
|
"record",
|
|
5335
6003
|
{
|
|
@@ -5357,21 +6025,21 @@ var restFeature = defineFeature({
|
|
|
5357
6025
|
},
|
|
5358
6026
|
onStack(ctx) {
|
|
5359
6027
|
for (const [id, routes] of Object.entries(ctx.stackConfig.rest ?? {})) {
|
|
5360
|
-
const restGroup = new
|
|
6028
|
+
const restGroup = new Group13(ctx.stack, "rest", id);
|
|
5361
6029
|
for (const [routeKey, props] of Object.entries(routes)) {
|
|
5362
|
-
const group = new
|
|
6030
|
+
const group = new Group13(restGroup, "route", routeKey);
|
|
5363
6031
|
const apiId = ctx.shared.entry("rest", "id", id);
|
|
5364
6032
|
const routeId = shortId(routeKey);
|
|
5365
6033
|
const { lambda } = createLambdaFunction(group, ctx, "rest", `${id}-${routeId}`, {
|
|
5366
6034
|
...props,
|
|
5367
6035
|
description: `${id} ${routeKey}`
|
|
5368
6036
|
});
|
|
5369
|
-
const permission = new
|
|
6037
|
+
const permission = new aws14.lambda.Permission(group, "permission", {
|
|
5370
6038
|
action: "lambda:InvokeFunction",
|
|
5371
6039
|
principal: "apigateway.amazonaws.com",
|
|
5372
6040
|
functionName: lambda.functionName
|
|
5373
6041
|
});
|
|
5374
|
-
const integration = new
|
|
6042
|
+
const integration = new aws14.apigatewayv2.Integration(group, "integration", {
|
|
5375
6043
|
apiId,
|
|
5376
6044
|
description: `${id} ${routeKey}`,
|
|
5377
6045
|
integrationType: "AWS_PROXY",
|
|
@@ -5381,7 +6049,7 @@ var restFeature = defineFeature({
|
|
|
5381
6049
|
return `arn:aws:apigateway:${ctx.appConfig.region}:lambda:path/2015-03-31/functions/${arn}/invocations`;
|
|
5382
6050
|
})
|
|
5383
6051
|
});
|
|
5384
|
-
new
|
|
6052
|
+
new aws14.apigatewayv2.Route(
|
|
5385
6053
|
group,
|
|
5386
6054
|
"route",
|
|
5387
6055
|
{
|
|
@@ -5400,13 +6068,13 @@ var restFeature = defineFeature({
|
|
|
5400
6068
|
|
|
5401
6069
|
// src/feature/rpc/index.ts
|
|
5402
6070
|
import { camelCase as camelCase6, constantCase as constantCase8, kebabCase as kebabCase6 } from "change-case";
|
|
5403
|
-
import { Group as
|
|
5404
|
-
import { aws as
|
|
5405
|
-
import { mebibytes as
|
|
5406
|
-
import { dirname as
|
|
5407
|
-
import { fileURLToPath } from "url";
|
|
5408
|
-
import { toSeconds as
|
|
5409
|
-
var
|
|
6071
|
+
import { Group as Group14 } from "@terraforge/core";
|
|
6072
|
+
import { aws as aws15 } from "@terraforge/aws";
|
|
6073
|
+
import { mebibytes as mebibytes6 } from "@awsless/size";
|
|
6074
|
+
import { dirname as dirname7, join as join15, relative as relative6 } from "path";
|
|
6075
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6076
|
+
import { toSeconds as toSeconds6 } from "@awsless/duration";
|
|
6077
|
+
var __dirname4 = dirname7(fileURLToPath3(import.meta.url));
|
|
5410
6078
|
var rpcFeature = defineFeature({
|
|
5411
6079
|
name: "rpc",
|
|
5412
6080
|
async onTypeGen(ctx) {
|
|
@@ -5450,8 +6118,8 @@ var rpcFeature = defineFeature({
|
|
|
5450
6118
|
} else {
|
|
5451
6119
|
list3.add(name);
|
|
5452
6120
|
}
|
|
5453
|
-
const timeout =
|
|
5454
|
-
const maxTimeout =
|
|
6121
|
+
const timeout = toSeconds6(props.function.timeout ?? ctx.appConfig.defaults.function.timeout);
|
|
6122
|
+
const maxTimeout = toSeconds6(ctx.appConfig.defaults.rpc[id].timeout) * 0.8;
|
|
5455
6123
|
if (timeout > maxTimeout) {
|
|
5456
6124
|
throw new FileError(
|
|
5457
6125
|
stack.file,
|
|
@@ -5464,19 +6132,19 @@ var rpcFeature = defineFeature({
|
|
|
5464
6132
|
},
|
|
5465
6133
|
onApp(ctx) {
|
|
5466
6134
|
for (const [id, props] of Object.entries(ctx.appConfig.defaults.rpc ?? {})) {
|
|
5467
|
-
const group = new
|
|
6135
|
+
const group = new Group14(ctx.base, "rpc", id);
|
|
5468
6136
|
const result = createPrebuildLambdaFunction(group, ctx, "rpc", id, {
|
|
5469
|
-
bundleFile:
|
|
5470
|
-
bundleHash:
|
|
5471
|
-
memorySize:
|
|
6137
|
+
bundleFile: join15(__dirname4, "/prebuild/rpc/bundle.zip"),
|
|
6138
|
+
bundleHash: join15(__dirname4, "/prebuild/rpc/HASH"),
|
|
6139
|
+
memorySize: mebibytes6(256),
|
|
5472
6140
|
timeout: props.timeout,
|
|
5473
6141
|
handler: "index.default",
|
|
5474
6142
|
runtime: "nodejs24.x",
|
|
5475
6143
|
warm: 3,
|
|
5476
6144
|
log: props.log
|
|
5477
6145
|
});
|
|
5478
|
-
result.setEnvironment("TIMEOUT",
|
|
5479
|
-
const schemaTable = new
|
|
6146
|
+
result.setEnvironment("TIMEOUT", toSeconds6(props.timeout).toString());
|
|
6147
|
+
const schemaTable = new aws15.dynamodb.Table(group, "schema", {
|
|
5480
6148
|
name: formatGlobalResourceName({
|
|
5481
6149
|
appName: ctx.app.name,
|
|
5482
6150
|
resourceType: "rpc-schema",
|
|
@@ -5498,7 +6166,7 @@ var rpcFeature = defineFeature({
|
|
|
5498
6166
|
resources: [schemaTable.arn]
|
|
5499
6167
|
});
|
|
5500
6168
|
ctx.shared.add("rpc", `schema-table`, id, schemaTable);
|
|
5501
|
-
const lockTable = new
|
|
6169
|
+
const lockTable = new aws15.dynamodb.Table(group, "lock", {
|
|
5502
6170
|
name: formatGlobalResourceName({
|
|
5503
6171
|
appName: ctx.app.name,
|
|
5504
6172
|
resourceType: "rpc-lock",
|
|
@@ -5524,7 +6192,7 @@ var rpcFeature = defineFeature({
|
|
|
5524
6192
|
resources: [lockTable.arn]
|
|
5525
6193
|
});
|
|
5526
6194
|
if (props.auth) {
|
|
5527
|
-
const authGroup = new
|
|
6195
|
+
const authGroup = new Group14(group, "auth", "authorizer");
|
|
5528
6196
|
const auth2 = createLambdaFunction(authGroup, ctx, "rpc", `${id}-auth`, props.auth);
|
|
5529
6197
|
result.setEnvironment("AUTH", auth2.name);
|
|
5530
6198
|
for (const [authId, userPoolId] of ctx.shared.list("auth", "user-pool-id")) {
|
|
@@ -5543,14 +6211,14 @@ var rpcFeature = defineFeature({
|
|
|
5543
6211
|
imageUri: result.lambda.imageUri
|
|
5544
6212
|
});
|
|
5545
6213
|
}
|
|
5546
|
-
const permission = new
|
|
6214
|
+
const permission = new aws15.lambda.Permission(group, "permission", {
|
|
5547
6215
|
principal: "cloudfront.amazonaws.com",
|
|
5548
6216
|
action: "lambda:InvokeFunctionUrl",
|
|
5549
6217
|
functionName: result.lambda.functionName,
|
|
5550
6218
|
functionUrlAuthType: "AWS_IAM",
|
|
5551
6219
|
sourceArn: `arn:aws:cloudfront::${ctx.accountId}:distribution/*`
|
|
5552
6220
|
});
|
|
5553
|
-
const url = new
|
|
6221
|
+
const url = new aws15.lambda.FunctionUrl(
|
|
5554
6222
|
group,
|
|
5555
6223
|
"url",
|
|
5556
6224
|
{
|
|
@@ -5585,15 +6253,15 @@ var rpcFeature = defineFeature({
|
|
|
5585
6253
|
throw new FileError(ctx.stackConfig.file, `RPC definition is not defined on app level for "${id}"`);
|
|
5586
6254
|
}
|
|
5587
6255
|
const table = ctx.shared.entry("rpc", "schema-table", id);
|
|
5588
|
-
const group = new
|
|
6256
|
+
const group = new Group14(ctx.stack, "rpc", id);
|
|
5589
6257
|
for (const [name, props] of Object.entries(queries ?? {})) {
|
|
5590
|
-
const queryGroup = new
|
|
6258
|
+
const queryGroup = new Group14(group, "query", name);
|
|
5591
6259
|
const entryId = kebabCase6(`${id}-${shortId(name)}`);
|
|
5592
6260
|
createLambdaFunction(queryGroup, ctx, `rpc`, entryId, {
|
|
5593
6261
|
...props.function,
|
|
5594
6262
|
description: `${id} ${name}`
|
|
5595
6263
|
});
|
|
5596
|
-
new
|
|
6264
|
+
new aws15.dynamodb.TableItem(queryGroup, "query", {
|
|
5597
6265
|
tableName: table.name,
|
|
5598
6266
|
hashKey: table.hashKey,
|
|
5599
6267
|
rangeKey: table.rangeKey,
|
|
@@ -5625,11 +6293,11 @@ var rpcFeature = defineFeature({
|
|
|
5625
6293
|
});
|
|
5626
6294
|
|
|
5627
6295
|
// src/feature/search/index.ts
|
|
5628
|
-
import { Group as
|
|
5629
|
-
import { aws as
|
|
6296
|
+
import { Group as Group15 } from "@terraforge/core";
|
|
6297
|
+
import { aws as aws16 } from "@terraforge/aws";
|
|
5630
6298
|
import { constantCase as constantCase9 } from "change-case";
|
|
5631
6299
|
import { toGibibytes as toGibibytes2 } from "@awsless/size";
|
|
5632
|
-
var
|
|
6300
|
+
var typeGenCode6 = `
|
|
5633
6301
|
import { AnyStruct, Table } from '@awsless/open-search'
|
|
5634
6302
|
|
|
5635
6303
|
type Search = {
|
|
@@ -5649,15 +6317,15 @@ var searchFeature = defineFeature({
|
|
|
5649
6317
|
}
|
|
5650
6318
|
resources2.addType(stack.name, list3);
|
|
5651
6319
|
}
|
|
5652
|
-
gen.addCode(
|
|
6320
|
+
gen.addCode(typeGenCode6);
|
|
5653
6321
|
gen.addInterface("SearchResources", resources2);
|
|
5654
6322
|
await ctx.write("search.d.ts", gen, true);
|
|
5655
6323
|
},
|
|
5656
6324
|
onStack(ctx) {
|
|
5657
6325
|
for (const [id, props] of Object.entries(ctx.stackConfig.searchs ?? {})) {
|
|
5658
|
-
const group = new
|
|
6326
|
+
const group = new Group15(ctx.stack, "search", id);
|
|
5659
6327
|
const name = `${ctx.app.name}-${shortId([ctx.app.name, ctx.stack.name, "search", id].join("--"))}`;
|
|
5660
|
-
const openSearch = new
|
|
6328
|
+
const openSearch = new aws16.opensearch.Domain(
|
|
5661
6329
|
group,
|
|
5662
6330
|
"domain",
|
|
5663
6331
|
{
|
|
@@ -5732,10 +6400,10 @@ var searchFeature = defineFeature({
|
|
|
5732
6400
|
});
|
|
5733
6401
|
|
|
5734
6402
|
// src/feature/site/index.ts
|
|
5735
|
-
import { Group as
|
|
5736
|
-
import { aws as
|
|
6403
|
+
import { Group as Group16 } from "@terraforge/core";
|
|
6404
|
+
import { aws as aws17 } from "@terraforge/aws";
|
|
5737
6405
|
import { glob as glob2 } from "glob";
|
|
5738
|
-
import { dirname as
|
|
6406
|
+
import { dirname as dirname8, join as join16 } from "path";
|
|
5739
6407
|
|
|
5740
6408
|
// src/feature/site/util.ts
|
|
5741
6409
|
import { contentType, lookup } from "mime-types";
|
|
@@ -5763,7 +6431,7 @@ var siteFeature = defineFeature({
|
|
|
5763
6431
|
name: "site",
|
|
5764
6432
|
onStack(ctx) {
|
|
5765
6433
|
for (const [id, props] of Object.entries(ctx.stackConfig.sites ?? {})) {
|
|
5766
|
-
const group = new
|
|
6434
|
+
const group = new Group16(ctx.stack, "site", id);
|
|
5767
6435
|
const name = formatLocalResourceName({
|
|
5768
6436
|
appName: ctx.app.name,
|
|
5769
6437
|
stackName: ctx.stack.name,
|
|
@@ -5781,7 +6449,7 @@ var siteFeature = defineFeature({
|
|
|
5781
6449
|
return build3(fingerprint, async (write) => {
|
|
5782
6450
|
const credentialProvider = await getCredentials(ctx.appConfig.profile);
|
|
5783
6451
|
const credentials = await credentialProvider();
|
|
5784
|
-
const cwd =
|
|
6452
|
+
const cwd = join16(directories.root, dirname8(ctx.stackConfig.file));
|
|
5785
6453
|
const env = {
|
|
5786
6454
|
...process.env,
|
|
5787
6455
|
// Pass the app config name
|
|
@@ -5828,14 +6496,14 @@ var siteFeature = defineFeature({
|
|
|
5828
6496
|
ctx.onBind((name2, value) => {
|
|
5829
6497
|
result.setEnvironment(name2, value);
|
|
5830
6498
|
});
|
|
5831
|
-
new
|
|
6499
|
+
new aws17.lambda.Permission(group, "ssr-permission", {
|
|
5832
6500
|
principal: "cloudfront.amazonaws.com",
|
|
5833
6501
|
action: "lambda:InvokeFunctionUrl",
|
|
5834
6502
|
functionName: result.lambda.functionName,
|
|
5835
6503
|
functionUrlAuthType: "AWS_IAM",
|
|
5836
6504
|
sourceArn: `arn:aws:cloudfront::${ctx.accountId}:distribution/*`
|
|
5837
6505
|
});
|
|
5838
|
-
const functionUrl = new
|
|
6506
|
+
const functionUrl = new aws17.lambda.FunctionUrl(group, "url", {
|
|
5839
6507
|
functionName: result.lambda.functionName,
|
|
5840
6508
|
authorizationType: "AWS_IAM"
|
|
5841
6509
|
});
|
|
@@ -5849,7 +6517,7 @@ var siteFeature = defineFeature({
|
|
|
5849
6517
|
});
|
|
5850
6518
|
}
|
|
5851
6519
|
if (props.static) {
|
|
5852
|
-
const bucket = new
|
|
6520
|
+
const bucket = new aws17.s3.Bucket(group, "bucket", {
|
|
5853
6521
|
bucket: formatLocalResourceName({
|
|
5854
6522
|
appName: ctx.app.name,
|
|
5855
6523
|
stackName: ctx.stack.name,
|
|
@@ -5871,7 +6539,7 @@ var siteFeature = defineFeature({
|
|
|
5871
6539
|
}
|
|
5872
6540
|
]
|
|
5873
6541
|
});
|
|
5874
|
-
new
|
|
6542
|
+
new aws17.s3.BucketPolicy(
|
|
5875
6543
|
group,
|
|
5876
6544
|
`policy`,
|
|
5877
6545
|
{
|
|
@@ -5926,20 +6594,20 @@ var siteFeature = defineFeature({
|
|
|
5926
6594
|
});
|
|
5927
6595
|
const staticRoutes = {};
|
|
5928
6596
|
for (const file of files) {
|
|
5929
|
-
const prefixedFile =
|
|
5930
|
-
const object = new
|
|
6597
|
+
const prefixedFile = join16("/", file);
|
|
6598
|
+
const object = new aws17.s3.BucketObject(group, prefixedFile, {
|
|
5931
6599
|
bucket: bucket.bucket,
|
|
5932
6600
|
key: prefixedFile,
|
|
5933
6601
|
cacheControl: getCacheControl(file),
|
|
5934
6602
|
contentType: getContentType(file),
|
|
5935
|
-
source:
|
|
5936
|
-
sourceHash: $hash(
|
|
6603
|
+
source: join16(props.static, file),
|
|
6604
|
+
sourceHash: $hash(join16(props.static, file))
|
|
5937
6605
|
});
|
|
5938
6606
|
versions.push(object.key);
|
|
5939
6607
|
versions.push(object.sourceHash);
|
|
5940
6608
|
const strippedHtmlFile = file.endsWith("index.html") ? file.slice(0, -11) : file.endsWith(".html") ? file.slice(0, -5) : file;
|
|
5941
6609
|
const urlFriendlyFile = strippedHtmlFile.endsWith("/") ? strippedHtmlFile.slice(0, -1) : strippedHtmlFile;
|
|
5942
|
-
const routeFileKey =
|
|
6610
|
+
const routeFileKey = join16(props.path, urlFriendlyFile);
|
|
5943
6611
|
staticRoutes[routeFileKey] = {
|
|
5944
6612
|
type: "s3",
|
|
5945
6613
|
domainName: bucket.bucketRegionalDomainName,
|
|
@@ -5956,10 +6624,10 @@ var siteFeature = defineFeature({
|
|
|
5956
6624
|
});
|
|
5957
6625
|
|
|
5958
6626
|
// src/feature/store/index.ts
|
|
5959
|
-
import { Group as
|
|
5960
|
-
import { toDays as
|
|
6627
|
+
import { Group as Group17 } from "@terraforge/core";
|
|
6628
|
+
import { toDays as toDays8 } from "@awsless/duration";
|
|
5961
6629
|
import { kebabCase as kebabCase7 } from "change-case";
|
|
5962
|
-
import { aws as
|
|
6630
|
+
import { aws as aws18 } from "@terraforge/aws";
|
|
5963
6631
|
import { glob as glob3 } from "glob";
|
|
5964
6632
|
|
|
5965
6633
|
// src/feature/store/util.ts
|
|
@@ -5983,8 +6651,8 @@ var getContentType2 = (file) => {
|
|
|
5983
6651
|
};
|
|
5984
6652
|
|
|
5985
6653
|
// src/feature/store/index.ts
|
|
5986
|
-
import { join as
|
|
5987
|
-
var
|
|
6654
|
+
import { join as join17 } from "path";
|
|
6655
|
+
var typeGenCode7 = `
|
|
5988
6656
|
import { Body, PutObjectProps, BodyStream } from '@awsless/s3'
|
|
5989
6657
|
|
|
5990
6658
|
type Store<Name extends string> = {
|
|
@@ -6013,7 +6681,7 @@ var storeFeature = defineFeature({
|
|
|
6013
6681
|
}
|
|
6014
6682
|
resources2.addType(stack.name, list3);
|
|
6015
6683
|
}
|
|
6016
|
-
gen.addCode(
|
|
6684
|
+
gen.addCode(typeGenCode7);
|
|
6017
6685
|
gen.addInterface("StoreResources", resources2);
|
|
6018
6686
|
await ctx.write("store.d.ts", gen, true);
|
|
6019
6687
|
},
|
|
@@ -6051,7 +6719,7 @@ var storeFeature = defineFeature({
|
|
|
6051
6719
|
},
|
|
6052
6720
|
onStack(ctx) {
|
|
6053
6721
|
for (const [id, props] of Object.entries(ctx.stackConfig.stores ?? {})) {
|
|
6054
|
-
const group = new
|
|
6722
|
+
const group = new Group17(ctx.stack, "store", id);
|
|
6055
6723
|
const name = formatLocalResourceName({
|
|
6056
6724
|
appName: ctx.app.name,
|
|
6057
6725
|
stackName: ctx.stack.name,
|
|
@@ -6063,9 +6731,9 @@ var storeFeature = defineFeature({
|
|
|
6063
6731
|
id: rule.prefix ? `expire-${kebabCase7(rule.prefix)}` : `expire-rule-${index}`,
|
|
6064
6732
|
enabled: true,
|
|
6065
6733
|
...rule.prefix ? { prefix: rule.prefix } : {},
|
|
6066
|
-
expiration: { days:
|
|
6734
|
+
expiration: { days: toDays8(rule.expiration) }
|
|
6067
6735
|
}));
|
|
6068
|
-
const bucket = new
|
|
6736
|
+
const bucket = new aws18.s3.Bucket(
|
|
6069
6737
|
group,
|
|
6070
6738
|
"store",
|
|
6071
6739
|
{
|
|
@@ -6097,13 +6765,13 @@ var storeFeature = defineFeature({
|
|
|
6097
6765
|
nodir: true
|
|
6098
6766
|
});
|
|
6099
6767
|
for (const file of files) {
|
|
6100
|
-
new
|
|
6768
|
+
new aws18.s3.BucketObject(group, file, {
|
|
6101
6769
|
bucket: bucket.bucket,
|
|
6102
6770
|
key: file,
|
|
6103
6771
|
cacheControl: getCacheControl2(file),
|
|
6104
6772
|
contentType: getContentType2(file),
|
|
6105
|
-
source:
|
|
6106
|
-
sourceHash: $hash(
|
|
6773
|
+
source: join17(props.static, file),
|
|
6774
|
+
sourceHash: $hash(join17(props.static, file))
|
|
6107
6775
|
});
|
|
6108
6776
|
}
|
|
6109
6777
|
}
|
|
@@ -6119,7 +6787,7 @@ var storeFeature = defineFeature({
|
|
|
6119
6787
|
"removed:marker": "s3:ObjectRemoved:DeleteMarkerCreated"
|
|
6120
6788
|
};
|
|
6121
6789
|
for (const [event, taskProps] of Object.entries(props.events ?? {})) {
|
|
6122
|
-
const eventGroup = new
|
|
6790
|
+
const eventGroup = new Group17(group, "event", event);
|
|
6123
6791
|
const eventId = kebabCase7(`${id}-${shortId(event)}`);
|
|
6124
6792
|
const { lambda } = createAsyncLambdaFunction(eventGroup, ctx, `store`, eventId, {
|
|
6125
6793
|
...taskProps,
|
|
@@ -6128,13 +6796,13 @@ var storeFeature = defineFeature({
|
|
|
6128
6796
|
description: `${id} event "${event}"`
|
|
6129
6797
|
}
|
|
6130
6798
|
});
|
|
6131
|
-
new
|
|
6799
|
+
new aws18.lambda.Permission(eventGroup, "permission", {
|
|
6132
6800
|
action: "lambda:InvokeFunction",
|
|
6133
6801
|
principal: "s3.amazonaws.com",
|
|
6134
6802
|
functionName: lambda.functionName,
|
|
6135
6803
|
sourceArn: `arn:aws:s3:::${name}`
|
|
6136
6804
|
});
|
|
6137
|
-
new
|
|
6805
|
+
new aws18.s3.BucketNotification(eventGroup, "notification", {
|
|
6138
6806
|
bucket: bucket.bucket,
|
|
6139
6807
|
lambdaFunction: [
|
|
6140
6808
|
{
|
|
@@ -6173,10 +6841,10 @@ var storeFeature = defineFeature({
|
|
|
6173
6841
|
});
|
|
6174
6842
|
|
|
6175
6843
|
// src/feature/table/index.ts
|
|
6176
|
-
import { Group as
|
|
6177
|
-
import { aws as
|
|
6844
|
+
import { Group as Group18 } from "@terraforge/core";
|
|
6845
|
+
import { aws as aws19 } from "@terraforge/aws";
|
|
6178
6846
|
import { constantCase as constantCase11 } from "change-case";
|
|
6179
|
-
import { toSeconds as
|
|
6847
|
+
import { toSeconds as toSeconds7 } from "@awsless/duration";
|
|
6180
6848
|
var tableFeature = defineFeature({
|
|
6181
6849
|
name: "table",
|
|
6182
6850
|
async onTypeGen(ctx) {
|
|
@@ -6225,7 +6893,7 @@ var tableFeature = defineFeature({
|
|
|
6225
6893
|
},
|
|
6226
6894
|
onStack(ctx) {
|
|
6227
6895
|
for (const [id, props] of Object.entries(ctx.stackConfig.tables ?? {})) {
|
|
6228
|
-
const group = new
|
|
6896
|
+
const group = new Group18(ctx.stack, "table", id);
|
|
6229
6897
|
const name = formatLocalResourceName({
|
|
6230
6898
|
appName: ctx.app.name,
|
|
6231
6899
|
stackName: ctx.stack.name,
|
|
@@ -6254,7 +6922,7 @@ var tableFeature = defineFeature({
|
|
|
6254
6922
|
type: types2[props.fields?.[name2] ?? "string"]
|
|
6255
6923
|
}));
|
|
6256
6924
|
};
|
|
6257
|
-
const table = new
|
|
6925
|
+
const table = new aws19.dynamodb.Table(
|
|
6258
6926
|
group,
|
|
6259
6927
|
"table",
|
|
6260
6928
|
{
|
|
@@ -6298,7 +6966,7 @@ var tableFeature = defineFeature({
|
|
|
6298
6966
|
const result = createLambdaFunction(group, ctx, "table", id, props.stream.consumer);
|
|
6299
6967
|
result.setEnvironment("THROW_EXPECTED_ERRORS", "1");
|
|
6300
6968
|
const onFailure = getGlobalOnFailure(ctx);
|
|
6301
|
-
new
|
|
6969
|
+
new aws19.lambda.EventSourceMapping(
|
|
6302
6970
|
group,
|
|
6303
6971
|
id,
|
|
6304
6972
|
{
|
|
@@ -6308,7 +6976,7 @@ var tableFeature = defineFeature({
|
|
|
6308
6976
|
// maximumRecordAgeInSeconds: toSeconds(props.stream.maxRecordAge),
|
|
6309
6977
|
// bisectBatchOnFunctionError: true,
|
|
6310
6978
|
batchSize: props.stream.batchSize,
|
|
6311
|
-
maximumBatchingWindowInSeconds: props.stream.batchWindow ?
|
|
6979
|
+
maximumBatchingWindowInSeconds: props.stream.batchWindow ? toSeconds7(props.stream.batchWindow) : void 0,
|
|
6312
6980
|
maximumRetryAttempts: props.stream.retryAttempts,
|
|
6313
6981
|
parallelizationFactor: props.stream.concurrencyPerShard,
|
|
6314
6982
|
functionResponseTypes: ["ReportBatchItemFailures"],
|
|
@@ -6374,11 +7042,11 @@ var tableFeature = defineFeature({
|
|
|
6374
7042
|
});
|
|
6375
7043
|
|
|
6376
7044
|
// src/feature/task/index.ts
|
|
6377
|
-
import { Group as
|
|
6378
|
-
import { aws as
|
|
7045
|
+
import { Group as Group19 } from "@terraforge/core";
|
|
7046
|
+
import { aws as aws20 } from "@terraforge/aws";
|
|
6379
7047
|
import { camelCase as camelCase7 } from "change-case";
|
|
6380
7048
|
import { relative as relative7 } from "path";
|
|
6381
|
-
var
|
|
7049
|
+
var typeGenCode8 = `
|
|
6382
7050
|
import { Duration } from '@awsless/duration'
|
|
6383
7051
|
import { InvokeOptions } from '@awsless/lambda'
|
|
6384
7052
|
import type { Mock } from 'vitest'
|
|
@@ -6436,26 +7104,26 @@ var taskFeature = defineFeature({
|
|
|
6436
7104
|
resources2.addType(stack.name, resource);
|
|
6437
7105
|
mockResponses.addType(stack.name, mockResponse);
|
|
6438
7106
|
}
|
|
6439
|
-
types2.addCode(
|
|
7107
|
+
types2.addCode(typeGenCode8);
|
|
6440
7108
|
types2.addInterface("TaskResources", resources2);
|
|
6441
7109
|
types2.addInterface("TaskMock", mocks);
|
|
6442
7110
|
types2.addInterface("TaskMockResponse", mockResponses);
|
|
6443
7111
|
await ctx.write("task.d.ts", types2, true);
|
|
6444
7112
|
},
|
|
6445
7113
|
onApp(ctx) {
|
|
6446
|
-
const group = new
|
|
7114
|
+
const group = new Group19(ctx.base, "task", "main");
|
|
6447
7115
|
const scheduleGroupName = formatGlobalResourceName({
|
|
6448
7116
|
appName: ctx.app.name,
|
|
6449
7117
|
resourceType: "task",
|
|
6450
7118
|
resourceName: "group"
|
|
6451
7119
|
});
|
|
6452
|
-
new
|
|
7120
|
+
new aws20.scheduler.ScheduleGroup(group, "group", {
|
|
6453
7121
|
name: scheduleGroupName,
|
|
6454
7122
|
tags: {
|
|
6455
7123
|
app: ctx.app.name
|
|
6456
7124
|
}
|
|
6457
7125
|
});
|
|
6458
|
-
const role = new
|
|
7126
|
+
const role = new aws20.iam.Role(group, "schedule", {
|
|
6459
7127
|
name: formatGlobalResourceName({
|
|
6460
7128
|
appName: ctx.app.name,
|
|
6461
7129
|
resourceType: "task",
|
|
@@ -6502,7 +7170,7 @@ var taskFeature = defineFeature({
|
|
|
6502
7170
|
},
|
|
6503
7171
|
onStack(ctx) {
|
|
6504
7172
|
for (const [id, props] of Object.entries(ctx.stackConfig.tasks ?? {})) {
|
|
6505
|
-
const group = new
|
|
7173
|
+
const group = new Group19(ctx.stack, "task", id);
|
|
6506
7174
|
createAsyncLambdaFunction(group, ctx, "task", id, props);
|
|
6507
7175
|
}
|
|
6508
7176
|
}
|
|
@@ -6527,9 +7195,9 @@ var testFeature = defineFeature({
|
|
|
6527
7195
|
});
|
|
6528
7196
|
|
|
6529
7197
|
// src/feature/topic/index.ts
|
|
6530
|
-
import { Group as
|
|
6531
|
-
import { aws as
|
|
6532
|
-
var
|
|
7198
|
+
import { Group as Group20 } from "@terraforge/core";
|
|
7199
|
+
import { aws as aws21 } from "@terraforge/aws";
|
|
7200
|
+
var typeGenCode9 = `
|
|
6533
7201
|
import type { PublishOptions } from '@awsless/sns'
|
|
6534
7202
|
|
|
6535
7203
|
type Publish<Name extends string> = {
|
|
@@ -6557,7 +7225,7 @@ var topicFeature = defineFeature({
|
|
|
6557
7225
|
resources2.addType(topic, `Publish<'${name}'>`);
|
|
6558
7226
|
mocks.addType(topic, `MockBuilder`);
|
|
6559
7227
|
}
|
|
6560
|
-
gen.addCode(
|
|
7228
|
+
gen.addCode(typeGenCode9);
|
|
6561
7229
|
gen.addInterface("TopicResources", resources2);
|
|
6562
7230
|
gen.addInterface("TopicMock", mocks);
|
|
6563
7231
|
gen.addInterface("TopicMockResponse", mockResponses);
|
|
@@ -6575,13 +7243,13 @@ var topicFeature = defineFeature({
|
|
|
6575
7243
|
},
|
|
6576
7244
|
onApp(ctx) {
|
|
6577
7245
|
for (const id of ctx.appConfig.defaults.topics ?? []) {
|
|
6578
|
-
const group = new
|
|
7246
|
+
const group = new Group20(ctx.base, "topic", id);
|
|
6579
7247
|
const name = formatGlobalResourceName({
|
|
6580
7248
|
appName: ctx.appConfig.name,
|
|
6581
7249
|
resourceType: "topic",
|
|
6582
7250
|
resourceName: id
|
|
6583
7251
|
});
|
|
6584
|
-
const topic = new
|
|
7252
|
+
const topic = new aws21.sns.Topic(group, "topic", {
|
|
6585
7253
|
name
|
|
6586
7254
|
});
|
|
6587
7255
|
ctx.shared.add("topic", `arn`, id, topic.arn);
|
|
@@ -6599,15 +7267,15 @@ var topicFeature = defineFeature({
|
|
|
6599
7267
|
},
|
|
6600
7268
|
onStack(ctx) {
|
|
6601
7269
|
for (const [id, props] of Object.entries(ctx.stackConfig.subscribers ?? {})) {
|
|
6602
|
-
const group = new
|
|
7270
|
+
const group = new Group20(ctx.stack, "topic", id);
|
|
6603
7271
|
const topicArn = ctx.shared.entry("topic", "arn", id);
|
|
6604
7272
|
const { lambda } = createAsyncLambdaFunction(group, ctx, `topic`, id, props);
|
|
6605
|
-
new
|
|
7273
|
+
new aws21.sns.TopicSubscription(group, id, {
|
|
6606
7274
|
topicArn,
|
|
6607
7275
|
protocol: "lambda",
|
|
6608
7276
|
endpoint: lambda.arn
|
|
6609
7277
|
});
|
|
6610
|
-
new
|
|
7278
|
+
new aws21.lambda.Permission(group, id, {
|
|
6611
7279
|
action: "lambda:InvokeFunction",
|
|
6612
7280
|
principal: "sns.amazonaws.com",
|
|
6613
7281
|
functionName: lambda.functionName,
|
|
@@ -6618,13 +7286,13 @@ var topicFeature = defineFeature({
|
|
|
6618
7286
|
});
|
|
6619
7287
|
|
|
6620
7288
|
// src/feature/vpc/index.ts
|
|
6621
|
-
import { Group as
|
|
6622
|
-
import { aws as
|
|
7289
|
+
import { Group as Group21 } from "@terraforge/core";
|
|
7290
|
+
import { aws as aws22 } from "@terraforge/aws";
|
|
6623
7291
|
var vpcFeature = defineFeature({
|
|
6624
7292
|
name: "vpc",
|
|
6625
7293
|
onApp(ctx) {
|
|
6626
|
-
const group = new
|
|
6627
|
-
const vpc = new
|
|
7294
|
+
const group = new Group21(ctx.base, "vpc", "main");
|
|
7295
|
+
const vpc = new aws22.Vpc(group, "vpc", {
|
|
6628
7296
|
tags: {
|
|
6629
7297
|
Name: ctx.app.name
|
|
6630
7298
|
},
|
|
@@ -6634,39 +7302,39 @@ var vpcFeature = defineFeature({
|
|
|
6634
7302
|
ipv6CidrBlockNetworkBorderGroup: ctx.appConfig.region,
|
|
6635
7303
|
assignGeneratedIpv6CidrBlock: true
|
|
6636
7304
|
});
|
|
6637
|
-
const privateRouteTable = new
|
|
7305
|
+
const privateRouteTable = new aws22.route.Table(group, "private", {
|
|
6638
7306
|
vpcId: vpc.id,
|
|
6639
7307
|
tags: {
|
|
6640
7308
|
Name: "private"
|
|
6641
7309
|
}
|
|
6642
7310
|
});
|
|
6643
|
-
const publicRouteTable = new
|
|
7311
|
+
const publicRouteTable = new aws22.route.Table(group, "public", {
|
|
6644
7312
|
vpcId: vpc.id,
|
|
6645
7313
|
tags: {
|
|
6646
7314
|
Name: "public"
|
|
6647
7315
|
}
|
|
6648
7316
|
});
|
|
6649
|
-
const gateway = new
|
|
7317
|
+
const gateway = new aws22.internet.Gateway(group, "gateway", {
|
|
6650
7318
|
tags: {
|
|
6651
7319
|
Name: ctx.app.name
|
|
6652
7320
|
}
|
|
6653
7321
|
});
|
|
6654
|
-
const egressOnlyInternetGateway = new
|
|
7322
|
+
const egressOnlyInternetGateway = new aws22.egress.OnlyInternetGateway(group, "gateway", {
|
|
6655
7323
|
vpcId: vpc.id,
|
|
6656
7324
|
tags: {
|
|
6657
7325
|
Name: ctx.app.name
|
|
6658
7326
|
}
|
|
6659
7327
|
});
|
|
6660
|
-
const attachment = new
|
|
7328
|
+
const attachment = new aws22.internet.GatewayAttachment(group, "attachment", {
|
|
6661
7329
|
vpcId: vpc.id,
|
|
6662
7330
|
internetGatewayId: gateway.id
|
|
6663
7331
|
});
|
|
6664
|
-
new
|
|
7332
|
+
new aws22.Route(group, "ipv4", {
|
|
6665
7333
|
routeTableId: publicRouteTable.id,
|
|
6666
7334
|
destinationCidrBlock: "0.0.0.0/0",
|
|
6667
7335
|
gatewayId: gateway.id
|
|
6668
7336
|
});
|
|
6669
|
-
new
|
|
7337
|
+
new aws22.Route(group, "ipv6", {
|
|
6670
7338
|
routeTableId: privateRouteTable.id,
|
|
6671
7339
|
destinationIpv6CidrBlock: "::/0",
|
|
6672
7340
|
egressOnlyGatewayId: egressOnlyInternetGateway.id
|
|
@@ -6691,7 +7359,7 @@ var vpcFeature = defineFeature({
|
|
|
6691
7359
|
for (const i in zones) {
|
|
6692
7360
|
const index = Number(i) + 1;
|
|
6693
7361
|
const id = `${type}-${index}`;
|
|
6694
|
-
const subnet = new
|
|
7362
|
+
const subnet = new aws22.Subnet(group, id, {
|
|
6695
7363
|
tags: {
|
|
6696
7364
|
Name: `${ctx.app.name}--${type}-${index}`
|
|
6697
7365
|
},
|
|
@@ -6705,7 +7373,7 @@ var vpcFeature = defineFeature({
|
|
|
6705
7373
|
return `${cidrBlock}${ipv6Identifier++}::/64`;
|
|
6706
7374
|
})
|
|
6707
7375
|
});
|
|
6708
|
-
new
|
|
7376
|
+
new aws22.route.TableAssociation(group, id, {
|
|
6709
7377
|
routeTableId: table.id,
|
|
6710
7378
|
subnetId: subnet.id
|
|
6711
7379
|
});
|
|
@@ -6718,9 +7386,9 @@ var vpcFeature = defineFeature({
|
|
|
6718
7386
|
});
|
|
6719
7387
|
|
|
6720
7388
|
// src/feature/alert/index.ts
|
|
6721
|
-
import { Group as
|
|
6722
|
-
import { aws as
|
|
6723
|
-
var
|
|
7389
|
+
import { Group as Group22 } from "@terraforge/core";
|
|
7390
|
+
import { aws as aws23 } from "@terraforge/aws";
|
|
7391
|
+
var typeGenCode10 = `
|
|
6724
7392
|
import type { PublishOptions } from '@awsless/sns'
|
|
6725
7393
|
|
|
6726
7394
|
type Alert<Name extends string> = {
|
|
@@ -6748,7 +7416,7 @@ var alertFeature = defineFeature({
|
|
|
6748
7416
|
mockResponses.addType(alert, "Mock");
|
|
6749
7417
|
mocks.addType(alert, `MockBuilder`);
|
|
6750
7418
|
}
|
|
6751
|
-
gen.addCode(
|
|
7419
|
+
gen.addCode(typeGenCode10);
|
|
6752
7420
|
gen.addInterface("AlertResources", resources2);
|
|
6753
7421
|
gen.addInterface("AlertMock", mocks);
|
|
6754
7422
|
gen.addInterface("AlertMockResponse", mockResponses);
|
|
@@ -6756,17 +7424,17 @@ var alertFeature = defineFeature({
|
|
|
6756
7424
|
},
|
|
6757
7425
|
onApp(ctx) {
|
|
6758
7426
|
for (const [id, emails] of Object.entries(ctx.appConfig.defaults.alerts ?? {})) {
|
|
6759
|
-
const group = new
|
|
7427
|
+
const group = new Group22(ctx.base, "alert", id);
|
|
6760
7428
|
const name = formatGlobalResourceName({
|
|
6761
7429
|
appName: ctx.appConfig.name,
|
|
6762
7430
|
resourceType: "alert",
|
|
6763
7431
|
resourceName: id
|
|
6764
7432
|
});
|
|
6765
|
-
const topic = new
|
|
7433
|
+
const topic = new aws23.sns.Topic(group, "topic", {
|
|
6766
7434
|
name
|
|
6767
7435
|
});
|
|
6768
7436
|
for (const email of emails) {
|
|
6769
|
-
new
|
|
7437
|
+
new aws23.sns.TopicSubscription(group, email, {
|
|
6770
7438
|
topicArn: topic.arn,
|
|
6771
7439
|
protocol: "email",
|
|
6772
7440
|
endpoint: email
|
|
@@ -6787,13 +7455,13 @@ var alertFeature = defineFeature({
|
|
|
6787
7455
|
});
|
|
6788
7456
|
|
|
6789
7457
|
// src/feature/layer/index.ts
|
|
6790
|
-
import { Group as
|
|
6791
|
-
import { aws as
|
|
7458
|
+
import { Group as Group23 } from "@terraforge/core";
|
|
7459
|
+
import { aws as aws24 } from "@terraforge/aws";
|
|
6792
7460
|
var layerFeature = defineFeature({
|
|
6793
7461
|
name: "layer",
|
|
6794
7462
|
onBefore(ctx) {
|
|
6795
|
-
const group = new
|
|
6796
|
-
const bucket = new
|
|
7463
|
+
const group = new Group23(ctx.base, "layer", "asset");
|
|
7464
|
+
const bucket = new aws24.s3.Bucket(group, "bucket", {
|
|
6797
7465
|
bucket: formatGlobalResourceName({
|
|
6798
7466
|
appName: ctx.app.name,
|
|
6799
7467
|
resourceType: "layer",
|
|
@@ -6825,15 +7493,15 @@ var layerFeature = defineFeature({
|
|
|
6825
7493
|
}
|
|
6826
7494
|
for (const [id, _props] of layers) {
|
|
6827
7495
|
const props = _props;
|
|
6828
|
-
const group = new
|
|
6829
|
-
const zip = new
|
|
7496
|
+
const group = new Group23(ctx.base, "layer", id);
|
|
7497
|
+
const zip = new aws24.s3.BucketObject(group, "zip", {
|
|
6830
7498
|
bucket: ctx.shared.get("layer", "bucket-name"),
|
|
6831
7499
|
key: `/layer/${id}.zip`,
|
|
6832
7500
|
contentType: "application/zip",
|
|
6833
7501
|
source: props.file,
|
|
6834
7502
|
sourceHash: $hash(props.file)
|
|
6835
7503
|
});
|
|
6836
|
-
const layer = new
|
|
7504
|
+
const layer = new aws24.lambda.LayerVersion(
|
|
6837
7505
|
group,
|
|
6838
7506
|
"layer",
|
|
6839
7507
|
{
|
|
@@ -6868,14 +7536,14 @@ var layerFeature = defineFeature({
|
|
|
6868
7536
|
});
|
|
6869
7537
|
|
|
6870
7538
|
// src/feature/image/index.ts
|
|
6871
|
-
import { Group as
|
|
6872
|
-
import { aws as
|
|
6873
|
-
import { join as
|
|
6874
|
-
import { mebibytes as
|
|
6875
|
-
import { seconds as
|
|
6876
|
-
import { fileURLToPath as
|
|
7539
|
+
import { Group as Group24 } from "@terraforge/core";
|
|
7540
|
+
import { aws as aws25 } from "@terraforge/aws";
|
|
7541
|
+
import { join as join18, dirname as dirname9 } from "path";
|
|
7542
|
+
import { mebibytes as mebibytes7 } from "@awsless/size";
|
|
7543
|
+
import { seconds as seconds9, toDays as toDays9 } from "@awsless/duration";
|
|
7544
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
6877
7545
|
import { glob as glob4 } from "glob";
|
|
6878
|
-
var
|
|
7546
|
+
var __dirname5 = dirname9(fileURLToPath4(import.meta.url));
|
|
6879
7547
|
var imageFeature = defineFeature({
|
|
6880
7548
|
name: "image",
|
|
6881
7549
|
onApp(ctx) {
|
|
@@ -6885,21 +7553,21 @@ var imageFeature = defineFeature({
|
|
|
6885
7553
|
if (found.length === 0) {
|
|
6886
7554
|
return;
|
|
6887
7555
|
}
|
|
6888
|
-
const group = new
|
|
6889
|
-
const path =
|
|
7556
|
+
const group = new Group24(ctx.base, "image", "layer");
|
|
7557
|
+
const path = join18(__dirname5, "/layers/sharp-arm.zip");
|
|
6890
7558
|
const layerId = formatGlobalResourceName({
|
|
6891
7559
|
appName: ctx.appConfig.name,
|
|
6892
7560
|
resourceType: "layer",
|
|
6893
7561
|
resourceName: "sharp"
|
|
6894
7562
|
});
|
|
6895
|
-
const zipFile = new
|
|
7563
|
+
const zipFile = new aws25.s3.BucketObject(group, "layer", {
|
|
6896
7564
|
bucket: ctx.shared.get("layer", "bucket-name"),
|
|
6897
7565
|
key: `/layer/${layerId}.zip`,
|
|
6898
7566
|
contentType: "application/zip",
|
|
6899
7567
|
source: path,
|
|
6900
7568
|
sourceHash: $hash(path)
|
|
6901
7569
|
});
|
|
6902
|
-
const layer = new
|
|
7570
|
+
const layer = new aws25.lambda.LayerVersion(
|
|
6903
7571
|
group,
|
|
6904
7572
|
"layer",
|
|
6905
7573
|
{
|
|
@@ -6926,7 +7594,7 @@ var imageFeature = defineFeature({
|
|
|
6926
7594
|
},
|
|
6927
7595
|
onStack(ctx) {
|
|
6928
7596
|
for (const [id, props] of Object.entries(ctx.stackConfig.images ?? {})) {
|
|
6929
|
-
const group = new
|
|
7597
|
+
const group = new Group24(ctx.stack, "image", id);
|
|
6930
7598
|
const routerId = ctx.shared.entry("router", "id", props.router);
|
|
6931
7599
|
const addRoutes = ctx.shared.entry("router", "addRoutes", props.router);
|
|
6932
7600
|
const routeKey = props.path.endsWith("/") ? `${props.path}*` : `${props.path}/*`;
|
|
@@ -6936,7 +7604,7 @@ var imageFeature = defineFeature({
|
|
|
6936
7604
|
}
|
|
6937
7605
|
let s3Origin;
|
|
6938
7606
|
if (props.origin.static) {
|
|
6939
|
-
s3Origin = new
|
|
7607
|
+
s3Origin = new aws25.s3.Bucket(group, "origin", {
|
|
6940
7608
|
bucket: formatLocalResourceName({
|
|
6941
7609
|
appName: ctx.app.name,
|
|
6942
7610
|
stackName: ctx.stack.name,
|
|
@@ -6946,7 +7614,7 @@ var imageFeature = defineFeature({
|
|
|
6946
7614
|
forceDestroy: true
|
|
6947
7615
|
});
|
|
6948
7616
|
}
|
|
6949
|
-
const cacheBucket = new
|
|
7617
|
+
const cacheBucket = new aws25.s3.Bucket(group, "cache", {
|
|
6950
7618
|
bucket: formatLocalResourceName({
|
|
6951
7619
|
appName: ctx.app.name,
|
|
6952
7620
|
stackName: ctx.stack.name,
|
|
@@ -6963,7 +7631,7 @@ var imageFeature = defineFeature({
|
|
|
6963
7631
|
enabled: true,
|
|
6964
7632
|
id: "image-cache-duration",
|
|
6965
7633
|
expiration: {
|
|
6966
|
-
days:
|
|
7634
|
+
days: toDays9(props.cacheDuration)
|
|
6967
7635
|
}
|
|
6968
7636
|
}
|
|
6969
7637
|
]
|
|
@@ -6975,23 +7643,23 @@ var imageFeature = defineFeature({
|
|
|
6975
7643
|
resourceName: "sharp"
|
|
6976
7644
|
});
|
|
6977
7645
|
const serverLambda = createPrebuildLambdaFunction(group, ctx, "image", id, {
|
|
6978
|
-
bundleFile:
|
|
6979
|
-
bundleHash:
|
|
6980
|
-
memorySize:
|
|
6981
|
-
timeout:
|
|
7646
|
+
bundleFile: join18(__dirname5, "/prebuild/image/bundle.zip"),
|
|
7647
|
+
bundleHash: join18(__dirname5, "/prebuild/image/HASH"),
|
|
7648
|
+
memorySize: mebibytes7(512),
|
|
7649
|
+
timeout: seconds9(10),
|
|
6982
7650
|
handler: "index.default",
|
|
6983
7651
|
runtime: "nodejs24.x",
|
|
6984
7652
|
log: props.log,
|
|
6985
7653
|
layers: [sharpLayerId]
|
|
6986
7654
|
});
|
|
6987
|
-
const permission = new
|
|
7655
|
+
const permission = new aws25.lambda.Permission(group, "permission", {
|
|
6988
7656
|
principal: "cloudfront.amazonaws.com",
|
|
6989
7657
|
action: "lambda:InvokeFunctionUrl",
|
|
6990
7658
|
functionName: serverLambda.lambda.functionName,
|
|
6991
7659
|
functionUrlAuthType: "AWS_IAM",
|
|
6992
7660
|
sourceArn: `arn:aws:cloudfront::${ctx.accountId}:distribution/*`
|
|
6993
7661
|
});
|
|
6994
|
-
const serverLambdaUrl = new
|
|
7662
|
+
const serverLambdaUrl = new aws25.lambda.FunctionUrl(
|
|
6995
7663
|
group,
|
|
6996
7664
|
"url",
|
|
6997
7665
|
{
|
|
@@ -7048,11 +7716,11 @@ var imageFeature = defineFeature({
|
|
|
7048
7716
|
nodir: true
|
|
7049
7717
|
});
|
|
7050
7718
|
for (const file of files) {
|
|
7051
|
-
new
|
|
7719
|
+
new aws25.s3.BucketObject(group, `static-${file}`, {
|
|
7052
7720
|
bucket: s3Origin.bucket,
|
|
7053
7721
|
key: file,
|
|
7054
|
-
source:
|
|
7055
|
-
sourceHash: $hash(
|
|
7722
|
+
source: join18(props.origin.static, file),
|
|
7723
|
+
sourceHash: $hash(join18(props.origin.static, file))
|
|
7056
7724
|
});
|
|
7057
7725
|
}
|
|
7058
7726
|
}
|
|
@@ -7065,19 +7733,19 @@ var imageFeature = defineFeature({
|
|
|
7065
7733
|
});
|
|
7066
7734
|
|
|
7067
7735
|
// src/feature/icon/index.ts
|
|
7068
|
-
import { Group as
|
|
7069
|
-
import { aws as
|
|
7070
|
-
import { join as
|
|
7071
|
-
import { mebibytes as
|
|
7072
|
-
import { seconds as
|
|
7073
|
-
import { fileURLToPath as
|
|
7736
|
+
import { Group as Group25 } from "@terraforge/core";
|
|
7737
|
+
import { aws as aws26 } from "@terraforge/aws";
|
|
7738
|
+
import { join as join19, dirname as dirname10 } from "path";
|
|
7739
|
+
import { mebibytes as mebibytes8 } from "@awsless/size";
|
|
7740
|
+
import { seconds as seconds10, toDays as toDays10 } from "@awsless/duration";
|
|
7741
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
7074
7742
|
import { glob as glob5 } from "glob";
|
|
7075
|
-
var
|
|
7743
|
+
var __dirname6 = dirname10(fileURLToPath5(import.meta.url));
|
|
7076
7744
|
var iconFeature = defineFeature({
|
|
7077
7745
|
name: "icon",
|
|
7078
7746
|
onStack(ctx) {
|
|
7079
7747
|
for (const [id, props] of Object.entries(ctx.stackConfig.icons ?? {})) {
|
|
7080
|
-
const group = new
|
|
7748
|
+
const group = new Group25(ctx.stack, "icon", id);
|
|
7081
7749
|
const routerId = ctx.shared.entry("router", "id", props.router);
|
|
7082
7750
|
const addRoutes = ctx.shared.entry("router", "addRoutes", props.router);
|
|
7083
7751
|
const routeKey = props.path.endsWith("/") ? `${props.path}*` : `${props.path}/*`;
|
|
@@ -7087,7 +7755,7 @@ var iconFeature = defineFeature({
|
|
|
7087
7755
|
}
|
|
7088
7756
|
let s3Origin;
|
|
7089
7757
|
if (props.origin.static) {
|
|
7090
|
-
s3Origin = new
|
|
7758
|
+
s3Origin = new aws26.s3.Bucket(group, "origin", {
|
|
7091
7759
|
bucket: formatLocalResourceName({
|
|
7092
7760
|
appName: ctx.app.name,
|
|
7093
7761
|
stackName: ctx.stack.name,
|
|
@@ -7097,7 +7765,7 @@ var iconFeature = defineFeature({
|
|
|
7097
7765
|
forceDestroy: true
|
|
7098
7766
|
});
|
|
7099
7767
|
}
|
|
7100
|
-
const cacheBucket = new
|
|
7768
|
+
const cacheBucket = new aws26.s3.Bucket(group, "cache", {
|
|
7101
7769
|
bucket: formatLocalResourceName({
|
|
7102
7770
|
appName: ctx.app.name,
|
|
7103
7771
|
stackName: ctx.stack.name,
|
|
@@ -7114,29 +7782,29 @@ var iconFeature = defineFeature({
|
|
|
7114
7782
|
enabled: true,
|
|
7115
7783
|
id: "icon-cache-duration",
|
|
7116
7784
|
expiration: {
|
|
7117
|
-
days:
|
|
7785
|
+
days: toDays10(props.cacheDuration)
|
|
7118
7786
|
}
|
|
7119
7787
|
}
|
|
7120
7788
|
]
|
|
7121
7789
|
} : {}
|
|
7122
7790
|
});
|
|
7123
7791
|
const serverLambda = createPrebuildLambdaFunction(group, ctx, "icon", id, {
|
|
7124
|
-
bundleFile:
|
|
7125
|
-
bundleHash:
|
|
7126
|
-
memorySize:
|
|
7127
|
-
timeout:
|
|
7792
|
+
bundleFile: join19(__dirname6, "/prebuild/icon/bundle.zip"),
|
|
7793
|
+
bundleHash: join19(__dirname6, "/prebuild/icon/HASH"),
|
|
7794
|
+
memorySize: mebibytes8(512),
|
|
7795
|
+
timeout: seconds10(10),
|
|
7128
7796
|
handler: "index.default",
|
|
7129
7797
|
runtime: "nodejs24.x",
|
|
7130
7798
|
log: props.log
|
|
7131
7799
|
});
|
|
7132
|
-
const permission = new
|
|
7800
|
+
const permission = new aws26.lambda.Permission(group, "permission", {
|
|
7133
7801
|
principal: "cloudfront.amazonaws.com",
|
|
7134
7802
|
action: "lambda:InvokeFunctionUrl",
|
|
7135
7803
|
functionName: serverLambda.lambda.functionName,
|
|
7136
7804
|
functionUrlAuthType: "AWS_IAM",
|
|
7137
7805
|
sourceArn: `arn:aws:cloudfront::${ctx.accountId}:distribution/*`
|
|
7138
7806
|
});
|
|
7139
|
-
const serverLambdaUrl = new
|
|
7807
|
+
const serverLambdaUrl = new aws26.lambda.FunctionUrl(
|
|
7140
7808
|
group,
|
|
7141
7809
|
"url",
|
|
7142
7810
|
{
|
|
@@ -7196,11 +7864,11 @@ var iconFeature = defineFeature({
|
|
|
7196
7864
|
if (!file.endsWith(".svg")) {
|
|
7197
7865
|
throw new Error(`Icon file "${file}" in "${props.origin.static}" is not an SVG file.`);
|
|
7198
7866
|
}
|
|
7199
|
-
new
|
|
7867
|
+
new aws26.s3.BucketObject(group, `static-${file}`, {
|
|
7200
7868
|
bucket: s3Origin.bucket,
|
|
7201
7869
|
key: file,
|
|
7202
|
-
source:
|
|
7203
|
-
sourceHash: $hash(
|
|
7870
|
+
source: join19(props.origin.static, file),
|
|
7871
|
+
sourceHash: $hash(join19(props.origin.static, file))
|
|
7204
7872
|
});
|
|
7205
7873
|
}
|
|
7206
7874
|
}
|
|
@@ -7213,30 +7881,30 @@ var iconFeature = defineFeature({
|
|
|
7213
7881
|
});
|
|
7214
7882
|
|
|
7215
7883
|
// src/feature/job/index.ts
|
|
7216
|
-
import { Group as
|
|
7217
|
-
import { aws as
|
|
7884
|
+
import { Group as Group27, Output as Output8, resolveInputs as resolveInputs5, findInputDeps as findInputDeps5 } from "@terraforge/core";
|
|
7885
|
+
import { aws as aws28 } from "@terraforge/aws";
|
|
7218
7886
|
import { camelCase as camelCase8 } from "change-case";
|
|
7219
7887
|
import deepmerge5 from "deepmerge";
|
|
7220
7888
|
import { relative as relative8 } from "path";
|
|
7221
7889
|
|
|
7222
7890
|
// src/feature/job/util.ts
|
|
7223
|
-
import { createHash as
|
|
7224
|
-
import { toDays as
|
|
7225
|
-
import { stringify } from "@awsless/json";
|
|
7891
|
+
import { createHash as createHash6 } from "crypto";
|
|
7892
|
+
import { toDays as toDays11, toSeconds as toSeconds8 } from "@awsless/duration";
|
|
7893
|
+
import { stringify as stringify2 } from "@awsless/json";
|
|
7226
7894
|
import { toMebibytes as toMebibytes5 } from "@awsless/size";
|
|
7227
7895
|
import { generateFileHash as generateFileHash2 } from "@awsless/ts-file-cache";
|
|
7228
|
-
import { aws as
|
|
7229
|
-
import { Group as
|
|
7230
|
-
import { constantCase as constantCase12, pascalCase as
|
|
7896
|
+
import { aws as aws27 } from "@terraforge/aws";
|
|
7897
|
+
import { Group as Group26, Output as Output7, findInputDeps as findInputDeps4, resolveInputs as resolveInputs4 } from "@terraforge/core";
|
|
7898
|
+
import { constantCase as constantCase12, pascalCase as pascalCase4 } from "change-case";
|
|
7231
7899
|
import deepmerge4 from "deepmerge";
|
|
7232
7900
|
|
|
7233
7901
|
// src/feature/job/build/executable.ts
|
|
7234
|
-
import { createHash as
|
|
7235
|
-
import { readFile as
|
|
7236
|
-
import { join as
|
|
7902
|
+
import { createHash as createHash5 } from "crypto";
|
|
7903
|
+
import { readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
|
|
7904
|
+
import { join as join20, resolve } from "path";
|
|
7237
7905
|
var buildJobExecutable = async (input, outputPath, architecture) => {
|
|
7238
|
-
const filePath =
|
|
7239
|
-
const wrapperPath =
|
|
7906
|
+
const filePath = join20(outputPath, "program");
|
|
7907
|
+
const wrapperPath = join20(outputPath, "wrapper.ts");
|
|
7240
7908
|
const handlerPath = resolve(input);
|
|
7241
7909
|
await writeFile3(
|
|
7242
7910
|
wrapperPath,
|
|
@@ -7291,16 +7959,16 @@ await handler(payload)
|
|
|
7291
7959
|
throw new ExpectedError(`Job executable build failed:
|
|
7292
7960
|
${result.logs?.map((log35) => log35.message).join("\n")}`);
|
|
7293
7961
|
}
|
|
7294
|
-
const file = await
|
|
7962
|
+
const file = await readFile6(filePath);
|
|
7295
7963
|
return {
|
|
7296
|
-
hash:
|
|
7964
|
+
hash: createHash5("sha1").update(file).update(target).digest("hex"),
|
|
7297
7965
|
file
|
|
7298
7966
|
};
|
|
7299
7967
|
};
|
|
7300
7968
|
|
|
7301
7969
|
// src/feature/job/util.ts
|
|
7302
7970
|
var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
7303
|
-
const group = new
|
|
7971
|
+
const group = new Group26(parentGroup, "job", ns);
|
|
7304
7972
|
const name = formatLocalResourceName({
|
|
7305
7973
|
appName: ctx.app.name,
|
|
7306
7974
|
stackName: ctx.stack.name,
|
|
@@ -7326,13 +7994,13 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7326
7994
|
};
|
|
7327
7995
|
});
|
|
7328
7996
|
});
|
|
7329
|
-
const code = new
|
|
7997
|
+
const code = new aws27.s3.BucketObject(group, "code", {
|
|
7330
7998
|
bucket: ctx.shared.get("job", "bucket-name"),
|
|
7331
7999
|
key: name,
|
|
7332
8000
|
source: relativePath(getBuildPath("job", name, "program")),
|
|
7333
8001
|
sourceHash: $file(getBuildPath("job", name, "HASH"))
|
|
7334
8002
|
});
|
|
7335
|
-
const executionRole = new
|
|
8003
|
+
const executionRole = new aws27.iam.Role(group, "execution-role", {
|
|
7336
8004
|
name: shortId(`${shortName}:execution-role`),
|
|
7337
8005
|
description: name,
|
|
7338
8006
|
assumeRolePolicy: JSON.stringify({
|
|
@@ -7349,7 +8017,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7349
8017
|
}),
|
|
7350
8018
|
managedPolicyArns: ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
|
|
7351
8019
|
});
|
|
7352
|
-
const role = new
|
|
8020
|
+
const role = new aws27.iam.Role(
|
|
7353
8021
|
group,
|
|
7354
8022
|
"task-role",
|
|
7355
8023
|
{
|
|
@@ -7375,7 +8043,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7375
8043
|
Version: "2012-10-17",
|
|
7376
8044
|
Statement: [
|
|
7377
8045
|
{
|
|
7378
|
-
Effect:
|
|
8046
|
+
Effect: pascalCase4("allow"),
|
|
7379
8047
|
Action: ["s3:GetObject", "s3:HeadObject"],
|
|
7380
8048
|
Resource: [`arn:aws:s3:::${bucket}/${key}`, `arn:aws:s3:::${bucket}/payloads/*`]
|
|
7381
8049
|
}
|
|
@@ -7391,16 +8059,16 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7391
8059
|
);
|
|
7392
8060
|
const statements = [];
|
|
7393
8061
|
const statementDeps = /* @__PURE__ */ new Set();
|
|
7394
|
-
const policy = new
|
|
8062
|
+
const policy = new aws27.iam.RolePolicy(group, "policy", {
|
|
7395
8063
|
role: role.name,
|
|
7396
8064
|
name: "task-policy",
|
|
7397
|
-
policy: new
|
|
7398
|
-
const list3 = await
|
|
8065
|
+
policy: new Output7(statementDeps, async (resolve2) => {
|
|
8066
|
+
const list3 = await resolveInputs4(statements);
|
|
7399
8067
|
resolve2(
|
|
7400
8068
|
JSON.stringify({
|
|
7401
8069
|
Version: "2012-10-17",
|
|
7402
8070
|
Statement: list3.map((statement) => ({
|
|
7403
|
-
Effect:
|
|
8071
|
+
Effect: pascalCase4(statement.effect ?? "allow"),
|
|
7404
8072
|
Action: statement.actions,
|
|
7405
8073
|
Resource: statement.resources
|
|
7406
8074
|
}))
|
|
@@ -7410,7 +8078,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7410
8078
|
});
|
|
7411
8079
|
const addPermission = (...permissions) => {
|
|
7412
8080
|
statements.push(...permissions);
|
|
7413
|
-
for (const dep of
|
|
8081
|
+
for (const dep of findInputDeps4(permissions)) {
|
|
7414
8082
|
statementDeps.add(dep);
|
|
7415
8083
|
}
|
|
7416
8084
|
};
|
|
@@ -7419,12 +8087,12 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7419
8087
|
});
|
|
7420
8088
|
let logGroup;
|
|
7421
8089
|
if (props.log.retention && props.log.retention.value > 0n) {
|
|
7422
|
-
logGroup = new
|
|
8090
|
+
logGroup = new aws27.cloudwatch.LogGroup(group, "log", {
|
|
7423
8091
|
name: `/aws/ecs/${name}`,
|
|
7424
|
-
retentionInDays:
|
|
8092
|
+
retentionInDays: toDays11(props.log.retention)
|
|
7425
8093
|
});
|
|
7426
8094
|
if (ctx.shared.has("on-error-log", "subscriber-arn")) {
|
|
7427
|
-
new
|
|
8095
|
+
new aws27.cloudwatch.LogSubscriptionFilter(group, "on-error-log", {
|
|
7428
8096
|
name: "error-log-subscription",
|
|
7429
8097
|
destinationArn: ctx.shared.get("on-error-log", "subscriber-arn"),
|
|
7430
8098
|
logGroupName: logGroup.name,
|
|
@@ -7442,7 +8110,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7442
8110
|
const taskDependsOn = [code];
|
|
7443
8111
|
const accessPoint = props.persistentStorage ? (() => {
|
|
7444
8112
|
const fileSystemId = ctx.shared.get("job", "persistent-storage-file-system-id");
|
|
7445
|
-
const accessPoint2 = new
|
|
8113
|
+
const accessPoint2 = new aws27.efs.AccessPoint(
|
|
7446
8114
|
group,
|
|
7447
8115
|
"access-point",
|
|
7448
8116
|
{
|
|
@@ -7467,7 +8135,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7467
8135
|
fileSystemId
|
|
7468
8136
|
};
|
|
7469
8137
|
})() : void 0;
|
|
7470
|
-
const task2 = new
|
|
8138
|
+
const task2 = new aws27.ecs.TaskDefinition(
|
|
7471
8139
|
group,
|
|
7472
8140
|
"task",
|
|
7473
8141
|
{
|
|
@@ -7497,9 +8165,9 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7497
8165
|
}
|
|
7498
8166
|
]
|
|
7499
8167
|
},
|
|
7500
|
-
containerDefinitions: new
|
|
7501
|
-
const data = await
|
|
7502
|
-
const { s3Bucket, s3Key } = await
|
|
8168
|
+
containerDefinitions: new Output7(variableDeps, async (resolve2) => {
|
|
8169
|
+
const data = await resolveInputs4(variables);
|
|
8170
|
+
const { s3Bucket, s3Key } = await resolveInputs4({
|
|
7503
8171
|
s3Bucket: code.bucket,
|
|
7504
8172
|
s3Key: code.key
|
|
7505
8173
|
});
|
|
@@ -7515,7 +8183,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7515
8183
|
[
|
|
7516
8184
|
...props.startupCommand?.length ? [props.startupCommand.join(" && ")] : [],
|
|
7517
8185
|
`if [ "$(cat /root/.code-hash 2>/dev/null)" != "$CODE_HASH" ]; then command -v aws >/dev/null 2>&1 || dnf install -y awscli && aws s3 cp s3://${s3Bucket}/${s3Key} /root/program.tmp && mv /root/program.tmp /root/program && chmod +x /root/program && echo "$CODE_HASH" > /root/.code-hash; fi`,
|
|
7518
|
-
`exec timeout --kill-after=10 ${
|
|
8186
|
+
`exec timeout --kill-after=10 ${toSeconds8(props.timeout)} /root/program`
|
|
7519
8187
|
].join(" && ")
|
|
7520
8188
|
],
|
|
7521
8189
|
environment: Object.entries(data).map(([name2, value]) => ({
|
|
@@ -7561,7 +8229,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7561
8229
|
);
|
|
7562
8230
|
ctx.onEnv((name2, value) => {
|
|
7563
8231
|
variables[name2] = value;
|
|
7564
|
-
for (const dep of
|
|
8232
|
+
for (const dep of findInputDeps4([value])) {
|
|
7565
8233
|
variableDeps.add(dep);
|
|
7566
8234
|
}
|
|
7567
8235
|
});
|
|
@@ -7570,7 +8238,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7570
8238
|
variables.AWS_ACCOUNT_ID = ctx.accountId;
|
|
7571
8239
|
variables.STACK = ctx.stackConfig.name;
|
|
7572
8240
|
variables.CODE_HASH = code.sourceHash;
|
|
7573
|
-
variables.JOB_CONFIG_HASH =
|
|
8241
|
+
variables.JOB_CONFIG_HASH = createHash6("sha1").update(stringify2(props)).digest("hex");
|
|
7574
8242
|
if (props.environment) {
|
|
7575
8243
|
for (const [key, value] of Object.entries(props.environment)) {
|
|
7576
8244
|
variables[key] = value;
|
|
@@ -7586,7 +8254,7 @@ var createFargateJob = (parentGroup, ctx, ns, id, local) => {
|
|
|
7586
8254
|
};
|
|
7587
8255
|
|
|
7588
8256
|
// src/feature/job/index.ts
|
|
7589
|
-
var
|
|
8257
|
+
var typeGenCode11 = `
|
|
7590
8258
|
import type { Mock } from 'vitest'
|
|
7591
8259
|
|
|
7592
8260
|
type Func = (...args: any[]) => any
|
|
@@ -7642,15 +8310,15 @@ var jobFeature = defineFeature({
|
|
|
7642
8310
|
resources2.addType(stack.name, resource);
|
|
7643
8311
|
mockResponses.addType(stack.name, mockResponse);
|
|
7644
8312
|
}
|
|
7645
|
-
types2.addCode(
|
|
8313
|
+
types2.addCode(typeGenCode11);
|
|
7646
8314
|
types2.addInterface("JobResources", resources2);
|
|
7647
8315
|
types2.addInterface("JobMock", mocks);
|
|
7648
8316
|
types2.addInterface("JobMockResponse", mockResponses);
|
|
7649
8317
|
await ctx.write("job.d.ts", types2, true);
|
|
7650
8318
|
},
|
|
7651
8319
|
onBefore(ctx) {
|
|
7652
|
-
const group = new
|
|
7653
|
-
const bucket = new
|
|
8320
|
+
const group = new Group27(ctx.base, "job", "asset");
|
|
8321
|
+
const bucket = new aws28.s3.Bucket(group, "bucket", {
|
|
7654
8322
|
bucket: formatGlobalResourceName({
|
|
7655
8323
|
appName: ctx.app.name,
|
|
7656
8324
|
resourceType: "job",
|
|
@@ -7676,8 +8344,8 @@ var jobFeature = defineFeature({
|
|
|
7676
8344
|
if (found.length === 0) {
|
|
7677
8345
|
return;
|
|
7678
8346
|
}
|
|
7679
|
-
const group = new
|
|
7680
|
-
const cluster = new
|
|
8347
|
+
const group = new Group27(ctx.base, "job", "cluster");
|
|
8348
|
+
const cluster = new aws28.ecs.Cluster(
|
|
7681
8349
|
group,
|
|
7682
8350
|
"cluster",
|
|
7683
8351
|
{
|
|
@@ -7689,7 +8357,7 @@ var jobFeature = defineFeature({
|
|
|
7689
8357
|
);
|
|
7690
8358
|
ctx.shared.set("job", "cluster-name", cluster.name);
|
|
7691
8359
|
ctx.shared.set("job", "cluster-arn", cluster.arn);
|
|
7692
|
-
const securityGroup = new
|
|
8360
|
+
const securityGroup = new aws28.security.Group(group, "security-group", {
|
|
7693
8361
|
name: `${ctx.app.name}-job`,
|
|
7694
8362
|
description: "Shared security group for jobs",
|
|
7695
8363
|
vpcId: ctx.shared.get("vpc", "id"),
|
|
@@ -7698,7 +8366,7 @@ var jobFeature = defineFeature({
|
|
|
7698
8366
|
APP: ctx.appConfig.name
|
|
7699
8367
|
}
|
|
7700
8368
|
});
|
|
7701
|
-
new
|
|
8369
|
+
new aws28.vpc.SecurityGroupEgressRule(group, "egress-rule", {
|
|
7702
8370
|
securityGroupId: securityGroup.id,
|
|
7703
8371
|
description: "Allow all outbound traffic from jobs",
|
|
7704
8372
|
ipProtocol: "-1",
|
|
@@ -7715,8 +8383,8 @@ var jobFeature = defineFeature({
|
|
|
7715
8383
|
})
|
|
7716
8384
|
);
|
|
7717
8385
|
if (needsPersistentStorage) {
|
|
7718
|
-
const storageGroup = new
|
|
7719
|
-
new
|
|
8386
|
+
const storageGroup = new Group27(ctx.base, "job", "persistent-storage");
|
|
8387
|
+
new aws28.vpc.SecurityGroupIngressRule(storageGroup, "ingress-rule", {
|
|
7720
8388
|
securityGroupId: securityGroup.id,
|
|
7721
8389
|
referencedSecurityGroupId: securityGroup.id,
|
|
7722
8390
|
description: "Allow NFS traffic from jobs",
|
|
@@ -7727,7 +8395,7 @@ var jobFeature = defineFeature({
|
|
|
7727
8395
|
APP: ctx.appConfig.name
|
|
7728
8396
|
}
|
|
7729
8397
|
});
|
|
7730
|
-
const fileSystem = new
|
|
8398
|
+
const fileSystem = new aws28.efs.FileSystem(storageGroup, "file-system", {
|
|
7731
8399
|
encrypted: true,
|
|
7732
8400
|
performanceMode: "generalPurpose",
|
|
7733
8401
|
throughputMode: "elastic",
|
|
@@ -7737,7 +8405,7 @@ var jobFeature = defineFeature({
|
|
|
7737
8405
|
}
|
|
7738
8406
|
});
|
|
7739
8407
|
for (const [index, subnetId] of ctx.shared.get("vpc", "public-subnets").entries()) {
|
|
7740
|
-
new
|
|
8408
|
+
new aws28.efs.MountTarget(storageGroup, `mount-target-${index + 1}`, {
|
|
7741
8409
|
fileSystemId: fileSystem.id,
|
|
7742
8410
|
subnetId,
|
|
7743
8411
|
securityGroups: [securityGroup.id]
|
|
@@ -7752,15 +8420,15 @@ var jobFeature = defineFeature({
|
|
|
7752
8420
|
const subnets = ctx.shared.get("vpc", "public-subnets");
|
|
7753
8421
|
ctx.addEnv(
|
|
7754
8422
|
"JOB_SUBNETS",
|
|
7755
|
-
new
|
|
7756
|
-
const resolved = await
|
|
8423
|
+
new Output8(new Set(findInputDeps5(subnets)), async (resolve2) => {
|
|
8424
|
+
const resolved = await resolveInputs5(subnets);
|
|
7757
8425
|
resolve2(JSON.stringify(resolved));
|
|
7758
8426
|
})
|
|
7759
8427
|
);
|
|
7760
8428
|
ctx.addEnv("JOB_SECURITY_GROUP", ctx.shared.get("job", "security-group-id"));
|
|
7761
8429
|
ctx.addEnv("JOB_PAYLOAD_BUCKET", ctx.shared.get("job", "bucket-name"));
|
|
7762
8430
|
for (const [id, props] of jobs) {
|
|
7763
|
-
const group = new
|
|
8431
|
+
const group = new Group27(ctx.stack, "job", id);
|
|
7764
8432
|
createFargateJob(group, ctx, "job", id, props);
|
|
7765
8433
|
}
|
|
7766
8434
|
ctx.addStackPermission({
|
|
@@ -7793,77 +8461,25 @@ var jobFeature = defineFeature({
|
|
|
7793
8461
|
});
|
|
7794
8462
|
|
|
7795
8463
|
// src/feature/instance/index.ts
|
|
7796
|
-
import { days as
|
|
8464
|
+
import { days as days11, seconds as seconds11, toSeconds as toSeconds10 } from "@awsless/duration";
|
|
7797
8465
|
import { kibibytes as kibibytes2, toBytes as toBytes2 } from "@awsless/size";
|
|
7798
|
-
import { Group as
|
|
7799
|
-
import { aws as
|
|
8466
|
+
import { Group as Group29 } from "@terraforge/core";
|
|
8467
|
+
import { aws as aws30 } from "@terraforge/aws";
|
|
7800
8468
|
import { constantCase as constantCase14 } from "change-case";
|
|
7801
8469
|
|
|
7802
8470
|
// src/feature/instance/util.ts
|
|
7803
|
-
import { toDays as
|
|
7804
|
-
import { stringify as
|
|
8471
|
+
import { toDays as toDays12, toSeconds as toSeconds9 } from "@awsless/duration";
|
|
8472
|
+
import { stringify as stringify3 } from "@awsless/json";
|
|
7805
8473
|
import { toMebibytes as toMebibytes6 } from "@awsless/size";
|
|
7806
8474
|
import { generateFileHash as generateFileHash3 } from "@awsless/ts-file-cache";
|
|
7807
|
-
import { aws as
|
|
7808
|
-
import { Group as
|
|
7809
|
-
import { constantCase as constantCase13, pascalCase as
|
|
7810
|
-
import { createHash as
|
|
8475
|
+
import { aws as aws29 } from "@terraforge/aws";
|
|
8476
|
+
import { Group as Group28, Output as Output9, findInputDeps as findInputDeps6, resolveInputs as resolveInputs6 } from "@terraforge/core";
|
|
8477
|
+
import { constantCase as constantCase13, pascalCase as pascalCase5 } from "change-case";
|
|
8478
|
+
import { createHash as createHash7 } from "crypto";
|
|
7811
8479
|
import deepmerge6 from "deepmerge";
|
|
7812
|
-
import { join as
|
|
7813
|
-
|
|
7814
|
-
// src/feature/instance/build/executable.ts
|
|
7815
|
-
import { createHash as createHash5 } from "crypto";
|
|
7816
|
-
import { readFile as readFile5 } from "fs/promises";
|
|
7817
|
-
import { join as join18 } from "path";
|
|
7818
|
-
var buildExecutable = async (input, outputPath, architecture) => {
|
|
7819
|
-
const filePath = join18(outputPath, "program");
|
|
7820
|
-
const target = architecture === "x86_64" ? "bun-linux-x64" : "bun-linux-arm64";
|
|
7821
|
-
let result;
|
|
7822
|
-
try {
|
|
7823
|
-
result = await Bun.build({
|
|
7824
|
-
entrypoints: [input],
|
|
7825
|
-
compile: {
|
|
7826
|
-
target,
|
|
7827
|
-
outfile: filePath
|
|
7828
|
-
},
|
|
7829
|
-
target: "bun",
|
|
7830
|
-
loader: {
|
|
7831
|
-
".md": "text",
|
|
7832
|
-
".txt": "text",
|
|
7833
|
-
".html": "text",
|
|
7834
|
-
".css": "text",
|
|
7835
|
-
".yaml": "text",
|
|
7836
|
-
".yml": "text",
|
|
7837
|
-
".xml": "text",
|
|
7838
|
-
".csv": "text",
|
|
7839
|
-
".svg": "text",
|
|
7840
|
-
".png": "file",
|
|
7841
|
-
".jpg": "file",
|
|
7842
|
-
".jpeg": "file",
|
|
7843
|
-
".gif": "file",
|
|
7844
|
-
".webp": "file",
|
|
7845
|
-
".wasm": "file"
|
|
7846
|
-
}
|
|
7847
|
-
});
|
|
7848
|
-
} catch (error) {
|
|
7849
|
-
throw new ExpectedError(
|
|
7850
|
-
`Executable build failed: ${error instanceof Error ? error.message : JSON.stringify(error)}`
|
|
7851
|
-
);
|
|
7852
|
-
}
|
|
7853
|
-
if (!result.success) {
|
|
7854
|
-
throw new ExpectedError(`Executable build failed:
|
|
7855
|
-
${result.logs?.map((log35) => log35.message).join("\n")}`);
|
|
7856
|
-
}
|
|
7857
|
-
const file = await readFile5(filePath);
|
|
7858
|
-
return {
|
|
7859
|
-
hash: createHash5("sha1").update(file).update("x86_64").digest("hex"),
|
|
7860
|
-
file
|
|
7861
|
-
};
|
|
7862
|
-
};
|
|
7863
|
-
|
|
7864
|
-
// src/feature/instance/util.ts
|
|
8480
|
+
import { join as join21 } from "path";
|
|
7865
8481
|
var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
7866
|
-
const group = new
|
|
8482
|
+
const group = new Group28(parentGroup, "instance", ns);
|
|
7867
8483
|
const name = formatLocalResourceName({
|
|
7868
8484
|
appName: ctx.app.name,
|
|
7869
8485
|
stackName: ctx.stack.name,
|
|
@@ -7889,13 +8505,13 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
7889
8505
|
};
|
|
7890
8506
|
});
|
|
7891
8507
|
});
|
|
7892
|
-
const code = new
|
|
8508
|
+
const code = new aws29.s3.BucketObject(group, "code", {
|
|
7893
8509
|
bucket: ctx.shared.get("instance", "bucket-name"),
|
|
7894
8510
|
key: name,
|
|
7895
8511
|
source: relativePath(getBuildPath("instance", name, "program")),
|
|
7896
8512
|
sourceHash: $file(getBuildPath("instance", name, "HASH"))
|
|
7897
8513
|
});
|
|
7898
|
-
const executionRole = new
|
|
8514
|
+
const executionRole = new aws29.iam.Role(group, "execution-role", {
|
|
7899
8515
|
name: shortId(`${shortName}:execution-role`),
|
|
7900
8516
|
description: name,
|
|
7901
8517
|
assumeRolePolicy: JSON.stringify({
|
|
@@ -7912,7 +8528,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
7912
8528
|
}),
|
|
7913
8529
|
managedPolicyArns: ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
|
|
7914
8530
|
});
|
|
7915
|
-
const role = new
|
|
8531
|
+
const role = new aws29.iam.Role(
|
|
7916
8532
|
group,
|
|
7917
8533
|
"task-role",
|
|
7918
8534
|
{
|
|
@@ -7938,7 +8554,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
7938
8554
|
Version: "2012-10-17",
|
|
7939
8555
|
Statement: [
|
|
7940
8556
|
{
|
|
7941
|
-
Effect:
|
|
8557
|
+
Effect: pascalCase5("allow"),
|
|
7942
8558
|
Action: ["s3:getObject", "s3:HeadObject"],
|
|
7943
8559
|
Resource: `arn:aws:s3:::${bucket}/${key}`
|
|
7944
8560
|
}
|
|
@@ -7954,16 +8570,16 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
7954
8570
|
);
|
|
7955
8571
|
const statements = [];
|
|
7956
8572
|
const statementDeps = /* @__PURE__ */ new Set();
|
|
7957
|
-
const policy = new
|
|
8573
|
+
const policy = new aws29.iam.RolePolicy(group, "policy", {
|
|
7958
8574
|
role: role.name,
|
|
7959
8575
|
name: "task-policy",
|
|
7960
|
-
policy: new
|
|
7961
|
-
const list3 = await
|
|
8576
|
+
policy: new Output9(statementDeps, async (resolve2) => {
|
|
8577
|
+
const list3 = await resolveInputs6(statements);
|
|
7962
8578
|
resolve2(
|
|
7963
8579
|
JSON.stringify({
|
|
7964
8580
|
Version: "2012-10-17",
|
|
7965
8581
|
Statement: list3.map((statement) => ({
|
|
7966
|
-
Effect:
|
|
8582
|
+
Effect: pascalCase5(statement.effect ?? "allow"),
|
|
7967
8583
|
Action: statement.actions,
|
|
7968
8584
|
Resource: statement.resources
|
|
7969
8585
|
}))
|
|
@@ -7973,7 +8589,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
7973
8589
|
});
|
|
7974
8590
|
const addPermission = (...permissions) => {
|
|
7975
8591
|
statements.push(...permissions);
|
|
7976
|
-
for (const dep of
|
|
8592
|
+
for (const dep of findInputDeps6(permissions)) {
|
|
7977
8593
|
statementDeps.add(dep);
|
|
7978
8594
|
}
|
|
7979
8595
|
};
|
|
@@ -7982,13 +8598,13 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
7982
8598
|
});
|
|
7983
8599
|
let logGroup;
|
|
7984
8600
|
if (props.log.retention && props.log.retention.value > 0n) {
|
|
7985
|
-
logGroup = new
|
|
8601
|
+
logGroup = new aws29.cloudwatch.LogGroup(group, "log", {
|
|
7986
8602
|
name: `/aws/ecs/${name}`,
|
|
7987
8603
|
// name: `/aws/lambda/${name}`,
|
|
7988
|
-
retentionInDays:
|
|
8604
|
+
retentionInDays: toDays12(props.log.retention)
|
|
7989
8605
|
});
|
|
7990
8606
|
if (ctx.shared.has("on-error-log", "subscriber-arn")) {
|
|
7991
|
-
new
|
|
8607
|
+
new aws29.cloudwatch.LogSubscriptionFilter(group, "on-error-log", {
|
|
7992
8608
|
name: "error-log-subscription",
|
|
7993
8609
|
destinationArn: ctx.shared.get("on-error-log", "subscriber-arn"),
|
|
7994
8610
|
logGroupName: logGroup.name,
|
|
@@ -8003,7 +8619,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8003
8619
|
};
|
|
8004
8620
|
const variables = {};
|
|
8005
8621
|
const variableDeps = /* @__PURE__ */ new Set();
|
|
8006
|
-
const task2 = new
|
|
8622
|
+
const task2 = new aws29.ecs.TaskDefinition(
|
|
8007
8623
|
group,
|
|
8008
8624
|
"task",
|
|
8009
8625
|
{
|
|
@@ -8019,9 +8635,9 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8019
8635
|
operatingSystemFamily: "LINUX"
|
|
8020
8636
|
},
|
|
8021
8637
|
trackLatest: true,
|
|
8022
|
-
containerDefinitions: new
|
|
8023
|
-
const data = await
|
|
8024
|
-
const { s3Bucket, s3Key } = await
|
|
8638
|
+
containerDefinitions: new Output9(variableDeps, async (resolve2) => {
|
|
8639
|
+
const data = await resolveInputs6(variables);
|
|
8640
|
+
const { s3Bucket, s3Key } = await resolveInputs6({
|
|
8025
8641
|
s3Bucket: code.bucket,
|
|
8026
8642
|
s3Key: code.key
|
|
8027
8643
|
});
|
|
@@ -8076,12 +8692,12 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8076
8692
|
healthCheck: props.healthCheck ? {
|
|
8077
8693
|
command: [
|
|
8078
8694
|
"CMD-SHELL",
|
|
8079
|
-
`curl -f http://${
|
|
8695
|
+
`curl -f http://${join21("localhost", props.healthCheck.path)} || exit 1`
|
|
8080
8696
|
],
|
|
8081
|
-
interval:
|
|
8697
|
+
interval: toSeconds9(props.healthCheck.interval),
|
|
8082
8698
|
retries: props.healthCheck.retries,
|
|
8083
|
-
startPeriod:
|
|
8084
|
-
timeout:
|
|
8699
|
+
startPeriod: toSeconds9(props.healthCheck.startPeriod),
|
|
8700
|
+
timeout: toSeconds9(props.healthCheck.timeout)
|
|
8085
8701
|
} : void 0
|
|
8086
8702
|
}
|
|
8087
8703
|
])
|
|
@@ -8101,14 +8717,14 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8101
8717
|
dependsOn: [code]
|
|
8102
8718
|
}
|
|
8103
8719
|
);
|
|
8104
|
-
const securityGroup = new
|
|
8720
|
+
const securityGroup = new aws29.security.Group(group, "security-group", {
|
|
8105
8721
|
name,
|
|
8106
8722
|
description: "Security group for the instance",
|
|
8107
8723
|
vpcId: ctx.shared.get("vpc", "id"),
|
|
8108
8724
|
revokeRulesOnDelete: true,
|
|
8109
8725
|
tags
|
|
8110
8726
|
});
|
|
8111
|
-
new
|
|
8727
|
+
new aws29.vpc.SecurityGroupEgressRule(group, "egress-rule", {
|
|
8112
8728
|
securityGroupId: securityGroup.id,
|
|
8113
8729
|
description: `Allow all outbound traffic from the ${name} instance`,
|
|
8114
8730
|
ipProtocol: "-1",
|
|
@@ -8117,7 +8733,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8117
8733
|
});
|
|
8118
8734
|
const clusterName = ctx.shared.get("instance", "cluster-name");
|
|
8119
8735
|
const clusterArn = ctx.shared.get("instance", "cluster-arn");
|
|
8120
|
-
const service = new
|
|
8736
|
+
const service = new aws29.ecs.Service(
|
|
8121
8737
|
group,
|
|
8122
8738
|
"service",
|
|
8123
8739
|
{
|
|
@@ -8153,7 +8769,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8153
8769
|
replaceOnChanges: ["cluster"]
|
|
8154
8770
|
}
|
|
8155
8771
|
);
|
|
8156
|
-
new
|
|
8772
|
+
new aws29.appautoscaling.Target(
|
|
8157
8773
|
group,
|
|
8158
8774
|
"autoscaling-target",
|
|
8159
8775
|
{
|
|
@@ -8172,7 +8788,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8172
8788
|
);
|
|
8173
8789
|
ctx.onEnv((name2, value) => {
|
|
8174
8790
|
variables[name2] = value;
|
|
8175
|
-
for (const dep of
|
|
8791
|
+
for (const dep of findInputDeps6([value])) {
|
|
8176
8792
|
variableDeps.add(dep);
|
|
8177
8793
|
}
|
|
8178
8794
|
});
|
|
@@ -8181,7 +8797,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8181
8797
|
variables.AWS_ACCOUNT_ID = ctx.accountId;
|
|
8182
8798
|
variables.STACK = ctx.stackConfig.name;
|
|
8183
8799
|
variables.CODE_HASH = code.sourceHash;
|
|
8184
|
-
variables.INSTANCE_CONFIG_HASH =
|
|
8800
|
+
variables.INSTANCE_CONFIG_HASH = createHash7("sha1").update(stringify3(props)).digest("hex");
|
|
8185
8801
|
if (props.environment) {
|
|
8186
8802
|
for (const [key, value] of Object.entries(props.environment)) {
|
|
8187
8803
|
variables[key] = value;
|
|
@@ -8197,7 +8813,7 @@ var createFargateTask = (parentGroup, ctx, ns, id, local) => {
|
|
|
8197
8813
|
};
|
|
8198
8814
|
|
|
8199
8815
|
// src/feature/instance/index.ts
|
|
8200
|
-
var
|
|
8816
|
+
var typeGenCode12 = `
|
|
8201
8817
|
import { SendMessageOptions } from '@awsless/sqs'
|
|
8202
8818
|
import type { Mock } from 'vitest'
|
|
8203
8819
|
|
|
@@ -8236,15 +8852,15 @@ var instanceFeature = defineFeature({
|
|
|
8236
8852
|
mocks.addType(stack.name, mock);
|
|
8237
8853
|
mockResponses.addType(stack.name, mockResponse);
|
|
8238
8854
|
}
|
|
8239
|
-
gen.addCode(
|
|
8855
|
+
gen.addCode(typeGenCode12);
|
|
8240
8856
|
gen.addInterface("InstanceResources", resources2);
|
|
8241
8857
|
gen.addInterface("InstanceMock", mocks);
|
|
8242
8858
|
gen.addInterface("InstanceMockResponse", mockResponses);
|
|
8243
8859
|
await ctx.write("instance.d.ts", gen, true);
|
|
8244
8860
|
},
|
|
8245
8861
|
onBefore(ctx) {
|
|
8246
|
-
const group = new
|
|
8247
|
-
const bucket = new
|
|
8862
|
+
const group = new Group29(ctx.base, "instance", "asset");
|
|
8863
|
+
const bucket = new aws30.s3.Bucket(group, "bucket", {
|
|
8248
8864
|
bucket: formatGlobalResourceName({
|
|
8249
8865
|
appName: ctx.app.name,
|
|
8250
8866
|
resourceType: "instance",
|
|
@@ -8262,8 +8878,8 @@ var instanceFeature = defineFeature({
|
|
|
8262
8878
|
if (found.length === 0) {
|
|
8263
8879
|
return;
|
|
8264
8880
|
}
|
|
8265
|
-
const group = new
|
|
8266
|
-
const cluster = new
|
|
8881
|
+
const group = new Group29(ctx.base, "instance", "cluster");
|
|
8882
|
+
const cluster = new aws30.ecs.Cluster(
|
|
8267
8883
|
group,
|
|
8268
8884
|
"cluster",
|
|
8269
8885
|
{
|
|
@@ -8278,14 +8894,14 @@ var instanceFeature = defineFeature({
|
|
|
8278
8894
|
},
|
|
8279
8895
|
onStack(ctx) {
|
|
8280
8896
|
for (const [id, props] of Object.entries(ctx.stackConfig.instances ?? {})) {
|
|
8281
|
-
const group = new
|
|
8897
|
+
const group = new Group29(ctx.stack, "instance", id);
|
|
8282
8898
|
const task2 = createFargateTask(group, ctx, "instance", id, props);
|
|
8283
|
-
const queue2 = new
|
|
8899
|
+
const queue2 = new aws30.sqs.Queue(group, "queue", {
|
|
8284
8900
|
name: task2.name,
|
|
8285
|
-
visibilityTimeoutSeconds:
|
|
8286
|
-
messageRetentionSeconds:
|
|
8901
|
+
visibilityTimeoutSeconds: toSeconds10(seconds11(30)),
|
|
8902
|
+
messageRetentionSeconds: toSeconds10(days11(4)),
|
|
8287
8903
|
maxMessageSize: toBytes2(kibibytes2(256)),
|
|
8288
|
-
receiveWaitTimeSeconds:
|
|
8904
|
+
receiveWaitTimeSeconds: toSeconds10(seconds11(20))
|
|
8289
8905
|
});
|
|
8290
8906
|
task2.addPermission({
|
|
8291
8907
|
actions: [
|
|
@@ -8307,11 +8923,11 @@ var instanceFeature = defineFeature({
|
|
|
8307
8923
|
});
|
|
8308
8924
|
|
|
8309
8925
|
// src/feature/metric/index.ts
|
|
8310
|
-
import { Group as
|
|
8311
|
-
import { aws as
|
|
8926
|
+
import { Group as Group30 } from "@terraforge/core";
|
|
8927
|
+
import { aws as aws31 } from "@terraforge/aws";
|
|
8312
8928
|
import { kebabCase as kebabCase8, constantCase as constantCase15 } from "change-case";
|
|
8313
|
-
import { toSeconds as
|
|
8314
|
-
var
|
|
8929
|
+
import { toSeconds as toSeconds11 } from "@awsless/duration";
|
|
8930
|
+
var typeGenCode13 = `
|
|
8315
8931
|
import { type PutDataProps, putData, batchPutData } from '@awsless/cloudwatch'
|
|
8316
8932
|
import { type Duration } from '@awsless/duration'
|
|
8317
8933
|
import { type Size } from '@awsless/size'
|
|
@@ -8359,7 +8975,7 @@ var metricFeature = defineFeature({
|
|
|
8359
8975
|
resources2.addType(stack.name, stackResources);
|
|
8360
8976
|
}
|
|
8361
8977
|
resources2.addType("batch", "Batch");
|
|
8362
|
-
gen.addCode(
|
|
8978
|
+
gen.addCode(typeGenCode13);
|
|
8363
8979
|
gen.addInterface("MetricResources", resources2);
|
|
8364
8980
|
await ctx.write("metric.d.ts", gen, true);
|
|
8365
8981
|
},
|
|
@@ -8376,16 +8992,16 @@ var metricFeature = defineFeature({
|
|
|
8376
8992
|
}
|
|
8377
8993
|
});
|
|
8378
8994
|
for (const [id, props] of Object.entries(ctx.stackConfig.metrics ?? {})) {
|
|
8379
|
-
const group = new
|
|
8995
|
+
const group = new Group30(ctx.stack, "metric", id);
|
|
8380
8996
|
ctx.addEnv(`METRIC_${constantCase15(id)}`, props.type);
|
|
8381
8997
|
for (const alarmId in props.alarms ?? []) {
|
|
8382
|
-
const alarmGroup = new
|
|
8998
|
+
const alarmGroup = new Group30(group, "alarm", alarmId);
|
|
8383
8999
|
const alarmName = kebabCase8(`${id}-${alarmId}`);
|
|
8384
9000
|
const alarmProps = props.alarms[alarmId];
|
|
8385
9001
|
let alarmAction;
|
|
8386
9002
|
let alarmLambda;
|
|
8387
9003
|
if (Array.isArray(alarmProps.trigger)) {
|
|
8388
|
-
const topic = new
|
|
9004
|
+
const topic = new aws31.sns.Topic(alarmGroup, "alarm-trigger", {
|
|
8389
9005
|
name: formatLocalResourceName({
|
|
8390
9006
|
appName: ctx.app.name,
|
|
8391
9007
|
stackName: ctx.stack.name,
|
|
@@ -8395,7 +9011,7 @@ var metricFeature = defineFeature({
|
|
|
8395
9011
|
});
|
|
8396
9012
|
alarmAction = topic.arn;
|
|
8397
9013
|
for (const email of alarmProps.trigger) {
|
|
8398
|
-
new
|
|
9014
|
+
new aws31.sns.TopicSubscription(alarmGroup, email, {
|
|
8399
9015
|
topicArn: topic.arn,
|
|
8400
9016
|
protocol: "email",
|
|
8401
9017
|
endpoint: email
|
|
@@ -8406,7 +9022,7 @@ var metricFeature = defineFeature({
|
|
|
8406
9022
|
alarmLambda = lambda;
|
|
8407
9023
|
alarmAction = lambda.arn;
|
|
8408
9024
|
}
|
|
8409
|
-
const alarm = new
|
|
9025
|
+
const alarm = new aws31.cloudwatch.MetricAlarm(alarmGroup, "alarm", {
|
|
8410
9026
|
namespace,
|
|
8411
9027
|
metricName: kebabCase8(id),
|
|
8412
9028
|
alarmName: formatLocalResourceName({
|
|
@@ -8418,13 +9034,13 @@ var metricFeature = defineFeature({
|
|
|
8418
9034
|
alarmDescription: alarmProps.description,
|
|
8419
9035
|
statistic: alarmProps.where.stat,
|
|
8420
9036
|
threshold: alarmProps.where.value,
|
|
8421
|
-
period:
|
|
9037
|
+
period: toSeconds11(alarmProps.period),
|
|
8422
9038
|
evaluationPeriods: alarmProps.minDataPoints,
|
|
8423
9039
|
comparisonOperator: alarmProps.where.op,
|
|
8424
9040
|
alarmActions: [alarmAction]
|
|
8425
9041
|
});
|
|
8426
9042
|
if (alarmLambda) {
|
|
8427
|
-
new
|
|
9043
|
+
new aws31.lambda.Permission(alarmGroup, "permission", {
|
|
8428
9044
|
action: "lambda:InvokeFunction",
|
|
8429
9045
|
principal: "lambda.alarms.cloudwatch.amazonaws.com",
|
|
8430
9046
|
functionName: alarmLambda.functionName,
|
|
@@ -8437,9 +9053,9 @@ var metricFeature = defineFeature({
|
|
|
8437
9053
|
});
|
|
8438
9054
|
|
|
8439
9055
|
// src/feature/router/index.ts
|
|
8440
|
-
import { days as
|
|
8441
|
-
import { Future, Group as
|
|
8442
|
-
import { aws as
|
|
9056
|
+
import { days as days12, seconds as seconds12, toSeconds as toSeconds12, years } from "@awsless/duration";
|
|
9057
|
+
import { Future, Group as Group31 } from "@terraforge/core";
|
|
9058
|
+
import { aws as aws32 } from "@terraforge/aws";
|
|
8443
9059
|
import { camelCase as camelCase9, constantCase as constantCase16 } from "change-case";
|
|
8444
9060
|
|
|
8445
9061
|
// src/feature/router/router-code.ts
|
|
@@ -8688,18 +9304,18 @@ async function handler(event) {
|
|
|
8688
9304
|
`;
|
|
8689
9305
|
|
|
8690
9306
|
// src/feature/router/index.ts
|
|
8691
|
-
import { createHash as
|
|
9307
|
+
import { createHash as createHash8 } from "crypto";
|
|
8692
9308
|
var routerFeature = defineFeature({
|
|
8693
9309
|
name: "router",
|
|
8694
9310
|
onApp(ctx) {
|
|
8695
9311
|
for (const [id, props] of Object.entries(ctx.appConfig.defaults.router ?? {})) {
|
|
8696
|
-
const group = new
|
|
9312
|
+
const group = new Group31(ctx.base, "router", id);
|
|
8697
9313
|
const name = formatGlobalResourceName({
|
|
8698
9314
|
appName: ctx.app.name,
|
|
8699
9315
|
resourceType: "router",
|
|
8700
9316
|
resourceName: id
|
|
8701
9317
|
});
|
|
8702
|
-
const routeStore = new
|
|
9318
|
+
const routeStore = new aws32.cloudfront.KeyValueStore(group, "routes", {
|
|
8703
9319
|
name,
|
|
8704
9320
|
comment: "Store for routes"
|
|
8705
9321
|
});
|
|
@@ -8729,11 +9345,11 @@ var routerFeature = defineFeature({
|
|
|
8729
9345
|
);
|
|
8730
9346
|
importedRoutes.push(importKeys);
|
|
8731
9347
|
});
|
|
8732
|
-
const cache = new
|
|
9348
|
+
const cache = new aws32.cloudfront.CachePolicy(group, "cache", {
|
|
8733
9349
|
name,
|
|
8734
|
-
minTtl:
|
|
8735
|
-
maxTtl:
|
|
8736
|
-
defaultTtl:
|
|
9350
|
+
minTtl: toSeconds12(seconds12(0)),
|
|
9351
|
+
maxTtl: toSeconds12(days12(365)),
|
|
9352
|
+
defaultTtl: toSeconds12(days12(0)),
|
|
8737
9353
|
parametersInCacheKeyAndForwardedToOrigin: {
|
|
8738
9354
|
enableAcceptEncodingBrotli: true,
|
|
8739
9355
|
enableAcceptEncodingGzip: true,
|
|
@@ -8761,7 +9377,7 @@ var routerFeature = defineFeature({
|
|
|
8761
9377
|
}
|
|
8762
9378
|
}
|
|
8763
9379
|
});
|
|
8764
|
-
const originRequest = new
|
|
9380
|
+
const originRequest = new aws32.cloudfront.OriginRequestPolicy(group, "request", {
|
|
8765
9381
|
name,
|
|
8766
9382
|
headersConfig: {
|
|
8767
9383
|
headerBehavior: camelCase9("all-except"),
|
|
@@ -8779,11 +9395,11 @@ var routerFeature = defineFeature({
|
|
|
8779
9395
|
queryStringBehavior: "all"
|
|
8780
9396
|
}
|
|
8781
9397
|
});
|
|
8782
|
-
const responseHeaders = new
|
|
9398
|
+
const responseHeaders = new aws32.cloudfront.ResponseHeadersPolicy(group, "response", {
|
|
8783
9399
|
name,
|
|
8784
9400
|
corsConfig: {
|
|
8785
9401
|
originOverride: props.cors?.override ?? true,
|
|
8786
|
-
accessControlMaxAgeSec:
|
|
9402
|
+
accessControlMaxAgeSec: toSeconds12(props.cors?.maxAge ?? years(1)),
|
|
8787
9403
|
accessControlAllowHeaders: { items: props.cors?.headers ?? ["*"] },
|
|
8788
9404
|
accessControlAllowMethods: { items: props.cors?.methods ?? ["ALL"] },
|
|
8789
9405
|
accessControlAllowOrigins: { items: props.cors?.origins ?? ["*"] },
|
|
@@ -8808,7 +9424,7 @@ var routerFeature = defineFeature({
|
|
|
8808
9424
|
strictTransportSecurity: {
|
|
8809
9425
|
override: true,
|
|
8810
9426
|
preload: true,
|
|
8811
|
-
accessControlMaxAgeSec:
|
|
9427
|
+
accessControlMaxAgeSec: toSeconds12(years(1)),
|
|
8812
9428
|
includeSubdomains: true
|
|
8813
9429
|
},
|
|
8814
9430
|
xssProtection: {
|
|
@@ -8818,7 +9434,7 @@ var routerFeature = defineFeature({
|
|
|
8818
9434
|
}
|
|
8819
9435
|
}
|
|
8820
9436
|
});
|
|
8821
|
-
const viewerRequest = new
|
|
9437
|
+
const viewerRequest = new aws32.cloudfront.Function(group, "viewer-request", {
|
|
8822
9438
|
name,
|
|
8823
9439
|
runtime: `cloudfront-js-2.0`,
|
|
8824
9440
|
comment: `Viewer Request - ${name}`,
|
|
@@ -8840,7 +9456,7 @@ var routerFeature = defineFeature({
|
|
|
8840
9456
|
rateBasedStatement: {
|
|
8841
9457
|
limit: wafSettingsConfig.rateLimiter.limit,
|
|
8842
9458
|
aggregateKeyType: "IP",
|
|
8843
|
-
evaluationWindowSec:
|
|
9459
|
+
evaluationWindowSec: toSeconds12(wafSettingsConfig.rateLimiter.window)
|
|
8844
9460
|
}
|
|
8845
9461
|
},
|
|
8846
9462
|
action: {
|
|
@@ -8920,7 +9536,7 @@ var routerFeature = defineFeature({
|
|
|
8920
9536
|
}
|
|
8921
9537
|
let waf;
|
|
8922
9538
|
if (wafRules.length && wafSettingsConfig) {
|
|
8923
|
-
waf = new
|
|
9539
|
+
waf = new aws32.wafv2.WebAcl(group, "waf", {
|
|
8924
9540
|
name: `${name}-wafv2`,
|
|
8925
9541
|
scope: "CLOUDFRONT",
|
|
8926
9542
|
defaultAction: {
|
|
@@ -8930,12 +9546,12 @@ var routerFeature = defineFeature({
|
|
|
8930
9546
|
rule: wafRules,
|
|
8931
9547
|
captchaConfig: {
|
|
8932
9548
|
immunityTimeProperty: {
|
|
8933
|
-
immunityTime:
|
|
9549
|
+
immunityTime: toSeconds12(wafSettingsConfig.captchaImmunityTime)
|
|
8934
9550
|
}
|
|
8935
9551
|
},
|
|
8936
9552
|
challengeConfig: {
|
|
8937
9553
|
immunityTimeProperty: {
|
|
8938
|
-
immunityTime:
|
|
9554
|
+
immunityTime: toSeconds12(wafSettingsConfig.challengeImmunityTime)
|
|
8939
9555
|
}
|
|
8940
9556
|
},
|
|
8941
9557
|
visibilityConfig: {
|
|
@@ -8945,7 +9561,7 @@ var routerFeature = defineFeature({
|
|
|
8945
9561
|
}
|
|
8946
9562
|
});
|
|
8947
9563
|
}
|
|
8948
|
-
const distribution = new
|
|
9564
|
+
const distribution = new aws32.cloudfront.MultitenantDistribution(group, "distribution", {
|
|
8949
9565
|
tags: {
|
|
8950
9566
|
name
|
|
8951
9567
|
},
|
|
@@ -8991,7 +9607,7 @@ var routerFeature = defineFeature({
|
|
|
8991
9607
|
}
|
|
8992
9608
|
return {
|
|
8993
9609
|
errorCode: Number(errorCode),
|
|
8994
|
-
errorCachingMinTtl: item.minTTL ?
|
|
9610
|
+
errorCachingMinTtl: item.minTTL ? toSeconds12(item.minTTL) : void 0,
|
|
8995
9611
|
responseCode: item.statusCode?.toString() ?? errorCode,
|
|
8996
9612
|
responsePagePath: item.path
|
|
8997
9613
|
};
|
|
@@ -9042,7 +9658,7 @@ var routerFeature = defineFeature({
|
|
|
9042
9658
|
version: new Future((resolve2) => {
|
|
9043
9659
|
$combine(...versions).then((versions2) => {
|
|
9044
9660
|
const combined = versions2.filter((v) => !!v).sort().join(",");
|
|
9045
|
-
const version =
|
|
9661
|
+
const version = createHash8("sha1").update(combined).digest("hex");
|
|
9046
9662
|
resolve2(version);
|
|
9047
9663
|
});
|
|
9048
9664
|
})
|
|
@@ -9057,10 +9673,10 @@ var routerFeature = defineFeature({
|
|
|
9057
9673
|
const domainName = formatFullDomainName(ctx.appConfig, props.domain, props.subDomain);
|
|
9058
9674
|
const certificateArn = ctx.shared.entry("domain", `global-certificate-arn`, props.domain);
|
|
9059
9675
|
const zoneId = ctx.shared.entry("domain", "zone-id", props.domain);
|
|
9060
|
-
const connectionGroup = new
|
|
9676
|
+
const connectionGroup = new aws32.cloudfront.ConnectionGroup(group, "connection-group", {
|
|
9061
9677
|
name
|
|
9062
9678
|
});
|
|
9063
|
-
new
|
|
9679
|
+
new aws32.cloudfront.DistributionTenant(group, `tenant`, {
|
|
9064
9680
|
name,
|
|
9065
9681
|
enabled: true,
|
|
9066
9682
|
distributionId: distribution.id,
|
|
@@ -9068,7 +9684,7 @@ var routerFeature = defineFeature({
|
|
|
9068
9684
|
domain: [{ domain: domainName }],
|
|
9069
9685
|
customizations: [{ certificate: [{ arn: certificateArn }] }]
|
|
9070
9686
|
});
|
|
9071
|
-
new
|
|
9687
|
+
new aws32.route53.Record(group, `record`, {
|
|
9072
9688
|
zoneId,
|
|
9073
9689
|
type: "A",
|
|
9074
9690
|
name: domainName,
|
|
@@ -10191,21 +10807,21 @@ import wildstring4 from "wildstring";
|
|
|
10191
10807
|
|
|
10192
10808
|
// src/cli/ui/complex/run-tests.ts
|
|
10193
10809
|
import { log as log18 } from "@awsless/clui";
|
|
10194
|
-
import { mkdir as mkdir4, readFile as
|
|
10195
|
-
import { join as
|
|
10810
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
10811
|
+
import { join as join23 } from "path";
|
|
10196
10812
|
import wildstring3 from "wildstring";
|
|
10197
|
-
import { parse as parse4, stringify as
|
|
10813
|
+
import { parse as parse4, stringify as stringify4 } from "@awsless/json";
|
|
10198
10814
|
import { generateFolderHash, loadWorkspace as loadWorkspace2 } from "@awsless/ts-file-cache";
|
|
10199
10815
|
|
|
10200
10816
|
// src/test/start.ts
|
|
10201
|
-
import { dirname as
|
|
10202
|
-
import { fileURLToPath as
|
|
10817
|
+
import { dirname as dirname11, join as join22 } from "path";
|
|
10818
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10203
10819
|
import { configDefaults } from "vitest/config";
|
|
10204
10820
|
import { startVitest } from "vitest/node";
|
|
10205
10821
|
var NullReporter = class {
|
|
10206
10822
|
};
|
|
10207
10823
|
var startTest = async (props) => {
|
|
10208
|
-
const
|
|
10824
|
+
const __dirname7 = dirname11(fileURLToPath6(import.meta.url));
|
|
10209
10825
|
const startTime = process.hrtime.bigint();
|
|
10210
10826
|
process.noDeprecation = true;
|
|
10211
10827
|
const vitest = await startVitest(
|
|
@@ -10236,7 +10852,7 @@ var startTest = async (props) => {
|
|
|
10236
10852
|
// },
|
|
10237
10853
|
setupFiles: [
|
|
10238
10854
|
//
|
|
10239
|
-
|
|
10855
|
+
join22(__dirname7, "test-global-setup.js")
|
|
10240
10856
|
]
|
|
10241
10857
|
// globalSetup: [
|
|
10242
10858
|
// //
|
|
@@ -10430,12 +11046,12 @@ var logTestErrors = (event) => {
|
|
|
10430
11046
|
};
|
|
10431
11047
|
var runTest = async (stack, dir, filters, workspace, opts) => {
|
|
10432
11048
|
await mkdir4(directories.test, { recursive: true });
|
|
10433
|
-
const file =
|
|
11049
|
+
const file = join23(directories.test, `${stack}.json`);
|
|
10434
11050
|
const fingerprint = await generateFolderHash(workspace, dir);
|
|
10435
11051
|
if (!process.env.NO_CACHE) {
|
|
10436
11052
|
const exists = await fileExist(file);
|
|
10437
11053
|
if (exists) {
|
|
10438
|
-
const raw = await
|
|
11054
|
+
const raw = await readFile7(file, { encoding: "utf8" });
|
|
10439
11055
|
const data = parse4(raw);
|
|
10440
11056
|
if (data.fingerprint === fingerprint) {
|
|
10441
11057
|
log18.step(
|
|
@@ -10480,7 +11096,7 @@ var runTest = async (stack, dir, filters, workspace, opts) => {
|
|
|
10480
11096
|
logTestErrors(result);
|
|
10481
11097
|
await writeFile4(
|
|
10482
11098
|
file,
|
|
10483
|
-
|
|
11099
|
+
stringify4({
|
|
10484
11100
|
...result,
|
|
10485
11101
|
fingerprint
|
|
10486
11102
|
})
|
|
@@ -11115,7 +11731,7 @@ import { log as log25 } from "@awsless/clui";
|
|
|
11115
11731
|
|
|
11116
11732
|
// src/type-gen/generate.ts
|
|
11117
11733
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
11118
|
-
import { dirname as
|
|
11734
|
+
import { dirname as dirname12, join as join24, relative as relative9 } from "path";
|
|
11119
11735
|
var generateTypes = async (props) => {
|
|
11120
11736
|
const files = [];
|
|
11121
11737
|
await Promise.all(
|
|
@@ -11124,12 +11740,12 @@ var generateTypes = async (props) => {
|
|
|
11124
11740
|
...props,
|
|
11125
11741
|
async write(file, data, include = false) {
|
|
11126
11742
|
const code = data?.toString("utf8");
|
|
11127
|
-
const path =
|
|
11743
|
+
const path = join24(directories.types, file);
|
|
11128
11744
|
if (code) {
|
|
11129
11745
|
if (include) {
|
|
11130
11746
|
files.push(relative9(directories.root, path));
|
|
11131
11747
|
}
|
|
11132
|
-
await mkdir5(
|
|
11748
|
+
await mkdir5(dirname12(path), { recursive: true });
|
|
11133
11749
|
await writeFile5(path, code);
|
|
11134
11750
|
}
|
|
11135
11751
|
}
|
|
@@ -11138,7 +11754,7 @@ var generateTypes = async (props) => {
|
|
|
11138
11754
|
);
|
|
11139
11755
|
if (files.length) {
|
|
11140
11756
|
const code = files.map((file) => `/// <reference path='${file}' />`).join("\n");
|
|
11141
|
-
await writeFile5(
|
|
11757
|
+
await writeFile5(join24(directories.root, `awsless.d.ts`), code);
|
|
11142
11758
|
}
|
|
11143
11759
|
};
|
|
11144
11760
|
|
|
@@ -11564,7 +12180,7 @@ var domain = (program2) => {
|
|
|
11564
12180
|
// src/cli/command/logs.ts
|
|
11565
12181
|
import { CloudWatchLogsClient, StartLiveTailCommand } from "@aws-sdk/client-cloudwatch-logs";
|
|
11566
12182
|
import { log as log30 } from "@awsless/clui";
|
|
11567
|
-
import { aws as
|
|
12183
|
+
import { aws as aws33 } from "@terraforge/aws";
|
|
11568
12184
|
import chalk6 from "chalk";
|
|
11569
12185
|
import chunk2 from "chunk";
|
|
11570
12186
|
import { formatDate } from "date-fns";
|
|
@@ -11587,7 +12203,7 @@ var logs = (program2) => {
|
|
|
11587
12203
|
for (const stack of app.stacks) {
|
|
11588
12204
|
if (filters.find((f) => wildstring7.match(f, stack.name))) {
|
|
11589
12205
|
for (const resource of stack.resources) {
|
|
11590
|
-
if (resource instanceof
|
|
12206
|
+
if (resource instanceof aws33.cloudwatch.LogGroup) {
|
|
11591
12207
|
logGroupArns.push(await resource.arn);
|
|
11592
12208
|
}
|
|
11593
12209
|
}
|