@fjall/components-infrastructure 0.96.0 → 0.99.3

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 (209) hide show
  1. package/dist/lib/app.d.ts +68 -1
  2. package/dist/lib/app.js +113 -4
  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 +2 -4
  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 +173 -0
  32. package/dist/lib/patterns/aws/clickhouseDatabase.js +601 -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 +93 -5
  36. package/dist/lib/patterns/aws/computeEcs.js +867 -37
  37. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +528 -25
  38. package/dist/lib/patterns/aws/computeEcsTypes.js +10 -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 +6 -4
  44. package/dist/lib/patterns/aws/index.d.ts +1 -0
  45. package/dist/lib/patterns/aws/index.js +1 -0
  46. package/dist/lib/patterns/aws/interfaces/compute.d.ts +7 -1
  47. package/dist/lib/patterns/aws/interfaces/database.d.ts +187 -8
  48. package/dist/lib/patterns/aws/interfaces/database.js +17 -3
  49. package/dist/lib/patterns/aws/interfaces/index.d.ts +2 -1
  50. package/dist/lib/patterns/aws/interfaces/index.js +3 -1
  51. package/dist/lib/patterns/aws/interfaces/messaging.d.ts +7 -0
  52. package/dist/lib/patterns/aws/interfaces/migrationContributor.d.ts +47 -0
  53. package/dist/lib/patterns/aws/interfaces/migrationContributor.js +9 -0
  54. package/dist/lib/patterns/aws/messaging.d.ts +66 -10
  55. package/dist/lib/patterns/aws/messaging.js +115 -20
  56. package/dist/lib/patterns/aws/network.js +16 -7
  57. package/dist/lib/patterns/aws/organisation.d.ts +4 -0
  58. package/dist/lib/patterns/aws/organisation.js +22 -4
  59. package/dist/lib/patterns/aws/storage.d.ts +1 -2
  60. package/dist/lib/patterns/aws/storage.js +3 -2
  61. package/dist/lib/patterns/aws/vpcPeer.js +3 -1
  62. package/dist/lib/resources/aws/analytics/clickhouse.js +18 -9
  63. package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +24 -9
  64. package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +61 -10
  65. package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +3 -3
  66. package/dist/lib/resources/aws/analytics/clickhouseConstants.js +3 -3
  67. package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +7 -1
  68. package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -1
  69. package/dist/lib/resources/aws/analytics/clickhouseUserData.js +53 -3
  70. package/dist/lib/resources/aws/base/awsStack.js +4 -2
  71. package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +2 -0
  72. package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +11 -0
  73. package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.d.ts +52 -0
  74. package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.js +60 -0
  75. package/dist/lib/resources/aws/compute/blockDeviceVolume.d.ts +8 -0
  76. package/dist/lib/resources/aws/compute/blockDeviceVolume.js +10 -0
  77. package/dist/lib/resources/aws/compute/ec2.d.ts +132 -12
  78. package/dist/lib/resources/aws/compute/ec2.js +163 -23
  79. package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.d.ts +41 -0
  80. package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +194 -0
  81. package/dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs +458 -0
  82. package/dist/lib/resources/aws/compute/ecs.d.ts +27 -1
  83. package/dist/lib/resources/aws/compute/ecs.js +42 -2
  84. package/dist/lib/resources/aws/compute/ecsConstants.d.ts +9 -0
  85. package/dist/lib/resources/aws/compute/ecsConstants.js +16 -0
  86. package/dist/lib/resources/aws/compute/ecsImages.js +32 -20
  87. package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.d.ts +96 -0
  88. package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.js +113 -0
  89. package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +2 -1
  90. package/dist/lib/resources/aws/compute/ecsNetworking.js +18 -6
  91. package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +13 -4
  92. package/dist/lib/resources/aws/compute/ecsServiceFactory.js +155 -33
  93. package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +31 -1
  94. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +102 -6
  95. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +173 -13
  96. package/dist/lib/resources/aws/compute/ecsValidation.d.ts +9 -0
  97. package/dist/lib/resources/aws/compute/ecsValidation.js +63 -0
  98. package/dist/lib/resources/aws/compute/index.d.ts +2 -0
  99. package/dist/lib/resources/aws/compute/index.js +2 -0
  100. package/dist/lib/resources/aws/compute/lambda.d.ts +7 -13
  101. package/dist/lib/resources/aws/compute/lambda.js +30 -38
  102. package/dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs +192 -0
  103. package/dist/lib/resources/aws/compute/persistentDataVolume.d.ts +104 -0
  104. package/dist/lib/resources/aws/compute/persistentDataVolume.js +245 -0
  105. package/dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs +398 -0
  106. package/dist/lib/resources/aws/compute/samApplication.d.ts +15 -0
  107. package/dist/lib/resources/aws/compute/samApplication.js +27 -0
  108. package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +159 -0
  109. package/dist/lib/resources/aws/database/clickhouseConstants.js +181 -0
  110. package/dist/lib/resources/aws/database/clickhouseSchemas.d.ts +71 -0
  111. package/dist/lib/resources/aws/database/clickhouseSchemas.js +160 -0
  112. package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +14 -0
  113. package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +23 -0
  114. package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +69 -0
  115. package/dist/lib/resources/aws/database/clickhouseUserData.js +371 -0
  116. package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +56 -0
  117. package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +112 -0
  118. package/dist/lib/resources/aws/database/rdsAurora.d.ts +8 -1
  119. package/dist/lib/resources/aws/database/rdsAurora.js +42 -32
  120. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +15 -2
  121. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +39 -43
  122. package/dist/lib/resources/aws/database/rdsDefaults.d.ts +6 -0
  123. package/dist/lib/resources/aws/database/rdsDefaults.js +7 -1
  124. package/dist/lib/resources/aws/database/rdsHelpers.d.ts +3 -3
  125. package/dist/lib/resources/aws/database/rdsHelpers.js +1 -0
  126. package/dist/lib/resources/aws/database/rdsInstance.d.ts +8 -1
  127. package/dist/lib/resources/aws/database/rdsInstance.js +51 -34
  128. package/dist/lib/resources/aws/database/rdsProxyOutput.d.ts +1 -1
  129. package/dist/lib/resources/aws/database/rdsProxyOutput.js +1 -1
  130. package/dist/lib/resources/aws/iam/delegationRole.js +1 -1
  131. package/dist/lib/resources/aws/iam/identityCenter/groupMembership.d.ts +9 -0
  132. package/dist/lib/resources/aws/iam/identityCenter/groupMembership.js +12 -0
  133. package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +1 -0
  134. package/dist/lib/resources/aws/iam/identityCenter/index.js +1 -0
  135. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -0
  136. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -0
  137. package/dist/lib/resources/aws/logging/logGroup.d.ts +0 -8
  138. package/dist/lib/resources/aws/logging/logGroup.js +0 -11
  139. package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +7 -0
  140. package/dist/lib/resources/aws/messaging/defaultEventBus.js +21 -0
  141. package/dist/lib/resources/aws/messaging/eventBridgeRule.d.ts +96 -0
  142. package/dist/lib/resources/aws/messaging/eventBridgeRule.js +110 -0
  143. package/dist/lib/resources/aws/messaging/eventTargets.d.ts +84 -0
  144. package/dist/lib/resources/aws/messaging/eventTargets.js +152 -0
  145. package/dist/lib/resources/aws/messaging/eventbridge.d.ts +25 -2
  146. package/dist/lib/resources/aws/messaging/eventbridge.js +22 -10
  147. package/dist/lib/resources/aws/messaging/index.d.ts +5 -0
  148. package/dist/lib/resources/aws/messaging/index.js +2 -0
  149. package/dist/lib/resources/aws/messaging/schedule.d.ts +118 -0
  150. package/dist/lib/resources/aws/messaging/schedule.js +64 -0
  151. package/dist/lib/resources/aws/messaging/sns.d.ts +2 -1
  152. package/dist/lib/resources/aws/messaging/sqs.d.ts +2 -1
  153. package/dist/lib/resources/aws/messaging/subscription.d.ts +112 -0
  154. package/dist/lib/resources/aws/messaging/subscription.js +67 -0
  155. package/dist/lib/resources/aws/messaging/utils.d.ts +6 -0
  156. package/dist/lib/resources/aws/messaging/utils.js +10 -0
  157. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +60 -0
  158. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +139 -0
  159. package/dist/lib/resources/aws/monitoring/index.d.ts +2 -0
  160. package/dist/lib/resources/aws/monitoring/index.js +2 -0
  161. package/dist/lib/resources/aws/monitoring/scheduleAlarms.d.ts +47 -0
  162. package/dist/lib/resources/aws/monitoring/scheduleAlarms.js +106 -0
  163. package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +6 -4
  164. package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +17 -13
  165. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -5
  166. package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
  167. package/dist/lib/resources/aws/networking/domainCertificate.js +6 -4
  168. package/dist/lib/resources/aws/networking/hostedZone.js +6 -5
  169. package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +96 -0
  170. package/dist/lib/resources/aws/networking/serviceDiscovery.js +96 -0
  171. package/dist/lib/resources/aws/networking/vpc.d.ts +4 -1
  172. package/dist/lib/resources/aws/networking/vpc.js +4 -1
  173. package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +21 -3
  174. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +16 -5
  175. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +17 -3
  176. package/dist/lib/resources/aws/organisation/index.d.ts +1 -1
  177. package/dist/lib/resources/aws/organisation/organisationPolicy.d.ts +2 -0
  178. package/dist/lib/resources/aws/organisation/organisationPolicy.js +3 -2
  179. package/dist/lib/resources/aws/secrets/secret.d.ts +7 -0
  180. package/dist/lib/resources/aws/secrets/secret.js +4 -3
  181. package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +16 -0
  182. package/dist/lib/resources/aws/storage/bucketDeployment.js +17 -0
  183. package/dist/lib/resources/aws/storage/ecr.js +5 -5
  184. package/dist/lib/resources/aws/storage/index.d.ts +1 -0
  185. package/dist/lib/resources/aws/storage/index.js +1 -0
  186. package/dist/lib/resources/aws/storage/s3.js +10 -3
  187. package/dist/lib/resources/aws/utilities/customResource.js +18 -9
  188. package/dist/lib/synth_dump.d.ts +1 -0
  189. package/dist/lib/synth_dump.js +42 -0
  190. package/dist/lib/utils/cdkContext.d.ts +2 -0
  191. package/dist/lib/utils/cdkContext.js +4 -2
  192. package/dist/lib/utils/connections.js +6 -0
  193. package/dist/lib/utils/connector.d.ts +12 -0
  194. package/dist/lib/utils/costAllocationTags.d.ts +9 -0
  195. package/dist/lib/utils/costAllocationTags.js +11 -1
  196. package/dist/lib/utils/databaseTypes.d.ts +14 -0
  197. package/dist/lib/utils/getConfig.d.ts +2 -0
  198. package/dist/lib/utils/getConfig.js +2 -0
  199. package/dist/lib/utils/index.d.ts +1 -0
  200. package/dist/lib/utils/index.js +1 -0
  201. package/dist/lib/utils/manifestWriter.d.ts +6 -89
  202. package/dist/lib/utils/manifestWriter.js +36 -23
  203. package/dist/lib/utils/migrationVersionResolvers.d.ts +2 -0
  204. package/dist/lib/utils/migrationVersionResolvers.js +2 -0
  205. package/dist/lib/utils/orgConfigParser.js +2 -1
  206. package/dist/lib/utils/resolveAlertsTopic.d.ts +14 -0
  207. package/dist/lib/utils/resolveAlertsTopic.js +30 -0
  208. package/dist/lib/utils/validationLogger.js +6 -3
  209. package/package.json +22 -19
@@ -3,11 +3,13 @@ import type { ITopic } from "aws-cdk-lib/aws-sns";
3
3
  import type { RdsAlarmThresholds } from "../../resources/aws/monitoring/index.js";
4
4
  import type App from "../../app.js";
5
5
  import { type DynamoDBKeySchema, type DynamoDBGlobalSecondaryIndex } from "../../resources/aws/database/dynamodb.js";
6
+ import { ClickHouseDatabase, type ClickHouseDatabaseProps } from "./clickhouseDatabase.js";
6
7
  import { type Connections, type IConnectable, type IVpc } from "aws-cdk-lib/aws-ec2";
7
8
  import { type ITable } from "aws-cdk-lib/aws-dynamodb";
8
9
  import { type Secret } from "../../resources/aws/secrets/index.js";
9
- import { type IGrantable, type Grant } from "aws-cdk-lib/aws-iam";
10
- import { type IRelationalDatabase, type IDynamoDBDatabase, type RelationalDatabaseType } from "./interfaces/database.js";
10
+ import { PolicyStatement, type IGrantable, type Grant } from "aws-cdk-lib/aws-iam";
11
+ import { type IRelationalDatabaseBase, type IRelationalInstanceDatabase, type IRelationalClusterDatabase, type IDynamoDBDatabase, type RelationalDatabaseType, type SnapshotTarget, type MigrationsConfig } from "./interfaces/database.js";
12
+ import { type MigrationContributions } from "./interfaces/migrationContributor.js";
11
13
  import { type IDynamoDBConnector, type ISecurityGroupConnector } from "./interfaces/connector.js";
12
14
  import { type IInstanceEngine, type IClusterEngine } from "aws-cdk-lib/aws-rds";
13
15
  import { Duration } from "aws-cdk-lib";
@@ -44,6 +46,14 @@ type BaseDatabaseProps = {
44
46
  alarms?: RdsAlarmThresholds | false;
45
47
  /** Application ID for alarm tagging. */
46
48
  applicationId?: string;
49
+ /**
50
+ * Schema-version gate. When set, every container of every service whose
51
+ * `connections:` includes this database receives `EXPECTED_SCHEMA_VERSION`
52
+ * baked into its env at synth, unless the service sets `schemaGate: false`.
53
+ * `tool: "prisma"` uses the built-in directory-name resolver;
54
+ * `tool: "custom"` accepts a user-supplied `versionResolver`.
55
+ */
56
+ migrations?: MigrationsConfig;
47
57
  };
48
58
  export interface AuroraDatabaseProps extends BaseDatabaseProps {
49
59
  type: "Aurora";
@@ -150,7 +160,7 @@ export type IRelationalDatabaseProps = AuroraDatabaseProps | InstanceDatabasePro
150
160
  /**
151
161
  * All database props union.
152
162
  */
153
- export type IDatabaseProps = AuroraDatabaseProps | InstanceDatabaseProps | GlobalAuroraDatabaseProps | DynamoDBDatabaseProps;
163
+ export type IDatabaseProps = AuroraDatabaseProps | InstanceDatabaseProps | GlobalAuroraDatabaseProps | DynamoDBDatabaseProps | ClickHouseDatabaseProps;
154
164
  /**
155
165
  * Factory for creating type-safe database resources.
156
166
  *
@@ -172,10 +182,11 @@ export type IDatabaseProps = AuroraDatabaseProps | InstanceDatabaseProps | Globa
172
182
  * cache.grantReadWriteData(lambda); // Available
173
183
  */
174
184
  export declare class DatabaseFactory {
175
- static build(id: string, props: AuroraDatabaseProps): (app: App, scope: Construct) => RelationalDatabase;
176
- static build(id: string, props: InstanceDatabaseProps): (app: App, scope: Construct) => RelationalDatabase;
177
- static build(id: string, props: GlobalAuroraDatabaseProps): (app: App, scope: Construct) => RelationalDatabase;
185
+ static build(id: string, props: AuroraDatabaseProps): (app: App, scope: Construct) => RelationalDatabase & IRelationalClusterDatabase;
186
+ static build(id: string, props: InstanceDatabaseProps): (app: App, scope: Construct) => RelationalDatabase & IRelationalInstanceDatabase;
187
+ static build(id: string, props: GlobalAuroraDatabaseProps): (app: App, scope: Construct) => RelationalDatabase & IRelationalClusterDatabase;
178
188
  static build(id: string, props: DynamoDBDatabaseProps): (app: App, scope: Construct) => DynamoDBDatabase;
189
+ static build(id: string, props: ClickHouseDatabaseProps): (app: App, scope: Construct) => ClickHouseDatabase;
179
190
  }
180
191
  /**
181
192
  * DynamoDB database wrapper implementing IDynamoDBDatabase interface.
@@ -203,6 +214,15 @@ export declare class DynamoDBDatabase extends Construct implements IDynamoDBData
203
214
  grantReadWriteData(grantee: IGrantable): Grant;
204
215
  grantFullAccess(grantee: IGrantable): Grant;
205
216
  grantStreamRead(grantee: IGrantable): Grant;
217
+ /**
218
+ * Migration contributions for a task connecting to this DynamoDB table via
219
+ * `service.connections:`. DynamoDB has no network primitive (no SG, no port),
220
+ * so contributions are limited to env (table name + region) and an IAM policy
221
+ * granting CRUD on the table. Callers that only need read access should
222
+ * shadow the policy in their own `migrations:` block or rely on the
223
+ * author-explicit-wins precedence at the merge boundary.
224
+ */
225
+ getMigrationContributions(): MigrationContributions;
206
226
  }
207
227
  /**
208
228
  * Relational database wrapper implementing IRelationalDatabase interface.
@@ -215,7 +235,7 @@ export declare class DynamoDBDatabase extends Construct implements IDynamoDBData
215
235
  * }));
216
236
  * db.grantConnect(lambda);
217
237
  */
218
- export declare class RelationalDatabase extends Construct implements IRelationalDatabase, ISecurityGroupConnector {
238
+ export declare class RelationalDatabase extends Construct implements IRelationalDatabaseBase, ISecurityGroupConnector {
219
239
  readonly id: string;
220
240
  readonly scope: Construct;
221
241
  readonly vpc: IVpc;
@@ -223,6 +243,7 @@ export declare class RelationalDatabase extends Construct implements IRelational
223
243
  readonly connectorType: "relational";
224
244
  connections: Connections;
225
245
  private readonly _databaseName;
246
+ private readonly migrationsConfig;
226
247
  private database;
227
248
  constructor(scope: Construct, id: string, props: IRelationalDatabaseProps);
228
249
  private resolveAlertsTopic;
@@ -234,12 +255,33 @@ export declare class RelationalDatabase extends Construct implements IRelational
234
255
  getCredentials(): Secret;
235
256
  getHostEndpoint(): string;
236
257
  getHostPort(): string;
258
+ getConnectionString(): string;
237
259
  getDatabaseName(): string;
260
+ getInstanceIdentifier(): string | undefined;
261
+ getClusterIdentifier(): string | undefined;
262
+ getSnapshotTarget(): SnapshotTarget;
263
+ getMigrationSnapshotPolicy(): PolicyStatement;
264
+ getMigrationsConfig(): MigrationsConfig | undefined;
265
+ getExpectedSchemaVersion(): string | undefined;
266
+ /**
267
+ * Migration contributions for a task connecting to this database via
268
+ * `service.connections:`. Returns env (host/port/name + snapshot identifiers
269
+ * when `migrations:` is declared), Secrets-Manager imports for credentials,
270
+ * the snapshot IAM policy when `migrations:` is declared, and egress to the
271
+ * database's primary security group on its port. Emits a synth warning when
272
+ * the primary SG is not yet bound (egress contribution is omitted in that
273
+ * case; callers may still wire egress manually in `separateTaskDef`).
274
+ */
275
+ getMigrationContributions(): MigrationContributions;
238
276
  /**
239
277
  * Grant connect permissions to a grantee by adding it to the database security group.
240
278
  * @param grantee The connectable principal to grant connect permissions to
241
279
  */
242
280
  grantConnect(grantee: IConnectable): void;
243
281
  }
282
+ export { ClickHouseDatabase, type ClickHouseDatabaseProps };
283
+ export { ClickHouseDefaultProfiles, ClickHouseSchemaAdminSchema, ManagedPasswordNameSchema, ProfileSpecSchema, type ClickHouseSchemaAdmin, type ManagedPasswordName, type ProfileSpec } from "../../resources/aws/database/clickhouseSchemas.js";
284
+ export { renderUsersXml } from "../../resources/aws/database/clickhouseXmlRenderer.js";
285
+ export type { RenderUsersXmlOptions } from "../../resources/aws/database/clickhouseXmlRenderer.js";
244
286
  export type { DynamoDBKeySchema, DynamoDBGlobalSecondaryIndex, DynamoDBTableProps } from "../../resources/aws/database/dynamodb.js";
245
- export { type IRelationalDatabase, type IDynamoDBDatabase, type AnyDatabase, type DatabaseType, type RelationalDatabaseType, isRelationalDatabase, isDynamoDBDatabase, isAuroraDatabase, isInstanceDatabase, isGlobalAuroraDatabase } from "./interfaces/database.js";
287
+ export { type IRelationalDatabase, type IDynamoDBDatabase, type IClickHouseDatabase, type AnyDatabase, type DatabaseType, type RelationalDatabaseType, isRelationalDatabase, isDynamoDBDatabase, isClickHouseDatabase, isAuroraDatabase, isInstanceDatabase, isGlobalAuroraDatabase } from "./interfaces/database.js";
@@ -1,11 +1,16 @@
1
1
  import { Construct } from "constructs";
2
- import { CfnOutput, Fn, Stack } from "aws-cdk-lib";
3
- import { Topic } from "aws-cdk-lib/aws-sns";
2
+ import { Annotations, ArnFormat, CfnOutput, Stack } from "aws-cdk-lib";
4
3
  import { RdsAurora, RdsInstance } from "../../resources/aws/database/index.js";
5
4
  import { RdsAuroraGlobal } from "../../resources/aws/database/rdsAuroraGlobal.js";
6
5
  import { DynamoDBTable } from "../../resources/aws/database/dynamodb.js";
6
+ import { ClickHouseDatabase } from "./clickhouseDatabase.js";
7
7
  import { FjallLogger, warnIfPropertiesIgnored } from "../../utils/validationLogger.js";
8
8
  import { toPascalCase } from "../../utils/capitaliseString.js";
9
+ import { resolveAlertsTopic as resolveAlertsTopicShared } from "../../utils/resolveAlertsTopic.js";
10
+ import { Port } from "aws-cdk-lib/aws-ec2";
11
+ import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
12
+ import { MIGRATION_SNAPSHOT_NAME_PREFIX } from "./interfaces/database.js";
13
+ import { pickLatestPrismaMigration } from "../../utils/migrationVersionResolvers.js";
9
14
  import { DatabaseClusterEngine, DatabaseInstanceEngine, AuroraPostgresEngineVersion, AuroraMysqlEngineVersion, PostgresEngineVersion, MysqlEngineVersion } from "aws-cdk-lib/aws-rds";
10
15
  import { Duration } from "aws-cdk-lib";
11
16
  export { isAwsManagedKey, isCMKRequested, AWS_MANAGED, USE_CMK } from "../../utils/databaseTypes.js";
@@ -63,6 +68,7 @@ export function getInstanceEngine(engine) {
63
68
  export function getEngineConfig(engine) {
64
69
  const config = DATABASE_ENGINE_CONFIG[engine];
65
70
  return {
71
+ family: engine,
66
72
  defaultUsername: config.defaultUsername,
67
73
  sslParameters: config.sslParameters,
68
74
  rotationAppName: config.rotationAppName
@@ -104,7 +110,9 @@ function validateDynamoDBProps(props) {
104
110
  * TypeScript's compile-time checks may not apply.
105
111
  */
106
112
  function validateRelationalDatabaseProps(props) {
107
- // GlobalAurora requires primaryRegion
113
+ if (!props.vpc) {
114
+ throw new Error("VPC is required for relational database");
115
+ }
108
116
  if (props.type === "GlobalAurora" && !props.primaryRegion) {
109
117
  throw new Error("GlobalAurora database requires 'primaryRegion'. " +
110
118
  "Specify the AWS region where the primary cluster will be created.");
@@ -124,7 +132,7 @@ function validateDatabaseProps(props) {
124
132
  if (props.type === "DynamoDB") {
125
133
  validateDynamoDBProps(props);
126
134
  }
127
- else {
135
+ else if (props.type !== "ClickHouse") {
128
136
  validateRelationalDatabaseProps(props);
129
137
  }
130
138
  }
@@ -151,14 +159,22 @@ function validateDatabaseProps(props) {
151
159
  export class DatabaseFactory {
152
160
  static build(id, props) {
153
161
  return (app, scope) => {
154
- validateDatabaseProps(props);
155
162
  if (props.type === "DynamoDB") {
163
+ validateDatabaseProps(props);
156
164
  return new DynamoDBDatabase(scope, id, props);
157
165
  }
166
+ if (props.type === "ClickHouse") {
167
+ const clickhouseProps = {
168
+ ...props,
169
+ vpc: props.vpc ?? app.getVpc()
170
+ };
171
+ return new ClickHouseDatabase(scope, id, clickhouseProps);
172
+ }
158
173
  const databaseProps = {
159
- ...{ vpc: app.getVpc() },
160
- ...props
174
+ ...props,
175
+ vpc: props.vpc ?? app.getVpc()
161
176
  };
177
+ validateDatabaseProps(databaseProps);
162
178
  return new RelationalDatabase(scope, id, databaseProps);
163
179
  };
164
180
  }
@@ -181,6 +197,7 @@ export class DynamoDBDatabase extends Construct {
181
197
  table;
182
198
  constructor(scope, id, props) {
183
199
  super(scope, id);
200
+ validateDynamoDBProps(props);
184
201
  this.id = id;
185
202
  const tableProps = {
186
203
  partitionKey: props.partitionKey,
@@ -224,7 +241,57 @@ export class DynamoDBDatabase extends Construct {
224
241
  grantStreamRead(grantee) {
225
242
  return this.table.grantStreamRead(grantee);
226
243
  }
244
+ /**
245
+ * Migration contributions for a task connecting to this DynamoDB table via
246
+ * `service.connections:`. DynamoDB has no network primitive (no SG, no port),
247
+ * so contributions are limited to env (table name + region) and an IAM policy
248
+ * granting CRUD on the table. Callers that only need read access should
249
+ * shadow the policy in their own `migrations:` block or rely on the
250
+ * author-explicit-wins precedence at the merge boundary.
251
+ */
252
+ getMigrationContributions() {
253
+ const environment = {
254
+ AWS_REGION: Stack.of(this).region,
255
+ DYNAMODB_TABLE_NAME: this.getTableName()
256
+ };
257
+ const taskRolePolicies = [
258
+ new PolicyStatement({
259
+ effect: Effect.ALLOW,
260
+ actions: [
261
+ "dynamodb:GetItem",
262
+ "dynamodb:PutItem",
263
+ "dynamodb:UpdateItem",
264
+ "dynamodb:DeleteItem",
265
+ "dynamodb:Query",
266
+ "dynamodb:Scan",
267
+ "dynamodb:BatchGetItem",
268
+ "dynamodb:BatchWriteItem",
269
+ "dynamodb:DescribeTable"
270
+ ],
271
+ resources: [this.getTableArn(), `${this.getTableArn()}/index/*`]
272
+ })
273
+ ];
274
+ return { environment, taskRolePolicies };
275
+ }
227
276
  }
277
+ /**
278
+ * Action-triple ↔ snapshot-kind lookup. Single source of truth for which RDS
279
+ * actions and ARN resource segment apply to instance vs cluster snapshots.
280
+ * Future variants (RDS Proxy, Aurora Serverless v2 with a new snapshot API)
281
+ * add a row here; no consumer needs updating.
282
+ */
283
+ const SNAPSHOT_ACTION_TABLE = {
284
+ instance: {
285
+ createAction: "rds:CreateDBSnapshot",
286
+ describeAction: "rds:DescribeDBSnapshots",
287
+ resourceArnSegment: "snapshot"
288
+ },
289
+ cluster: {
290
+ createAction: "rds:CreateDBClusterSnapshot",
291
+ describeAction: "rds:DescribeDBClusterSnapshots",
292
+ resourceArnSegment: "cluster-snapshot"
293
+ }
294
+ };
228
295
  /**
229
296
  * Relational database wrapper implementing IRelationalDatabase interface.
230
297
  * Supports Aurora, RDS Instance, and GlobalAurora database types.
@@ -244,31 +311,24 @@ export class RelationalDatabase extends Construct {
244
311
  connectorType = "relational";
245
312
  connections;
246
313
  _databaseName;
314
+ migrationsConfig;
247
315
  database;
248
316
  constructor(scope, id, props) {
249
317
  super(scope, id);
318
+ validateRelationalDatabaseProps(props);
250
319
  this.id = id;
251
320
  this.scope = scope;
252
321
  this.databaseType = props.type;
253
- if (!props.vpc) {
254
- throw new Error("VPC is required for relational database");
255
- }
256
322
  this.vpc = props.vpc;
257
323
  this._databaseName = props.databaseName;
324
+ this.migrationsConfig = props.migrations;
258
325
  this.addDatabase(props);
259
326
  }
260
327
  resolveAlertsTopic(alertsTopic) {
261
- if (alertsTopic === undefined)
262
- return undefined;
263
- if (typeof alertsTopic === "string") {
264
- const arn = alertsTopic.startsWith("import:")
265
- ? Fn.importValue(alertsTopic.slice("import:".length))
266
- : alertsTopic;
267
- return Topic.fromTopicArn(this, "AlertsTopic", arn);
268
- }
269
- return alertsTopic;
328
+ return resolveAlertsTopicShared(this, "AlertsTopic", alertsTopic);
270
329
  }
271
330
  addDatabase(props) {
331
+ validateRelationalDatabaseProps(props);
272
332
  switch (props.type) {
273
333
  case "Aurora":
274
334
  this.addAurora(props);
@@ -286,8 +346,6 @@ export class RelationalDatabase extends Construct {
286
346
  }
287
347
  }
288
348
  addAurora(props) {
289
- if (!props.vpc)
290
- throw new Error("VPC is required for Aurora database");
291
349
  const resolvedDatabaseEngine = props.databaseEngine ?? "postgresql";
292
350
  const resolvedEngine = props.engine ?? getAuroraClusterEngine(resolvedDatabaseEngine);
293
351
  const engineConfig = getEngineConfig(resolvedDatabaseEngine);
@@ -324,8 +382,6 @@ export class RelationalDatabase extends Construct {
324
382
  this.addDatabaseOutputs(props);
325
383
  }
326
384
  addAuroraGlobal(props) {
327
- if (!props.vpc)
328
- throw new Error("VPC is required for Global Aurora database");
329
385
  if (!props.primaryRegion)
330
386
  throw new Error("primaryRegion is required for Global Aurora database");
331
387
  const resolvedDatabaseEngine = props.databaseEngine ?? "postgresql";
@@ -358,8 +414,6 @@ export class RelationalDatabase extends Construct {
358
414
  this.addDatabaseOutputs(props);
359
415
  }
360
416
  addRdsInstance(props) {
361
- if (!props.vpc)
362
- throw new Error("VPC is required for Instance database");
363
417
  const resolvedDatabaseEngine = props.databaseEngine ?? "postgresql";
364
418
  const resolvedEngine = props.engine ?? getInstanceEngine(resolvedDatabaseEngine);
365
419
  const engineConfig = getEngineConfig(resolvedDatabaseEngine);
@@ -431,9 +485,109 @@ export class RelationalDatabase extends Construct {
431
485
  getHostPort() {
432
486
  return this.database.getHostPort();
433
487
  }
488
+ getConnectionString() {
489
+ return this.database.getConnectionString();
490
+ }
434
491
  getDatabaseName() {
435
492
  return this._databaseName;
436
493
  }
494
+ getInstanceIdentifier() {
495
+ return "getInstanceIdentifier" in this.database
496
+ ? this.database.getInstanceIdentifier()
497
+ : undefined;
498
+ }
499
+ getClusterIdentifier() {
500
+ return "getClusterIdentifier" in this.database
501
+ ? this.database.getClusterIdentifier()
502
+ : undefined;
503
+ }
504
+ getSnapshotTarget() {
505
+ return this.database.getSnapshotTarget();
506
+ }
507
+ getMigrationSnapshotPolicy() {
508
+ const target = this.getSnapshotTarget();
509
+ const triple = SNAPSHOT_ACTION_TABLE[target.kind];
510
+ return new PolicyStatement({
511
+ effect: Effect.ALLOW,
512
+ actions: [
513
+ triple.createAction,
514
+ triple.describeAction,
515
+ "rds:AddTagsToResource"
516
+ ],
517
+ resources: [
518
+ target.arn,
519
+ Stack.of(this).formatArn({
520
+ service: "rds",
521
+ resource: triple.resourceArnSegment,
522
+ resourceName: `${MIGRATION_SNAPSHOT_NAME_PREFIX}-*`,
523
+ arnFormat: ArnFormat.COLON_RESOURCE_NAME
524
+ })
525
+ ]
526
+ });
527
+ }
528
+ getMigrationsConfig() {
529
+ return this.migrationsConfig;
530
+ }
531
+ getExpectedSchemaVersion() {
532
+ const config = this.migrationsConfig;
533
+ if (config === undefined)
534
+ return undefined;
535
+ const version = config.tool === "prisma"
536
+ ? pickLatestPrismaMigration(config.dir)
537
+ : config.versionResolver(config.dir);
538
+ // Empty / whitespace-only resolver output would silently bake an empty
539
+ // EXPECTED_SCHEMA_VERSION into containers; the runner's `!== ""` guard
540
+ // then skips the gate. Fail loud at synth instead.
541
+ if (version.trim() === "") {
542
+ throw new Error(`Database '${this._databaseName}': migrations.versionResolver returned an empty string for dir '${config.dir}' — refusing to inject an empty EXPECTED_SCHEMA_VERSION.`);
543
+ }
544
+ return version;
545
+ }
546
+ /**
547
+ * Migration contributions for a task connecting to this database via
548
+ * `service.connections:`. Returns env (host/port/name + snapshot identifiers
549
+ * when `migrations:` is declared), Secrets-Manager imports for credentials,
550
+ * the snapshot IAM policy when `migrations:` is declared, and egress to the
551
+ * database's primary security group on its port. Emits a synth warning when
552
+ * the primary SG is not yet bound (egress contribution is omitted in that
553
+ * case; callers may still wire egress manually in `separateTaskDef`).
554
+ */
555
+ getMigrationContributions() {
556
+ const environment = {
557
+ AWS_REGION: Stack.of(this).region,
558
+ DATABASE_HOST: this.getHostEndpoint(),
559
+ DATABASE_PORT: this.getHostPort(),
560
+ DATABASE_NAME: this.getDatabaseName()
561
+ };
562
+ if (this.migrationsConfig !== undefined) {
563
+ const target = this.getSnapshotTarget();
564
+ environment.SNAPSHOT_TARGET_KIND = target.kind;
565
+ environment.SNAPSHOT_TARGET_ARN = target.arn;
566
+ }
567
+ const credentials = this.getCredentials();
568
+ const secretsImport = {
569
+ DATABASE_USER: credentials.getImport("username"),
570
+ DATABASE_PASSWORD: credentials.getImport("password")
571
+ };
572
+ const taskRolePolicies = [];
573
+ if (this.migrationsConfig !== undefined) {
574
+ taskRolePolicies.push(this.getMigrationSnapshotPolicy());
575
+ }
576
+ const primarySg = this.connections.securityGroups[0];
577
+ const egress = [];
578
+ if (primarySg !== undefined) {
579
+ egress.push({
580
+ peer: primarySg,
581
+ port: Port.tcp(parseInt(this.getHostPort(), 10)),
582
+ description: `Migration runner to ${this._databaseName} for schema apply`
583
+ });
584
+ }
585
+ else {
586
+ Annotations.of(this).addWarning(`Database '${this._databaseName}': no primary security group exposed; ` +
587
+ "migration runner egress not auto-wired. Provide egress manually in separateTaskDef if needed.");
588
+ }
589
+ return { environment, secretsImport, taskRolePolicies, egress };
590
+ }
437
591
  /**
438
592
  * Grant connect permissions to a grantee by adding it to the database security group.
439
593
  * @param grantee The connectable principal to grant connect permissions to
@@ -442,5 +596,7 @@ export class RelationalDatabase extends Construct {
442
596
  this.connections.allowDefaultPortFrom(grantee);
443
597
  }
444
598
  }
445
- // Re-export interface types
446
- export { isRelationalDatabase, isDynamoDBDatabase, isAuroraDatabase, isInstanceDatabase, isGlobalAuroraDatabase } from "./interfaces/database.js";
599
+ export { ClickHouseDatabase };
600
+ export { ClickHouseDefaultProfiles, ClickHouseSchemaAdminSchema, ManagedPasswordNameSchema, ProfileSpecSchema } from "../../resources/aws/database/clickhouseSchemas.js";
601
+ export { renderUsersXml } from "../../resources/aws/database/clickhouseXmlRenderer.js";
602
+ export { isRelationalDatabase, isDynamoDBDatabase, isClickHouseDatabase, isAuroraDatabase, isInstanceDatabase, isGlobalAuroraDatabase } from "./interfaces/database.js";
@@ -6,7 +6,7 @@ import { validateDomainProps } from "./domainValidation.js";
6
6
  import { composeApexDomain } from "./apexDomainPattern.js";
7
7
  import { composeDelegatedDomain } from "./delegatedDomainPattern.js";
8
8
  import { composeExternalRecords } from "./externalRecordsPattern.js";
9
- import { DEFAULT_COST_ALLOCATION_ENVIRONMENT } from "../../utils/costAllocationTags.js";
9
+ import { applyCostAllocationTags } from "../../utils/costAllocationTags.js";
10
10
  /**
11
11
  * User-facing Route53-oriented domain construct. Dispatches on
12
12
  * `props.registrar` to one of three per-registrar patterns:
@@ -74,9 +74,11 @@ export class Domain extends Construct {
74
74
  const effectiveZone = resolveEffectiveZoneName(props);
75
75
  const description = props.description ?? `Fjall-managed domain for ${effectiveZone}`;
76
76
  Tags.of(this).add("fjall:description", description);
77
- Tags.of(this).add("fjall:costAllocation:environment", props.costAllocationEnvironment ?? DEFAULT_COST_ALLOCATION_ENVIRONMENT);
78
- Tags.of(this).add("fjall:costAllocation:service", "domain");
79
- Tags.of(this).add("fjall:costAllocation:domain", props.zoneName);
77
+ applyCostAllocationTags(this, {
78
+ service: "domain",
79
+ domain: props.zoneName,
80
+ environment: props.costAllocationEnvironment
81
+ });
80
82
  }
81
83
  #applyUserTags(props) {
82
84
  if (!props.tags) {
@@ -12,6 +12,7 @@ export * from "./domainDelegation.js";
12
12
  export { Domain } from "./domain.js";
13
13
  export * from "./targets/index.js";
14
14
  export { getDomainExportNames, type DnsRecordInput, type DelegationInput, type CertificateInput, type DomainApexProps, type DomainDelegatedProps, type IDomainProps, type ManagedDomainExports, type FjallTarget, type StandardRecord, type DnsRecord, type Certificate, type SubdomainDelegation, type DomainCommonProps, type Route53ApexProps, type ExternalDelegatedProps, type ExternalRecordsProps, type DomainProps, type ManualRecord } from "./interfaces/domain.js";
15
+ export { MIGRATION_SNAPSHOT_NAME_PREFIX, EXPECTED_SCHEMA_VERSION_ENV, EXPECTED_SCHEMA_VERSION_TOOL_ENV } from "./interfaces/database.js";
15
16
  export * from "./compute.js";
16
17
  export * from "./storage.js";
17
18
  export * from "./auditRole.js";
@@ -18,6 +18,7 @@ export * from "./targets/index.js";
18
18
  // `AliasRecord` DNS-record construct re-exported via `resources/aws/networking`
19
19
  // and the `AliasRecord` TypeScript type declared in `interfaces/domain.ts`.
20
20
  export { getDomainExportNames } from "./interfaces/domain.js";
21
+ export { MIGRATION_SNAPSHOT_NAME_PREFIX, EXPECTED_SCHEMA_VERSION_ENV, EXPECTED_SCHEMA_VERSION_TOOL_ENV } from "./interfaces/database.js";
21
22
  // Patterns
22
23
  export * from "./compute.js";
23
24
  export * from "./storage.js";
@@ -12,7 +12,7 @@
12
12
  * lambda.getFunctionUrl(); // ✓ Available on ILambdaCompute
13
13
  * lambda.getLoadBalancer(); // ✗ Compile error - not on ILambdaCompute
14
14
  */
15
- import { type ICluster, type IBaseService } from "aws-cdk-lib/aws-ecs";
15
+ import { type ICluster, type IBaseService, type ITaskDefinition } from "aws-cdk-lib/aws-ecs";
16
16
  import { type IApplicationLoadBalancer } from "aws-cdk-lib/aws-elasticloadbalancingv2";
17
17
  import { type IFunction } from "aws-cdk-lib/aws-lambda";
18
18
  import { type IAutoScalingGroup } from "aws-cdk-lib/aws-autoscaling";
@@ -52,6 +52,12 @@ export interface IEcsCompute extends ICompute, IConnectable {
52
52
  getService(name: string): IBaseService | undefined;
53
53
  /** Get all services in the cluster. */
54
54
  getAllServices(): IBaseService[];
55
+ /**
56
+ * Get the task definition for a specific service. Used by Schedule /
57
+ * Subscription targets to construct the EcsTask adapter for EventBridge
58
+ * invocation. Returns undefined for unknown service names.
59
+ */
60
+ getTaskDefinition(serviceName: string): ITaskDefinition | undefined;
55
61
  /** Get the security group for the cluster. */
56
62
  getSecurityGroup(): ISecurityGroup;
57
63
  /**