nukebase 2.5.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/project-commands.js +38 -17
- package/package.json +1 -1
package/lib/project-commands.js
CHANGED
|
@@ -908,8 +908,9 @@ async function domainCommand() {
|
|
|
908
908
|
if (args.has('wait')) {
|
|
909
909
|
const ip = await regionIp();
|
|
910
910
|
const needTxt = (await currentDomain()) !== sub; // already ours: proven when connected
|
|
911
|
-
|
|
912
|
-
|
|
911
|
+
const kind = domainKind(sub);
|
|
912
|
+
printDnsRecords(ip, needTxt, kind);
|
|
913
|
+
await waitForDns(sub, ip, needTxt, kind);
|
|
913
914
|
}
|
|
914
915
|
await connectDomain(sub, email);
|
|
915
916
|
if (args.has('email-domain')) await emailDomainCommand(null);
|
|
@@ -939,8 +940,9 @@ async function domainCommand() {
|
|
|
939
940
|
if (!/^[a-z0-9.-]+\.[a-z]{2,}$/.test(domain)) { console.log(` "${domain}" does not look like a domain.`); domain = ''; }
|
|
940
941
|
}
|
|
941
942
|
|
|
942
|
-
|
|
943
|
-
|
|
943
|
+
const kind = domainKind(domain);
|
|
944
|
+
printDnsRecords(ip, true, kind);
|
|
945
|
+
await waitForDns(domain, ip, true, kind);
|
|
944
946
|
|
|
945
947
|
// Step 3 — the server does the real verification and issues the cert.
|
|
946
948
|
await connectDomain(domain, email);
|
|
@@ -1083,7 +1085,7 @@ async function connectDomain(domain, email) {
|
|
|
1083
1085
|
});
|
|
1084
1086
|
console.log(`\n✓ https://${r.domain} is live.`);
|
|
1085
1087
|
if (r.wwwNote) console.log(` ${r.wwwNote}`);
|
|
1086
|
-
else if (r.verified) console.log(' www redirects to the
|
|
1088
|
+
else if (r.verified) console.log(' www redirects to the main domain.');
|
|
1087
1089
|
}
|
|
1088
1090
|
|
|
1089
1091
|
// This region's public IP, from /region-info. null when it cannot be read;
|
|
@@ -1099,31 +1101,47 @@ async function regionIp() {
|
|
|
1099
1101
|
// The ownership record the server checks on a domain's first connection.
|
|
1100
1102
|
const domainTxtValue = () => `nukebase-uid=${uid}`;
|
|
1101
1103
|
|
|
1102
|
-
|
|
1104
|
+
// A domain of its own (example.com) or a subdomain (app.example.com), and
|
|
1105
|
+
// what its record is called (@, or "app"). By the dots: two labels is a
|
|
1106
|
+
// domain, three or more a subdomain, except under a two-part ending
|
|
1107
|
+
// (example.co.uk is a domain). Only for the instructions; the server decides
|
|
1108
|
+
// at connect. Same rule as the dashboard's domainKind.
|
|
1109
|
+
const TWO_PART_ENDING = /^(co|com|net|org|gov|edu|ac|ltd|plc|sch)\.[a-z]{2}$/;
|
|
1110
|
+
function domainKind(domain) {
|
|
1111
|
+
const labels = domain.split('.');
|
|
1112
|
+
const base = labels.length >= 3 && TWO_PART_ENDING.test(labels.slice(-2).join('.')) ? 3 : 2;
|
|
1113
|
+
if (labels.length <= base) return { subdomain: false, zone: domain, name: '@' };
|
|
1114
|
+
return { subdomain: true, zone: labels.slice(-base).join('.'), name: labels.slice(0, -base).join('.') };
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
function printDnsRecords(ip, withTxt, kind) {
|
|
1118
|
+
const sub = kind && kind.subdomain;
|
|
1119
|
+
const pad = (s) => s.padEnd(10);
|
|
1103
1120
|
console.log('\n Step 1 — point it here. At your registrar (GoDaddy, Namecheap,');
|
|
1104
|
-
console.log(
|
|
1121
|
+
console.log(` Cloudflare, ...) add these DNS records${sub ? ` to ${kind.zone}` : ''}:\n`);
|
|
1105
1122
|
console.log(' Type Name Value');
|
|
1106
|
-
console.log(` A @
|
|
1107
|
-
console.log(` A www ${ip || '(same)'}`);
|
|
1123
|
+
console.log(` A ${pad(sub ? kind.name : '@')} ${ip || "(this region's IP — see the dashboard)"}`);
|
|
1124
|
+
if (!sub) console.log(` A www ${ip || '(same)'}`);
|
|
1108
1125
|
if (withTxt) {
|
|
1109
1126
|
console.log(` TXT nukebase ${domainTxtValue()}`);
|
|
1110
1127
|
console.log('\n The TXT record proves the domain is yours, so no other account can');
|
|
1111
1128
|
console.log(' connect it. One on your main domain covers its subdomains too.');
|
|
1112
1129
|
}
|
|
1130
|
+
if (sub) console.log(`\n ${kind.name}.${kind.zone} is a subdomain, so no www record is needed.`);
|
|
1113
1131
|
console.log('\n If you use Cloudflare, set the records to "DNS only" (grey cloud)');
|
|
1114
1132
|
console.log(' so the certificate can be issued.\n');
|
|
1115
1133
|
}
|
|
1116
1134
|
|
|
1117
1135
|
// Step 2 — wait for DNS. Poll quietly; Enter forces a check; Ctrl+C leaves
|
|
1118
1136
|
// the records in place and the command can be re-run later. Resolves once
|
|
1119
|
-
// the apex
|
|
1137
|
+
// the apex and www point here (only the apex for a subdomain).
|
|
1120
1138
|
//
|
|
1121
1139
|
// Ask public resolvers directly, not the machine's. Two reasons: the OS
|
|
1122
1140
|
// resolver caches, so a record changed a minute ago can look unchanged here
|
|
1123
1141
|
// long after the server sees it — and on some Windows setups Node's own
|
|
1124
1142
|
// resolver cannot reach the system DNS server at all (ECONNREFUSED on every
|
|
1125
1143
|
// name). getaddrinfo is the fallback for a machine that blocks 1.1.1.1.
|
|
1126
|
-
async function waitForDns(domain, ip, needTxt) {
|
|
1144
|
+
async function waitForDns(domain, ip, needTxt, kind) {
|
|
1127
1145
|
console.log(' Step 2 — waiting for DNS. This can take a few minutes.');
|
|
1128
1146
|
console.log(' Press Enter to check now, Ctrl+C to stop and come back later.\n');
|
|
1129
1147
|
const dns = require('dns').promises;
|
|
@@ -1144,6 +1162,12 @@ async function waitForDns(domain, ip, needTxt) {
|
|
|
1144
1162
|
return false;
|
|
1145
1163
|
};
|
|
1146
1164
|
let apexOk = false, wwwOk = false, txtOk = !needTxt;
|
|
1165
|
+
// The server connects a domain of its own with www or not at all (since
|
|
1166
|
+
// 2026-11); only a subdomain (no NS records of its own) goes without it.
|
|
1167
|
+
// By the dots, not "resolveNs says ENODATA": a subdomain whose record is
|
|
1168
|
+
// not added yet is NXDOMAIN, which read as a domain of its own and waited
|
|
1169
|
+
// for www.
|
|
1170
|
+
const subdomain = (kind || domainKind(domain)).subdomain;
|
|
1147
1171
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1148
1172
|
let poke = null;
|
|
1149
1173
|
rl.on('line', () => { if (poke) poke(); });
|
|
@@ -1155,18 +1179,15 @@ async function waitForDns(domain, ip, needTxt) {
|
|
|
1155
1179
|
wwwOk = ip ? www.includes(ip) : www.length > 0;
|
|
1156
1180
|
txtOk = txt;
|
|
1157
1181
|
const mark = ok => ok ? '✓' : '…';
|
|
1158
|
-
|
|
1159
|
-
|
|
1182
|
+
const wwwPart = subdomain ? '' : ` ${mark(wwwOk)} www ${www.length ? '→ ' + www.join(', ') : '(no record yet)'}`;
|
|
1183
|
+
process.stdout.write(`\r ${mark(apexOk)} ${domain} ${apex.length ? '→ ' + apex.join(', ') : '(no record yet)'}${wwwPart}${needTxt ? ` ${mark(txtOk)} TXT ${txtOk ? 'found' : '(not yet)'}` : ''} `);
|
|
1184
|
+
if (apexOk && txtOk && (wwwOk || subdomain)) break;
|
|
1160
1185
|
await wait(15000);
|
|
1161
1186
|
}
|
|
1162
1187
|
} finally {
|
|
1163
1188
|
rl.close();
|
|
1164
1189
|
}
|
|
1165
1190
|
console.log('\n');
|
|
1166
|
-
if (!wwwOk) {
|
|
1167
|
-
console.log(' www is not pointing here yet — connecting the apex only. Re-run');
|
|
1168
|
-
console.log(' `nukebase domain ' + domain + '` later to add the www redirect.\n');
|
|
1169
|
-
}
|
|
1170
1191
|
}
|
|
1171
1192
|
|
|
1172
1193
|
// nukebase logs [--follow] the recent journal for the unit; --follow keeps
|