Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| domains | 1 | import * as cloudflare from "@pulumi/cloudflare"; |
| 2 | import * as pulumi from "@pulumi/pulumi"; | |
| 3 | ||
| 4 | const config = new pulumi.Config(); | |
| 5 | const accountId = config.require("cloudflareAccountId"); | |
| 6 | const targetUrl = normalizeTarget( | |
| 7 | config.get("targetUrl") ?? "https://flagon.io", | |
| 8 | ); | |
| 9 | const domains = normalizeDomains(config.requireObject<string[]>("domains")); | |
| 10 | ||
| 11 | const redirectListName = "flagon_alternate_domains"; | |
| 12 | const redirectList = new cloudflare.List("alternate-domains", { | |
| 13 | accountId, | |
| 14 | name: redirectListName, | |
| 15 | description: "Alternate and commonly misspelled Flagon domains", | |
| 16 | kind: "redirect", | |
| 17 | items: domains.map((domain) => ({ | |
| 18 | comment: `Redirect ${domain} and its subdomains to ${targetUrl}`, | |
| 19 | redirect: { | |
| 20 | sourceUrl: `${domain}/`, | |
| 21 | targetUrl, | |
| 22 | statusCode: 301, | |
| 23 | includeSubdomains: true, | |
| 24 | subpathMatching: true, | |
| 25 | preservePathSuffix: true, | |
| 26 | preserveQueryString: true, | |
| 27 | }, | |
| 28 | })), | |
| 29 | }); | |
| 30 | ||
| 31 | const zones = domains.map((domain) => { | |
| 32 | const resourceName = toResourceName(domain); | |
| 33 | const zone = new cloudflare.Zone(resourceName, { | |
| 34 | account: { id: accountId }, | |
| 35 | name: domain, | |
| 36 | type: "full", | |
| 37 | }); | |
| 38 | ||
| 39 | // Bulk Redirects only see traffic proxied by Cloudflare. These documentation | |
| 40 | // addresses must never be used as origins; the redirect executes first. | |
| 41 | for (const [label, name] of [ | |
| 42 | ["apex", domain], | |
| 43 | ["wildcard", `*.${domain}`], | |
| 44 | ] as const) { | |
| 45 | new cloudflare.DnsRecord(`${resourceName}-${label}`, { | |
| 46 | zoneId: zone.id, | |
| 47 | name, | |
| 48 | type: "A", | |
| 49 | content: "192.0.2.1", | |
| 50 | ttl: 1, | |
| 51 | proxied: true, | |
| 52 | comment: "Proxied placeholder for the account-level Bulk Redirect", | |
| 53 | }); | |
| 54 | } | |
| 55 | ||
| 56 | return zone; | |
| 57 | }); | |
| 58 | ||
| 59 | new cloudflare.Ruleset( | |
| 60 | "alternate-domain-redirects", | |
| 61 | { | |
| 62 | accountId, | |
| 63 | name: "Flagon alternate domain redirects", | |
| 64 | description: "Enables the managed list of alternate Flagon domains", | |
| 65 | kind: "root", | |
| 66 | phase: "http_request_redirect", | |
| 67 | rules: [ | |
| 68 | { | |
| 69 | ref: "redirect_flagon_alternate_domains", | |
| 70 | action: "redirect", | |
| 71 | actionParameters: { | |
| 72 | fromList: { | |
| 73 | key: "http.request.full_uri", | |
| 74 | name: redirectListName, | |
| 75 | }, | |
| 76 | }, | |
| 77 | description: "Redirect alternate Flagon domains", | |
| 78 | expression: `http.request.full_uri in $${redirectListName}`, | |
| 79 | enabled: true, | |
| 80 | }, | |
| 81 | ], | |
| 82 | }, | |
| 83 | { dependsOn: [redirectList] }, | |
| 84 | ); | |
| 85 | ||
| 86 | export const configuredDomains = domains; | |
| 87 | export const target = targetUrl; | |
| 88 | export const zoneNameServers = Object.fromEntries( | |
| 89 | domains.map((domain, index) => [domain, zones[index]!.nameServers]), | |
| 90 | ); | |
| 91 | ||
| 92 | function normalizeDomains(values: string[]): string[] { | |
| 93 | if (values.length === 0) { | |
| 94 | throw new pulumi.RunError("The 'domains' configuration must not be empty."); | |
| 95 | } | |
| 96 | ||
| 97 | const domains = values.map((value) => | |
| 98 | value.trim().toLowerCase().replace(/\.$/, ""), | |
| 99 | ); | |
| 100 | const invalid = domains.find( | |
| 101 | (domain) => | |
| 102 | !/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/.test( | |
| 103 | domain, | |
| 104 | ), | |
| 105 | ); | |
| 106 | if (invalid) { | |
| 107 | throw new pulumi.RunError( | |
| 108 | `Invalid domain in 'domains' configuration: ${invalid}`, | |
| 109 | ); | |
| 110 | } | |
| 111 | ||
| 112 | const unique = [...new Set(domains)].sort(); | |
| 113 | if (unique.includes(new URL(targetUrl).hostname)) { | |
| 114 | throw new pulumi.RunError( | |
| 115 | "The redirect target must not also appear in 'domains'.", | |
| 116 | ); | |
| 117 | } | |
| 118 | return unique; | |
| 119 | } | |
| 120 | ||
| 121 | function normalizeTarget(value: string): string { | |
| 122 | let url: URL; | |
| 123 | try { | |
| 124 | url = new URL(value); | |
| 125 | } catch { | |
| 126 | throw new pulumi.RunError(`Invalid 'targetUrl' configuration: ${value}`); | |
| 127 | } | |
| 128 | if ( | |
| 129 | url.protocol !== "https:" || | |
| 130 | url.username || | |
| 131 | url.password || | |
| 132 | url.search || | |
| 133 | url.hash | |
| 134 | ) { | |
| 135 | throw new pulumi.RunError( | |
| 136 | "The 'targetUrl' configuration must be an HTTPS URL without credentials, a query, or a fragment.", | |
| 137 | ); | |
| 138 | } | |
| 139 | return url.toString().replace(/\/$/, ""); | |
| 140 | } | |
| 141 | ||
| 142 | function toResourceName(domain: string): string { | |
| 143 | return domain.replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""); | |
| 144 | } |