Monorepo for Aesthetic.Computer aesthetic.computer
at main 143 lines 4.3 kB view raw
1#!/usr/bin/env node 2// Update Chat DNS, 25.11.28 3// Updates Cloudflare DNS records to point chat subdomains to session-server 4 5import dotenv from "dotenv"; 6dotenv.config({ path: "../aesthetic-computer-vault/nanos/conductor.env" }); 7 8const CLOUDFLARE_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN; 9const CLOUDFLARE_BASE_URL = "https://api.cloudflare.com/client/v4"; 10 11// Session server IP (DigitalOcean) 12const SESSION_SERVER_IP = "157.245.134.225"; 13 14const headers = { 15 "Authorization": `Bearer ${CLOUDFLARE_API_TOKEN}`, 16 "Content-Type": "application/json", 17}; 18 19// Chat subdomains to migrate 20const chatDomains = [ 21 { subdomain: "chat-system.aesthetic.computer", zone: "aesthetic.computer" }, 22 { subdomain: "chat-clock.aesthetic.computer", zone: "aesthetic.computer" }, 23 { subdomain: "chat.sotce.net", zone: "sotce.net" }, 24]; 25 26async function fetchZones() { 27 const response = await fetch(`${CLOUDFLARE_BASE_URL}/zones`, { headers }); 28 return response.json(); 29} 30 31async function fetchZone(zoneName) { 32 const zones = await fetchZones(); 33 return zones.result?.find((zone) => zone.name === zoneName); 34} 35 36async function fetchARecord(zoneId, recordName) { 37 const response = await fetch( 38 `${CLOUDFLARE_BASE_URL}/zones/${zoneId}/dns_records?type=A&name=${recordName}`, 39 { headers } 40 ); 41 return response.json(); 42} 43 44async function updateDNSRecord(zoneId, recordId, data) { 45 const response = await fetch( 46 `${CLOUDFLARE_BASE_URL}/zones/${zoneId}/dns_records/${recordId}`, 47 { method: "PUT", headers, body: JSON.stringify(data) } 48 ); 49 return response.json(); 50} 51 52async function createDNSRecord(zoneId, data) { 53 const response = await fetch( 54 `${CLOUDFLARE_BASE_URL}/zones/${zoneId}/dns_records`, 55 { method: "POST", headers, body: JSON.stringify(data) } 56 ); 57 return response.json(); 58} 59 60async function createOrUpdateARecord(subdomain, zone, ip) { 61 console.log(`\n🔄 Processing ${subdomain}...`); 62 63 const zoneId = (await fetchZone(zone))?.id; 64 if (!zoneId) { 65 console.error(` ❌ Zone ID not found for ${zone}`); 66 return false; 67 } 68 console.log(` 📍 Zone ID: ${zoneId}`); 69 70 const recordResponse = await fetchARecord(zoneId, subdomain); 71 const record = recordResponse.result?.[0]; 72 73 const data = { 74 type: "A", 75 name: subdomain, 76 content: ip, 77 ttl: 1, // Auto 78 proxied: true, 79 }; 80 81 let response; 82 if (record) { 83 console.log(` 📝 Updating existing record (current: ${record.content})`); 84 response = await updateDNSRecord(zoneId, record.id, data); 85 } else { 86 console.log(` ➕ Creating new record`); 87 response = await createDNSRecord(zoneId, data); 88 } 89 90 if (response.success) { 91 console.log(` ✅ Success: ${subdomain} -> ${ip}`); 92 return true; 93 } else { 94 console.log(` ❌ Failed:`, response.errors); 95 return false; 96 } 97} 98 99async function main() { 100 console.log("🌐 Chat DNS Migration Tool"); 101 console.log("=========================="); 102 console.log(`Target IP: ${SESSION_SERVER_IP}`); 103 104 if (!CLOUDFLARE_API_TOKEN) { 105 console.error("\n❌ Missing Cloudflare API token!"); 106 console.log("Make sure aesthetic-computer-vault/nanos/conductor.env exists with:"); 107 console.log(" CLOUDFLARE_API_TOKEN=..."); 108 process.exit(1); 109 } 110 111 console.log(`\nUsing Bearer token authentication`); 112 113 const dryRun = process.argv.includes("--dry-run"); 114 if (dryRun) { 115 console.log("\n⚠️ DRY RUN MODE - No changes will be made\n"); 116 } 117 118 let successCount = 0; 119 let failCount = 0; 120 121 for (const { subdomain, zone } of chatDomains) { 122 if (dryRun) { 123 console.log(`\n🔍 Would update: ${subdomain} -> ${SESSION_SERVER_IP}`); 124 successCount++; 125 } else { 126 const success = await createOrUpdateARecord(subdomain, zone, SESSION_SERVER_IP); 127 if (success) successCount++; 128 else failCount++; 129 } 130 } 131 132 console.log("\n=========================="); 133 console.log(`✅ Success: ${successCount}`); 134 console.log(`❌ Failed: ${failCount}`); 135 136 if (!dryRun && successCount === chatDomains.length) { 137 console.log("\n🎉 All DNS records updated successfully!"); 138 console.log("\n⏳ DNS propagation may take a few minutes."); 139 console.log("Test with: curl https://chat-system.aesthetic.computer"); 140 } 141} 142 143main().catch(console.error);