doomain 0.1.2 → 0.1.3
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/dist/commands/domains/list.js +10 -1
- package/dist/lib/link-domain.js +55 -5
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,15 @@ import { domainFlag, jsonFlag, providerFlag } from '../../lib/flags.js';
|
|
|
4
4
|
import { createOutput, outputError } from '../../lib/output.js';
|
|
5
5
|
import { createProvider } from '../../lib/providers/registry.js';
|
|
6
6
|
import { normalizeDomain } from '../../lib/validate.js';
|
|
7
|
+
async function resolveZones(provider, domain) {
|
|
8
|
+
if (!domain)
|
|
9
|
+
return provider.listZones();
|
|
10
|
+
const normalized = normalizeDomain(domain);
|
|
11
|
+
const zone = await provider.getZone(normalized);
|
|
12
|
+
if (!zone)
|
|
13
|
+
throw new Error(`${provider.name} does not have a DNS zone for ${normalized}.`);
|
|
14
|
+
return [zone];
|
|
15
|
+
}
|
|
7
16
|
export default class DomainsList extends Command {
|
|
8
17
|
static description = 'List DNS zones and records for a provider.';
|
|
9
18
|
static flags = {
|
|
@@ -17,7 +26,7 @@ export default class DomainsList extends Command {
|
|
|
17
26
|
try {
|
|
18
27
|
const config = await loadConfig();
|
|
19
28
|
const provider = await createProvider(flags.provider ?? process.env.DOOMAIN_PROVIDER ?? config.defaults?.provider ?? 'spaceship');
|
|
20
|
-
const zones =
|
|
29
|
+
const zones = await resolveZones(provider, flags.domain);
|
|
21
30
|
const results = [];
|
|
22
31
|
for (const zone of zones) {
|
|
23
32
|
const records = await provider.listRecords(zone);
|
package/dist/lib/link-domain.js
CHANGED
|
@@ -187,6 +187,20 @@ function uniqueRecords(records) {
|
|
|
187
187
|
}
|
|
188
188
|
return unique;
|
|
189
189
|
}
|
|
190
|
+
function recordKey(record) {
|
|
191
|
+
return `${record.type}:${record.name}:${record.value}:${record.proxied ?? ''}`;
|
|
192
|
+
}
|
|
193
|
+
function mergeRecords(records, nextRecords) {
|
|
194
|
+
const existing = new Set(records.map(recordKey));
|
|
195
|
+
const added = nextRecords.filter((record) => !existing.has(recordKey(record)));
|
|
196
|
+
return { records: [...records, ...added], added };
|
|
197
|
+
}
|
|
198
|
+
function errorDetails(error) {
|
|
199
|
+
return error instanceof DoomainError ? error.details : undefined;
|
|
200
|
+
}
|
|
201
|
+
function isDomainConfigReady(config) {
|
|
202
|
+
return config?.misconfigured !== true;
|
|
203
|
+
}
|
|
190
204
|
export function verificationRecords(raw, zoneDomain) {
|
|
191
205
|
const verification = collectVerificationRecords(raw);
|
|
192
206
|
return verification.flatMap((record) => {
|
|
@@ -239,32 +253,58 @@ async function waitForVercelDomainReady(opts) {
|
|
|
239
253
|
const startedAt = Date.now();
|
|
240
254
|
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
241
255
|
let lastError;
|
|
256
|
+
let lastConfig;
|
|
242
257
|
let propagated = false;
|
|
243
258
|
let attempt = 1;
|
|
259
|
+
let records = opts.records;
|
|
260
|
+
async function applyVerificationRecords(raw) {
|
|
261
|
+
const nextRecords = planVerificationRecords(opts.providerId, raw, opts.zoneDomain);
|
|
262
|
+
const merged = mergeRecords(records, nextRecords);
|
|
263
|
+
if (merged.added.length === 0)
|
|
264
|
+
return;
|
|
265
|
+
reportProgress(opts.input, 'dns:plan', `Found ${merged.added.length} new Vercel ownership record${merged.added.length === 1 ? '' : 's'}`);
|
|
266
|
+
const dnsPlan = await opts.provider.planChanges(opts.zone, merged.added, { force: opts.force });
|
|
267
|
+
reportProgress(opts.input, 'dns:apply', `Updating ownership records in ${opts.provider.name}`);
|
|
268
|
+
await opts.provider.applyChanges(opts.zone, dnsPlan, { force: opts.force });
|
|
269
|
+
records = merged.records;
|
|
270
|
+
}
|
|
271
|
+
async function isVercelReady(raw) {
|
|
272
|
+
await applyVerificationRecords(raw);
|
|
273
|
+
if (raw.verified !== true)
|
|
274
|
+
return false;
|
|
275
|
+
lastConfig = await vercel.getDomainConfig(opts.domain);
|
|
276
|
+
return isDomainConfigReady(lastConfig);
|
|
277
|
+
}
|
|
244
278
|
while (Date.now() <= deadline) {
|
|
245
279
|
const elapsedSeconds = Math.round((Date.now() - startedAt) / 1000);
|
|
246
280
|
reportProgress(opts.input, 'vercel:verify', `Verifying domain in Vercel (attempt ${attempt}, ${elapsedSeconds}s elapsed)`);
|
|
247
281
|
try {
|
|
248
282
|
const current = await vercel.getProjectDomain(opts.project, opts.domain);
|
|
249
|
-
if (current
|
|
283
|
+
if (await isVercelReady(current))
|
|
250
284
|
return { propagated: true, verified: true };
|
|
251
285
|
const result = await vercel.verifyProjectDomain(opts.project, opts.domain);
|
|
252
|
-
if (result
|
|
286
|
+
if (await isVercelReady(result))
|
|
253
287
|
return { propagated: true, verified: true };
|
|
254
288
|
}
|
|
255
289
|
catch (error) {
|
|
256
290
|
// Vercel returns an error while DNS is still propagating.
|
|
257
291
|
lastError = error;
|
|
292
|
+
await applyVerificationRecords(errorDetails(error));
|
|
258
293
|
}
|
|
259
|
-
propagated = await areRecordsPropagated(
|
|
294
|
+
propagated = await areRecordsPropagated(records, opts.zoneDomain);
|
|
260
295
|
reportProgress(opts.input, 'dns:wait', propagated
|
|
261
296
|
? 'DNS is visible publicly; Vercel verification is still pending'
|
|
262
297
|
: 'DNS records were saved; public DNS is still catching up');
|
|
263
298
|
attempt += 1;
|
|
299
|
+
if (Date.now() > deadline)
|
|
300
|
+
break;
|
|
264
301
|
await wait(5000);
|
|
265
302
|
}
|
|
266
303
|
if (lastError) {
|
|
267
|
-
throw new DoomainError('DOMAIN_VERIFY_FAILED', `Vercel did not verify ${opts.domain} within ${timeoutSeconds} seconds. Last Vercel response: ${errorMessage(lastError)}
|
|
304
|
+
throw new DoomainError('DOMAIN_VERIFY_FAILED', `Vercel did not verify ${opts.domain} within ${timeoutSeconds} seconds. Last Vercel response: ${errorMessage(lastError)}`, { domainConfig: lastConfig, error: errorDetails(lastError) });
|
|
305
|
+
}
|
|
306
|
+
if (lastConfig?.misconfigured === true) {
|
|
307
|
+
throw new DoomainError('DOMAIN_VERIFY_FAILED', `Vercel verified ${opts.domain}, but its DNS configuration is still invalid after ${timeoutSeconds} seconds.`, { domainConfig: lastConfig });
|
|
268
308
|
}
|
|
269
309
|
return { propagated, verified: false };
|
|
270
310
|
}
|
|
@@ -324,7 +364,17 @@ export async function linkDomain(input) {
|
|
|
324
364
|
reportProgress(input, 'dns:wait', verificationDnsRecords.length > 0 ? 'DNS records saved; asking Vercel to verify ownership' : 'DNS records saved; asking Vercel to verify');
|
|
325
365
|
}
|
|
326
366
|
const waitResult = shouldWait
|
|
327
|
-
? await waitForVercelDomainReady({
|
|
367
|
+
? await waitForVercelDomainReady({
|
|
368
|
+
domain: plan.domain,
|
|
369
|
+
force: input.force,
|
|
370
|
+
input,
|
|
371
|
+
project: plan.project,
|
|
372
|
+
provider,
|
|
373
|
+
providerId: plan.provider,
|
|
374
|
+
records,
|
|
375
|
+
zone,
|
|
376
|
+
zoneDomain: plan.zoneDomain,
|
|
377
|
+
})
|
|
328
378
|
: { propagated: false, verified: false };
|
|
329
379
|
return {
|
|
330
380
|
...plan,
|
package/oclif.manifest.json
CHANGED