doomain 0.1.2 → 0.1.4
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/commands/wizard.js +4 -10
- package/dist/lib/link-domain.js +55 -5
- package/oclif.manifest.json +36 -36
- 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/commands/wizard.js
CHANGED
|
@@ -12,7 +12,6 @@ import { listGlobalVercelTokens } from '../lib/vercel-auth.js';
|
|
|
12
12
|
import { createVercelClient } from '../lib/vercel.js';
|
|
13
13
|
const PERSONAL_ACCOUNT = '__personal__';
|
|
14
14
|
const NEW_TOKEN = '__new_token__';
|
|
15
|
-
const SAVED_TOKEN = '__saved_token__';
|
|
16
15
|
function cancelIfNeeded(value) {
|
|
17
16
|
if (p.isCancel(value)) {
|
|
18
17
|
p.cancel('Cancelled');
|
|
@@ -111,23 +110,18 @@ function teamLabel(team) {
|
|
|
111
110
|
function globalTokenLabel(token) {
|
|
112
111
|
return token.source === 'environment' ? `Use ${token.label}` : `Use ${token.label} token`;
|
|
113
112
|
}
|
|
114
|
-
async function promptVercelToken(globalTokens
|
|
113
|
+
async function promptVercelToken(globalTokens) {
|
|
115
114
|
if (globalTokens.length > 0) {
|
|
116
115
|
const selected = await p.select({
|
|
117
116
|
message: 'Vercel token',
|
|
118
117
|
options: [
|
|
119
118
|
...globalTokens.map((token, index) => ({ label: globalTokenLabel(token), value: String(index), hint: maskSecret(token.token) })),
|
|
120
|
-
...(savedToken && !globalTokens.some((token) => token.token === savedToken)
|
|
121
|
-
? [{ label: 'Use saved Doomain token', value: SAVED_TOKEN, hint: maskSecret(savedToken) }]
|
|
122
|
-
: []),
|
|
123
119
|
{ label: 'Enter a new token', value: NEW_TOKEN },
|
|
124
120
|
],
|
|
125
121
|
});
|
|
126
122
|
const resolved = cancelIfNeeded(selected);
|
|
127
123
|
if (resolved === null)
|
|
128
124
|
return null;
|
|
129
|
-
if (resolved === SAVED_TOKEN)
|
|
130
|
-
return savedToken ?? null;
|
|
131
125
|
if (resolved !== NEW_TOKEN)
|
|
132
126
|
return globalTokens[Number(resolved)]?.token ?? null;
|
|
133
127
|
}
|
|
@@ -156,13 +150,13 @@ export default class Wizard extends Command {
|
|
|
156
150
|
const config = await loadConfig();
|
|
157
151
|
const providerDefinitions = listProviderDefinitions();
|
|
158
152
|
const localProject = detectLocalVercelProject();
|
|
159
|
-
const globalVercelTokens = await listGlobalVercelTokens();
|
|
160
153
|
let vercelToken = config.vercel?.token;
|
|
161
154
|
let vercelTeamId = process.env.VERCEL_TEAM_ID || localProject?.orgId || config.vercel?.teamId;
|
|
162
155
|
const defaultProvider = process.env.DOOMAIN_PROVIDER || config.defaults?.provider;
|
|
163
156
|
const defaultDomain = process.env.DOOMAIN_DOMAIN || config.defaults?.domain;
|
|
164
|
-
if (
|
|
165
|
-
|
|
157
|
+
if (!vercelToken) {
|
|
158
|
+
const globalVercelTokens = await listGlobalVercelTokens();
|
|
159
|
+
vercelToken = (await promptVercelToken(globalVercelTokens)) ?? undefined;
|
|
166
160
|
if (!vercelToken)
|
|
167
161
|
return;
|
|
168
162
|
}
|
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
|
@@ -300,41 +300,6 @@
|
|
|
300
300
|
"list.js"
|
|
301
301
|
]
|
|
302
302
|
},
|
|
303
|
-
"projects:list": {
|
|
304
|
-
"aliases": [],
|
|
305
|
-
"args": {},
|
|
306
|
-
"description": "List Vercel projects.",
|
|
307
|
-
"flags": {
|
|
308
|
-
"json": {
|
|
309
|
-
"description": "Output a single JSON object and never prompt.",
|
|
310
|
-
"name": "json",
|
|
311
|
-
"allowNo": false,
|
|
312
|
-
"type": "boolean"
|
|
313
|
-
},
|
|
314
|
-
"search": {
|
|
315
|
-
"description": "Filter projects by search term.",
|
|
316
|
-
"name": "search",
|
|
317
|
-
"hasDynamicHelp": false,
|
|
318
|
-
"multiple": false,
|
|
319
|
-
"type": "option"
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
"hasDynamicHelp": false,
|
|
323
|
-
"hiddenAliases": [],
|
|
324
|
-
"id": "projects:list",
|
|
325
|
-
"pluginAlias": "doomain",
|
|
326
|
-
"pluginName": "doomain",
|
|
327
|
-
"pluginType": "core",
|
|
328
|
-
"strict": true,
|
|
329
|
-
"enableJsonFlag": false,
|
|
330
|
-
"isESM": true,
|
|
331
|
-
"relativePath": [
|
|
332
|
-
"dist",
|
|
333
|
-
"commands",
|
|
334
|
-
"projects",
|
|
335
|
-
"list.js"
|
|
336
|
-
]
|
|
337
|
-
},
|
|
338
303
|
"providers:add": {
|
|
339
304
|
"aliases": [],
|
|
340
305
|
"args": {
|
|
@@ -595,6 +560,41 @@
|
|
|
595
560
|
"verify.js"
|
|
596
561
|
]
|
|
597
562
|
},
|
|
563
|
+
"projects:list": {
|
|
564
|
+
"aliases": [],
|
|
565
|
+
"args": {},
|
|
566
|
+
"description": "List Vercel projects.",
|
|
567
|
+
"flags": {
|
|
568
|
+
"json": {
|
|
569
|
+
"description": "Output a single JSON object and never prompt.",
|
|
570
|
+
"name": "json",
|
|
571
|
+
"allowNo": false,
|
|
572
|
+
"type": "boolean"
|
|
573
|
+
},
|
|
574
|
+
"search": {
|
|
575
|
+
"description": "Filter projects by search term.",
|
|
576
|
+
"name": "search",
|
|
577
|
+
"hasDynamicHelp": false,
|
|
578
|
+
"multiple": false,
|
|
579
|
+
"type": "option"
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
"hasDynamicHelp": false,
|
|
583
|
+
"hiddenAliases": [],
|
|
584
|
+
"id": "projects:list",
|
|
585
|
+
"pluginAlias": "doomain",
|
|
586
|
+
"pluginName": "doomain",
|
|
587
|
+
"pluginType": "core",
|
|
588
|
+
"strict": true,
|
|
589
|
+
"enableJsonFlag": false,
|
|
590
|
+
"isESM": true,
|
|
591
|
+
"relativePath": [
|
|
592
|
+
"dist",
|
|
593
|
+
"commands",
|
|
594
|
+
"projects",
|
|
595
|
+
"list.js"
|
|
596
|
+
]
|
|
597
|
+
},
|
|
598
598
|
"auth:logout:vercel": {
|
|
599
599
|
"aliases": [],
|
|
600
600
|
"args": {},
|
|
@@ -629,5 +629,5 @@
|
|
|
629
629
|
]
|
|
630
630
|
}
|
|
631
631
|
},
|
|
632
|
-
"version": "0.1.
|
|
632
|
+
"version": "0.1.4"
|
|
633
633
|
}
|