@fjall/components-infrastructure 0.95.0 → 0.99.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/dist/lib/app.d.ts +90 -107
  2. package/dist/lib/app.js +149 -139
  3. package/dist/lib/config/aws/__t17fixture.d.ts +1 -0
  4. package/dist/lib/config/aws/__t17fixture.js +3 -0
  5. package/dist/lib/config/aws/__t17fixtureType.d.ts +2 -0
  6. package/dist/lib/config/aws/__t17fixtureType.js +1 -0
  7. package/dist/lib/config/aws/alarmTopic.js +8 -4
  8. package/dist/lib/config/aws/cloudTrail.js +1 -1
  9. package/dist/lib/config/aws/disasterRecovery.js +11 -16
  10. package/dist/lib/config/aws/ecrDefaultImage.d.ts +0 -1
  11. package/dist/lib/config/aws/ecrDefaultImage.js +13 -23
  12. package/dist/lib/config/aws/identityCenter.d.ts +10 -3
  13. package/dist/lib/config/aws/identityCenter.js +101 -37
  14. package/dist/lib/config/aws/identityCenterGroupMembership.js +8 -2
  15. package/dist/lib/config/aws/identityCenterMembership.d.ts +11 -0
  16. package/dist/lib/config/aws/identityCenterMembership.js +61 -0
  17. package/dist/lib/config/aws/index.d.ts +1 -1
  18. package/dist/lib/config/aws/index.js +1 -1
  19. package/dist/lib/config/aws/ipam.js +6 -11
  20. package/dist/lib/config/aws/oidcConnector.js +5 -1
  21. package/dist/lib/config/aws/scpPreset.js +4 -1
  22. package/dist/lib/patterns/aws/_eslint_test_tmp/leak.d.ts +1 -0
  23. package/dist/lib/patterns/aws/_eslint_test_tmp/leak.js +4 -0
  24. package/dist/lib/patterns/aws/account.js +7 -8
  25. package/dist/lib/patterns/aws/apexDomainPattern.js +10 -10
  26. package/dist/lib/patterns/aws/bastionFactory.d.ts +10 -0
  27. package/dist/lib/patterns/aws/bastionFactory.js +29 -0
  28. package/dist/lib/patterns/aws/buildkite.d.ts +2 -2
  29. package/dist/lib/patterns/aws/buildkite.js +51 -97
  30. package/dist/lib/patterns/aws/cdn.js +1 -1
  31. package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +172 -0
  32. package/dist/lib/patterns/aws/clickhouseDatabase.js +600 -0
  33. package/dist/lib/patterns/aws/compute.d.ts +4 -6
  34. package/dist/lib/patterns/aws/compute.js +7 -13
  35. package/dist/lib/patterns/aws/computeEcs.d.ts +95 -396
  36. package/dist/lib/patterns/aws/computeEcs.js +880 -46
  37. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +889 -0
  38. package/dist/lib/patterns/aws/computeEcsTypes.js +12 -0
  39. package/dist/lib/patterns/aws/computeLambda.d.ts +0 -5
  40. package/dist/lib/patterns/aws/computeLambda.js +1 -2
  41. package/dist/lib/patterns/aws/database.d.ts +50 -8
  42. package/dist/lib/patterns/aws/database.js +183 -27
  43. package/dist/lib/patterns/aws/domain.js +8 -7
  44. package/dist/lib/patterns/aws/index.d.ts +3 -0
  45. package/dist/lib/patterns/aws/index.js +3 -0
  46. package/dist/lib/patterns/aws/interfaces/compute.d.ts +13 -1
  47. package/dist/lib/patterns/aws/interfaces/connector.d.ts +1 -1
  48. package/dist/lib/patterns/aws/interfaces/connector.js +1 -1
  49. package/dist/lib/patterns/aws/interfaces/database.d.ts +187 -8
  50. package/dist/lib/patterns/aws/interfaces/database.js +17 -3
  51. package/dist/lib/patterns/aws/interfaces/index.d.ts +4 -2
  52. package/dist/lib/patterns/aws/interfaces/index.js +4 -2
  53. package/dist/lib/patterns/aws/interfaces/messaging.d.ts +7 -0
  54. package/dist/lib/patterns/aws/interfaces/migrationContributor.d.ts +47 -0
  55. package/dist/lib/patterns/aws/interfaces/migrationContributor.js +9 -0
  56. package/dist/lib/patterns/aws/interfaces/vpcPeer.d.ts +7 -0
  57. package/dist/lib/patterns/aws/interfaces/vpcPeer.js +1 -0
  58. package/dist/lib/patterns/aws/messaging.d.ts +66 -10
  59. package/dist/lib/patterns/aws/messaging.js +115 -20
  60. package/dist/lib/patterns/aws/network.js +16 -7
  61. package/dist/lib/patterns/aws/organisation.d.ts +4 -0
  62. package/dist/lib/patterns/aws/organisation.js +24 -5
  63. package/dist/lib/patterns/aws/storage.d.ts +1 -2
  64. package/dist/lib/patterns/aws/storage.js +3 -2
  65. package/dist/lib/patterns/aws/vpcPeer.d.ts +34 -0
  66. package/dist/lib/patterns/aws/vpcPeer.js +38 -0
  67. package/dist/lib/patterns/aws/vpcPeerAccepter.d.ts +29 -0
  68. package/dist/lib/patterns/aws/vpcPeerAccepter.js +196 -0
  69. package/dist/lib/resources/aws/analytics/clickhouse.js +25 -7
  70. package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +49 -0
  71. package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +140 -0
  72. package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +4 -4
  73. package/dist/lib/resources/aws/analytics/clickhouseConstants.js +6 -4
  74. package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +12 -0
  75. package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -0
  76. package/dist/lib/resources/aws/analytics/clickhouseUserData.js +56 -5
  77. package/dist/lib/resources/aws/analytics/index.d.ts +2 -0
  78. package/dist/lib/resources/aws/analytics/index.js +1 -0
  79. package/dist/lib/resources/aws/base/awsStack.js +4 -2
  80. package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +2 -0
  81. package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +11 -0
  82. package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.d.ts +52 -0
  83. package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.js +60 -0
  84. package/dist/lib/resources/aws/compute/blockDeviceVolume.d.ts +8 -0
  85. package/dist/lib/resources/aws/compute/blockDeviceVolume.js +10 -0
  86. package/dist/lib/resources/aws/compute/ec2.d.ts +132 -12
  87. package/dist/lib/resources/aws/compute/ec2.js +163 -23
  88. package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.d.ts +41 -0
  89. package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +194 -0
  90. package/dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs +458 -0
  91. package/dist/lib/resources/aws/compute/ecs.d.ts +27 -1
  92. package/dist/lib/resources/aws/compute/ecs.js +42 -2
  93. package/dist/lib/resources/aws/compute/ecsConstants.d.ts +9 -0
  94. package/dist/lib/resources/aws/compute/ecsConstants.js +16 -0
  95. package/dist/lib/resources/aws/compute/ecsImages.js +32 -20
  96. package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.d.ts +96 -0
  97. package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.js +113 -0
  98. package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +2 -1
  99. package/dist/lib/resources/aws/compute/ecsNetworking.js +18 -6
  100. package/dist/lib/resources/aws/compute/ecsRemoteConnections.d.ts +38 -0
  101. package/dist/lib/resources/aws/compute/ecsRemoteConnections.js +80 -0
  102. package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +13 -4
  103. package/dist/lib/resources/aws/compute/ecsServiceFactory.js +155 -33
  104. package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +31 -1
  105. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +110 -6
  106. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +180 -13
  107. package/dist/lib/resources/aws/compute/ecsValidation.d.ts +9 -0
  108. package/dist/lib/resources/aws/compute/ecsValidation.js +63 -0
  109. package/dist/lib/resources/aws/compute/index.d.ts +2 -0
  110. package/dist/lib/resources/aws/compute/index.js +2 -0
  111. package/dist/lib/resources/aws/compute/lambda.d.ts +7 -13
  112. package/dist/lib/resources/aws/compute/lambda.js +30 -38
  113. package/dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs +192 -0
  114. package/dist/lib/resources/aws/compute/persistentDataVolume.d.ts +104 -0
  115. package/dist/lib/resources/aws/compute/persistentDataVolume.js +245 -0
  116. package/dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs +398 -0
  117. package/dist/lib/resources/aws/compute/samApplication.d.ts +15 -0
  118. package/dist/lib/resources/aws/compute/samApplication.js +27 -0
  119. package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +159 -0
  120. package/dist/lib/resources/aws/database/clickhouseConstants.js +181 -0
  121. package/dist/lib/resources/aws/database/clickhouseSchemas.d.ts +71 -0
  122. package/dist/lib/resources/aws/database/clickhouseSchemas.js +157 -0
  123. package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +14 -0
  124. package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +23 -0
  125. package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +69 -0
  126. package/dist/lib/resources/aws/database/clickhouseUserData.js +371 -0
  127. package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +56 -0
  128. package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +112 -0
  129. package/dist/lib/resources/aws/database/rdsAurora.d.ts +8 -1
  130. package/dist/lib/resources/aws/database/rdsAurora.js +42 -32
  131. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +15 -2
  132. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +39 -43
  133. package/dist/lib/resources/aws/database/rdsDefaults.d.ts +6 -0
  134. package/dist/lib/resources/aws/database/rdsDefaults.js +7 -1
  135. package/dist/lib/resources/aws/database/rdsHelpers.d.ts +3 -3
  136. package/dist/lib/resources/aws/database/rdsHelpers.js +1 -0
  137. package/dist/lib/resources/aws/database/rdsInstance.d.ts +8 -1
  138. package/dist/lib/resources/aws/database/rdsInstance.js +51 -34
  139. package/dist/lib/resources/aws/database/rdsProxyOutput.d.ts +1 -1
  140. package/dist/lib/resources/aws/database/rdsProxyOutput.js +1 -1
  141. package/dist/lib/resources/aws/iam/delegationRole.js +12 -5
  142. package/dist/lib/resources/aws/iam/identityCenter/groupMembership.d.ts +9 -0
  143. package/dist/lib/resources/aws/iam/identityCenter/groupMembership.js +12 -0
  144. package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +1 -0
  145. package/dist/lib/resources/aws/iam/identityCenter/index.js +1 -0
  146. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -0
  147. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -0
  148. package/dist/lib/resources/aws/logging/logGroup.d.ts +0 -8
  149. package/dist/lib/resources/aws/logging/logGroup.js +0 -11
  150. package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +7 -0
  151. package/dist/lib/resources/aws/messaging/defaultEventBus.js +21 -0
  152. package/dist/lib/resources/aws/messaging/eventBridgeRule.d.ts +96 -0
  153. package/dist/lib/resources/aws/messaging/eventBridgeRule.js +110 -0
  154. package/dist/lib/resources/aws/messaging/eventTargets.d.ts +84 -0
  155. package/dist/lib/resources/aws/messaging/eventTargets.js +152 -0
  156. package/dist/lib/resources/aws/messaging/eventbridge.d.ts +25 -2
  157. package/dist/lib/resources/aws/messaging/eventbridge.js +22 -10
  158. package/dist/lib/resources/aws/messaging/index.d.ts +5 -0
  159. package/dist/lib/resources/aws/messaging/index.js +2 -0
  160. package/dist/lib/resources/aws/messaging/schedule.d.ts +118 -0
  161. package/dist/lib/resources/aws/messaging/schedule.js +64 -0
  162. package/dist/lib/resources/aws/messaging/sns.d.ts +2 -1
  163. package/dist/lib/resources/aws/messaging/sqs.d.ts +2 -1
  164. package/dist/lib/resources/aws/messaging/subscription.d.ts +112 -0
  165. package/dist/lib/resources/aws/messaging/subscription.js +67 -0
  166. package/dist/lib/resources/aws/messaging/utils.d.ts +6 -0
  167. package/dist/lib/resources/aws/messaging/utils.js +10 -0
  168. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +60 -0
  169. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +139 -0
  170. package/dist/lib/resources/aws/monitoring/index.d.ts +2 -0
  171. package/dist/lib/resources/aws/monitoring/index.js +2 -0
  172. package/dist/lib/resources/aws/monitoring/scheduleAlarms.d.ts +47 -0
  173. package/dist/lib/resources/aws/monitoring/scheduleAlarms.js +106 -0
  174. package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +6 -3
  175. package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.d.ts +40 -0
  176. package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +158 -0
  177. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -4
  178. package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
  179. package/dist/lib/resources/aws/networking/domainCertificate.js +6 -3
  180. package/dist/lib/resources/aws/networking/hostedZone.js +6 -4
  181. package/dist/lib/resources/aws/networking/index.d.ts +3 -0
  182. package/dist/lib/resources/aws/networking/index.js +3 -0
  183. package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +96 -0
  184. package/dist/lib/resources/aws/networking/serviceDiscovery.js +96 -0
  185. package/dist/lib/resources/aws/networking/vpc.d.ts +4 -1
  186. package/dist/lib/resources/aws/networking/vpc.js +10 -3
  187. package/dist/lib/resources/aws/networking/vpcPeeringAccepterRole.d.ts +18 -0
  188. package/dist/lib/resources/aws/networking/vpcPeeringAccepterRole.js +61 -0
  189. package/dist/lib/resources/aws/networking/vpcPeeringConnection.d.ts +49 -0
  190. package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +106 -0
  191. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +16 -5
  192. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +17 -3
  193. package/dist/lib/resources/aws/organisation/index.d.ts +1 -1
  194. package/dist/lib/resources/aws/organisation/organisationPolicy.d.ts +2 -0
  195. package/dist/lib/resources/aws/organisation/organisationPolicy.js +3 -2
  196. package/dist/lib/resources/aws/secrets/secret.d.ts +7 -0
  197. package/dist/lib/resources/aws/secrets/secret.js +4 -3
  198. package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +16 -0
  199. package/dist/lib/resources/aws/storage/bucketDeployment.js +17 -0
  200. package/dist/lib/resources/aws/storage/ecr.js +5 -5
  201. package/dist/lib/resources/aws/storage/index.d.ts +1 -0
  202. package/dist/lib/resources/aws/storage/index.js +1 -0
  203. package/dist/lib/resources/aws/storage/s3.js +10 -3
  204. package/dist/lib/resources/aws/utilities/customResource.js +18 -9
  205. package/dist/lib/synth_dump.d.ts +1 -0
  206. package/dist/lib/synth_dump.js +42 -0
  207. package/dist/lib/utils/bastionFactory.d.ts +10 -0
  208. package/dist/lib/utils/bastionFactory.js +29 -0
  209. package/dist/lib/utils/capitaliseString.d.ts +1 -1
  210. package/dist/lib/utils/capitaliseString.js +1 -1
  211. package/dist/lib/utils/cdkContext.d.ts +10 -0
  212. package/dist/lib/utils/cdkContext.js +13 -0
  213. package/dist/lib/utils/connections.d.ts +7 -1
  214. package/dist/lib/utils/connections.js +21 -0
  215. package/dist/lib/utils/connector.d.ts +30 -2
  216. package/dist/lib/utils/connector.js +6 -1
  217. package/dist/lib/utils/costAllocationTags.d.ts +15 -0
  218. package/dist/lib/utils/costAllocationTags.js +16 -0
  219. package/dist/lib/utils/databaseTypes.d.ts +14 -0
  220. package/dist/lib/utils/getConfig.d.ts +2 -0
  221. package/dist/lib/utils/getConfig.js +2 -0
  222. package/dist/lib/utils/index.d.ts +4 -0
  223. package/dist/lib/utils/index.js +4 -0
  224. package/dist/lib/utils/manifestWriter.d.ts +6 -89
  225. package/dist/lib/utils/manifestWriter.js +36 -23
  226. package/dist/lib/utils/migrationVersionResolvers.d.ts +2 -0
  227. package/dist/lib/utils/migrationVersionResolvers.js +2 -0
  228. package/dist/lib/utils/orgConfigParser.js +2 -1
  229. package/dist/lib/utils/resolveAlertsTopic.d.ts +14 -0
  230. package/dist/lib/utils/resolveAlertsTopic.js +30 -0
  231. package/dist/lib/utils/validationLogger.js +6 -3
  232. package/dist/lib/utils/vpcPeerInterface.d.ts +22 -0
  233. package/dist/lib/utils/vpcPeerInterface.js +1 -0
  234. package/package.json +22 -18
@@ -0,0 +1,889 @@
1
+ import { type Repository } from "aws-cdk-lib/aws-ecr";
2
+ import { type RepositoryImage, type ContainerImage, type PortMapping, type Secret as EcsSecret, type NetworkMode } from "aws-cdk-lib/aws-ecs";
3
+ import { type IPeer, type ISecurityGroup, type IVpc, type Port, type SubnetSelection } from "aws-cdk-lib/aws-ec2";
4
+ import { type ILogGroup, type RetentionDays } from "aws-cdk-lib/aws-logs";
5
+ import { type PolicyDocument, type IManagedPolicy, type PolicyStatement } from "aws-cdk-lib/aws-iam";
6
+ import type { ITopic } from "aws-cdk-lib/aws-sns";
7
+ import { type ConnectionSpec } from "./interfaces/connector.js";
8
+ import { type RemoteConnectionSpec } from "../../resources/aws/compute/ecsRemoteConnections.js";
9
+ import { type EcsRoutingConfig, type EcsContainerDependency } from "../../resources/aws/compute/ecsTypes.js";
10
+ import { ScalingType, type DomainConfig, type EcsCapacityProvider, type Ec2CapacityConfig } from "../../resources/aws/compute/ecs.js";
11
+ import type { EcsServiceAlarmThresholds } from "../../resources/aws/monitoring/index.js";
12
+ import { type SecretImport } from "../../resources/aws/secrets/index.js";
13
+ import type { DockerBuild } from "@fjall/util/manifest/schemas";
14
+ export type { RemoteConnectionSpec };
15
+ export { ScalingType };
16
+ export type { EcsCapacityProvider, Ec2CapacityConfig };
17
+ /**
18
+ * Configuration for ECS capacity providers.
19
+ */
20
+ export interface EcsCapacityProviderConfig {
21
+ /** Whether this uses Spot pricing */
22
+ usesSpot: boolean;
23
+ /** Whether this runs on EC2 instances (vs serverless Fargate) */
24
+ usesEc2Instances: boolean;
25
+ }
26
+ /**
27
+ * A dependency on another container in the same task definition.
28
+ * Maps directly to ECS `ContainerDependency` and the `addContainerDependencies`
29
+ * CDK API. `condition` corresponds to ECS's `ContainerDependencyCondition`:
30
+ *
31
+ * - `START` — dependency must have entered the running state
32
+ * - `COMPLETE` — dependency must have exited (any code); only valid for non-essential containers
33
+ * - `SUCCESS` — dependency must have exited 0; only valid for non-essential containers
34
+ * - `HEALTHY` — dependency must have passed its health check
35
+ *
36
+ * Public-facing alias for the canonical resource-layer `EcsContainerDependency`.
37
+ * Re-exported here so factory consumers can import it from the patterns barrel.
38
+ *
39
+ * @see https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDependency.html
40
+ */
41
+ export type ContainerDependency = EcsContainerDependency;
42
+ /**
43
+ * Configuration for a container in an ECS task.
44
+ *
45
+ * For single-container services, `name` is optional and defaults to `${serviceName}Container`.
46
+ * For multi-container tasks, the first container with a `port` is the **primary container**
47
+ * that receives load balancer traffic.
48
+ *
49
+ * @example
50
+ * // Single container (name auto-generated)
51
+ * containers: [{ port: 3000 }]
52
+ *
53
+ * @example
54
+ * // Multi-container with sidecars
55
+ * containers: [
56
+ * { name: "app", port: 3000 }, // Primary - receives ALB traffic
57
+ * { name: "datadog", image: "datadog/agent" } // Sidecar - monitoring
58
+ * ]
59
+ *
60
+ * @example
61
+ * // Init container with explicit dependsOn
62
+ * containers: [
63
+ * { name: "migrate", essential: false, command: ["npx", "payload", "migrate"] },
64
+ * { name: "app", port: 3000, dependsOn: [{ container: "migrate", condition: "SUCCESS" }] }
65
+ * ]
66
+ */
67
+ export interface EcsContainerConfig {
68
+ /**
69
+ * Container name. Optional for single-container services.
70
+ * Required when this container is referenced by another's `dependsOn`,
71
+ * or when the `migrations` sugar would otherwise collide with this name.
72
+ */
73
+ name?: string;
74
+ /**
75
+ * Container image. Options:
76
+ * - Omit: Uses app's default ECR repository (primary container only)
77
+ * - string: ECR repository name or public image URL
78
+ * - Repository: CDK ECR Repository construct
79
+ */
80
+ image?: string | Repository;
81
+ /**
82
+ * Port the container listens on.
83
+ * The first container with a port becomes the **primary container**
84
+ * and is registered with the load balancer.
85
+ */
86
+ port?: number;
87
+ /** Environment variables */
88
+ environment?: Record<string, string>;
89
+ /**
90
+ * Secrets from AWS SSM Parameter Store.
91
+ * Array of secret names that will be fetched from the service's SSM namespace.
92
+ * The namespace path is auto-determined from app/cluster/service names.
93
+ *
94
+ * @example
95
+ * // Secrets at /myapp/api-cluster/users/API_KEY and /myapp/api-cluster/users/DB_PASSWORD
96
+ * secrets: ["API_KEY", "DB_PASSWORD"]
97
+ */
98
+ secrets?: string[];
99
+ /** Secrets imported from other CDK resources (AWS Secrets Manager) */
100
+ secretsImport?: Record<string, SecretImport>;
101
+ /** Command to run in the container */
102
+ command?: string[];
103
+ /** Entry point for the container */
104
+ entryPoint?: string[];
105
+ /**
106
+ * Whether this container is essential.
107
+ * If an essential container stops, all containers in the task stop.
108
+ * Default: true
109
+ */
110
+ essential?: boolean;
111
+ /**
112
+ * Health check configuration.
113
+ * Default: For primary container with port, uses curl health check.
114
+ */
115
+ healthCheck?: {
116
+ command: string[];
117
+ interval?: number;
118
+ timeout?: number;
119
+ retries?: number;
120
+ startPeriod?: number;
121
+ };
122
+ /**
123
+ * Containers in the same service that must reach a given state before this
124
+ * container starts. Resolved at synth time — referenced container names must
125
+ * match another container's `name` field in the same service.
126
+ *
127
+ * @example
128
+ * dependsOn: [{ container: "migrate", condition: "SUCCESS" }]
129
+ */
130
+ dependsOn?: ContainerDependency[];
131
+ /**
132
+ * Multi-port containers. CDK `PortMapping[]` verbatim. Mutually exclusive
133
+ * with `port` — supplying both throws a synth-time error (AC30).
134
+ */
135
+ portMappings?: PortMapping[];
136
+ /**
137
+ * Host-bind volumes mounted into this container. Each entry produces a
138
+ * matching `taskDefinition.addVolume(...)` + `container.addMountPoints(...)`
139
+ * pair (AC31).
140
+ */
141
+ volumes?: ContainerVolume[];
142
+ /**
143
+ * Time (seconds) ECS waits for the container to exit gracefully after
144
+ * sending SIGTERM before sending SIGKILL. Range: 1–120.
145
+ *
146
+ * Stateful containers (databases, queues mid-flush, anything with on-disk
147
+ * state) generally need longer than the CDK default (30s) to flush buffers,
148
+ * close connections, and persist state. Raise this when SIGTERM-to-SIGKILL
149
+ * inside the default window risks data loss or corruption (e.g. ClickHouse
150
+ * draining merges, Postgres flushing WAL).
151
+ *
152
+ * @default 30 (ECS default; CDK omits the field when unset)
153
+ */
154
+ stopTimeout?: number;
155
+ }
156
+ /**
157
+ * How the migration command is executed during deployment.
158
+ *
159
+ * - `"init-container"` (default) — synthesises a non-essential init container
160
+ * in the service's task definition that runs to completion before any other
161
+ * container starts. Every replica task pays the migration startup cost, but
162
+ * the migration runs inside the same task family so the deployment cannot
163
+ * move forward until migrations succeed. Recommended for ≤10-replica
164
+ * services and any service whose `migrations.command` does work other than
165
+ * migrations (seeding, cache warming, environment validation).
166
+ * - `"lifecycle-hook"` — runs the migration once per deployment via an ECS
167
+ * `PRE_SCALE_UP` deployment lifecycle hook (AWS, September 2025). The hook
168
+ * invokes a Lambda that launches the migration as a one-off task; the new
169
+ * replica tasks scale up only after the hook reports `SUCCEEDED`. Cuts
170
+ * per-replica startup latency at the cost of an extra Lambda + IAM role
171
+ * per service. Suitable for high-replica services where the init-container
172
+ * tax dominates rollout time.
173
+ *
174
+ * @see aiDocs/decisions/2026-04-29-ecs-init-container-over-runtask.md
175
+ * @see aiDocs/plans/2026-04-29-ecs-factory-hardening.md § 4.3.4 — threshold
176
+ * guidance for choosing between modes.
177
+ * @see https://aws.amazon.com/blogs/containers/announcing-amazon-ecs-deployment-lifecycle-hooks/
178
+ */
179
+ export type EcsMigrationsMode = "init-container" | "lifecycle-hook" | "post-deploy";
180
+ /**
181
+ * Shorthand for the canonical "run migrations before the app starts" pattern.
182
+ *
183
+ * Default mode (`"init-container"`) synthesises a non-essential init container
184
+ * that runs to completion before any other container in the service starts.
185
+ * Optional `mode: "lifecycle-hook"` shifts the migration to an ECS deployment
186
+ * lifecycle hook — see {@link EcsMigrationsMode} for the trade-off.
187
+ *
188
+ * Defaults inherit from the primary container (first container with a `port`,
189
+ * or the first container if none have a port):
190
+ *
191
+ * - `image` → primary's `image`
192
+ * - `environment` → primary's `environment`
193
+ * - `secrets` → primary's `secrets` (SSM Parameter Store)
194
+ * - `secretsImport` → primary's `secretsImport` (Secrets Manager)
195
+ *
196
+ * Idempotency is the migration tool's responsibility — Payload, Prisma, Drizzle,
197
+ * Rails, Django, and Flyway are all idempotent by default.
198
+ *
199
+ * @example
200
+ * migrations: { command: ["npx", "payload", "migrate"] }
201
+ *
202
+ * @example
203
+ * migrations: {
204
+ * command: ["prisma", "migrate", "deploy"],
205
+ * timeoutSeconds: 600
206
+ * }
207
+ *
208
+ * @example
209
+ * // High-replica service: shift migration off the per-task startup path
210
+ * migrations: {
211
+ * command: ["npx", "payload", "migrate"],
212
+ * mode: "lifecycle-hook"
213
+ * }
214
+ *
215
+ * @see aiDocs/decisions/2026-04-29-ecs-init-container-over-runtask.md
216
+ */
217
+ /**
218
+ * Discriminated on `mode`. The init-container variant keeps its narrow surface
219
+ * (no risk of authors setting CPU/memory/IAM overrides that would silently
220
+ * apply to the per-replica path). The lifecycle-hook variant carries `entryPoint?`
221
+ * and an opt-in `separateTaskDef?` sub-object for cross-cutting migrations
222
+ * that need permissions the service doesn't (e.g. RDS snapshot grants,
223
+ * cross-service Secrets Manager reads).
224
+ *
225
+ * Setting `separateTaskDef` on the init-container variant — or any
226
+ * lifecycle-hook-only field — is a typecheck error. This protects against
227
+ * the Pitfall-5 trap (silent field drift across union variants).
228
+ *
229
+ * @see aiDocs/designs/2026-05-12-migration-runner-abstraction-choice.md
230
+ * @see .claude/rules/typescript-standards.md § "Pitfall 5"
231
+ */
232
+ export type EcsMigrationsConfig = EcsInitContainerMigrationsConfig | EcsLifecycleHookMigrationsConfig | EcsPostDeployMigrationsConfig;
233
+ /**
234
+ * Union of the two lambda-driven deployment hook variants. Internal helper
235
+ * type — narrows from `EcsMigrationsConfig` once `expandMigrationsSugar` has
236
+ * established the migration runs out-of-band via a lifecycle hook (vs as an
237
+ * init container).
238
+ */
239
+ export type EcsHookMigrationsConfig = EcsLifecycleHookMigrationsConfig | EcsPostDeployMigrationsConfig;
240
+ /**
241
+ * Type-narrowing predicate for the two lambda-driven hook variants. Returns
242
+ * true for `"lifecycle-hook"` (PRE_SCALE_UP) and `"post-deploy"` (POST_SCALE_UP).
243
+ * Narrows the whole `EcsMigrationsConfig` to the hook-variant union, not just
244
+ * the `mode` property, so callers can read `separateTaskDef` / `entryPoint`
245
+ * etc. on the narrowed object.
246
+ */
247
+ export declare function isHookMigrations(config: EcsMigrationsConfig): config is EcsHookMigrationsConfig;
248
+ /**
249
+ * `mode: "init-container"` variant — migration runs as a non-essential init
250
+ * container inside each replica's task, dependsOn `COMPLETE` before main starts.
251
+ * `entryPoint` and `separateTaskDef` are intentionally absent — the per-replica
252
+ * init-container path has no separate IAM role to grant against.
253
+ */
254
+ export interface EcsInitContainerMigrationsConfig {
255
+ /**
256
+ * Where the migration command runs during deployment. Defaults to
257
+ * `"init-container"`. Either omit (defaults) or set explicitly.
258
+ */
259
+ mode?: "init-container";
260
+ /** Migration command, e.g. `["npx", "payload", "migrate"]`. Required. */
261
+ command: string[];
262
+ /** Override timeout in seconds. Defaults to 300 (5 min). */
263
+ timeoutSeconds?: number;
264
+ /** Override image. Defaults to inheriting from the primary container. */
265
+ image?: string | Repository;
266
+ /** Override environment. Defaults to inheriting from the primary container. */
267
+ environment?: Record<string, string>;
268
+ /** Override Secrets-Manager imports. Defaults to inheriting from the primary container. */
269
+ secretsImport?: Record<string, SecretImport>;
270
+ /** Override SSM secret keys. Defaults to inheriting from the primary container. */
271
+ secrets?: string[];
272
+ /**
273
+ * Synthetic container name. Defaults to `"migrate"`.
274
+ * Override when a service container is already named `migrate`.
275
+ */
276
+ name?: string;
277
+ }
278
+ /**
279
+ * `mode: "lifecycle-hook"` variant — migration runs out-of-band via an ECS
280
+ * deployment lifecycle hook (PRE_SCALE_UP). The service rollout BLOCKS until
281
+ * the migration succeeds; one task per deploy.
282
+ *
283
+ * When `separateTaskDef` is present, `wireLifecycleHookMigrations` synthesises
284
+ * a SEPARATE migration task definition (its own IAM role, log group, runtime
285
+ * platform) instead of using `ContainerOverrides` on the service task def.
286
+ * Required when migrations need permissions the service doesn't.
287
+ */
288
+ export interface EcsLifecycleHookMigrationsConfig {
289
+ /** Required for the lifecycle-hook variant. */
290
+ mode: "lifecycle-hook";
291
+ /** Migration command, e.g. `["node", "scripts/migration-runner.mjs"]`. Required. */
292
+ command: string[];
293
+ /** Override timeout in seconds. Defaults to 300 (5 min). Capped at 900s per Lambda invocation; longer migrations use the IN_PROGRESS callback chain. */
294
+ timeoutSeconds?: number;
295
+ /**
296
+ * Override image URI (string only). CDK `Repository` constructs cannot be
297
+ * JSON-serialised into the runner Lambda's `MIGRATE_CONFIG` env var; synth
298
+ * throws if a `Repository` is passed in lifecycle-hook mode.
299
+ */
300
+ image?: string;
301
+ /** Override environment. */
302
+ environment?: Record<string, string>;
303
+ /** Secrets-Manager imports for the migration container. */
304
+ secretsImport?: Record<string, SecretImport>;
305
+ /** SSM Parameter Store secret keys. */
306
+ secrets?: string[];
307
+ /** Synthetic container name. Defaults to `"migrate"`. */
308
+ name?: string;
309
+ /**
310
+ * Container entrypoint. Defaults to inheriting from the image. Set to
311
+ * `["/usr/bin/tini", "--"]` (or similar) to keep PID-1 signalling clean
312
+ * inside long-running migration containers.
313
+ */
314
+ entryPoint?: string[];
315
+ /**
316
+ * When present, synthesise a SEPARATE migration task definition (its own
317
+ * IAM role, log group, runtime platform) instead of using `ContainerOverrides`
318
+ * on the service task def. Required when migrations need permissions the
319
+ * service doesn't (e.g. `rds:CreateDBSnapshot`, cross-service Secrets Manager
320
+ * reads) — preserves least-privilege on the service task role.
321
+ *
322
+ * When absent, the lifecycle-hook runner uses the service's task def via
323
+ * ContainerOverrides — existing behaviour, unchanged.
324
+ */
325
+ separateTaskDef?: EcsLifecycleHookMigrationsSeparateTaskDef;
326
+ }
327
+ /**
328
+ * `mode: "post-deploy"` variant — runs out-of-band via an ECS deployment
329
+ * lifecycle hook on the POST_SCALE_UP stage. Fires AFTER the new task revision
330
+ * has scaled up and is healthy. A `FAILED` return from the hook triggers ECS
331
+ * deployment circuit-breaker rollback to the previous revision.
332
+ *
333
+ * Use cases: post-deploy data backfills that should run against the new code
334
+ * (not gate the rollout), cache warming, smoke tests that exercise the live
335
+ * service, sanity-check migrations that don't need to block traffic shift.
336
+ * Do NOT use for schema migrations that the new code depends on — use the
337
+ * pre-deploy `mode: "lifecycle-hook"` variant for those.
338
+ *
339
+ * Identical input shape to the lifecycle-hook variant; the only difference is
340
+ * the stage at which AWS fires the hook.
341
+ */
342
+ export interface EcsPostDeployMigrationsConfig {
343
+ /** Required for the post-deploy variant. */
344
+ mode: "post-deploy";
345
+ /** Migration/backfill command. Required. */
346
+ command: string[];
347
+ /** Override timeout in seconds. Defaults to 300 (5 min). Capped at 900s per Lambda invocation. */
348
+ timeoutSeconds?: number;
349
+ /** Override image URI (string only). */
350
+ image?: string;
351
+ /** Override environment. */
352
+ environment?: Record<string, string>;
353
+ /** Secrets-Manager imports for the migration container. */
354
+ secretsImport?: Record<string, SecretImport>;
355
+ /** SSM Parameter Store secret keys. */
356
+ secrets?: string[];
357
+ /** Synthetic container name. Defaults to `"migrate"`. */
358
+ name?: string;
359
+ /** Container entrypoint. Defaults to inheriting from the image. */
360
+ entryPoint?: string[];
361
+ /**
362
+ * When present, synthesise a SEPARATE migration task definition. Same
363
+ * semantics as `EcsLifecycleHookMigrationsConfig.separateTaskDef`.
364
+ */
365
+ separateTaskDef?: EcsLifecycleHookMigrationsSeparateTaskDef;
366
+ }
367
+ /**
368
+ * Sub-config for `EcsLifecycleHookMigrationsConfig.separateTaskDef`. The
369
+ * migration container is parameterised exactly like every other container via
370
+ * the same `<ServiceName>ImageTag` CfnParameter — task-def revisions roll over
371
+ * whenever the parameter value changes.
372
+ */
373
+ export interface EcsLifecycleHookMigrationsSeparateTaskDef {
374
+ /** Fargate task CPU (256, 512, 1024, 2048, 4096, 8192, 16384). */
375
+ cpu: number;
376
+ /** Task memory in MiB — must be compatible with `cpu` per the AWS Fargate task-size matrix. */
377
+ memoryLimitMiB: number;
378
+ /** Extra IAM statements appended to the migration task role only. */
379
+ taskRolePolicies?: PolicyStatement[];
380
+ /**
381
+ * Extra SG egress for the migration task. Omit to reuse the service's
382
+ * security group(s). Use this when the migration reaches a peer the
383
+ * service itself doesn't talk to.
384
+ */
385
+ egressTo?: Array<{
386
+ peer: IPeer;
387
+ port: Port;
388
+ description: string;
389
+ }>;
390
+ /**
391
+ * Runtime Secrets Manager reads — typed sugar that grants the migration task
392
+ * role `secretsmanager:GetSecretValue` on the named secrets, scoped to the
393
+ * specific ARNs (never `*`).
394
+ *
395
+ * Different from `secretsImport`: `secretsImport` mounts a secret value as
396
+ * an env var at container start via the ECS agent (execution role permission).
397
+ * `extraSecretReads` is for migrations that fetch secret values dynamically
398
+ * at runtime via the AWS SDK — e.g. when the secret name is computed inside
399
+ * the migration script, or when the migration writes back into Secrets
400
+ * Manager after rotation.
401
+ *
402
+ * Equivalent to passing the same statement via `taskRolePolicies`; this form
403
+ * is preferred for readability.
404
+ */
405
+ extraSecretReads?: Array<{
406
+ /** Secrets Manager secret name or ARN. */
407
+ secretName: string;
408
+ /** Optional human-facing description used in IAM statement Sid. */
409
+ description?: string;
410
+ }>;
411
+ }
412
+ /**
413
+ * Deployment circuit breaker policy for an ECS service.
414
+ *
415
+ * The circuit breaker watches a new deployment and, on detecting persistent
416
+ * task launch failures, marks the deployment as failed. With `rollback: true`
417
+ * the service automatically returns to the previous stable task definition.
418
+ *
419
+ * Defaults to `{ rollback: true }` when omitted — matches every example in
420
+ * AWS's own circuit-breaker documentation. CDK's default is `rollback: false`;
421
+ * we override to the safer shape.
422
+ *
423
+ * Set `circuitBreaker: false` to disable the breaker entirely (not recommended
424
+ * for production services).
425
+ *
426
+ * Set `circuitBreaker: { rollback: false }` to enable detection without
427
+ * automatic rollback — useful for first deploys where there is no prior
428
+ * baseline to roll back to.
429
+ *
430
+ * @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-circuit-breaker.html
431
+ */
432
+ export interface EcsCircuitBreakerConfig {
433
+ /**
434
+ * Roll back to the previous stable deployment when the circuit breaker
435
+ * trips. Defaults to `true`.
436
+ */
437
+ rollback?: boolean;
438
+ }
439
+ /**
440
+ * ECS scaling configuration.
441
+ * - Omit: enabled, `minCapacity` tracks `desiredCount`, `maxCapacity` defaults to `Math.max(desiredCount + 1, 3)`
442
+ * - `{}`: same as omit
443
+ * - `{ minCapacity: 2, maxCapacity: 10 }`: custom scaling (explicit values win)
444
+ * - `false`: explicitly disabled
445
+ *
446
+ * Setting `minCapacity > 0` while `desiredCount: 0` throws at synth — Application
447
+ * Auto Scaling would immediately scale the service back up, defeating the toggle.
448
+ */
449
+ export interface EcsScalingConfig {
450
+ minCapacity?: number;
451
+ maxCapacity?: number;
452
+ scalingType?: ScalingType;
453
+ }
454
+ /**
455
+ * Host-bind volume mounted into one or more containers in the same task.
456
+ * Maps to ECS `Volume` + `MountPoint` pairs — see AC29 + AC31.
457
+ */
458
+ export interface ContainerVolume {
459
+ /** Volume name. Used as `sourceVolume` on the container's mount point. */
460
+ name: string;
461
+ /**
462
+ * Host path bound into the container. Omit for an empty Docker volume that
463
+ * lives only for the task's lifetime (no host directory mount).
464
+ */
465
+ hostSourcePath?: string;
466
+ /** Path inside the container the volume is mounted at. */
467
+ mountPath: string;
468
+ /** Mount the volume read-only. Default: false. */
469
+ readOnly?: boolean;
470
+ }
471
+ /**
472
+ * Scheduled-task entry on the cluster. Each entry produces one
473
+ * `Ec2TaskDefinition` registered under the synthetic key `name` in
474
+ * `EcsCompute`'s task-definition map (collision-checked against steady-state
475
+ * service names) and an `app.addSchedule(...)` invocation. See AC27 + AC34.
476
+ */
477
+ export interface EcsScheduledTaskConfig {
478
+ /** Synthetic name. Must not collide with any steady-state `serviceName`. */
479
+ name: string;
480
+ /** Cron or rate expression — passed verbatim to `app.addSchedule`. */
481
+ schedule: string;
482
+ /** CDK `ContainerImage` — typically `ContainerImage.fromRegistry(...)`. */
483
+ image: ContainerImage;
484
+ cpu: number;
485
+ memoryLimitMiB: number;
486
+ command?: string[];
487
+ /** Container secrets (Secrets Manager / SSM) — same shape as ECS `secrets`. */
488
+ secrets?: Record<string, EcsSecret>;
489
+ /** Pre-existing CDK log group. Mutually exclusive with `logRetention`. */
490
+ logGroup?: ILogGroup;
491
+ /** When `logGroup` is omitted, the awsLogs driver creates one with this retention. */
492
+ logRetention?: RetentionDays;
493
+ securityGroups?: ISecurityGroup[];
494
+ subnetSelection?: SubnetSelection;
495
+ networkMode?: NetworkMode;
496
+ /** Host-bind volumes mounted into the task's container. */
497
+ volumes?: ContainerVolume[];
498
+ }
499
+ /**
500
+ * Cluster-level configuration.
501
+ * Controls the shared ALB for all services in this cluster.
502
+ */
503
+ export interface EcsClusterConfig {
504
+ /**
505
+ * Domain for HTTPS access.
506
+ * - Omit: ALB created with default DNS (*.elb.amazonaws.com)
507
+ * - Specified: Creates ACM certificate + Route53 DNS A record
508
+ */
509
+ domain?: string;
510
+ /**
511
+ * Load balancer configuration.
512
+ * - Omit or "public": Internet-facing ALB (default)
513
+ * - "internal": VPC-only ALB
514
+ * - false: No ALB (for workers/background processors)
515
+ */
516
+ loadBalancer?: false | "public" | "internal";
517
+ /**
518
+ * Enable direct EC2 access without ALB.
519
+ * Uses host network mode for predictable ports.
520
+ * Access via EC2 public IP at container port.
521
+ */
522
+ directAccess?: boolean;
523
+ /**
524
+ * Advanced domain configuration for routing policies (latency, weighted, geo).
525
+ * Only used when domain is specified.
526
+ * Allows for multi-region deployments with advanced DNS routing.
527
+ */
528
+ domainConfig?: DomainConfig;
529
+ /**
530
+ * Externally-supplied security group for the cluster's EC2 capacity. When
531
+ * provided, the ECS service factory wires this SG onto the underlying
532
+ * `Ec2Instance` instead of creating its own. Used by stateful workloads
533
+ * (e.g. ClickHouseDatabase) that own their security group lifecycle.
534
+ */
535
+ securityGroup?: ISecurityGroup;
536
+ /**
537
+ * Scheduled tasks materialised into `Ec2TaskDefinition`s and registered via
538
+ * `app.addSchedule(...)` against the existing `EcsScheduleTarget` shape
539
+ * ({ ecs, serviceName, taskCount }). See AC34.
540
+ */
541
+ scheduledTasks?: EcsScheduledTaskConfig[];
542
+ }
543
+ export type { EcsRoutingConfig };
544
+ /**
545
+ * Configuration for a service in an ECS cluster.
546
+ * Each service gets its own task definition, scaling config, and target group.
547
+ *
548
+ * @example
549
+ * // Simple service
550
+ * { name: "api", containers: [{ port: 3000 }] }
551
+ *
552
+ * @example
553
+ * // Service with routing (for multi-service clusters)
554
+ * { name: "users", containers: [{ port: 3000 }], routing: { path: "/users/*", priority: 100 } }
555
+ *
556
+ * @example
557
+ * // Service with multiple routing rules (same target group)
558
+ * { name: "web", containers: [{ port: 3000 }], routing: [
559
+ * { path: "/api/v2/*", priority: 50 },
560
+ * { path: "/*", priority: 200 },
561
+ * ]}
562
+ *
563
+ * @example
564
+ * // Service with sidecars
565
+ * {
566
+ * name: "api",
567
+ * containers: [
568
+ * { name: "app", port: 3000 },
569
+ * { name: "datadog", image: "datadog/agent" }
570
+ * ]
571
+ * }
572
+ */
573
+ export interface EcsServiceConfig {
574
+ /** Service name (unique within cluster) */
575
+ name: string;
576
+ /**
577
+ * Container image for this service (applies to first container without explicit image).
578
+ * - Omit: Uses app's default ECR repository
579
+ * - string: ECR repository name or public image URL
580
+ * - Repository: CDK ECR Repository construct
581
+ */
582
+ image?: string | Repository;
583
+ /**
584
+ * Container configuration(s) for this service.
585
+ * For single-container services, container name is optional and auto-generated.
586
+ * For multi-container services, the first container with a port is the primary container.
587
+ */
588
+ containers?: EcsContainerConfig[];
589
+ /**
590
+ * Routing rules for this service on the cluster's ALB.
591
+ * Required when cluster has multiple services with ports.
592
+ * Optional for single service (gets /* automatically).
593
+ * Can be a single rule or an array of rules pointing to the same target group.
594
+ *
595
+ * @example
596
+ * // Multiple routes for the same service
597
+ * routing: [
598
+ * { path: "/api/v2/*", priority: 50 },
599
+ * { path: "/*", priority: 200 },
600
+ * ]
601
+ */
602
+ routing?: EcsRoutingConfig | EcsRoutingConfig[];
603
+ /** CPU units for this service's tasks (256-4096) */
604
+ cpu?: number;
605
+ /** Memory in MiB for this service's tasks (512-30720) */
606
+ memoryLimitMiB?: number;
607
+ /** Desired number of tasks. Default: 2 */
608
+ desiredCount?: number;
609
+ /**
610
+ * Scaling configuration.
611
+ * - Omit: enabled with defaults
612
+ * - false: disabled
613
+ */
614
+ scaling?: EcsScalingConfig | false;
615
+ /**
616
+ * Dockerfile build configuration for this service. Carries the path
617
+ * (absolute or relative), an optional build `context` for monorepo
618
+ * layouts, and an optional multi-stage `target`.
619
+ *
620
+ * Tagged image suffix when `target` is set: `<service>-<target>-latest`.
621
+ * Mutually exclusive with `image` (pre-built URI).
622
+ */
623
+ docker?: DockerBuild;
624
+ /**
625
+ * Additional inline policies for this service's task role.
626
+ * Added on top of the default ECS Exec permissions.
627
+ * Use for service-specific AWS permissions (S3, DynamoDB, SQS, etc.).
628
+ */
629
+ taskRoleInlinePolicies?: Record<string, PolicyDocument>;
630
+ /**
631
+ * Additional managed policies for this service's task role.
632
+ * Added on top of the default ECS Exec permissions.
633
+ */
634
+ taskRoleManagedPolicies?: IManagedPolicy[];
635
+ /**
636
+ * Resources this service needs to connect to (e.g., databases, S3 buckets, SQS queues).
637
+ * Creates security group rules for IConnectable resources and IAM grants for IAM resources.
638
+ * Follows least-privilege - only this service gets access, not all services in the cluster.
639
+ *
640
+ * Supports:
641
+ * - IConnectable: Security group resources (RDS, ECS, etc.)
642
+ * - IStorageConnector: S3 buckets (IAM grants)
643
+ * - IDynamoDBConnector: DynamoDB tables (IAM grants)
644
+ * - IQueueConnector: SQS queues (IAM grants)
645
+ * - ConnectionConfig: Explicit access level configuration
646
+ *
647
+ * @example
648
+ * // Simple connections (default permissions)
649
+ * connections: [database, bucket, cache, queue]
650
+ *
651
+ * @example
652
+ * // Explicit access levels
653
+ * connections: [
654
+ * database, // Security group (RDS)
655
+ * { resource: cache, access: "read" }, // Read-only DynamoDB
656
+ * { resource: bucket, access: "write" }, // Write-only S3
657
+ * { resource: queue, access: "consume" } // Consume-only SQS
658
+ * ]
659
+ */
660
+ connections?: ConnectionSpec[];
661
+ /**
662
+ * Schema-version gate opt-out. Defaults `true`.
663
+ *
664
+ * When any database in `connections` carries a `migrations` block, every
665
+ * container in this service receives `EXPECTED_SCHEMA_VERSION` resolved
666
+ * from that database's migration tool at synth time. Set `false` to skip
667
+ * the injection — intended for sidecars that intentionally tolerate
668
+ * schema drift or one-shot maintenance tasks.
669
+ *
670
+ * Named opt-out is auditable: grep-recoverable across the monorepo. Note
671
+ * the spelling collision with `@fjall/generator`'s codemod pipeline gate
672
+ * at `validationGate/gates/schema.ts` — different surface, different
673
+ * concept.
674
+ */
675
+ schemaGate?: boolean;
676
+ /**
677
+ * Cross-app resources reachable via VPC peering. Each entry resolves the
678
+ * peered app's exposed resource at synth time (SSM `valueForStringParameter`
679
+ * reads) and injects `${PREFIX}_HOST` + `${PREFIX}_PORT` env vars into every
680
+ * container in this service's task definition.
681
+ *
682
+ * @example
683
+ * remoteConnections: [
684
+ * { peer, resource: "MainDatabase" },
685
+ * { peer, resource: "CoreApi", envPrefix: "DATA_PLATFORM_API" }
686
+ * ]
687
+ */
688
+ remoteConnections?: RemoteConnectionSpec[];
689
+ /**
690
+ * Capacity provider for this service. REQUIRED.
691
+ * Each service specifies its own capacity provider.
692
+ *
693
+ * @example
694
+ * // Mixed FARGATE and EC2 services in same cluster
695
+ * {
696
+ * services: [
697
+ * { name: "api", capacityProvider: "FARGATE" },
698
+ * { name: "worker", capacityProvider: "EC2", ec2Config: { instanceType: "t4g.micro" } }
699
+ * ]
700
+ * }
701
+ */
702
+ capacityProvider: EcsCapacityProvider;
703
+ /**
704
+ * EC2 capacity configuration for this service.
705
+ * Only used when service capacityProvider is "EC2".
706
+ * Services with matching ec2Config share an ASG for efficiency.
707
+ */
708
+ ec2Config?: Ec2CapacityConfig;
709
+ /**
710
+ * SSM Parameter Store path for secrets.
711
+ * If not specified, secrets are fetched from /<app>/<cluster>/<service>.
712
+ * Use this to override the default convention.
713
+ *
714
+ * @example
715
+ * // Override default path
716
+ * ssmSecretsPath: "/custom/path/to/secrets"
717
+ */
718
+ ssmSecretsPath?: string;
719
+ /**
720
+ * Per-service alarm configuration.
721
+ * - undefined: use defaults (CPU, memory, running tasks, 5xx if ALB)
722
+ * - false: disable alarms for this service
723
+ * - object: override specific thresholds
724
+ */
725
+ alarms?: EcsServiceAlarmThresholds | false;
726
+ /**
727
+ * Run an init container before any other container in this service starts.
728
+ * Synthesises a non-essential container with the given migration command,
729
+ * inherits image / env / secrets from the primary container, and auto-wires
730
+ * every other container to wait on `SUCCESS`.
731
+ *
732
+ * @example
733
+ * migrations: { command: ["npx", "payload", "migrate"] }
734
+ */
735
+ migrations?: EcsMigrationsConfig;
736
+ /**
737
+ * Deployment circuit breaker policy. Omit for the safe default
738
+ * `{ enable: true, rollback: true }` — failed deployments automatically
739
+ * roll back to the previous stable task definition.
740
+ *
741
+ * Set to `false` to disable the breaker entirely. Set to
742
+ * `{ rollback: false }` for detection without automatic rollback (useful
743
+ * for first deploys where there is no prior baseline).
744
+ *
745
+ * @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-circuit-breaker.html
746
+ */
747
+ circuitBreaker?: false | EcsCircuitBreakerConfig;
748
+ /**
749
+ * Rolling-deploy capacity bounds (percent of `desiredCount`).
750
+ *
751
+ * - `minHealthyPercent` (0–100): floor of healthy tasks during a deploy.
752
+ * `0` allows full task drain before the new task starts (recreate
753
+ * semantics — required for singletons backed by an EBS volume that only
754
+ * one task can attach to at a time, e.g. ClickHouse).
755
+ * - `maxHealthyPercent` (100–200): ceiling of running tasks during a
756
+ * deploy. `100` forbids overlap (matches the singleton/recreate shape).
757
+ * The default `200` allows a fresh task to start before the old one
758
+ * drains (rolling shape — fits stateless services).
759
+ *
760
+ * Both must satisfy `min <= max`, and they cannot both be `100`
761
+ * (a no-op deploy that can't drain or expand).
762
+ *
763
+ * @default `{ minHealthyPercent: 100, maxHealthyPercent: 200 }` (CDK default)
764
+ */
765
+ deployment?: {
766
+ minHealthyPercent?: number;
767
+ maxHealthyPercent?: number;
768
+ };
769
+ /**
770
+ * Cloud Map service discovery for this service. When provided, the pattern
771
+ * registers the service against the application-level Cloud Map namespace
772
+ * (`app.getNamespace().registerService({ name })`) and threads the resulting
773
+ * `IService` to the resources layer, which calls `associateCloudMapService`
774
+ * after service construction. The namespace is `<appName>.local` and is
775
+ * lazily created on first registration — no cluster-level configuration.
776
+ *
777
+ * `dnsRecordType` defaults to `"A"` (paired with the AWS_VPC networkMode
778
+ * default). Set to `"SRV"` only when explicitly overriding `networkMode` to
779
+ * `HOST` or `BRIDGE` — CDK's `Ec2Service.associateCloudMapService(...)`
780
+ * rejects A records under those modes (the task shares the host's ENI IP,
781
+ * so the published port must travel with the record).
782
+ */
783
+ serviceDiscovery?: {
784
+ name: string;
785
+ dnsRecordType?: "A" | "SRV";
786
+ };
787
+ /**
788
+ * Override the task definition's `NetworkMode`. Defaults:
789
+ * - EC2 services: `AWS_VPC` (per-task ENI → per-task SG, A-record service
790
+ * discovery works, current AWS recommendation for new workloads).
791
+ * - EC2 services with `cluster.directAccess: true`: `HOST` (direct port
792
+ * binding to the instance, required for ECS Exec → host-port flows).
793
+ * - Fargate services: `AWS_VPC` (CDK requirement, not overridable).
794
+ *
795
+ * Cloud Map service discovery works under all three modes:
796
+ * - `AWS_VPC`: A records (default `serviceDiscovery.dnsRecordType`).
797
+ * - `HOST` / `BRIDGE`: SRV records — set
798
+ * `serviceDiscovery.dnsRecordType: "SRV"` so the published port travels
799
+ * with the record.
800
+ *
801
+ * ENI quota: each task under `AWS_VPC` attaches an ENI to the host
802
+ * instance. Instance ENI limits cap tasks-per-instance (e.g. t4g.medium
803
+ * → 2 tasks). For scale beyond the limit, enable ENI trunking at the
804
+ * account+instance level, pick larger instances, or override to `BRIDGE`.
805
+ */
806
+ networkMode?: NetworkMode;
807
+ /**
808
+ * Pre-existing security groups attached to this service's task ENIs (AWS_VPC
809
+ * mode). When omitted, CDK auto-creates a default service SG. Stateful
810
+ * patterns that own a wrapper SG (e.g. `ClickHouseDatabase`) set this so
811
+ * `this.connections.securityGroups[0]` is honest — the SG it points at is
812
+ * the SG the task ENI actually wears, not a CDK-autogenerated sibling that
813
+ * arbitrates no traffic.
814
+ */
815
+ securityGroups?: ISecurityGroup[];
816
+ }
817
+ /**
818
+ * ECS compute configuration.
819
+ * Creates an ECS cluster with one or more services sharing a load balancer.
820
+ *
821
+ * @example
822
+ * // Single service
823
+ * app.addCompute(ComputeFactory.build("WebApp", {
824
+ * type: "ecs",
825
+ * cluster: { domain: "app.example.com" },
826
+ * services: [{ name: "web", containers: [{ port: 3000 }] }]
827
+ * }));
828
+ *
829
+ * @example
830
+ * // Multi-service cluster with routing
831
+ * app.addCompute(ComputeFactory.build("ApiCluster", {
832
+ * type: "ecs",
833
+ * cluster: { domain: "api.example.com" },
834
+ * services: [
835
+ * { name: "users", containers: [{ port: 3000 }], routing: { path: "/users/*" } },
836
+ * { name: "orders", containers: [{ port: 3001 }], routing: { path: "/orders/*" } }
837
+ * ]
838
+ * }));
839
+ *
840
+ * @example
841
+ * // Internal workers (no ALB)
842
+ * app.addCompute(ComputeFactory.build("Workers", {
843
+ * type: "ecs",
844
+ * cluster: { loadBalancer: false },
845
+ * services: [{ name: "processor" }, { name: "emailer" }]
846
+ * }));
847
+ */
848
+ export interface EcsComputeProps {
849
+ type: "ecs";
850
+ vpc?: IVpc;
851
+ /**
852
+ * Application name for SSM secrets namespace.
853
+ * When containers use secrets, the path is derived as: /<appName>/<clusterName>/<serviceName>
854
+ * Auto-derived from App.getName() if not specified.
855
+ */
856
+ appName?: string;
857
+ /**
858
+ * Cluster configuration.
859
+ * Controls the shared ALB for all services in this cluster.
860
+ * - Omit: ALB created with default settings
861
+ * - `{ domain: "..." }`: ALB with HTTPS + DNS
862
+ * - `{ loadBalancer: false }`: No ALB (internal workers)
863
+ */
864
+ cluster?: EcsClusterConfig;
865
+ /**
866
+ * Services in this cluster.
867
+ * Each service gets its own task definition, scaling, and target group.
868
+ * Each service MUST specify its own capacityProvider.
869
+ * All services share the cluster's ALB (unless disabled).
870
+ */
871
+ services: EcsServiceConfig[];
872
+ /**
873
+ * ECR repository for all services (default image).
874
+ * Individual services can override with their own `image` property.
875
+ */
876
+ ecrRepository?: Repository | RepositoryImage;
877
+ /**
878
+ * Cluster-level Dockerfile build configuration. Used when no service-level
879
+ * `docker` is set. Metadata for the CLI build process; not used during synth.
880
+ */
881
+ docker?: DockerBuild;
882
+ /**
883
+ * SNS topic for alarm notifications. Resolved to ITopic and passed to EcsCluster.
884
+ * Accepts either an ITopic directly or a topic ARN string (resolved internally).
885
+ */
886
+ alertsTopic?: ITopic | string;
887
+ /** Application ID for alarm tagging (used by webhook to map alarms to applications). */
888
+ applicationId?: string;
889
+ }