3 * Bulk Nameserver Updater
5 * This script updates nameservers for multiple domains at once.
6 * Supports Moniker and eNom registrars.
9 * node scripts/bulk-update-nameservers.js --registrar moniker --file domains.json --nameservers "ns1.example.com,ns2.example.com"
10 * node scripts/bulk-update-nameservers.js --registrar moniker --domain example.com --cloudflare
11 * node scripts/bulk-update-nameservers.js --registrar enom --file domains.txt --cloudflare
14 * --registrar <name> Registrar API to use (moniker or enom)
15 * --domain <domain> Single domain to update
16 * --file <path> File with list of domains (JSON array or newline-separated)
17 * --nameservers <ns1,ns2> Comma-separated list of nameservers
18 * --cloudflare Use Cloudflare nameservers (auto-fetches from API)
19 * --dry-run Test mode - show what would be updated without making changes
20 * --delay <ms> Delay between API calls in milliseconds (default: 1000)
23require('dotenv').config();
24const fs = require('fs').promises;
25const path = require('path');
26const moniker = require('../services/moniker');
27const enom = require('../services/enom');
28const { createZone, getZone } = require('../services/cloudflare');
30// Parse command line arguments
35 const args = process.argv.slice(2);
46 for (let i = 0; i < args.length; i++) {
48 const next = args[i + 1];
52 options.registrar = next;
56 options.domain = next;
64 options.nameservers = next.split(',').map(ns => ns.trim());
68 options.cloudflare = true;
71 options.dryRun = true;
74 options.delay = parseInt(next, 10);
93Bulk Nameserver Updater
94=======================
96Update nameservers for multiple domains across different registrars.
99 node scripts/bulk-update-nameservers.js [options]
102 --registrar <name> Required. Registrar API (moniker or enom)
103 --domain <domain> Single domain to update
104 --file <path> File with domains (JSON or text)
105 --nameservers <ns1,ns2> Comma-separated nameservers
106 --cloudflare Use Cloudflare nameservers
107 --dry-run Test without making changes
108 --delay <ms> Delay between calls (default: 1000ms)
109 --help, -h Show this help
112 # Update single domain to Cloudflare
113 node scripts/bulk-update-nameservers.js --registrar moniker --domain example.com --cloudflare
115 # Update domains from file to custom nameservers
116 node scripts/bulk-update-nameservers.js --registrar enom --file domains.txt --nameservers "ns1.host.com,ns2.host.com"
118 # Dry run to see what would change
119 node scripts/bulk-update-nameservers.js --registrar moniker --file domains.json --cloudflare --dry-run
122 - JSON: ["domain1.com", "domain2.com", "domain3.com"]
123 - Text: One domain per line
128 * Load domains from file
131async function loadDomainsFromFile(filePath) {
132 const content = await fs.readFile(filePath, 'utf8');
133 const ext = path.extname(filePath).toLowerCase();
135 if (ext === '.json') {
136 const data = JSON.parse(content);
137 // Handle both array and object with domains property
138 return Array.isArray(data) ? data : data.domains || [];
140 // Text file - one domain per line
141 return content.split('\n')
142 .map(line => line.trim())
143 .filter(line => line && !line.startsWith('#'));
148 * Get Cloudflare nameservers for a domain
151async function getCloudflareNameservers(domain) {
153 console.log(`[Cloudflare] Checking if zone exists for ${domain}...`);
155 // Try to get existing zone
156 let zone = await getZone(domain);
158 // If no zone, create one
159 if (!zone || !zone.id) {
160 console.log(`[Cloudflare] Creating new zone for ${domain}...`);
161 zone = await createZone(domain);
164 if (!zone || !zone.name_servers || zone.name_servers.length === 0) {
165 throw new Error('Failed to get Cloudflare nameservers');
168 console.log(`[Cloudflare] Zone ID: ${zone.id}`);
169 console.log(`[Cloudflare] Nameservers: ${zone.name_servers.join(', ')}`);
173 nameservers: zone.name_servers
176 console.error(`[Cloudflare] Error for ${domain}:`, error.message);
182 * Update nameservers for a domain
188async function updateDomainNameservers(registrar, domain, nameservers, dryRun = false) {
189 console.log(`\n${'='.repeat(60)}`);
190 console.log(`Processing: ${domain}`);
191 console.log(`${'='.repeat(60)}`);
194 console.log('[DRY RUN] Would update nameservers to:', nameservers);
206 if (registrar === 'moniker') {
207 console.log('[Moniker] Updating nameservers...');
208 result = await moniker.updateNameservers(domain, nameservers);
209 } else if (registrar === 'enom') {
210 console.log('[eNom] Updating nameservers...');
211 result = await enom.updateNameservers(domain, nameservers);
213 throw new Error(`Unsupported registrar: ${registrar}`);
216 console.log('✅ Success!');
217 console.log('Updated nameservers:', result.nameservers);
222 nameservers: result.nameservers,
226 console.error('❌ Error:', error.message);
241 return new Promise(resolve => setTimeout(resolve, ms));
247async function main() {
248 const options = parseArgs();
251 if (!options.registrar) {
252 console.error('❌ Error: --registrar is required');
253 console.log('Run with --help for usage information');
257 if (!['moniker', 'enom'].includes(options.registrar)) {
258 console.error('❌ Error: --registrar must be "moniker" or "enom"');
262 if (!options.domain && !options.file) {
263 console.error('❌ Error: Either --domain or --file is required');
264 console.log('Run with --help for usage information');
268 if (!options.cloudflare && options.nameservers.length === 0) {
269 console.error('❌ Error: Either --cloudflare or --nameservers is required');
274╔════════════════════════════════════════════════════════════╗
275║ Bulk Nameserver Updater ║
276╚════════════════════════════════════════════════════════════╝
279 Registrar: ${options.registrar}
280 Mode: ${options.dryRun ? 'DRY RUN (no changes)' : 'LIVE'}
281 Delay: ${options.delay}ms between requests
286 if (options.domain) {
287 domains = [options.domain];
288 } else if (options.file) {
289 console.log(`Loading domains from: ${options.file}`);
290 domains = await loadDomainsFromFile(options.file);
291 console.log(`Loaded ${domains.length} domain(s)\n`);
294 if (domains.length === 0) {
295 console.error('❌ No domains to process');
301 let successCount = 0;
304 // Process each domain
305 for (let i = 0; i < domains.length; i++) {
306 const domain = domains[i];
310 let nameservers = options.nameservers;
312 if (options.cloudflare) {
313 console.log(`\n[${i + 1}/${domains.length}] Getting Cloudflare nameservers for ${domain}...`);
314 const cfData = await getCloudflareNameservers(domain);
315 nameservers = cfData.nameservers;
318 // Update nameservers
319 const result = await updateDomainNameservers(
326 results.push(result);
328 if (result.success) {
334 // Delay between requests (except for last one)
335 if (i < domains.length - 1) {
336 console.log(`\nWaiting ${options.delay}ms before next request...`);
337 await delay(options.delay);
340 console.error(`\n❌ Fatal error processing ${domain}:`, error.message);
351 console.log(`\n${'='.repeat(60)}`);
352 console.log('SUMMARY');
353 console.log(`${'='.repeat(60)}`);
354 console.log(`Total domains: ${domains.length}`);
355 console.log(`✅ Successful: ${successCount}`);
356 console.log(`❌ Failed: ${failCount}`);
358 if (options.dryRun) {
359 console.log('\n⚠️ DRY RUN - No actual changes were made');
362 // Print failed domains
364 console.log('\n\nFailed Domains:');
366 .filter(r => !r.success)
368 console.log(` • ${r.domain}: ${r.error}`);
372 // Save results to file
373 const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
374 const resultFile = `nameserver-update-results-${timestamp}.json`;
377 JSON.stringify(results, null, 2),
380 console.log(`\nResults saved to: ${resultFile}`);
382 process.exit(failCount > 0 ? 1 : 0);
385// Run if called directly
386if (require.main === module) {
387 main().catch(error => {
388 console.error('Fatal error:', error);
394 updateDomainNameservers,
395 getCloudflareNameservers,