1import * as route53 from "@distilled.cloud/aws/route-53";
2import * as Effect from "effect/Effect";
3
4/**
5 * Find the most specific PUBLIC Route 53 hosted zone containing
6 * `domainName`, walking up its labels (`svc.api.example.com` →
7 * `api.example.com` → `example.com`). Wildcard labels (`*`) never name a
8 * zone, so they fall through to the parent naturally. Returns the bare
9 * zone id (no `/hostedzone/` prefix), or `undefined` when no public zone
10 * matches.
11 *
12 * Shared by every provider that infers a hosted zone from a hostname
13 * (Route 53 Record/Records, ACM Certificate validation, ECS Service DNS).
14 */
15export const findPublicHostedZoneId = Effect.fn("findPublicHostedZoneId")(
16 function* (domainName: string) {
17 const labels = domainName
18 .replace(/\.$/, "")
19 .split(".")
20 .filter((label) => label.length > 0);
21 for (let i = 0; i < labels.length - 1; i++) {
22 const candidate = `${labels.slice(i).join(".")}.`;
23 const listed = yield* route53.listHostedZonesByName({
24 DNSName: candidate,
25 MaxItems: 1,
26 });
27 const zone = listed.HostedZones?.[0];
28 if (
29 zone?.Id !== undefined &&
30 zone.Name === candidate &&
31 zone.Config?.PrivateZone !== true
32 ) {
33 return zone.Id.replace(/^\/hostedzone\//, "");
34 }
35 }
36 return undefined;
37 },
38);
39
40/**
41 * Resolve the hosted zone for `domainName`: the explicit id when given,
42 * otherwise the most specific public zone in the account (see
43 * {@link findPublicHostedZoneId}). Fails with an actionable error when
44 * neither yields a zone.
45 */
46export const resolveHostedZoneId = Effect.fn("resolveHostedZoneId")(function* (
47 hostedZoneId: string | undefined,
48 domainName: string,
49) {
50 if (hostedZoneId !== undefined) {
51 return hostedZoneId;
52 }
53 const inferred = yield* findPublicHostedZoneId(domainName);
54 if (inferred === undefined) {
55 return yield* Effect.fail(
56 new Error(
57 `No public Route 53 hosted zone in this account contains "${domainName}" — ` +
58 `create the zone first or pass "hostedZoneId" explicitly.`,
59 ),
60 );
61 }
62 return inferred;
63});