@fjall/components-infrastructure 9.0.0 → 10.1.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 (36) hide show
  1. package/dist/lib/patterns/aws/compute.js +13 -1
  2. package/dist/lib/patterns/aws/computeEcs.d.ts +80 -1
  3. package/dist/lib/patterns/aws/computeEcs.js +450 -70
  4. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +113 -6
  5. package/dist/lib/patterns/aws/computeEcsTypes.js +19 -0
  6. package/dist/lib/patterns/aws/computePropApplicability.js +1 -0
  7. package/dist/lib/patterns/aws/database.d.ts +12 -1
  8. package/dist/lib/patterns/aws/database.js +16 -0
  9. package/dist/lib/patterns/aws/devSubstrate.js +64 -8
  10. package/dist/lib/patterns/aws/interfaces/database.d.ts +26 -0
  11. package/dist/lib/patterns/aws/storage.d.ts +7 -0
  12. package/dist/lib/patterns/aws/storage.js +14 -1
  13. package/dist/lib/resources/aws/compute/ecs.d.ts +12 -0
  14. package/dist/lib/resources/aws/compute/ecs.js +32 -2
  15. package/dist/lib/resources/aws/compute/ecsImages.js +4 -0
  16. package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +29 -3
  17. package/dist/lib/resources/aws/compute/ecsServiceFactory.js +32 -0
  18. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +3 -0
  19. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +42 -2
  20. package/dist/lib/resources/aws/compute/ecsValidation.d.ts +6 -0
  21. package/dist/lib/resources/aws/compute/ecsValidation.js +13 -0
  22. package/dist/lib/resources/aws/database/rdsAurora.d.ts +7 -1
  23. package/dist/lib/resources/aws/database/rdsAurora.js +1 -1
  24. package/dist/lib/resources/aws/messaging/eventTargets.d.ts +4 -2
  25. package/dist/lib/resources/aws/messaging/eventTargets.js +55 -2
  26. package/dist/lib/resources/aws/monitoring/alarmDefaults.d.ts +1 -0
  27. package/dist/lib/resources/aws/monitoring/alarmDefaults.js +1 -1
  28. package/dist/lib/resources/aws/monitoring/ecsTaskStopWatchdog.d.ts +59 -0
  29. package/dist/lib/resources/aws/monitoring/ecsTaskStopWatchdog.js +115 -0
  30. package/dist/lib/resources/aws/monitoring/index.d.ts +1 -0
  31. package/dist/lib/resources/aws/monitoring/index.js +1 -0
  32. package/dist/lib/resources/aws/monitoring/metricNamespaces.d.ts +1 -0
  33. package/dist/lib/resources/aws/monitoring/metricNamespaces.js +1 -0
  34. package/dist/lib/utils/manifestWriter.d.ts +16 -2
  35. package/dist/lib/utils/manifestWriter.js +22 -0
  36. package/package.json +4 -3
@@ -173,6 +173,10 @@ export class ComputeFactory {
173
173
  const collector = app.getManifestCollector();
174
174
  const clusterName = id;
175
175
  const appName = computeProps.appName ?? app.getName();
176
+ // Buffered until after construction: only the EcsCompute ctor knows
177
+ // whether each service materialised the schema-gate container (the
178
+ // eligibility resolution needs the connected database constructs).
179
+ const pendingManifestServices = [];
176
180
  for (const service of computeProps.services) {
177
181
  // Promote public-prefixed declared-env vars into docker.buildArgs
178
182
  // (with their values) BEFORE the manifest copy and before the
@@ -220,9 +224,17 @@ export class ComputeFactory {
220
224
  cluster: clusterName,
221
225
  service: service.name
222
226
  });
227
+ pendingManifestServices.push(manifestService);
228
+ }
229
+ const ecsCompute = new EcsCompute(scope, id, computeProps);
230
+ for (const manifestService of pendingManifestServices) {
231
+ const gateTag = ecsCompute.schemaGateImageTags.get(manifestService.name);
232
+ if (gateTag !== undefined) {
233
+ manifestService.schemaGateImageTag = gateTag;
234
+ }
223
235
  collector.addService(manifestService);
224
236
  }
225
- return new EcsCompute(scope, id, computeProps);
237
+ return ecsCompute;
226
238
  }
227
239
  case "lambda": {
228
240
  // Add appName to props for Lambda (needed for secrets path derivation)
@@ -16,6 +16,24 @@ export declare function getEcsCapacityProviderConfig(provider: EcsCapacityProvid
16
16
  * Extracted for clarity and detail parity with database/network patterns.
17
17
  */
18
18
  export declare function validateEcsProps(props: EcsComputeProps): void;
19
+ /**
20
+ * Resolved inputs for the synthetic `fjall-schema-gate` container. Produced by
21
+ * `EcsCompute.resolveSchemaGateMaterialisation`, consumed by
22
+ * `buildContainerConfigs` (topology wiring).
23
+ * @internal Exported for testing only
24
+ */
25
+ export interface SchemaGateContainerSpec {
26
+ environment: Record<string, string>;
27
+ secretsImport: Record<string, SecretImport>;
28
+ image: string;
29
+ /**
30
+ * The exact package semver used to tag the DEFAULT gate image, absent when
31
+ * the author brought their own via `schemaGate.image`. Surfaced through
32
+ * `EcsCompute.schemaGateImageTags` into the fjall manifest so deploy-core's
33
+ * `ensureSchemaGateImage` knows which tag to mirror pre-deploy.
34
+ */
35
+ defaultImageTag?: string;
36
+ }
19
37
  /**
20
38
  * Expand a service's `migrations` sugar into a synthetic init container plus
21
39
  * auto-injected `dependsOn` entries on every other container.
@@ -47,12 +65,17 @@ export declare function expandMigrationsSugar(service: EcsServiceConfig, userCon
47
65
  * @param annotationsScope Construct used as the source for synth-time
48
66
  * warnings when the author has set `EXPECTED_SCHEMA_VERSION`
49
67
  * themselves and the resolved value differs.
68
+ * @param schemaGate Resolved spec for the synthetic `fjall-schema-gate`
69
+ * container, or `undefined` when materialisation is off
70
+ * (opted out, ineligible, or nothing to gate). When set,
71
+ * the gate container is prepended and every non-migrate
72
+ * container gains a `dependsOn` SUCCESS edge on it.
50
73
  * @internal Exported for testing only
51
74
  */
52
75
  export declare function buildContainerConfigs(service: EcsServiceConfig, schemaVersionEnv?: Record<string, string>, annotationsScope?: Construct, chGate?: {
53
76
  environment: Record<string, string>;
54
77
  secretsImport: Record<string, SecretImport>;
55
- }): EcsClusterProps["services"][number]["containers"];
78
+ }, schemaGate?: SchemaGateContainerSpec): EcsClusterProps["services"][number]["containers"];
56
79
  /**
57
80
  * Resolved scaling configuration for an ECS service.
58
81
  * @internal Exported for testing only
@@ -80,6 +103,15 @@ export declare class EcsCompute extends Construct implements IEcsCompute {
80
103
  private readonly clusterId;
81
104
  private readonly appName;
82
105
  private readonly migrationTaskDefinitions;
106
+ /**
107
+ * Service name → exact `@fjall/schema-gate` semver, for every service that
108
+ * materialised the gate container with the DEFAULT image this synth.
109
+ * ComputeFactory copies it onto the manifest entry (`schemaGateImageTag`)
110
+ * so deploy-core's `ensureSchemaGateImage` mirrors the tag pre-deploy.
111
+ * BYO-image services (`schemaGate.image`) are deliberately absent — the
112
+ * author owns that image's availability.
113
+ */
114
+ readonly schemaGateImageTags: ReadonlyMap<string, string>;
83
115
  constructor(scope: Construct, id: string, props: EcsComputeProps);
84
116
  /**
85
117
  * Walks a service's `connections:` for a relational database carrying a
@@ -113,8 +145,55 @@ export declare class EcsCompute extends Construct implements IEcsCompute {
113
145
  * - Two or more migrated CHs → throws via `resolveClickHouseDatabaseForService`
114
146
  */
115
147
  private resolveClickHouseSchemaVersionEnv;
148
+ /**
149
+ * Decide whether the synthetic `fjall-schema-gate` container materialises
150
+ * for this service, and compose its env/secrets/image when it does.
151
+ * Returns `undefined` (env-injection-only, the pre-10.x behaviour) when:
152
+ *
153
+ * - `schemaGate: false` or `{ materialise: false }` (author opt-out)
154
+ * - Neither a PG nor a CH gate resolved for the service
155
+ * - `migrations.mode: "post-deploy"` — expected is deliberately ahead of
156
+ * the DB during scale-up, so a materialised gate would refuse every task
157
+ * (synth warning)
158
+ * - `migrations.mode: "lifecycle-hook"` WITHOUT `separateTaskDef` — the
159
+ * hook's migration RunTask reuses the service task definition, so a
160
+ * materialised gate would refuse the migration task itself while the DB
161
+ * still holds the pre-migration schema (synth warning; adding
162
+ * `separateTaskDef` restores full gating)
163
+ * - No eligible half survives the v1 scope filters: the relational half
164
+ * requires `tool: "prisma"` and a postgres-family connection scheme
165
+ * (per-half synth warnings; env injection into app containers stays on)
166
+ * - The default image URI cannot be derived because the constructs package
167
+ * version is unresolvable and no `schemaGate.image` override is set
168
+ *
169
+ * The relational half re-resolves the migrated DB for its
170
+ * `getSchemaGateContribution()` (credential-free URL base + user/password
171
+ * secret imports). The CH half composes `CLICKHOUSE_URL` / database name /
172
+ * CA-cert import from the resolved CH database — `chGate` alone carries
173
+ * only the version + schema-admin entries the app containers get.
174
+ */
175
+ private resolveSchemaGateMaterialisation;
116
176
  private materialiseScheduledTasks;
117
177
  private buildScheduledTaskDefinition;
178
+ /**
179
+ * Compose a scheduled task's container env and secrets: schema-version gate
180
+ * env resolved from the entry's `connections` merges beneath the author's
181
+ * `environment` (author wins — the same semantics as service containers),
182
+ * and the ClickHouse gate's credential imports merge beneath the author's
183
+ * `secrets`. Returns `undefined` halves when nothing applies so the
184
+ * container definition stays byte-identical for unconnected entries.
185
+ */
186
+ private composeScheduledTaskEnvAndSecrets;
187
+ /**
188
+ * A sibling service that consumes a hook-migrated database materialises a
189
+ * schema gate that refuses while the owner's migration is still in flight.
190
+ * Without `awaitMigrationsFrom` the sibling rolls out in parallel with the
191
+ * owner, so its gate-refused task churn can trip the deployment circuit
192
+ * breaker before the migration lands. The gate refusing is by design (new
193
+ * code must not serve the old schema); the missing DependsOn is the
194
+ * author-fixable part — warn, don't disable.
195
+ */
196
+ private warnUngatedSiblingsOfHookOwners;
118
197
  /**
119
198
  * For each service whose `migrations.mode` is a lambda-hook variant
120
199
  * (`"lifecycle-hook"` for PRE_SCALE_UP, `"post-deploy"` for POST_SCALE_UP),