@fjall/components-infrastructure 2.33.0 → 3.0.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.
- package/dist/lib/app.d.ts +19 -2
- package/dist/lib/app.js +61 -4
- package/dist/lib/patterns/aws/account.js +6 -1
- package/dist/lib/patterns/aws/apexDomainPattern.d.ts +11 -12
- package/dist/lib/patterns/aws/apexDomainPattern.js +11 -31
- package/dist/lib/patterns/aws/cdn.js +25 -10
- package/dist/lib/patterns/aws/computeEcs.js +15 -6
- package/dist/lib/patterns/aws/computeEcsTypes.d.ts +13 -4
- package/dist/lib/patterns/aws/delegatedDomainPattern.d.ts +13 -4
- package/dist/lib/patterns/aws/delegatedDomainPattern.js +57 -8
- package/dist/lib/patterns/aws/devSubstrate.d.ts +2 -1
- package/dist/lib/patterns/aws/devSubstrate.js +18 -8
- package/dist/lib/patterns/aws/dnsRecordComposer.d.ts +2 -9
- package/dist/lib/patterns/aws/dnsRecordComposer.js +5 -97
- package/dist/lib/patterns/aws/domain.d.ts +3 -2
- package/dist/lib/patterns/aws/domain.js +3 -2
- package/dist/lib/patterns/aws/domainValidation.js +71 -46
- package/dist/lib/patterns/aws/externalRecordsPattern.js +2 -11
- package/dist/lib/patterns/aws/index.d.ts +1 -3
- package/dist/lib/patterns/aws/index.js +2 -3
- package/dist/lib/patterns/aws/interfaces/domain.d.ts +22 -8
- package/dist/lib/patterns/aws/interfaces/index.d.ts +0 -1
- package/dist/lib/patterns/aws/interfaces/index.js +3 -0
- package/dist/lib/patterns/aws/interfaces/pattern.d.ts +55 -10
- package/dist/lib/patterns/aws/patternDomain.d.ts +77 -0
- package/dist/lib/patterns/aws/patternDomain.js +198 -0
- package/dist/lib/patterns/aws/payload.js +23 -30
- package/dist/lib/patterns/aws/staticSite.d.ts +1 -0
- package/dist/lib/patterns/aws/staticSite.js +28 -33
- package/dist/lib/resources/aws/base/awsStack.d.ts +8 -0
- package/dist/lib/resources/aws/base/awsStack.js +20 -17
- package/dist/lib/resources/aws/compute/ecs.d.ts +1 -1
- package/dist/lib/resources/aws/compute/ecs.js +1 -1
- package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +1 -1
- package/dist/lib/resources/aws/compute/ecsNetworking.js +212 -47
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +4 -4
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +60 -9
- package/dist/lib/resources/aws/compute/ecsValidation.d.ts +14 -1
- package/dist/lib/resources/aws/compute/ecsValidation.js +51 -0
- package/dist/lib/resources/aws/logging/logGroup.d.ts +6 -0
- package/dist/lib/resources/aws/logging/logGroup.js +11 -1
- package/dist/lib/resources/aws/networking/dnsRecord/aRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/aaaaRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.d.ts +23 -1
- package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.js +14 -3
- package/dist/lib/resources/aws/networking/dnsRecord/caaRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/cnameRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.d.ts +10 -1
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +21 -4
- package/dist/lib/resources/aws/networking/dnsRecord/mxRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/nsRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/srvRecord.js +3 -2
- package/dist/lib/resources/aws/networking/dnsRecord/txtRecord.js +3 -2
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +28 -4
- package/dist/lib/resources/aws/networking/domainCertificate.js +24 -10
- package/dist/lib/resources/aws/networking/hostedZone.d.ts +11 -0
- package/dist/lib/resources/aws/networking/hostedZone.js +6 -0
- package/dist/lib/utils/costAllocationTags.d.ts +9 -0
- package/dist/lib/utils/costAllocationTags.js +6 -1
- package/dist/lib/utils/dnsRecordRegistry.d.ts +52 -0
- package/dist/lib/utils/dnsRecordRegistry.js +64 -0
- package/dist/lib/utils/domainTypes.d.ts +43 -36
- package/dist/lib/utils/domainTypes.js +65 -2
- package/dist/lib/utils/managedDomainContext.d.ts +37 -0
- package/dist/lib/utils/managedDomainContext.js +111 -0
- package/package.json +4 -4
|
@@ -1,2 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import { DNS_APEX } from "@fjall/util";
|
|
2
|
+
export { DNS_APEX, getDomainExportNames, isManagedDomainBinding } from "@fjall/util";
|
|
3
|
+
/**
|
|
4
|
+
* Dot-boundary suffix matching. Rejects pathological cases where a user-supplied
|
|
5
|
+
* zone appears as a suffix of another zone (e.g. 'evilexample.com' against
|
|
6
|
+
* zone 'example.com' — `endsWith('example.com')` returns true without the
|
|
7
|
+
* leading dot). Shared by the patterns-layer domain validation and the
|
|
8
|
+
* resources-layer ECS networking (lowest common layer per generator-standards
|
|
9
|
+
* § Infrastructure Layer Boundaries).
|
|
10
|
+
*/
|
|
11
|
+
export function isWithinZone(candidate, zoneName) {
|
|
12
|
+
if (candidate === zoneName) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return candidate.endsWith(`.${zoneName}`);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Canonical BIND-semantics resolver for DNS record names — the single
|
|
19
|
+
* authority shared by the patterns-layer domain validation and the
|
|
20
|
+
* resources-layer dnsRecord family (lowest common layer per
|
|
21
|
+
* generator-standards § Infrastructure Layer Boundaries). Contract:
|
|
22
|
+
*
|
|
23
|
+
* - `'@'` — the zone apex; resolves to the zone name.
|
|
24
|
+
* - Trailing dot — an absolute FQDN; must equal the zone or end with
|
|
25
|
+
* `.<zone>.`, otherwise the name belongs to another zone and is rejected.
|
|
26
|
+
* The conventional trailing dot is shed on return because CloudFormation
|
|
27
|
+
* RecordSet names carry none at this layer (CDK re-appends it).
|
|
28
|
+
* - No trailing dot — relative to the zone regardless of label count
|
|
29
|
+
* (`www` and `s1._domainkey` alike); the zone is appended exactly once.
|
|
30
|
+
* - A dotless name that already ends with the bare zone is ambiguous between
|
|
31
|
+
* the relative and absolute readings and is rejected, naming both honest
|
|
32
|
+
* spellings.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveRecordFqdn(recordName, zoneName) {
|
|
35
|
+
if (recordName === DNS_APEX) {
|
|
36
|
+
return zoneName;
|
|
37
|
+
}
|
|
38
|
+
if (recordName.endsWith(".")) {
|
|
39
|
+
const absolute = recordName.slice(0, -1);
|
|
40
|
+
if (absolute !== zoneName && !absolute.endsWith(`.${zoneName}`)) {
|
|
41
|
+
throw new Error(`DNS record name '${recordName}' is absolute (trailing dot) but ` +
|
|
42
|
+
`lies outside zone '${zoneName}'. Cure: an absolute name must be ` +
|
|
43
|
+
`'${zoneName}.' or end with '.${zoneName}.'; records for another ` +
|
|
44
|
+
`zone belong on that zone's own Domain construct.`);
|
|
45
|
+
}
|
|
46
|
+
return absolute;
|
|
47
|
+
}
|
|
48
|
+
if (recordName === zoneName || recordName.endsWith(`.${zoneName}`)) {
|
|
49
|
+
const relativeSpelling = recordName === zoneName
|
|
50
|
+
? DNS_APEX
|
|
51
|
+
: recordName.slice(0, -(zoneName.length + 1));
|
|
52
|
+
throw new Error(`DNS record name '${recordName}' ends with zone '${zoneName}' but has ` +
|
|
53
|
+
`no trailing dot, so it is ambiguous between relative ` +
|
|
54
|
+
`('${recordName}.${zoneName}') and absolute ('${recordName}'). ` +
|
|
55
|
+
`Cure: spell it '${relativeSpelling}' (relative to the zone) or ` +
|
|
56
|
+
`'${recordName}.' (absolute).`);
|
|
57
|
+
}
|
|
58
|
+
return `${recordName}.${zoneName}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Default deploy phase when `phase` is omitted — the complete build. The
|
|
62
|
+
* two-step guard (R2) sets `"zone"` explicitly for step 1, so the safe
|
|
63
|
+
* default for a single-shot deploy is everything.
|
|
64
|
+
*/
|
|
65
|
+
export const DOMAIN_DEPLOY_DEFAULT_PHASE = "full";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDK-context channel for CLI-injected managed-domain bindings (design
|
|
3
|
+
* 2026-07-17 domain-management gold-plating, D2 — resolution by injection).
|
|
4
|
+
*
|
|
5
|
+
* At deploy time the Fjall CLI resolves each app-consumed domain against the
|
|
6
|
+
* declared `fjall/domains/` components (DescribeStacks on the domain stack)
|
|
7
|
+
* and injects one context entry per zone:
|
|
8
|
+
*
|
|
9
|
+
* -c fjall:managedDomain:<zoneName>=<JSON ManagedDomainBinding>
|
|
10
|
+
*
|
|
11
|
+
* (emitter: deploy-core `CdkArgumentBuilder.buildContextArgs` — keep the
|
|
12
|
+
* prefix literal in sync). Constructs read the entry ahead of their BYO
|
|
13
|
+
* `zoneName`/`hostedZone` props; an EXPLICIT `managedDomain` prop still wins
|
|
14
|
+
* over the injected value. Bare-CDK synth simply lacks the context and falls
|
|
15
|
+
* back to explicit props.
|
|
16
|
+
*
|
|
17
|
+
* Utils layer on purpose: consumed by both the resources layer
|
|
18
|
+
* (`ecsNetworking.addHostedZone`) and the patterns layer
|
|
19
|
+
* (`patternDomain.resolvePatternZone`), and utils is their lowest common
|
|
20
|
+
* layer (generator-standards § Infrastructure Layer Boundaries).
|
|
21
|
+
*/
|
|
22
|
+
import type { Node } from "constructs";
|
|
23
|
+
import type { ManagedDomainBinding } from "@fjall/util";
|
|
24
|
+
export declare const MANAGED_DOMAIN_CONTEXT_PREFIX: "fjall:managedDomain:";
|
|
25
|
+
export declare function getManagedDomainContextKey(zoneName: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Read the CLI-injected {@link ManagedDomainBinding} for `domainName`,
|
|
28
|
+
* walking exact → parent zones (mirroring the CLI's
|
|
29
|
+
* `DomainService.matchManagedDomain` semantics: `app.example.com` matches a
|
|
30
|
+
* binding injected for `example.com`). Returns undefined when no entry is
|
|
31
|
+
* present (bare-CDK synth); throws a context-prefixed, value-echoing,
|
|
32
|
+
* cure-naming error when an entry exists but is malformed — a corrupt
|
|
33
|
+
* binding must fail the synth, never fall through to a guessed zone.
|
|
34
|
+
*
|
|
35
|
+
* `context` prefixes every error, e.g. `Static site 'marketing'`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function readInjectedManagedDomainBinding(node: Node, domainName: string, context: string): ManagedDomainBinding | undefined;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDK-context channel for CLI-injected managed-domain bindings (design
|
|
3
|
+
* 2026-07-17 domain-management gold-plating, D2 — resolution by injection).
|
|
4
|
+
*
|
|
5
|
+
* At deploy time the Fjall CLI resolves each app-consumed domain against the
|
|
6
|
+
* declared `fjall/domains/` components (DescribeStacks on the domain stack)
|
|
7
|
+
* and injects one context entry per zone:
|
|
8
|
+
*
|
|
9
|
+
* -c fjall:managedDomain:<zoneName>=<JSON ManagedDomainBinding>
|
|
10
|
+
*
|
|
11
|
+
* (emitter: deploy-core `CdkArgumentBuilder.buildContextArgs` — keep the
|
|
12
|
+
* prefix literal in sync). Constructs read the entry ahead of their BYO
|
|
13
|
+
* `zoneName`/`hostedZone` props; an EXPLICIT `managedDomain` prop still wins
|
|
14
|
+
* over the injected value. Bare-CDK synth simply lacks the context and falls
|
|
15
|
+
* back to explicit props.
|
|
16
|
+
*
|
|
17
|
+
* Utils layer on purpose: consumed by both the resources layer
|
|
18
|
+
* (`ecsNetworking.addHostedZone`) and the patterns layer
|
|
19
|
+
* (`patternDomain.resolvePatternZone`), and utils is their lowest common
|
|
20
|
+
* layer (generator-standards § Infrastructure Layer Boundaries).
|
|
21
|
+
*/
|
|
22
|
+
export const MANAGED_DOMAIN_CONTEXT_PREFIX = "fjall:managedDomain:";
|
|
23
|
+
export function getManagedDomainContextKey(zoneName) {
|
|
24
|
+
return `${MANAGED_DOMAIN_CONTEXT_PREFIX}${zoneName}`;
|
|
25
|
+
}
|
|
26
|
+
const REQUIRED_STRING_FIELDS = ["zoneName", "hostedZoneId"];
|
|
27
|
+
const OPTIONAL_STRING_FIELDS = [
|
|
28
|
+
"certificateArn",
|
|
29
|
+
"usEast1CertificateArn",
|
|
30
|
+
"delegationRoleArn"
|
|
31
|
+
];
|
|
32
|
+
const KNOWN_FIELDS = [
|
|
33
|
+
...REQUIRED_STRING_FIELDS,
|
|
34
|
+
...OPTIONAL_STRING_FIELDS
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Read the CLI-injected {@link ManagedDomainBinding} for `domainName`,
|
|
38
|
+
* walking exact → parent zones (mirroring the CLI's
|
|
39
|
+
* `DomainService.matchManagedDomain` semantics: `app.example.com` matches a
|
|
40
|
+
* binding injected for `example.com`). Returns undefined when no entry is
|
|
41
|
+
* present (bare-CDK synth); throws a context-prefixed, value-echoing,
|
|
42
|
+
* cure-naming error when an entry exists but is malformed — a corrupt
|
|
43
|
+
* binding must fail the synth, never fall through to a guessed zone.
|
|
44
|
+
*
|
|
45
|
+
* `context` prefixes every error, e.g. `Static site 'marketing'`.
|
|
46
|
+
*/
|
|
47
|
+
export function readInjectedManagedDomainBinding(node, domainName, context) {
|
|
48
|
+
const labels = domainName.split(".");
|
|
49
|
+
for (let i = 0; i < labels.length; i++) {
|
|
50
|
+
const candidate = labels.slice(i).join(".");
|
|
51
|
+
const key = getManagedDomainContextKey(candidate);
|
|
52
|
+
const raw = node.tryGetContext(key);
|
|
53
|
+
if (raw === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
return parseManagedDomainBinding(raw, candidate, key, context);
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
function parseManagedDomainBinding(raw, zoneName, key, context) {
|
|
60
|
+
let value = raw;
|
|
61
|
+
if (typeof raw === "string") {
|
|
62
|
+
try {
|
|
63
|
+
value = JSON.parse(raw);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
throw new Error(`${context}: CDK context '${key}' is not valid JSON (got '${raw}'). ` +
|
|
67
|
+
"The value must be a JSON ManagedDomainBinding " +
|
|
68
|
+
"({ zoneName, hostedZoneId, certificateArn?, " +
|
|
69
|
+
"usEast1CertificateArn?, delegationRoleArn? }) — re-run the deploy " +
|
|
70
|
+
"through the Fjall CLI, or correct the hand-set context entry.");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
74
|
+
throw new Error(`${context}: CDK context '${key}' must be a JSON object ` +
|
|
75
|
+
`ManagedDomainBinding (got ${JSON.stringify(value)}). Re-run the ` +
|
|
76
|
+
"deploy through the Fjall CLI, or correct the hand-set context entry.");
|
|
77
|
+
}
|
|
78
|
+
const record = value;
|
|
79
|
+
for (const field of Object.keys(record)) {
|
|
80
|
+
if (!KNOWN_FIELDS.includes(field)) {
|
|
81
|
+
throw new Error(`${context}: CDK context '${key}' carries unknown field '${field}' ` +
|
|
82
|
+
`(got ${JSON.stringify(record)}). Known fields: ` +
|
|
83
|
+
`${KNOWN_FIELDS.join(", ")}. Re-run the deploy through the Fjall ` +
|
|
84
|
+
"CLI, or correct the hand-set context entry.");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const field of REQUIRED_STRING_FIELDS) {
|
|
88
|
+
if (typeof record[field] !== "string" || record[field] === "") {
|
|
89
|
+
throw new Error(`${context}: CDK context '${key}' is missing required string field ` +
|
|
90
|
+
`'${field}' (got ${JSON.stringify(record[field])}). Redeploy the ` +
|
|
91
|
+
`domain stack ('fjall domain deploy ${zoneName}') so the CLI ` +
|
|
92
|
+
"injects a complete binding, or correct the hand-set context entry.");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const field of OPTIONAL_STRING_FIELDS) {
|
|
96
|
+
const fieldValue = record[field];
|
|
97
|
+
if (fieldValue !== undefined && typeof fieldValue !== "string") {
|
|
98
|
+
throw new Error(`${context}: CDK context '${key}' field '${field}' must be a string ` +
|
|
99
|
+
`when present (got ${JSON.stringify(fieldValue)}). Re-run the ` +
|
|
100
|
+
"deploy through the Fjall CLI, or correct the hand-set context entry.");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (record.zoneName !== zoneName) {
|
|
104
|
+
throw new Error(`${context}: CDK context '${key}' declares zoneName ` +
|
|
105
|
+
`'${String(record.zoneName)}', which does not match the key's zone ` +
|
|
106
|
+
`'${zoneName}'. The injection contract keys each binding by its own ` +
|
|
107
|
+
"zone — re-run the deploy through the Fjall CLI, or correct the " +
|
|
108
|
+
"hand-set context entry.");
|
|
109
|
+
}
|
|
110
|
+
return record;
|
|
111
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
70
|
-
"@fjall/generator": "^
|
|
71
|
-
"@fjall/util": "^
|
|
70
|
+
"@fjall/generator": "^3.0.0",
|
|
71
|
+
"@fjall/util": "^3.0.0",
|
|
72
72
|
"constructs": "^10.6.0"
|
|
73
73
|
},
|
|
74
74
|
"overrides": {
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
"engines": {
|
|
83
83
|
"node": ">=18.0.0"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "848a386e3e2244401b76faabd02818c682d231e8"
|
|
86
86
|
}
|