84 lines · 3.2 KB
import { env } from "cloudflare:workers";
import { z } from "zod";
import { badRequest, HttpError } from "../errors";

const API = "https://api.cloudflare.com/client/v4";
const HTTP_UNAVAILABLE = 503;
const HTTP_BAD_GATEWAY = 502;

const hostnameSchema = z.object({
  id: z.string(),
  hostname: z.string(),
  status: z.string(),
  ssl: z
    .object({
      status: z.string().optional(),
      txt_name: z.string().optional(),
      txt_value: z.string().optional(),
      validation_records: z.array(z.object({ txt_name: z.string().optional(), txt_value: z.string().optional() })),
    })
    .partial()
    .optional(),
  verification_errors: z.array(z.string()).optional(),
  ownership_verification: z.object({ type: z.string(), name: z.string(), value: z.string() }).optional(),
});

const envelope = z.object({
  success: z.boolean(),
  errors: z.array(z.object({ message: z.string() })).default([]),
  result: z.unknown(),
});

export type CustomHostname = z.infer<typeof hostnameSchema>;

/** Whether Cloudflare for SaaS is configured: a zone with a fallback origin and an API token secret. */
export function customDomainsEnabled(): boolean {
  return Boolean(env.CUSTOM_DOMAINS_ZONE_ID && env.CF_API_TOKEN);
}

/** The hostname customers CNAME their domain to: the zone's SaaS fallback origin. */
export function customDomainsTarget(): string | null {