@fjall/components-infrastructure 0.96.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 (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 +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 +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 +157 -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
package/dist/lib/app.d.ts CHANGED
@@ -10,7 +10,11 @@ import { type INetworkProps, type Network } from "./patterns/aws/network.js";
10
10
  import { type Cdn } from "./patterns/aws/cdn.js";
11
11
  import { type VpcPeer } from "./patterns/aws/vpcPeer.js";
12
12
  import { type VpcPeerAccepter } from "./patterns/aws/vpcPeerAccepter.js";
13
- import { type AnyMessaging } from "./patterns/aws/messaging.js";
13
+ import { type AnyMessaging, type EventBusMessaging } from "./patterns/aws/messaging.js";
14
+ import { Schedule, type ScheduleProps } from "./resources/aws/messaging/schedule.js";
15
+ import { type RemovalPolicyString } from "./resources/aws/messaging/utils.js";
16
+ import { type ServiceRegistrationProps } from "./resources/aws/networking/serviceDiscovery.js";
17
+ import { type IPrivateDnsNamespace, type IService } from "aws-cdk-lib/aws-servicediscovery";
14
18
  import { type AnyCompute } from "./patterns/aws/compute.js";
15
19
  import { type Storage, type StorageFactoryFn } from "./patterns/aws/storage.js";
16
20
  import { type AnyPattern } from "./patterns/aws/pattern.js";
@@ -63,6 +67,20 @@ export interface IAppOptions {
63
67
  tunnel?: {
64
68
  instanceType?: string;
65
69
  } | boolean;
70
+ /**
71
+ * EventBridge default-bus override (T7a, D2 + D17).
72
+ *
73
+ * - `name?` overrides the AWS `EventBus.Name` (defaults to the app name).
74
+ * - `removalPolicy?` overrides the env-resolved default. Default resolves
75
+ * via `env({ default: "DESTROY", production: "RETAIN" })` per D17 — NOT
76
+ * `process.env.NODE_ENV` (which is not set during CDK synth in Fjall's
77
+ * deployment paths). The shape is the normalised string union per
78
+ * D18(d), NOT the raw CDK `RemovalPolicy` enum.
79
+ */
80
+ eventBus?: {
81
+ name?: string;
82
+ removalPolicy?: RemovalPolicyString;
83
+ };
66
84
  }
67
85
  /**
68
86
  * The basic corner-stone of all Fjall-hosted applications.
@@ -78,6 +96,9 @@ export declare class App extends CdkApp {
78
96
  private vpc?;
79
97
  private additionalVpcs;
80
98
  private defaultEcr;
99
+ private defaultEventBus?;
100
+ private eventBusOverride?;
101
+ private defaultNamespace?;
81
102
  private defaultAuditRole;
82
103
  private auditRoleExternalId?;
83
104
  private bastion?;
@@ -148,6 +169,37 @@ export declare class App extends CdkApp {
148
169
  getVpc(name?: string): IVpc;
149
170
  getVpcNames(): string[];
150
171
  getDefaultContainerRegistry(): Ecr;
172
+ /**
173
+ * Lazy getter for the per-app default custom EventBridge bus (D2).
174
+ *
175
+ * Buses are recreatable in non-prod; the env-resolved default keeps prod
176
+ * history. The override (`App.getApp({ eventBus: { name?, removalPolicy? } })`)
177
+ * is consulted first; absent override falls back to the app name and the
178
+ * `env({ default: "DESTROY", production: "RETAIN" })` resolution per D17.
179
+ * NODE_ENV is not consulted — it is not set during CDK synth in Fjall's
180
+ * deployment paths.
181
+ */
182
+ getEventBus(): EventBusMessaging;
183
+ /**
184
+ * Lazy getter for the per-app Cloud Map private DNS namespace (D7 + D29 of
185
+ * the ClickHouse Database Factory promotion design).
186
+ *
187
+ * The namespace is constructed in the network stack on first call and
188
+ * reused thereafter — `app.getNamespace() === app.getNamespace()`. Default
189
+ * name is `${toKebab(appName)}.local` per the implementation-defined
190
+ * derivation rule; v1 has no override config option (D29). Returns the
191
+ * `IPrivateDnsNamespace` interface per D18(a), never the concrete class.
192
+ */
193
+ getNamespace(): IPrivateDnsNamespace;
194
+ /**
195
+ * Register a Cloud Map service against the per-app namespace. Lazily creates
196
+ * the namespace on first call (same construct as `getNamespace()`) and
197
+ * delegates to the `ServiceDiscoveryNamespace` wrapper's `registerService`
198
+ * — keeping both halves of Cloud Map (namespace + services) routed through
199
+ * the wrapper layer per § Wrapper Routing Discipline.
200
+ */
201
+ registerService(props: ServiceRegistrationProps): IService;
202
+ private ensureNamespace;
151
203
  /**
152
204
  * Create a cross-account audit role in the Network stack that allows
153
205
  * the Fjall platform to use CloudQuery for comprehensive AWS resource auditing.
@@ -288,6 +340,21 @@ export declare class App extends CdkApp {
288
340
  * }));
289
341
  */
290
342
  addMessaging<T extends AnyMessaging & Construct>(fn: (app: App, scope: Construct) => T): T;
343
+ /**
344
+ * Register an EventBridge schedule against a Fjall wrapper target.
345
+ *
346
+ * Defaults to the messaging stack; set `props.stackPlacement = "compute"`
347
+ * when the schedule's target lives in the compute stack and cross-stack
348
+ * output churn is undesired. `applicationId` is threaded automatically
349
+ * from `app.getName()` for alarm webhook routing per D13.
350
+ *
351
+ * @example
352
+ * app.addSchedule("MetricsCollection", {
353
+ * schedule: "rate(5 minutes)",
354
+ * target: notificationsQueue
355
+ * });
356
+ */
357
+ addSchedule(id: string, props: Omit<ScheduleProps, "applicationId">): Schedule;
291
358
  /**
292
359
  * Add a high-level infrastructure pattern to the application.
293
360
  *
package/dist/lib/app.js CHANGED
@@ -1,9 +1,13 @@
1
1
  import { App as CdkApp, Aspects, Tags } from "aws-cdk-lib";
2
+ import { maskSensitiveOutput } from "@fjall/util";
2
3
  import { Vpc } from "./resources/aws/networking/vpc.js";
3
- import { createBastion } from "./utils/bastionFactory.js";
4
+ import { createBastion } from "./patterns/aws/bastionFactory.js";
4
5
  import { AwsStack } from "./resources/index.js";
5
6
  import { EcrFactory } from "./resources/aws/storage/ecr.js";
6
7
  import { NetworkFactory } from "./patterns/aws/network.js";
8
+ import { MessagingFactory } from "./patterns/aws/messaging.js";
9
+ import { Schedule } from "./resources/aws/messaging/schedule.js";
10
+ import { ServiceDiscoveryNamespace } from "./resources/aws/networking/serviceDiscovery.js";
7
11
  import { StandardTagsAspect } from "./utils/standardTagsAspect.js";
8
12
  import { BACKUP_TIER_TAG_KEY, BACKUP_TIER_TAG_MAP } from "./utils/backupTierMapping.js";
9
13
  import { randomBytes } from "crypto";
@@ -28,6 +32,9 @@ export class App extends CdkApp {
28
32
  vpc;
29
33
  additionalVpcs = new Map();
30
34
  defaultEcr;
35
+ defaultEventBus;
36
+ eventBusOverride;
37
+ defaultNamespace;
31
38
  defaultAuditRole;
32
39
  auditRoleExternalId;
33
40
  bastion;
@@ -59,6 +66,9 @@ export class App extends CdkApp {
59
66
  if (options?.tunnel) {
60
67
  this.initialiseTunnel(options.tunnel);
61
68
  }
69
+ if (options?.eventBus !== undefined) {
70
+ this.eventBusOverride = options.eventBus;
71
+ }
62
72
  }
63
73
  applyBackupTag(tier) {
64
74
  this.globalTags[BACKUP_TIER_TAG_KEY] = BACKUP_TIER_TAG_MAP[tier];
@@ -128,6 +138,19 @@ export class App extends CdkApp {
128
138
  if (options?.tunnel && !App.instance.bastion) {
129
139
  App.instance.initialiseTunnel(options.tunnel);
130
140
  }
141
+ if (options?.eventBus !== undefined) {
142
+ if (App.instance.eventBusOverride === undefined &&
143
+ App.instance.defaultEventBus === undefined) {
144
+ App.instance.eventBusOverride = options.eventBus;
145
+ }
146
+ else {
147
+ const reason = App.instance.defaultEventBus !== undefined
148
+ ? "bus was already materialised via getEventBus()"
149
+ : "override was already set on a prior App.getApp() call";
150
+ FjallLogger.warn(`App.getApp() eventBus override ignored: ${reason}. ` +
151
+ `Pass eventBus options to the first App.getApp() call.`);
152
+ }
153
+ }
131
154
  }
132
155
  return App.instance;
133
156
  }
@@ -248,6 +271,67 @@ export class App extends CdkApp {
248
271
  }
249
272
  return this.defaultEcr;
250
273
  }
274
+ /**
275
+ * Lazy getter for the per-app default custom EventBridge bus (D2).
276
+ *
277
+ * Buses are recreatable in non-prod; the env-resolved default keeps prod
278
+ * history. The override (`App.getApp({ eventBus: { name?, removalPolicy? } })`)
279
+ * is consulted first; absent override falls back to the app name and the
280
+ * `env({ default: "DESTROY", production: "RETAIN" })` resolution per D17.
281
+ * NODE_ENV is not consulted — it is not set during CDK synth in Fjall's
282
+ * deployment paths.
283
+ */
284
+ getEventBus() {
285
+ if (this.defaultEventBus) {
286
+ return this.defaultEventBus;
287
+ }
288
+ const eventBusName = this.eventBusOverride?.name ?? this.getName();
289
+ const removalPolicy = this.eventBusOverride?.removalPolicy;
290
+ const bus = this.addMessaging(MessagingFactory.build(`${this.stackPrefix}EventBus`, {
291
+ type: "eventBus",
292
+ eventBusName,
293
+ appName: this.name,
294
+ removalPolicy
295
+ }));
296
+ this.defaultEventBus = bus;
297
+ return bus;
298
+ }
299
+ /**
300
+ * Lazy getter for the per-app Cloud Map private DNS namespace (D7 + D29 of
301
+ * the ClickHouse Database Factory promotion design).
302
+ *
303
+ * The namespace is constructed in the network stack on first call and
304
+ * reused thereafter — `app.getNamespace() === app.getNamespace()`. Default
305
+ * name is `${toKebab(appName)}.local` per the implementation-defined
306
+ * derivation rule; v1 has no override config option (D29). Returns the
307
+ * `IPrivateDnsNamespace` interface per D18(a), never the concrete class.
308
+ */
309
+ getNamespace() {
310
+ return this.ensureNamespace().getNamespace();
311
+ }
312
+ /**
313
+ * Register a Cloud Map service against the per-app namespace. Lazily creates
314
+ * the namespace on first call (same construct as `getNamespace()`) and
315
+ * delegates to the `ServiceDiscoveryNamespace` wrapper's `registerService`
316
+ * — keeping both halves of Cloud Map (namespace + services) routed through
317
+ * the wrapper layer per § Wrapper Routing Discipline.
318
+ */
319
+ registerService(props) {
320
+ return this.ensureNamespace().registerService(props);
321
+ }
322
+ ensureNamespace() {
323
+ if (this.defaultNamespace) {
324
+ return this.defaultNamespace;
325
+ }
326
+ const networkStack = this.getDefaultNetworkStack();
327
+ const namespace = new ServiceDiscoveryNamespace(networkStack.getStack(), `${this.stackPrefix}Namespace`, {
328
+ vpc: this.getVpc(),
329
+ name: `${toKebab(this.name)}.local`
330
+ });
331
+ networkStack.addConstruct(namespace);
332
+ this.defaultNamespace = namespace;
333
+ return namespace;
334
+ }
251
335
  /**
252
336
  * Create a cross-account audit role in the Network stack that allows
253
337
  * the Fjall platform to use CloudQuery for comprehensive AWS resource auditing.
@@ -467,6 +551,32 @@ export class App extends CdkApp {
467
551
  messagingStack.addConstruct(messaging);
468
552
  return messaging;
469
553
  }
554
+ /**
555
+ * Register an EventBridge schedule against a Fjall wrapper target.
556
+ *
557
+ * Defaults to the messaging stack; set `props.stackPlacement = "compute"`
558
+ * when the schedule's target lives in the compute stack and cross-stack
559
+ * output churn is undesired. `applicationId` is threaded automatically
560
+ * from `app.getName()` for alarm webhook routing per D13.
561
+ *
562
+ * @example
563
+ * app.addSchedule("MetricsCollection", {
564
+ * schedule: "rate(5 minutes)",
565
+ * target: notificationsQueue
566
+ * });
567
+ */
568
+ addSchedule(id, props) {
569
+ const stack = props.stackPlacement === "compute"
570
+ ? this.getDefaultComputeStack()
571
+ : this.getDefaultMessagingStack();
572
+ const schedule = new Schedule(stack.getStack(), id, {
573
+ ...props,
574
+ applicationId: this.getName(),
575
+ appName: props.appName ?? this.getName()
576
+ });
577
+ stack.addConstruct(schedule);
578
+ return schedule;
579
+ }
470
580
  /**
471
581
  * Add a high-level infrastructure pattern to the application.
472
582
  *
@@ -590,9 +700,8 @@ export class App extends CdkApp {
590
700
  writeManifest(assembly, this.manifestCollector);
591
701
  }
592
702
  catch (error) {
593
- // Don't fail synth if manifest export fails
594
- const errorMessage = error instanceof Error ? error.message : String(error);
595
- FjallLogger.warn(`Failed to export Fjall manifest: ${errorMessage}`);
703
+ const maskedMessage = maskSensitiveOutput(error instanceof Error ? error.message : String(error));
704
+ FjallLogger.warn(`Failed to export Fjall manifest: ${maskedMessage}`);
596
705
  }
597
706
  return assembly;
598
707
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { Rule } from "aws-cdk-lib/aws-events";
2
+ import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
3
+ console.log(Rule, LambdaFunction);
@@ -0,0 +1,2 @@
1
+ import { type IRule } from "aws-cdk-lib/aws-events";
2
+ export type T = IRule;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,18 +1,22 @@
1
1
  import { CfnOutput } from "aws-cdk-lib";
2
- import * as sns from "aws-cdk-lib/aws-sns";
3
2
  import { Construct } from "constructs";
3
+ import { SNSTopic } from "../../resources/aws/messaging/sns.js";
4
4
  export class SharedAlarmTopic extends Construct {
5
5
  topic;
6
6
  topicArn;
7
7
  constructor(scope, id) {
8
8
  super(scope, id);
9
- const topic = new sns.Topic(this, "AlarmNotifications", {
9
+ const wrapped = new SNSTopic(this, "AlarmNotifications", {
10
10
  displayName: "Fjall CloudWatch Alarm Notifications"
11
11
  });
12
- this.topic = topic;
12
+ this.topic = wrapped.getTopic();
13
+ // SharedAlarmTopicArn is a well-known cross-stack export consumed via
14
+ // Fn.importValue (see resolveAlertsTopic + its tests). Do not delete
15
+ // thinking it duplicates the wrapper's AlarmNotificationsTopicArn —
16
+ // the wrapper's auto-output has no exportName and cannot be imported.
13
17
  this.topicArn = new CfnOutput(this, "SharedAlarmTopicArn", {
14
18
  key: "SharedAlarmTopicArn",
15
- value: topic.topicArn,
19
+ value: wrapped.getTopicArn(),
16
20
  exportName: "SharedAlarmTopicArn"
17
21
  });
18
22
  }
@@ -3,7 +3,7 @@ import { Trail } from "../../resources/aws/logging/cloudTrail.js";
3
3
  export class ManagementEventsTrail extends Construct {
4
4
  constructor(scope, id, props) {
5
5
  super(scope, id);
6
- new Trail(this, "managementEventsTrail", {
6
+ new Trail(this, "ManagementEventsTrail", {
7
7
  bucketName: `cloudtrail-management-events-${props.accountId}-${props.region}`,
8
8
  trailName: "managementEvents",
9
9
  isMultiRegionTrail: true
@@ -2,10 +2,10 @@ import { CfnOutput, Duration, RemovalPolicy } from "aws-cdk-lib";
2
2
  import { Construct } from "constructs";
3
3
  import { BackupVault, BackupPlan } from "../../resources/aws/backup/index.js";
4
4
  import { BackupPlanRule, BackupVault as Vault } from "aws-cdk-lib/aws-backup";
5
- import * as events from "aws-cdk-lib/aws-events";
5
+ import { cronSchedule } from "../../resources/aws/messaging/index.js";
6
6
  import { AccountPrincipal, Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
7
- import App from "../../app.js";
8
- import { parseOrgConfig } from "../../utils/orgConfigParser.js";
7
+ import { getConfig } from "../../utils/getConfig.js";
8
+ import { toPascalCase } from "../../utils/capitaliseString.js";
9
9
  // Backup retention constants (in days)
10
10
  const RETENTION_PERIODS = {
11
11
  STANDARD: 90,
@@ -34,16 +34,11 @@ export class DisasterRecovery extends Construct {
34
34
  customBackupPlans;
35
35
  constructor(scope, id, props) {
36
36
  super(scope, id);
37
- // Read org config from CDK context
38
- const app = App.getInstance();
39
- const orgConfigRaw = app.node.tryGetContext("orgConfig");
40
- const orgConfig = parseOrgConfig(typeof orgConfigRaw === "string" ? orgConfigRaw : undefined);
41
- const providerAccounts = orgConfig.providerAccounts;
42
- // Determine if this is a compliance account
37
+ const config = getConfig();
38
+ const providerAccounts = config.providerAccounts;
43
39
  const account = providerAccounts.find((pa) => pa.id === props.accountId);
44
40
  const isComplianceAccount = account?.environment === "compliance";
45
- // Get DR configuration
46
- const disasterRecoveryRegion = orgConfig.disasterRecoveryRegion;
41
+ const disasterRecoveryRegion = config.disasterRecoveryRegion;
47
42
  // Look up compliance account for cross-account replication
48
43
  // Skip if the compliance account (prevent self-replication)
49
44
  const disasterRecoveryAccount = isComplianceAccount
@@ -110,7 +105,7 @@ export class DisasterRecovery extends Construct {
110
105
  // Create custom backup plans if provided
111
106
  if (props.customBackupPlans && props.customBackupPlans.length > 0) {
112
107
  this.customBackupPlans = props.customBackupPlans.map((config) => {
113
- return new BackupPlan(this, `CustomBackupPlan-${config.planName}`, {
108
+ return new BackupPlan(this, `CustomBackupPlan${toPascalCase(config.planName)}`, {
114
109
  planName: config.planName,
115
110
  rules: config.rules,
116
111
  tagValue: config.tagValue,
@@ -143,7 +138,7 @@ export class DisasterRecovery extends Construct {
143
138
  return [
144
139
  new BackupPlanRule({
145
140
  ruleName: `${planName}Daily`,
146
- scheduleExpression: events.Schedule.cron({ hour: "2", minute: "0" }), // 2 AM daily
141
+ scheduleExpression: cronSchedule({ hour: "2", minute: "0" }), // 2 AM daily
147
142
  deleteAfter: Duration.days(RETENTION_PERIODS.STANDARD),
148
143
  startWindow: BACKUP_WINDOWS.START,
149
144
  completionWindow: BACKUP_WINDOWS.COMPLETION
@@ -155,7 +150,7 @@ export class DisasterRecovery extends Construct {
155
150
  return [
156
151
  new BackupPlanRule({
157
152
  ruleName: `${planName}Daily`,
158
- scheduleExpression: events.Schedule.cron({ hour: "2", minute: "0" }), // 2 AM daily
153
+ scheduleExpression: cronSchedule({ hour: "2", minute: "0" }), // 2 AM daily
159
154
  deleteAfter: Duration.days(RETENTION_PERIODS.ENTERPRISE_CONTINUOUS),
160
155
  enableContinuousBackup: true,
161
156
  startWindow: BACKUP_WINDOWS.START,
@@ -171,7 +166,7 @@ export class DisasterRecovery extends Construct {
171
166
  // Continuous backup (35-day max PITR window)
172
167
  new BackupPlanRule({
173
168
  ruleName: `${planName}Continuous`,
174
- scheduleExpression: events.Schedule.cron({ hour: "2", minute: "0" }), // Daily for continuous backup
169
+ scheduleExpression: cronSchedule({ hour: "2", minute: "0" }), // Daily for continuous backup
175
170
  deleteAfter: Duration.days(RETENTION_PERIODS.ENTERPRISE_CONTINUOUS),
176
171
  enableContinuousBackup: true,
177
172
  startWindow: BACKUP_WINDOWS.START,
@@ -181,7 +176,7 @@ export class DisasterRecovery extends Construct {
181
176
  // Hourly snapshots for long-term compliance (7 years)
182
177
  new BackupPlanRule({
183
178
  ruleName: `${planName}HourlyCompliance`,
184
- scheduleExpression: events.Schedule.cron({ minute: "0" }), // Every hour
179
+ scheduleExpression: cronSchedule({ minute: "0" }), // Every hour
185
180
  deleteAfter: Duration.days(RETENTION_PERIODS.ENTERPRISE_COMPLIANCE),
186
181
  moveToColdStorageAfter: Duration.days(RETENTION_PERIODS.COLD_STORAGE_ONE_YEAR),
187
182
  startWindow: BACKUP_WINDOWS.START,
@@ -3,7 +3,6 @@ import { type StackProps } from "aws-cdk-lib";
3
3
  interface EcrDefaultImageProps extends StackProps {
4
4
  region: string;
5
5
  accountId: string;
6
- eventBusArn: string;
7
6
  }
8
7
  export declare class EcrDefaultImage extends Construct {
9
8
  constructor(scope: Construct, id: string, props: EcrDefaultImageProps);
@@ -5,8 +5,7 @@ import { LogGroup } from "../../resources/aws/logging/logGroup.js";
5
5
  import { RemovalPolicy } from "aws-cdk-lib";
6
6
  import { Role } from "../../resources/aws/iam/role.js";
7
7
  import { PolicyDocument, PolicyStatement, ServicePrincipal } from "aws-cdk-lib/aws-iam";
8
- import { EventBus, EventField, Rule, RuleTargetInput } from "aws-cdk-lib/aws-events";
9
- import * as Targets from "aws-cdk-lib/aws-events-targets";
8
+ import { EventBusMessaging, EventField } from "../../patterns/aws/messaging.js";
10
9
  export class EcrDefaultImage extends Construct {
11
10
  constructor(scope, id, props) {
12
11
  super(scope, id);
@@ -86,23 +85,10 @@ export class EcrDefaultImage extends Construct {
86
85
  },
87
86
  role: ecrDefaultImageRole
88
87
  });
89
- const eventInputMapping = {
90
- repositoryUri: EventField.fromPath("$.detail.responseElements.repository.repositoryUri")
91
- };
92
- const eventInputTemplate = {
93
- environmentVariablesOverride: [
94
- {
95
- name: "ECR_REPOSITORY",
96
- value: eventInputMapping.repositoryUri
97
- }
98
- ]
99
- };
100
- new Rule(this, `${id}EventRule`, {
101
- ruleName: "ecrCreationRule",
88
+ const awsServiceBus = EventBusMessaging.fromAwsServiceBus(this, `${id}EventBus`, props.region, props.accountId);
89
+ awsServiceBus.subscribe(`${id}EventRule`, {
102
90
  description: "Trigger the default ECR image build when a new repository is created",
103
- enabled: true,
104
- eventBus: EventBus.fromEventBusArn(this, `${id}EventBus`, props.eventBusArn),
105
- eventPattern: {
91
+ pattern: {
106
92
  source: ["aws.ecr"],
107
93
  detailType: ["AWS API Call via CloudTrail"],
108
94
  detail: {
@@ -110,11 +96,15 @@ export class EcrDefaultImage extends Construct {
110
96
  eventName: ["CreateRepository"]
111
97
  }
112
98
  },
113
- targets: [
114
- new Targets.CodeBuildProject(codeBuildProject.project, {
115
- event: RuleTargetInput.fromObject(eventInputTemplate)
116
- })
117
- ]
99
+ target: codeBuildProject,
100
+ payload: {
101
+ environmentVariablesOverride: [
102
+ {
103
+ name: "ECR_REPOSITORY",
104
+ value: EventField.fromPath("$.detail.responseElements.repository.repositoryUri")
105
+ }
106
+ ]
107
+ }
118
108
  });
119
109
  }
120
110
  }
@@ -6,16 +6,23 @@ interface IdentityCenterProps extends NestedStackProps {
6
6
  tags?: KeyValue[];
7
7
  }
8
8
  export interface PermissionSetConfig {
9
- Policy: string;
10
- Description?: string;
9
+ managedPolicies: string[];
10
+ description?: string;
11
+ sessionDuration?: string;
11
12
  }
13
+ export type CustomPermissionSets = Record<string, PermissionSetConfig>;
12
14
  export declare class IdentityCenter extends NestedStack {
13
15
  identityStoreId: string;
14
16
  identityCenterArn: string;
15
17
  private listInstancesRole;
18
+ private accountsConfig;
19
+ private customTags?;
20
+ private groupIds;
16
21
  constructor(scope: Construct, id: string, props: IdentityCenterProps);
22
+ declarePermissionSets(customs: CustomPermissionSets): void;
23
+ assignGroupMembers(members: Record<string, string[]>): void;
17
24
  private createListInstancesRole;
18
25
  private listIdentityCenterInstance;
19
- private createPermissionSets;
26
+ private createPermissionSetAndAssignments;
20
27
  }
21
28
  export {};