@fjall/components-infrastructure 14.0.0 → 14.2.0

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.
@@ -6,9 +6,50 @@ import { type ICachePolicy, type IResponseHeadersPolicy } from "aws-cdk-lib/aws-
6
6
  import type App from "../../app.js";
7
7
  import { CloudFrontDistribution, type CachePolicyPreset, type AccessGateConfig } from "../../resources/aws/cdn/index.js";
8
8
  import { type ICdn } from "./interfaces/cdn.js";
9
- import type { StaticSiteRouting } from "@fjall/util";
9
+ import { type StaticSiteRouting } from "@fjall/util";
10
+ import { type ManagedDomainBinding, type ManagedDomainExports } from "../../utils/domainTypes.js";
10
11
  import { type Storage } from "./storage.js";
11
12
  import { type AnyCompute } from "./compute.js";
13
+ /**
14
+ * Managed-domain surface for a CDN — the distribution's counterpart to the
15
+ * ECS cluster's `domainConfig` (design 2026-08-17 cdn-domain-ownership C1).
16
+ * The CDN resolves its zone and us-east-1 viewer certificate exactly like
17
+ * the staticSite/payload patterns (explicit `managedDomain` beats the
18
+ * CLI-injected binding, which beats BYO `zoneName`/`hostedZoneId`), derives
19
+ * `domainNames` from `domainName`, and — unless `record: "none"` — owns the
20
+ * alias record for it in the CDN stack, satellite-style.
21
+ */
22
+ export interface CdnDomainConfig {
23
+ /** Public hostname the distribution serves, e.g. the zone apex. */
24
+ domainName: string;
25
+ /**
26
+ * "alias" (default) mints the Route53 alias record in the CDN stack.
27
+ * "none" claims the alternate domain name + certificate WITHOUT the DNS
28
+ * record — the pre-flip validation state: the distribution answers for
29
+ * `domainName` (testable via `curl --resolve`) while live DNS still points
30
+ * elsewhere.
31
+ */
32
+ record?: "alias" | "none";
33
+ /**
34
+ * Routing policy for the alias record. Use latency with a region label
35
+ * DIFFERENT from an existing compute-owned variant on the same name —
36
+ * Route53 allows one latency record per region, and sibling variants are
37
+ * exactly how an apex migrates between owners with no delete window (the
38
+ * claim registry enforces the legal shapes).
39
+ */
40
+ routingPolicy?: {
41
+ type: "latency";
42
+ region: string;
43
+ };
44
+ /** Defaults to `${id}${region}` when `routingPolicy` is set — the same
45
+ * derivation convention as the ECS cluster's apex record. */
46
+ setIdentifier?: string;
47
+ /** Explicit managed-domain identity — beats the CLI-injected binding. */
48
+ managedDomain?: ManagedDomainExports | ManagedDomainBinding;
49
+ /** BYO zone identity (with `hostedZoneId` to skip the runtime lookup). */
50
+ zoneName?: string;
51
+ hostedZoneId?: string;
52
+ }
12
53
  /**
13
54
  * Common CDN props shared across all origin types.
14
55
  */
@@ -19,6 +60,20 @@ interface BaseCdnProps {
19
60
  * is only set by hand for a directly-instantiated `Cdn`.
20
61
  */
21
62
  appName?: string;
63
+ /**
64
+ * Managed-domain surface: resolve the zone + us-east-1 viewer certificate
65
+ * through the domain helpers and own the domain's alias record in the CDN
66
+ * stack. Mutually exclusive with the literal
67
+ * `domainNames`/`certificate`/`certificateArn` surface, and requires the
68
+ * factory path (`app.addCdn(CdnFactory.build(...))`) so the `App` is known.
69
+ */
70
+ domainConfig?: CdnDomainConfig;
71
+ /**
72
+ * App instance backing `domainConfig` resolution (certificate placement,
73
+ * zone lookups). `CdnFactory.build` fills it — only set by hand for a
74
+ * directly-instantiated `Cdn`.
75
+ */
76
+ app?: App;
22
77
  cachePolicy?: CachePolicyPreset | ICachePolicy;
23
78
  defaultAllowedMethods?: "GET_HEAD" | "GET_HEAD_OPTIONS" | "ALL";
24
79
  behaviours?: SmartCdnBehaviour[];
@@ -75,11 +130,36 @@ export interface HttpCdnProps extends BaseCdnProps {
75
130
  protocolPolicy?: "HTTP_ONLY" | "HTTPS_ONLY" | "MATCH_VIEWER";
76
131
  }
77
132
  /**
78
- * Smart origin CDN props - auto-detect origin type from Fjall resource
133
+ * Smart origin CDN props - auto-detect origin type from Fjall resource.
134
+ *
135
+ * ECS compute origins (design 2026-08-18 cdn-app-origin, D3) resolve a
136
+ * TLS-valid ORIGIN HOSTNAME from the compute's own ingress profile instead
137
+ * of the raw ELB hostname (which no ACM certificate ever covers): a routing
138
+ * host when the compute declares exactly one, else `origin.<domain>`,
139
+ * derived. Certificate coverage and listener forwarding are validated at
140
+ * synth; when the Cdn owns the hostname it mints the alias record in this
141
+ * stack, record-before-distribution ordered.
79
142
  */
80
143
  export interface SmartCdnProps extends BaseCdnProps {
81
144
  originType: "auto";
82
145
  origin: Storage | AnyCompute | string;
146
+ /**
147
+ * Origin hostname override for the DEFAULT origin's ECS compute (a
148
+ * behaviour's ECS origin takes the same override on the behaviour
149
+ * entry). A literal hostname: a compute-declared routing host (the
150
+ * compute keeps owning its record), or a free name inside the cluster's
151
+ * zone (the Cdn mints its record). Refused for `redirectHosts` entries —
152
+ * they 301, never serve. Default: auto-resolution (sole routing host,
153
+ * else `origin.<domain>`).
154
+ */
155
+ originHostname?: string;
156
+ /**
157
+ * Whether the Cdn mints the origin alias record when it owns the DEFAULT
158
+ * origin's hostname (behaviour entries carry their own). "none" = the
159
+ * record is managed elsewhere (BYO or a migration state). Refused when
160
+ * the hostname is a routing host — the compute owns that record (P1).
161
+ */
162
+ originRecord?: "alias" | "none";
83
163
  }
84
164
  export type ICdnProps = S3CdnProps | AlbCdnProps | HttpCdnProps | SmartCdnProps;
85
165
  /**
@@ -91,12 +171,59 @@ export interface SmartCdnBehaviour {
91
171
  origin: Storage | AnyCompute | string;
92
172
  cachePolicy?: CachePolicyPreset | ICachePolicy;
93
173
  allowedMethods?: "GET_HEAD" | "GET_HEAD_OPTIONS" | "ALL";
174
+ /**
175
+ * Origin hostname override for THIS behaviour's ECS compute origin — the
176
+ * behaviour-level counterpart of the distribution's `originHostname`
177
+ * (same semantics; see {@link SmartCdnProps.originHostname}). Overrides
178
+ * bind per compute: two entries naming the same compute must agree.
179
+ */
180
+ originHostname?: string;
181
+ /**
182
+ * Record-minting override for THIS behaviour's ECS compute origin — the
183
+ * behaviour-level counterpart of {@link SmartCdnProps.originRecord}.
184
+ */
185
+ originRecord?: "alias" | "none";
94
186
  }
95
187
  /**
96
188
  * CDN wrapper class that extends CloudFrontDistribution with Fjall patterns.
97
189
  */
98
190
  export declare class Cdn extends CloudFrontDistribution implements ICdn {
99
191
  constructor(scope: Construct, id: string, props: ICdnProps);
192
+ private static createEcsOriginResolver;
193
+ /**
194
+ * Assemble the per-compute `originHostname`/`originRecord` overrides the
195
+ * resolver binds by compute identity: the distribution-level props apply
196
+ * to the DEFAULT origin's compute, each behaviour's own overrides apply
197
+ * to that behaviour's compute. Two entries naming the same compute must
198
+ * agree — one alias record cannot carry two spellings.
199
+ */
200
+ private static collectEcsOriginOverrides;
201
+ /**
202
+ * Mint the Cdn-owned origin alias records (P1) after the distribution
203
+ * exists, using the compute profile's own zone instance so the DNS claim
204
+ * registry sees the same zone identity as the cluster's records. The
205
+ * distribution depends on each record: the hostname must resolve before a
206
+ * distribution update referencing it propagates.
207
+ */
208
+ private createOriginRecords;
209
+ /**
210
+ * Resolve a `domainConfig` through the shared pattern-domain helpers
211
+ * (design C1): zone identity via `resolvePatternZone` (explicit
212
+ * `managedDomain` → CLI-injected binding → BYO `zoneName`/`hostedZoneId`),
213
+ * viewer certificate via `resolvePatternCloudFrontCertificate` (binding's
214
+ * literal us-east-1 ARN, else app-owned provisioning). The exact resolution
215
+ * chain staticSite and payload already use — the CDN stops being the one
216
+ * CloudFront-fronted pattern without it.
217
+ */
218
+ private static resolveDomain;
219
+ /**
220
+ * Own the domain's DNS record in the CDN stack (satellite doctrine — the
221
+ * app owns its records, the domain stack owns zone-level records), exactly
222
+ * as the ECS cluster owns its apex alias. Latency routing gets the
223
+ * cluster's setIdentifier derivation (`${id}${region}`) unless overridden;
224
+ * `record: "none"` skips this entirely (pre-flip validation state).
225
+ */
226
+ private createDomainRecord;
100
227
  /**
101
228
  * Resolve ICdnProps to CloudFrontDistributionProps.
102
229
  */
@@ -148,6 +275,20 @@ export declare class Cdn extends CloudFrontDistribution implements ICdn {
148
275
  * domainNames: ["app.example.com"],
149
276
  * certificate: myCert
150
277
  * }));
278
+ *
279
+ * @example
280
+ * // Managed domain — the CDN resolves the zone + us-east-1 certificate and
281
+ * // owns the alias record in its own stack (satellite doctrine), like the
282
+ * // ECS cluster's domainConfig.
283
+ * app.addCdn(CdnFactory.build("AppCdn", {
284
+ * originType: "http",
285
+ * domainName: "origin.example.com",
286
+ * forwardHostHeader: true,
287
+ * domainConfig: {
288
+ * domainName: "example.com",
289
+ * routingPolicy: { type: "latency", region: "us-east-1" }
290
+ * }
291
+ * }));
151
292
  */
152
293
  export declare class CdnFactory {
153
294
  /**