UNPKG

dh2cf

Version:

Syncs DreamHost DNS records to Cloudflare in case you want to use both services.

360 lines (343 loc) 11.8 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); var __export = (target, all) => { __markAsModule(target); for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __reExport = (target, module2, desc) => { if (module2 && typeof module2 === "object" || typeof module2 === "function") { for (let key of __getOwnPropNames(module2)) if (!__hasOwnProp.call(target, key) && key !== "default") __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable }); } return target; }; var __toModule = (module2) => { return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2); }; var __decorateClass = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp(target, key, result); return result; }; // src/cli.ts __export(exports, { default: () => main }); var import_yargs = __toModule(require("yargs")); // src/index.ts var import_typescript_memoize = __toModule(require("typescript-memoize")); var import_got = __toModule(require("got")); // node_modules/read-pkg-up/index.js var import_node_path4 = __toModule(require("node:path")); // node_modules/read-pkg-up/node_modules/find-up/index.js var import_node_path2 = __toModule(require("node:path")); // node_modules/read-pkg-up/node_modules/locate-path/index.js var import_node_process = __toModule(require("node:process")); var import_node_path = __toModule(require("node:path")); var import_node_fs = __toModule(require("node:fs")); // node_modules/read-pkg-up/node_modules/yocto-queue/index.js var Node = class { value; next; constructor(value) { this.value = value; } }; var Queue = class { #head; #tail; #size; constructor() { this.clear(); } enqueue(value) { const node = new Node(value); if (this.#head) { this.#tail.next = node; this.#tail = node; } else { this.#head = node; this.#tail = node; } this.#size++; } dequeue() { const current = this.#head; if (!current) { return; } this.#head = this.#head.next; this.#size--; return current.value; } clear() { this.#head = void 0; this.#tail = void 0; this.#size = 0; } get size() { return this.#size; } *[Symbol.iterator]() { let current = this.#head; while (current) { yield current.value; current = current.next; } } }; // node_modules/read-pkg-up/node_modules/locate-path/index.js var typeMappings = { directory: "isDirectory", file: "isFile" }; function checkType(type) { if (type in typeMappings) { return; } throw new Error(`Invalid type specified: ${type}`); } var matchType = (type, stat) => type === void 0 || stat[typeMappings[type]](); function locatePathSync(paths, { cwd = import_node_process.default.cwd(), type = "file", allowSymlinks = true } = {}) { checkType(type); const statFunction = allowSymlinks ? import_node_fs.default.statSync : import_node_fs.default.lstatSync; for (const path_ of paths) { try { const stat = statFunction(import_node_path.default.resolve(cwd, path_)); if (matchType(type, stat)) { return path_; } } catch { } } } // node_modules/read-pkg-up/node_modules/path-exists/index.js var import_node_fs2 = __toModule(require("node:fs")); // node_modules/read-pkg-up/node_modules/find-up/index.js var findUpStop = Symbol("findUpStop"); function findUpMultipleSync(name, options = {}) { let directory = import_node_path2.default.resolve(options.cwd || ""); const { root } = import_node_path2.default.parse(directory); const stopAt = options.stopAt || root; const limit = options.limit || Number.POSITIVE_INFINITY; const paths = [name].flat(); const runMatcher = (locateOptions) => { if (typeof name !== "function") { return locatePathSync(paths, locateOptions); } const foundPath = name(locateOptions.cwd); if (typeof foundPath === "string") { return locatePathSync([foundPath], locateOptions); } return foundPath; }; const matches = []; while (true) { const foundPath = runMatcher(__spreadProps(__spreadValues({}, options), { cwd: directory })); if (foundPath === findUpStop) { break; } if (foundPath) { matches.push(import_node_path2.default.resolve(directory, foundPath)); } if (directory === stopAt || matches.length >= limit) { break; } directory = import_node_path2.default.dirname(directory); } return matches; } function findUpSync(name, options = {}) { const matches = findUpMultipleSync(name, __spreadProps(__spreadValues({}, options), { limit: 1 })); return matches[0]; } // node_modules/read-pkg/index.js var import_node_process2 = __toModule(require("node:process")); var import_node_fs3 = __toModule(require("node:fs")); var import_node_path3 = __toModule(require("node:path")); var import_parse_json = __toModule(require("parse-json")); var import_normalize_package_data = __toModule(require("normalize-package-data")); function readPackageSync({ cwd = import_node_process2.default.cwd(), normalize = true } = {}) { const filePath = import_node_path3.default.resolve(cwd, "package.json"); const json = (0, import_parse_json.default)(import_node_fs3.default.readFileSync(filePath, "utf8")); if (normalize) { (0, import_normalize_package_data.default)(json); } return json; } // node_modules/read-pkg-up/index.js function readPackageUpSync(options) { const filePath = findUpSync("package.json", options); if (!filePath) { return; } return { packageJson: readPackageSync(__spreadProps(__spreadValues({}, options), { cwd: import_node_path4.default.dirname(filePath) })), path: filePath }; } // src/version.ts var { packageJson } = readPackageUpSync({ cwd: __dirname }); var version = packageJson.version; var version_default = version; // src/dh-list-records-response.ts var z = __toModule(require("zod")); var DhListRecordsResponseSchema = z.object({ result: z.enum(["success"]), data: z.array(z.object({ record: z.string(), type: z.string(), value: z.string(), zone: z.string() })) }); // src/index.ts var Dh2Cf = class { constructor(config) { this.config = config; const client = import_got.default.extend({ headers: { "User-Agent": `npmjs.com/package/dh2cf/v/${version_default}` }, responseType: "json", prefixUrl: "https://api.dreamhost.com" }); this.dhClient = client.extend({ prefixUrl: "https://api.dreamhost.com" }); this.cfClient = client.extend({ prefixUrl: "https://api.cloudflare.com/client/v4" }); } async run() { console.dir({ options: this.config }); const dhRecords = await this.getDreamHostRecords(); console.dir({ dhRecords }, { depth: null }); } get allowedTypes() { return new Set(this.config.types); } get ignoredRecords() { return new Set(this.config.ignoreNames.map((name) => name === "@" ? this.config.zone : name).map((name) => `${name}.${this.config.zone}`)); } async getDreamHostRecords() { console.log("Fetching dns records from DreamHost"); const query = `?key=${this.config.dhToken}&cmd=dns-list_records&format=json`; const response = await this.dhClient.get(query).json(); const dhListRecordsResponse = DhListRecordsResponseSchema.parse(response); const records = dhListRecordsResponse.data.filter((record) => record.zone === this.config.zone); if (this.config.verbose) { console.log(`DreamHost records for zone '${this.config.zone}`); for (const record of records) { console.log(JSON.stringify(record)); } } return records; } }; __decorateClass([ (0, import_typescript_memoize.Memoize)() ], Dh2Cf.prototype, "allowedTypes", 1); __decorateClass([ (0, import_typescript_memoize.Memoize)() ], Dh2Cf.prototype, "ignoredRecords", 1); // src/config.ts var z2 = __toModule(require("zod")); var ConfigSchema = z2.object({ cfEmail: z2.string().min(1), cfToken: z2.string().min(1), dhToken: z2.string().min(1), ignoreNames: z2.array(z2.string()).default([]), sync: z2.boolean().default(false), types: z2.array(z2.string()).default([]), verbose: z2.boolean().default(false), zone: z2.string().min(1) }); // src/cli.ts async function main() { const cliConfig = import_yargs.default.env("DH2CF").option("cf-email", { type: "string", demandOption: true, describe: "Cloudflare account email" }).option("cf-token", { type: "string", demandOption: true, describe: "Cloudflare API token" }).option("dh-token", { type: "string", demandOption: true, describe: "DreamHost API token" }).option("ignore-names", { type: "array", alias: "i", describe: 'Record names to ignore, e.g. for zone example.com, the value "ssh @" would skip ssh.example.com and example.com', default: [] }).option("sync", { type: "boolean", alias: "S", default: false, describe: "Sync records from DreamHost to Cloudflare. Does not delete records that only exist in Cloudflare. This option is required in order to actually perform any operations." }).option("types", { type: "array", alias: "t", describe: 'Record types to process, e.g. "A CNAME MX"', default: "A CNAME MX TXT".split(" ") }).option("verbose", { type: "boolean", alias: "v", default: false }).option("zone", { type: "string", alias: "z", demandOption: true, describe: 'Zone to compare, e.g. "example.com"' }).group(["cf-email", "cf-token", "dh-token"], "Cloudflare and DreamHost credentials:").group(["ignore-names", "sync", "types", "zone"], "DNS sync options:").example("$0 --zone example.com", "Preview changes that would sync for example.com").example("$0 --zone example.com --sync", "Perform the sync for example.com").argv; let config; try { config = ConfigSchema.parse(cliConfig); } catch (error) { console.error(`${error} `); import_yargs.default.showHelp(); process.exit(1); } const dh2cf = new Dh2Cf(config); await dh2cf.run(); } main().catch((error) => { throw error; }); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = {});