@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,16 @@
1
+ import { BucketDeployment as CdkBucketDeployment, type BucketDeploymentProps } from "aws-cdk-lib/aws-s3-deployment";
2
+ import { type Construct } from "constructs";
3
+ /**
4
+ * Routing-point wrapper for `aws-cdk-lib/aws-s3-deployment.BucketDeployment`.
5
+ *
6
+ * Currently a thin pass-through — no defaults are applied today. The wrapper
7
+ * exists so that future SOC2 / compliance defaults (tags, retention, encryption
8
+ * on the underlying Lambda + Custom Resource) reach every consumer in one edit.
9
+ * Per `.claude/rules/generator-standards.md § Wrapper Routing Discipline` and
10
+ * `patterns/infrastructure-wrapper-routing-pattern.md § A3` ("a wrapper that
11
+ * is a thin pass-through today is still the routing point"), `lib/{config,
12
+ * patterns}/` MUST instantiate this class rather than the raw CDK construct.
13
+ */
14
+ export declare class BucketDeployment extends CdkBucketDeployment {
15
+ constructor(scope: Construct, id: string, props: BucketDeploymentProps);
16
+ }
@@ -0,0 +1,17 @@
1
+ import { BucketDeployment as CdkBucketDeployment } from "aws-cdk-lib/aws-s3-deployment";
2
+ /**
3
+ * Routing-point wrapper for `aws-cdk-lib/aws-s3-deployment.BucketDeployment`.
4
+ *
5
+ * Currently a thin pass-through — no defaults are applied today. The wrapper
6
+ * exists so that future SOC2 / compliance defaults (tags, retention, encryption
7
+ * on the underlying Lambda + Custom Resource) reach every consumer in one edit.
8
+ * Per `.claude/rules/generator-standards.md § Wrapper Routing Discipline` and
9
+ * `patterns/infrastructure-wrapper-routing-pattern.md § A3` ("a wrapper that
10
+ * is a thin pass-through today is still the routing point"), `lib/{config,
11
+ * patterns}/` MUST instantiate this class rather than the raw CDK construct.
12
+ */
13
+ export class BucketDeployment extends CdkBucketDeployment {
14
+ constructor(scope, id, props) {
15
+ super(scope, id, props);
16
+ }
17
+ }
@@ -24,14 +24,14 @@ export class Ecr extends Repository {
24
24
  });
25
25
  }
26
26
  static getRepositoryProps(props) {
27
- // todo: lifeCycleRules
28
- // todo: Encryption & EncryptionKey (default is AWS managed KMS key)
27
+ // Gotcha: DESTROY + emptyOnDelete:true silently wipes every pushed image
28
+ // on stack teardown next deploy pulls "not found" for any referenced tag.
29
29
  return {
30
30
  ...(props?.repositoryName && { repositoryName: props.repositoryName }),
31
31
  imageScanOnPush: true,
32
- imageTagMutability: TagMutability.MUTABLE,
33
- emptyOnDelete: true,
34
- removalPolicy: RemovalPolicy.DESTROY
32
+ imageTagMutability: TagMutability.IMMUTABLE,
33
+ emptyOnDelete: false,
34
+ removalPolicy: RemovalPolicy.RETAIN
35
35
  };
36
36
  }
37
37
  static build(id, props) {
@@ -1,2 +1,3 @@
1
1
  export * from "./s3.js";
2
2
  export * from "./ecr.js";
3
+ export * from "./bucketDeployment.js";
@@ -1,2 +1,3 @@
1
1
  export * from "./s3.js";
2
2
  export * from "./ecr.js";
3
+ export * from "./bucketDeployment.js";
@@ -1,5 +1,6 @@
1
1
  import { CfnOutput, Duration, RemovalPolicy } from "aws-cdk-lib";
2
2
  import { BlockPublicAccess, Bucket } from "aws-cdk-lib/aws-s3";
3
+ import { RegionInfo } from "aws-cdk-lib/region-info";
3
4
  import { toPascalCase } from "../../../utils/capitaliseString.js";
4
5
  function shouldAutoVersion(tier) {
5
6
  return tier === "resilient" || tier === "enterprise";
@@ -36,18 +37,24 @@ export class S3Bucket extends Bucket {
36
37
  });
37
38
  this.backupVaultTier = backupVaultTier;
38
39
  if (websiteHosting) {
39
- const safeBucket = toPascalCase((props.bucketName ?? id).replace(/[^A-Za-z0-9]/g, ""));
40
+ const safeBucket = toPascalCase((props.bucketName ?? id).replace(/[^A-Za-z0-9-]/g, ""));
40
41
  new CfnOutput(this, `${safeBucket}WebsiteEndpoint`, {
41
42
  key: `${safeBucket}WebsiteEndpoint`,
42
43
  exportName: `${safeBucket}WebsiteEndpoint`,
43
44
  value: this.bucketWebsiteDomainName,
44
45
  description: `S3 website endpoint for ${id} (consumed by Domain alias targets)`
45
46
  });
47
+ const region = this.stack.region;
48
+ const websiteHostedZoneId = RegionInfo.get(region).s3StaticWebsiteHostedZoneId;
49
+ if (websiteHostedZoneId === undefined) {
50
+ throw new Error(`S3 website hosted zone id is not known for region "${region}". ` +
51
+ `Update aws-cdk-lib/region-info or provide the bucket's hosted zone id explicitly.`);
52
+ }
46
53
  new CfnOutput(this, `${safeBucket}WebsiteHostedZoneId`, {
47
54
  key: `${safeBucket}WebsiteHostedZoneId`,
48
55
  exportName: `${safeBucket}WebsiteHostedZoneId`,
49
- value: this.stack.region,
50
- description: `AWS region for ${id}; consumer maps to S3 website Route53 zone ID`
56
+ value: websiteHostedZoneId,
57
+ description: `Route 53 hosted zone id for the S3 website endpoint of ${id}`
51
58
  });
52
59
  }
53
60
  }
@@ -3,6 +3,7 @@ import { Provider } from "aws-cdk-lib/custom-resources";
3
3
  import { Code } from "aws-cdk-lib/aws-lambda";
4
4
  import { Construct } from "constructs";
5
5
  import { SingletonFunction, LambdaFunction } from "../compute/lambda.js";
6
+ import { DEFAULT_CUSTOM_RESOURCE_TIMEOUT_SECONDS } from "../compute/ecsConstants.js";
6
7
  export class CustomResource extends Construct {
7
8
  response;
8
9
  resource;
@@ -15,12 +16,20 @@ export class CustomResource extends Construct {
15
16
  if (props.codePath && props.inlineCode) {
16
17
  throw new Error("CustomResource requires exactly one of codePath or inlineCode, not both");
17
18
  }
18
- const isInlineCode = !!props.inlineCode;
19
- const code = isInlineCode
20
- ? Code.fromInline(props.inlineCode)
21
- : Code.fromAsset(props.codePath, props.assetOptions);
19
+ const isInlineCode = props.inlineCode !== undefined;
20
+ let code;
21
+ if (props.inlineCode !== undefined) {
22
+ code = Code.fromInline(props.inlineCode);
23
+ }
24
+ else if (props.codePath !== undefined) {
25
+ code = Code.fromAsset(props.codePath, props.assetOptions);
26
+ }
27
+ else {
28
+ // Unreachable — earlier validation rejects this case
29
+ throw new Error("CustomResource requires codePath or inlineCode");
30
+ }
22
31
  const handler = props.handler ?? (isInlineCode ? "index.handler" : `${id}.handler`);
23
- const timeout = props.timeout?.toSeconds() ?? 300;
32
+ const timeout = props.timeout?.toSeconds() ?? DEFAULT_CUSTOM_RESOURCE_TIMEOUT_SECONDS;
24
33
  // Use LambdaFunction for inline code (unique per use), SingletonFunction for assets (shared)
25
34
  const lambdaFunction = isInlineCode
26
35
  ? new LambdaFunction(this, `${id}Lambda`, {
@@ -28,16 +37,16 @@ export class CustomResource extends Construct {
28
37
  handler,
29
38
  runtime: props.runtime,
30
39
  timeout,
31
- lambdaDescription: props.lambdaDescription || `${id} lambda`,
32
- roleDescription: props.roleDescription || `${id} custom resource lambda`,
40
+ lambdaDescription: props.lambdaDescription ?? `${id} lambda`,
41
+ roleDescription: props.roleDescription ?? `${id} custom resource lambda`,
33
42
  inlinePolicy: props.inlinePolicy
34
43
  })
35
44
  : new SingletonFunction(this, `${id}Lambda`, {
36
45
  code,
37
46
  handler,
38
47
  runtime: props.runtime,
39
- lambdaDescription: props.lambdaDescription || `${id} lambda`,
40
- roleDescription: props.roleDescription || `${id} custom resource lambda`,
48
+ lambdaDescription: props.lambdaDescription ?? `${id} lambda`,
49
+ roleDescription: props.roleDescription ?? `${id} custom resource lambda`,
41
50
  inlinePolicy: props.inlinePolicy
42
51
  });
43
52
  const provider = new Provider(this, `${id}Provider`, {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import { App, Stack } from "aws-cdk-lib";
2
+ import { Template } from "aws-cdk-lib/assertions";
3
+ import { Vpc } from "aws-cdk-lib/aws-ec2";
4
+ import { Repository } from "aws-cdk-lib/aws-ecr";
5
+ import { mkdtempSync, mkdirSync } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { EcsCompute } from "./patterns/aws/computeEcs.js";
9
+ import { RelationalDatabase } from "./patterns/aws/database.js";
10
+ const root = mkdtempSync(join(tmpdir(), "ds-"));
11
+ mkdirSync(join(root, "20260512000000_init"));
12
+ const app = new App();
13
+ const stack = new Stack(app, "S", { env: { account: "123456789012", region: "us-east-1" } });
14
+ const vpc = new Vpc(stack, "Vpc");
15
+ const db = new RelationalDatabase(stack, "Db", {
16
+ type: "Instance", vpc, databaseName: "appdata",
17
+ migrations: { tool: "prisma", dir: root }
18
+ });
19
+ new EcsCompute(stack, "Cluster", {
20
+ type: "ecs",
21
+ ecrRepository: new Repository(stack, "Ecr"),
22
+ services: [{
23
+ name: "web", capacityProvider: "FARGATE",
24
+ containers: [{ name: "app", image: "nginx:latest", port: 3000 }],
25
+ connections: [db],
26
+ migrations: {
27
+ mode: "lifecycle-hook", command: ["node", "migrate.mjs"], entryPoint: ["/usr/bin/tini", "--"],
28
+ separateTaskDef: { cpu: 512, memoryLimitMiB: 1024 }
29
+ }
30
+ }]
31
+ });
32
+ const t = Template.fromStack(stack);
33
+ const ing = t.findResources("AWS::EC2::SecurityGroupIngress");
34
+ for (const [name, res] of Object.entries(ing)) {
35
+ console.log("INGRESS:", name);
36
+ console.log(" props:", JSON.stringify(res.Properties));
37
+ }
38
+ const eg = t.findResources("AWS::EC2::SecurityGroupEgress");
39
+ for (const [name, res] of Object.entries(eg)) {
40
+ console.log("EGRESS:", name);
41
+ console.log(" props:", JSON.stringify(res.Properties));
42
+ }
@@ -0,0 +1,10 @@
1
+ import { type IVpc } from "aws-cdk-lib/aws-ec2";
2
+ import { Ec2Instance } from "../resources/aws/compute/ec2.js";
3
+ import { type AwsStack } from "../resources/index.js";
4
+ export interface BastionConfig {
5
+ instanceType?: string;
6
+ }
7
+ export interface BastionResult {
8
+ bastion: Ec2Instance;
9
+ }
10
+ export declare function createBastion(networkStack: AwsStack, appName: string, stackPrefix: string, vpc: IVpc, config: BastionConfig | true): BastionResult;
@@ -0,0 +1,29 @@
1
+ import { CfnOutput } from "aws-cdk-lib";
2
+ import { Ec2Instance } from "../resources/aws/compute/ec2.js";
3
+ import { toPascalCase } from "./capitaliseString.js";
4
+ export function createBastion(networkStack, appName, stackPrefix, vpc, config) {
5
+ const instanceType = typeof config === "object" && config.instanceType
6
+ ? config.instanceType
7
+ : "t4g.micro";
8
+ const bastionId = `${stackPrefix}Bastion`;
9
+ const scope = networkStack.getStack();
10
+ const bastion = new Ec2Instance(scope, bastionId, {
11
+ serviceName: `${stackPrefix}Bastion`,
12
+ instanceType,
13
+ vpc,
14
+ enableSSH: false,
15
+ minCapacity: 1,
16
+ maxCapacity: 1
17
+ });
18
+ networkStack.addConstruct(bastion);
19
+ const outputPrefix = toPascalCase(appName);
20
+ new CfnOutput(scope, `${outputPrefix}BastionInstanceId`, {
21
+ value: bastion.getAutoScalingGroup().autoScalingGroupName,
22
+ description: "Bastion ASG name for SSM tunnel discovery"
23
+ });
24
+ new CfnOutput(scope, `${outputPrefix}BastionSecurityGroupId`, {
25
+ value: bastion.asgSecurityGroup.securityGroupId,
26
+ description: "Bastion security group ID"
27
+ });
28
+ return { bastion };
29
+ }
@@ -1 +1 @@
1
- export { capitalise as capitaliseString, toPascalCase, toKebab, toValidDatabaseName, getSafeZoneName } from "@fjall/util";
1
+ export { capitalise as capitaliseString, toPascalCase, toKebab, toValidDatabaseName, toScreamingSnake, getSafeZoneName } from "@fjall/util";
@@ -1 +1 @@
1
- export { capitalise as capitaliseString, toPascalCase, toKebab, toValidDatabaseName, getSafeZoneName } from "@fjall/util";
1
+ export { capitalise as capitaliseString, toPascalCase, toKebab, toValidDatabaseName, toScreamingSnake, getSafeZoneName } from "@fjall/util";
@@ -0,0 +1,10 @@
1
+ import type { Node } from "constructs";
2
+ export declare const CDK_CONTEXT_KEYS: {
3
+ readonly ORG_ID: "orgId";
4
+ readonly ROOT_ID: "rootId";
5
+ readonly MANAGEMENT_ACCOUNT_ID: "managementAccountId";
6
+ };
7
+ export declare const DEFAULT_ORG_ID: "default";
8
+ export declare function resolveOrgId(node: Node, fallback: string): string;
9
+ export declare function resolveOrgId(node: Node): string | undefined;
10
+ export declare function buildSsmPrefix(orgId: string, appName: string): string;
@@ -0,0 +1,13 @@
1
+ export const CDK_CONTEXT_KEYS = {
2
+ ORG_ID: "orgId",
3
+ ROOT_ID: "rootId",
4
+ MANAGEMENT_ACCOUNT_ID: "managementAccountId"
5
+ };
6
+ export const DEFAULT_ORG_ID = "default";
7
+ export function resolveOrgId(node, fallback) {
8
+ const raw = node.tryGetContext(CDK_CONTEXT_KEYS.ORG_ID);
9
+ return typeof raw === "string" && raw !== "" ? raw : fallback;
10
+ }
11
+ export function buildSsmPrefix(orgId, appName) {
12
+ return `/fjall/${orgId}/${appName}`;
13
+ }
@@ -23,7 +23,7 @@
23
23
  */
24
24
  import { type IConnectable } from "aws-cdk-lib/aws-ec2";
25
25
  import { type IGrantable } from "aws-cdk-lib/aws-iam";
26
- import { type ConnectionSpec, type ConnectionResult } from "./connector.js";
26
+ import { type ConnectionSpec, type ConnectionResult, type IRemoteConnector } from "./connector.js";
27
27
  /**
28
28
  * Process connections from compute resources to data resources.
29
29
  *
@@ -44,3 +44,9 @@ import { type ConnectionSpec, type ConnectionResult } from "./connector.js";
44
44
  * );
45
45
  */
46
46
  export declare function processConnections(connections: ConnectionSpec[], grantee: IGrantable, connectable?: IConnectable): ConnectionResult[];
47
+ /**
48
+ * Build an env-vars connection result for a remote connector.
49
+ * Used by the cross-app VPC peering path — env vars are surfaced from SSM
50
+ * lookups upstream and merged into the consuming compute's container env.
51
+ */
52
+ export declare function buildEnvVarsResult(connector: IRemoteConnector, envVars: Record<string, string>): ConnectionResult;
@@ -21,6 +21,7 @@
21
21
  * this.lambdaFunction // IConnectable (security group)
22
22
  * );
23
23
  */
24
+ import { Port } from "aws-cdk-lib/aws-ec2";
24
25
  import { CONNECTION_TYPE, isConnectionConfig, isConnector, isConnectable, isConnectionAccess, isMessagingAccess } from "./connector.js";
25
26
  /** Default access levels for each connector type. */
26
27
  const DEFAULT_ACCESS = {
@@ -140,8 +141,16 @@ export function processConnections(connections, grantee, connectable) {
140
141
  case "relational": {
141
142
  requireConnectable(connectable, `${resource.connectorType} connector`);
142
143
  connectable.connections.allowToDefaultPort(resource);
144
+ if (resource.additionalTcpPorts !== undefined) {
145
+ for (const port of resource.additionalTcpPorts) {
146
+ connectable.connections.allowTo(resource, Port.tcp(port));
147
+ }
148
+ }
143
149
  return buildSecurityGroupResult(resource);
144
150
  }
151
+ case "remote": {
152
+ return buildEnvVarsResult(resource, resource.environmentVariables);
153
+ }
145
154
  }
146
155
  }
147
156
  // Legacy IConnectable path
@@ -153,3 +162,15 @@ export function processConnections(connections, grantee, connectable) {
153
162
  throw new Error("Connection resource must be either an IConnector or IConnectable");
154
163
  });
155
164
  }
165
+ /**
166
+ * Build an env-vars connection result for a remote connector.
167
+ * Used by the cross-app VPC peering path — env vars are surfaced from SSM
168
+ * lookups upstream and merged into the consuming compute's container env.
169
+ */
170
+ export function buildEnvVarsResult(connector, envVars) {
171
+ return {
172
+ resource: connector,
173
+ connectionType: CONNECTION_TYPE.ENV_VARS,
174
+ environmentVariables: envVars
175
+ };
176
+ }
@@ -45,8 +45,9 @@ import { type IGrantable, type Grant } from "aws-cdk-lib/aws-iam";
45
45
  * - "queue": SQS queues
46
46
  * - "securityGroup": Resources with security groups (ECS, Lambda with VPC)
47
47
  * - "relational": RDS databases (uses security groups)
48
+ * - "remote": Cross-app resource exposed via VPC peering, surfaced as env vars
48
49
  */
49
- export type ConnectorType = "storage" | "dynamodb" | "queue" | "securityGroup" | "relational";
50
+ export type ConnectorType = "storage" | "dynamodb" | "queue" | "securityGroup" | "relational" | "remote";
50
51
  /**
51
52
  * Access level for storage and DynamoDB connectors.
52
53
  */
@@ -114,11 +115,33 @@ export interface ISecurityGroupConnector extends IConnector {
114
115
  readonly connectorType: "securityGroup" | "relational";
115
116
  /** The security group connections for this resource. */
116
117
  readonly connections: IConnectable["connections"];
118
+ /**
119
+ * Additional TCP ports to open beyond the default port carried by
120
+ * `connections`. Used by dual-port resources such as ClickHouse, where the
121
+ * primary port (HTTP, 8123) flows through `connections.allowDefaultPortFrom`
122
+ * and the native protocol port (9000) is appended here. Optional; existing
123
+ * single-port consumers (Aurora, Instance, GlobalAurora) leave this
124
+ * undefined and behave unchanged.
125
+ *
126
+ * Surfaced as `number[]` (not `aws-cdk-lib/aws-ec2.Port[]`) per the
127
+ * 2026-05-05 ClickHouse design D18(k); `Port.tcp(n)` is plumbing.
128
+ */
129
+ readonly additionalTcpPorts?: number[];
130
+ }
131
+ /**
132
+ * Remote connector interface.
133
+ * Represents a resource exposed by a peered app via VPC peering.
134
+ * Carries the env vars that should be injected into the consuming compute.
135
+ */
136
+ export interface IRemoteConnector extends IConnector {
137
+ readonly connectorType: "remote";
138
+ /** Env vars to inject (e.g. `{PREFIX}_HOST`, `{PREFIX}_PORT`). */
139
+ readonly environmentVariables: Record<string, string>;
117
140
  }
118
141
  /**
119
142
  * Union type representing any connector interface.
120
143
  */
121
- export type AnyConnector = IStorageConnector | IDynamoDBConnector | IQueueConnector | ISecurityGroupConnector;
144
+ export type AnyConnector = IStorageConnector | IDynamoDBConnector | IQueueConnector | ISecurityGroupConnector | IRemoteConnector;
122
145
  /**
123
146
  * Connection configuration with explicit access level.
124
147
  * Use this to specify non-default access levels.
@@ -141,6 +164,7 @@ export type ConnectionSpec = IConnectable | AnyConnector | ConnectionConfig;
141
164
  export declare const CONNECTION_TYPE: {
142
165
  readonly SECURITY_GROUP: "securityGroup";
143
166
  readonly IAM: "iam";
167
+ readonly ENV_VARS: "envVars";
144
168
  };
145
169
  export type ConnectionType = (typeof CONNECTION_TYPE)[keyof typeof CONNECTION_TYPE];
146
170
  /**
@@ -154,6 +178,8 @@ export interface ConnectionResult {
154
178
  grant?: Grant;
155
179
  /** The type of connection that was made. */
156
180
  connectionType: ConnectionType;
181
+ /** Env vars to inject when connectionType is "envVars". */
182
+ environmentVariables?: Record<string, string>;
157
183
  }
158
184
  /** Check if a value is a valid ConnectionAccess. */
159
185
  export declare function isConnectionAccess(value: unknown): value is ConnectionAccess;
@@ -181,3 +207,5 @@ export declare function isDynamoDBConnector(connector: IConnector): connector is
181
207
  export declare function isQueueConnector(connector: IConnector): connector is IQueueConnector;
182
208
  /** Type guard for security group connectors (RDS, ECS). */
183
209
  export declare function isSecurityGroupConnector(connector: IConnector): connector is ISecurityGroupConnector;
210
+ /** Type guard for remote connectors (cross-app exposed resources). */
211
+ export declare function isRemoteConnector(connector: IConnector): connector is IRemoteConnector;
@@ -39,7 +39,8 @@
39
39
  /** Connection result types. */
40
40
  export const CONNECTION_TYPE = {
41
41
  SECURITY_GROUP: "securityGroup",
42
- IAM: "iam"
42
+ IAM: "iam",
43
+ ENV_VARS: "envVars"
43
44
  };
44
45
  const VALID_CONNECTION_ACCESS = [
45
46
  "read",
@@ -102,3 +103,7 @@ export function isSecurityGroupConnector(connector) {
102
103
  return (connector.connectorType === "securityGroup" ||
103
104
  connector.connectorType === "relational");
104
105
  }
106
+ /** Type guard for remote connectors (cross-app exposed resources). */
107
+ export function isRemoteConnector(connector) {
108
+ return connector.connectorType === "remote";
109
+ }
@@ -0,0 +1,15 @@
1
+ import type { IConstruct } from "constructs";
2
+ export declare const COST_ALLOCATION_TAGS: {
3
+ readonly ENVIRONMENT: "fjall:costAllocation:environment";
4
+ readonly SERVICE: "fjall:costAllocation:service";
5
+ readonly DOMAIN: "fjall:costAllocation:domain";
6
+ readonly OWNER: "fjall:costAllocation:owner";
7
+ };
8
+ export declare const DEFAULT_COST_ALLOCATION_ENVIRONMENT: "management";
9
+ export interface CostAllocationTagsArgs {
10
+ readonly service: string;
11
+ readonly domain: string;
12
+ readonly environment?: string;
13
+ readonly owner?: string;
14
+ }
15
+ export declare function applyCostAllocationTags(scope: IConstruct, args: CostAllocationTagsArgs): void;
@@ -0,0 +1,16 @@
1
+ import { Tags } from "aws-cdk-lib";
2
+ export const COST_ALLOCATION_TAGS = {
3
+ ENVIRONMENT: "fjall:costAllocation:environment",
4
+ SERVICE: "fjall:costAllocation:service",
5
+ DOMAIN: "fjall:costAllocation:domain",
6
+ OWNER: "fjall:costAllocation:owner"
7
+ };
8
+ export const DEFAULT_COST_ALLOCATION_ENVIRONMENT = "management";
9
+ export function applyCostAllocationTags(scope, args) {
10
+ Tags.of(scope).add(COST_ALLOCATION_TAGS.ENVIRONMENT, args.environment ?? DEFAULT_COST_ALLOCATION_ENVIRONMENT);
11
+ Tags.of(scope).add(COST_ALLOCATION_TAGS.SERVICE, args.service);
12
+ Tags.of(scope).add(COST_ALLOCATION_TAGS.DOMAIN, args.domain);
13
+ if (args.owner !== undefined) {
14
+ Tags.of(scope).add(COST_ALLOCATION_TAGS.OWNER, args.owner);
15
+ }
16
+ }
@@ -2,7 +2,21 @@ import { type Duration } from "aws-cdk-lib";
2
2
  import { type IKey } from "aws-cdk-lib/aws-kms";
3
3
  import { type SubnetSelection } from "aws-cdk-lib/aws-ec2";
4
4
  export type DatabaseEngine = "postgresql" | "mysql";
5
+ /**
6
+ * Discriminated snapshot target. Instance variants return
7
+ * `{ kind: "instance", arn }`; cluster variants return
8
+ * `{ kind: "cluster", arn }`. Consumers branch on `kind` to choose between
9
+ * `rds:CreateDBSnapshot` and `rds:CreateDBClusterSnapshot`.
10
+ */
11
+ export type SnapshotTarget = {
12
+ kind: "instance";
13
+ arn: string;
14
+ } | {
15
+ kind: "cluster";
16
+ arn: string;
17
+ };
5
18
  export interface EngineConfig {
19
+ family: DatabaseEngine;
6
20
  defaultUsername: string;
7
21
  sslParameters: Record<string, string>;
8
22
  rotationAppName: string;
@@ -1,9 +1,11 @@
1
+ import { type ProviderAccount } from "@fjall/util/config";
1
2
  export interface Config {
2
3
  region: string;
3
4
  environment: string;
4
5
  accountId?: string;
5
6
  accountName?: string;
6
7
  accountIds?: Record<string, string>;
8
+ providerAccounts: ProviderAccount[];
7
9
  primaryRegion?: string;
8
10
  secondaryRegions: string[];
9
11
  allRegions: string[];
@@ -6,6 +6,7 @@ export function getConfig(accountName) {
6
6
  const config = {
7
7
  region: process.env.AWS_REGION || "us-east-1",
8
8
  environment: "unknown",
9
+ providerAccounts: [],
9
10
  secondaryRegions: [],
10
11
  allRegions: []
11
12
  };
@@ -18,6 +19,7 @@ export function getConfig(accountName) {
18
19
  }
19
20
  const orgConfig = parseOrgConfig(typeof orgConfigRaw === "string" ? orgConfigRaw : undefined);
20
21
  const providerAccounts = orgConfig.providerAccounts;
22
+ config.providerAccounts = providerAccounts;
21
23
  config.primaryRegion = orgConfig.primaryRegion;
22
24
  config.secondaryRegions = orgConfig.secondaryRegions;
23
25
  config.disasterRecoveryRegion = orgConfig.disasterRecoveryRegion;
@@ -1,6 +1,8 @@
1
1
  export * from "./backupTierMapping.js";
2
2
  export * from "./capitaliseString.js";
3
+ export * from "./cdkContext.js";
3
4
  export * from "./connections.js";
5
+ export * from "./connector.js";
4
6
  export * from "./databaseTypes.js";
5
7
  export * from "./getConfig.js";
6
8
  export * from "./removalPolicy.js";
@@ -8,5 +10,7 @@ export * from "./resourceNaming.js";
8
10
  export * from "./standardTagsAspect.js";
9
11
  export * from "./validationLogger.js";
10
12
  export * from "./env.js";
13
+ export * from "./vpcPeerInterface.js";
11
14
  export * from "./vpcUtils.js";
12
15
  export * from "./domainTypes.js";
16
+ export * from "./migrationVersionResolvers.js";
@@ -1,6 +1,8 @@
1
1
  export * from "./backupTierMapping.js";
2
2
  export * from "./capitaliseString.js";
3
+ export * from "./cdkContext.js";
3
4
  export * from "./connections.js";
5
+ export * from "./connector.js";
4
6
  export * from "./databaseTypes.js";
5
7
  export * from "./getConfig.js";
6
8
  export * from "./removalPolicy.js";
@@ -8,5 +10,7 @@ export * from "./resourceNaming.js";
8
10
  export * from "./standardTagsAspect.js";
9
11
  export * from "./validationLogger.js";
10
12
  export * from "./env.js";
13
+ export * from "./vpcPeerInterface.js";
11
14
  export * from "./vpcUtils.js";
12
15
  export * from "./domainTypes.js";
16
+ export * from "./migrationVersionResolvers.js";