@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.
Files changed (66) hide show
  1. package/dist/lib/app.d.ts +19 -2
  2. package/dist/lib/app.js +61 -4
  3. package/dist/lib/patterns/aws/account.js +6 -1
  4. package/dist/lib/patterns/aws/apexDomainPattern.d.ts +11 -12
  5. package/dist/lib/patterns/aws/apexDomainPattern.js +11 -31
  6. package/dist/lib/patterns/aws/cdn.js +25 -10
  7. package/dist/lib/patterns/aws/computeEcs.js +15 -6
  8. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +13 -4
  9. package/dist/lib/patterns/aws/delegatedDomainPattern.d.ts +13 -4
  10. package/dist/lib/patterns/aws/delegatedDomainPattern.js +57 -8
  11. package/dist/lib/patterns/aws/devSubstrate.d.ts +2 -1
  12. package/dist/lib/patterns/aws/devSubstrate.js +18 -8
  13. package/dist/lib/patterns/aws/dnsRecordComposer.d.ts +2 -9
  14. package/dist/lib/patterns/aws/dnsRecordComposer.js +5 -97
  15. package/dist/lib/patterns/aws/domain.d.ts +3 -2
  16. package/dist/lib/patterns/aws/domain.js +3 -2
  17. package/dist/lib/patterns/aws/domainValidation.js +71 -46
  18. package/dist/lib/patterns/aws/externalRecordsPattern.js +2 -11
  19. package/dist/lib/patterns/aws/index.d.ts +1 -3
  20. package/dist/lib/patterns/aws/index.js +2 -3
  21. package/dist/lib/patterns/aws/interfaces/domain.d.ts +22 -8
  22. package/dist/lib/patterns/aws/interfaces/index.d.ts +0 -1
  23. package/dist/lib/patterns/aws/interfaces/index.js +3 -0
  24. package/dist/lib/patterns/aws/interfaces/pattern.d.ts +55 -10
  25. package/dist/lib/patterns/aws/patternDomain.d.ts +77 -0
  26. package/dist/lib/patterns/aws/patternDomain.js +198 -0
  27. package/dist/lib/patterns/aws/payload.js +23 -30
  28. package/dist/lib/patterns/aws/staticSite.d.ts +1 -0
  29. package/dist/lib/patterns/aws/staticSite.js +28 -33
  30. package/dist/lib/resources/aws/base/awsStack.d.ts +8 -0
  31. package/dist/lib/resources/aws/base/awsStack.js +20 -17
  32. package/dist/lib/resources/aws/compute/ecs.d.ts +1 -1
  33. package/dist/lib/resources/aws/compute/ecs.js +1 -1
  34. package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +1 -1
  35. package/dist/lib/resources/aws/compute/ecsNetworking.js +212 -47
  36. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +4 -4
  37. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +60 -9
  38. package/dist/lib/resources/aws/compute/ecsValidation.d.ts +14 -1
  39. package/dist/lib/resources/aws/compute/ecsValidation.js +51 -0
  40. package/dist/lib/resources/aws/logging/logGroup.d.ts +6 -0
  41. package/dist/lib/resources/aws/logging/logGroup.js +11 -1
  42. package/dist/lib/resources/aws/networking/dnsRecord/aRecord.js +3 -2
  43. package/dist/lib/resources/aws/networking/dnsRecord/aaaaRecord.js +3 -2
  44. package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.d.ts +23 -1
  45. package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.js +14 -3
  46. package/dist/lib/resources/aws/networking/dnsRecord/caaRecord.js +3 -2
  47. package/dist/lib/resources/aws/networking/dnsRecord/cnameRecord.js +3 -2
  48. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.d.ts +10 -1
  49. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +21 -4
  50. package/dist/lib/resources/aws/networking/dnsRecord/mxRecord.js +3 -2
  51. package/dist/lib/resources/aws/networking/dnsRecord/nsRecord.js +3 -2
  52. package/dist/lib/resources/aws/networking/dnsRecord/srvRecord.js +3 -2
  53. package/dist/lib/resources/aws/networking/dnsRecord/txtRecord.js +3 -2
  54. package/dist/lib/resources/aws/networking/domainCertificate.d.ts +28 -4
  55. package/dist/lib/resources/aws/networking/domainCertificate.js +24 -10
  56. package/dist/lib/resources/aws/networking/hostedZone.d.ts +11 -0
  57. package/dist/lib/resources/aws/networking/hostedZone.js +6 -0
  58. package/dist/lib/utils/costAllocationTags.d.ts +9 -0
  59. package/dist/lib/utils/costAllocationTags.js +6 -1
  60. package/dist/lib/utils/dnsRecordRegistry.d.ts +52 -0
  61. package/dist/lib/utils/dnsRecordRegistry.js +64 -0
  62. package/dist/lib/utils/domainTypes.d.ts +43 -36
  63. package/dist/lib/utils/domainTypes.js +65 -2
  64. package/dist/lib/utils/managedDomainContext.d.ts +37 -0
  65. package/dist/lib/utils/managedDomainContext.js +111 -0
  66. package/package.json +4 -4
@@ -1,2 +1,65 @@
1
- export { DNS_APEX, getDomainExportNames } from "@fjall/util";
2
- export const ALIAS_CDK_PREFIX = "ALIAS:";
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": "2.33.0",
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": "^2.33.0",
71
- "@fjall/util": "^2.33.0",
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": "61c0d1917597c6d02e8e78b03420afdd194eaafc"
85
+ "gitHead": "848a386e3e2244401b76faabd02818c682d231e8"
86
86
  }