@myapihq/cli 1.2.0 → 1.2.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/dist/commands/domain.d.ts +1 -0
- package/dist/commands/domain.js +99 -7
- package/dist/index.js +0 -0
- package/package.json +2 -2
- package/dist/commands/verify.d.ts +0 -7
- package/dist/commands/verify.js +0 -56
|
@@ -5,6 +5,7 @@ export declare const EXPOSES: Exposes;
|
|
|
5
5
|
export declare const SCHEMA: FlagSchema;
|
|
6
6
|
export declare function check(domainArg: string, flags: Flags): Promise<void>;
|
|
7
7
|
export declare function register(domainArg: string, flags: Flags): Promise<void>;
|
|
8
|
+
export declare function importCmd(domainArg: string, flags: Flags): Promise<void>;
|
|
8
9
|
export declare function renew(domainArg: string, flags: Flags): Promise<void>;
|
|
9
10
|
export declare function list(flags: Flags): Promise<void>;
|
|
10
11
|
export declare function assign(domainArg: string, flags: Flags): Promise<void>;
|
package/dist/commands/domain.js
CHANGED
|
@@ -23,6 +23,8 @@ export const SCHEMA = {
|
|
|
23
23
|
security: 'string',
|
|
24
24
|
'browser-check': 'string',
|
|
25
25
|
'purge-cache': 'boolean',
|
|
26
|
+
// Poll `status` until the domain reaches a terminal state.
|
|
27
|
+
'watch': 'boolean',
|
|
26
28
|
// WHOIS registrant — required by ICANN at register time. Resolution
|
|
27
29
|
// order is JSON > per-field flags > stored config > TTY prompt > error.
|
|
28
30
|
// See packages/cli/src/registrant.ts for the full flow.
|
|
@@ -78,6 +80,41 @@ export async function register(domainArg, flags) {
|
|
|
78
80
|
}
|
|
79
81
|
// Renew a registered domain for one more registration period (typically 1 year).
|
|
80
82
|
// Charged against the org's billing balance — surface a confirmation unless --yes.
|
|
83
|
+
// BYOD: snapshot existing DNS records, create a CF zone, hand back the NS
|
|
84
|
+
// values the customer needs to set at their current registrar. No registrar
|
|
85
|
+
// credentials needed — backend is registrar-agnostic now.
|
|
86
|
+
export async function importCmd(domainArg, flags) {
|
|
87
|
+
const config = requireConfig();
|
|
88
|
+
const orgId = requireOrg(flags, config, 'myapi domain import <domain> [--org <id>]');
|
|
89
|
+
if (!domainArg)
|
|
90
|
+
error('Missing required arguments.\nUsage: myapi domain import <domain> [--org <id>]');
|
|
91
|
+
const res = await sdkDomain.importDomain(config.api_key, orgId, domainArg);
|
|
92
|
+
if (flags.json) {
|
|
93
|
+
printJson(res);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
success(`Imported ${res.domain} (status: ${res.status})`);
|
|
97
|
+
info('');
|
|
98
|
+
info(`Nameservers (set these at your current registrar):`);
|
|
99
|
+
for (const ns of res.nameservers)
|
|
100
|
+
info(` ${ns}`);
|
|
101
|
+
info('');
|
|
102
|
+
if (res.preserved_records.length > 0) {
|
|
103
|
+
info(`Preserved DNS records (${res.preserved_count} found — verify before the NS change):`);
|
|
104
|
+
printTable(res.preserved_records.map(r => ({ type: r.type, name: r.name, content: r.content, ttl: r.ttl })), { flags });
|
|
105
|
+
info('');
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
info(`No DNS records detected via public probe — verify directly with your registrar before the NS change.`);
|
|
109
|
+
info('');
|
|
110
|
+
}
|
|
111
|
+
info(res.probe_warning);
|
|
112
|
+
info('');
|
|
113
|
+
info(res.next_step);
|
|
114
|
+
info('');
|
|
115
|
+
info(`After changing nameservers, watch activation with:`);
|
|
116
|
+
info(` myapi domain status ${res.domain} --watch`);
|
|
117
|
+
}
|
|
81
118
|
export async function renew(domainArg, flags) {
|
|
82
119
|
const config = requireConfig();
|
|
83
120
|
const orgId = requireOrg(flags, config, 'myapi domain renew <domain> [--yes] [--org <id>]');
|
|
@@ -124,21 +161,55 @@ export async function unassign(domainArg, flags) {
|
|
|
124
161
|
await sdkDomain.unassignDomain(config.api_key, orgId, domainArg);
|
|
125
162
|
success(`Unassigned ${domainArg} from org ${orgId}`);
|
|
126
163
|
}
|
|
164
|
+
// Terminal states — stop polling under --watch.
|
|
165
|
+
const TERMINAL_STATUSES = new Set(['active', 'failed', 'error', 'expired']);
|
|
127
166
|
export async function status(domainArg, flags) {
|
|
128
167
|
const config = requireConfig();
|
|
129
|
-
const orgId = requireOrg(flags, config, 'myapi domain status <domain> [--org <id>]');
|
|
130
|
-
const domain = requireDomain(domainArg, flags, config, 'myapi domain status <domain> [--org <id>]');
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
168
|
+
const orgId = requireOrg(flags, config, 'myapi domain status <domain> [--org <id>] [--watch]');
|
|
169
|
+
const domain = requireDomain(domainArg, flags, config, 'myapi domain status <domain> [--org <id>] [--watch]');
|
|
170
|
+
if (!flags.watch) {
|
|
171
|
+
const res = await sdkDomain.getDomainStatus(config.api_key, orgId, domain);
|
|
172
|
+
if (flags.json) {
|
|
173
|
+
printJson(res);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
renderStatus(res);
|
|
134
177
|
return;
|
|
135
178
|
}
|
|
179
|
+
// Watch mode: 10s × 30 (5 min), then 30s × 60 (30 min). Total ~35 min budget.
|
|
180
|
+
// Backend live-checks CF on each poll for `pending_ns_change` rows, so polling
|
|
181
|
+
// both reports state AND triggers the flip to `provisioning`.
|
|
182
|
+
let lastStatus = '';
|
|
183
|
+
const schedule = [
|
|
184
|
+
{ count: 30, intervalMs: 10_000 },
|
|
185
|
+
{ count: 60, intervalMs: 30_000 },
|
|
186
|
+
];
|
|
187
|
+
info(`Watching ${domain} — press Ctrl-C to stop.`);
|
|
188
|
+
for (const phase of schedule) {
|
|
189
|
+
for (let i = 0; i < phase.count; i++) {
|
|
190
|
+
const res = await sdkDomain.getDomainStatus(config.api_key, orgId, domain);
|
|
191
|
+
if (res.status !== lastStatus) {
|
|
192
|
+
renderStatus(res);
|
|
193
|
+
lastStatus = res.status;
|
|
194
|
+
}
|
|
195
|
+
if (TERMINAL_STATUSES.has(res.status))
|
|
196
|
+
return;
|
|
197
|
+
await new Promise(r => setTimeout(r, phase.intervalMs));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
info(`Watch budget exhausted (~35 min). Rerun "myapi domain status ${domain} --watch" to keep waiting.`);
|
|
201
|
+
}
|
|
202
|
+
function renderStatus(res) {
|
|
136
203
|
info(`Domain: ${res.domain}`);
|
|
137
204
|
info(`Status: ${res.status}`);
|
|
138
205
|
if (res.expires_at)
|
|
139
206
|
info(`Expires: ${formatDate(res.expires_at)}`);
|
|
140
|
-
if (res.status === '
|
|
207
|
+
if (res.status === 'pending_ns_change') {
|
|
208
|
+
info('Waiting for you to change nameservers at your current registrar. Each poll re-checks Cloudflare.');
|
|
209
|
+
}
|
|
210
|
+
if (res.status === 'active') {
|
|
141
211
|
info('Note: if recently activated, the SSL certificate may still be provisioning — allow a few minutes before the site is reachable over HTTPS.');
|
|
212
|
+
}
|
|
142
213
|
}
|
|
143
214
|
export async function settings(domainArg, flags) {
|
|
144
215
|
const config = requireConfig();
|
|
@@ -203,6 +274,20 @@ Registrant (required at every register call):
|
|
|
203
274
|
|
|
204
275
|
After registering: myapi domain assign <domain>
|
|
205
276
|
DNS propagation takes a few minutes — track it with: myapi domain status <domain>`,
|
|
277
|
+
'import': `myapi domain import <domain> [--org <id>] [--json]
|
|
278
|
+
|
|
279
|
+
Bring your own domain (BYOD). Snapshots existing DNS records via a best-effort
|
|
280
|
+
public probe and creates a Cloudflare zone for the domain. Returns the
|
|
281
|
+
nameservers you need to set at your current registrar.
|
|
282
|
+
|
|
283
|
+
No registrar credentials needed — works with any registrar (Namecheap, GoDaddy,
|
|
284
|
+
Cloudflare Registrar, etc.).
|
|
285
|
+
|
|
286
|
+
After running:
|
|
287
|
+
1. Verify the preserved-records table covers your MX/SPF/DKIM/DMARC etc.
|
|
288
|
+
2. At your current registrar, change the nameservers to the values returned.
|
|
289
|
+
3. Wait for propagation. Use "myapi domain status <domain> --watch" to track
|
|
290
|
+
activation — the backend live-checks Cloudflare each time you poll.`,
|
|
206
291
|
'renew': `myapi domain renew <domain> [--org <id>]
|
|
207
292
|
|
|
208
293
|
Renews a registered domain for one more registration period (typically 1 year).
|
|
@@ -217,7 +302,12 @@ https://<domain> after DNS propagation completes.
|
|
|
217
302
|
|
|
218
303
|
To transfer to a different org: unassign first, then assign to the new org.`,
|
|
219
304
|
'unassign': 'myapi domain unassign <domain> [--org <id>]',
|
|
220
|
-
'status':
|
|
305
|
+
'status': `myapi domain status <domain> [--org <id>] [--watch] [--json]
|
|
306
|
+
|
|
307
|
+
--watch Poll until the domain reaches a terminal state (active / failed /
|
|
308
|
+
expired). Backoff: 10s × 30 then 30s × 60 (~35 min budget). Useful
|
|
309
|
+
after "myapi domain import" — each poll also live-checks Cloudflare,
|
|
310
|
+
so polling drives the flip from pending_ns_change → provisioning.`,
|
|
221
311
|
'settings': `myapi domain settings <domain> [--org <id>]
|
|
222
312
|
|
|
223
313
|
Gets current edge/CDN settings (security level, browser check, cache).
|
|
@@ -239,6 +329,7 @@ Subcommands:
|
|
|
239
329
|
list List domains
|
|
240
330
|
check Check domain availability
|
|
241
331
|
register Register a domain
|
|
332
|
+
import Bring your own domain (BYOD) — registrar-agnostic
|
|
242
333
|
renew Renew a registered domain for another period
|
|
243
334
|
assign Assign domain to an org
|
|
244
335
|
unassign Unassign domain from its current org
|
|
@@ -261,6 +352,7 @@ Tip: Set defaults with "myapi config set-org <id>" / "set-domain <domain>" to sk
|
|
|
261
352
|
case 'list': return list(flags);
|
|
262
353
|
case 'check': return check(args[0], flags);
|
|
263
354
|
case 'register': return register(args[0], flags);
|
|
355
|
+
case 'import': return importCmd(args[0], flags);
|
|
264
356
|
case 'renew': return renew(args[0], flags);
|
|
265
357
|
case 'assign': return assign(args[0], flags);
|
|
266
358
|
case 'unassign': return unassign(args[0], flags);
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myapihq/cli",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"description": "MyAPI command-line interface",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"lint:changelog": "node ../../scripts/lint-changelog.js"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@myapihq/sdk": "^1.2.
|
|
30
|
+
"@myapihq/sdk": "^1.2.1",
|
|
31
31
|
"omelette": "^0.4.17"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { FlagSchema } from '../flags.js';
|
|
2
|
-
import { type Flags } from '../helpers.js';
|
|
3
|
-
import type { Exposes } from '../exposes.js';
|
|
4
|
-
export declare const EXPOSES: Exposes;
|
|
5
|
-
export declare const SCHEMA: FlagSchema;
|
|
6
|
-
export declare const VERIFY_HELP = "Usage: myapi verify <email> [--org <id>] [--json]\n\nSync single-address email verification. Cheap layer only: syntax + DNS +\nMicrosoft GetCredentialType. Returns a verdict in <1s for ~50% of inputs;\nthe rest get verdict='unknown' with smtp_recommended=true.\n\nVerdicts:\n deliverable high-confidence \u2014 the address accepts mail\n undeliverable high-confidence \u2014 syntax bad, DNS missing, or Microsoft rejects\n unknown not enough signal; consider an SMTP probe (not in this API)\n\nUse --json for the full check breakdown (syntax / DNS / Microsoft probes).\n";
|
|
7
|
-
export declare function run(arg: string | undefined, _rest: string[], flags?: Flags): Promise<void>;
|
package/dist/commands/verify.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { email as sdkEmail } from '@myapihq/sdk';
|
|
2
|
-
import { requireConfig } from '../config.js';
|
|
3
|
-
import { error, info, printJson } from '../output.js';
|
|
4
|
-
import { requireOrg } from '../helpers.js';
|
|
5
|
-
export const EXPOSES = [
|
|
6
|
-
'POST /email/orgs/{org_id}/verify',
|
|
7
|
-
];
|
|
8
|
-
export const SCHEMA = {
|
|
9
|
-
org: 'string',
|
|
10
|
-
};
|
|
11
|
-
export const VERIFY_HELP = `Usage: myapi verify <email> [--org <id>] [--json]
|
|
12
|
-
|
|
13
|
-
Sync single-address email verification. Cheap layer only: syntax + DNS +
|
|
14
|
-
Microsoft GetCredentialType. Returns a verdict in <1s for ~50% of inputs;
|
|
15
|
-
the rest get verdict='unknown' with smtp_recommended=true.
|
|
16
|
-
|
|
17
|
-
Verdicts:
|
|
18
|
-
deliverable high-confidence — the address accepts mail
|
|
19
|
-
undeliverable high-confidence — syntax bad, DNS missing, or Microsoft rejects
|
|
20
|
-
unknown not enough signal; consider an SMTP probe (not in this API)
|
|
21
|
-
|
|
22
|
-
Use --json for the full check breakdown (syntax / DNS / Microsoft probes).
|
|
23
|
-
`;
|
|
24
|
-
export async function run(arg, _rest, flags = {}) {
|
|
25
|
-
if (flags.help) {
|
|
26
|
-
info(VERIFY_HELP);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
if (!arg)
|
|
30
|
-
error('Missing required argument <email>.\nUsage: myapi verify <email> [--org <id>] [--json]');
|
|
31
|
-
const config = requireConfig();
|
|
32
|
-
const orgId = requireOrg(flags, config, 'myapi verify <email> [--org <id>]');
|
|
33
|
-
const res = await sdkEmail.verifyEmail(config.api_key, orgId, arg);
|
|
34
|
-
if (flags.json) {
|
|
35
|
-
printJson(res);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
// Compact human render. The verdict + confidence is the headline; the
|
|
39
|
-
// checks block is verbose enough that we hide it behind --json.
|
|
40
|
-
const verdictLabel = res.verdict === 'deliverable' ? '✓ deliverable'
|
|
41
|
-
: res.verdict === 'undeliverable' ? '✗ undeliverable'
|
|
42
|
-
: '? unknown';
|
|
43
|
-
info(`Email: ${res.email}`);
|
|
44
|
-
info(`Verdict: ${verdictLabel} (confidence ${res.confidence.toFixed(2)})`);
|
|
45
|
-
info(`SMTP next: ${res.smtp_recommended ? 'yes — consider an SMTP probe' : 'no — verdict is definitive'}`);
|
|
46
|
-
info(`Took: ${res.elapsed_ms}ms`);
|
|
47
|
-
if (res.checks.syntax.detail)
|
|
48
|
-
info(`Syntax: ${res.checks.syntax.detail}`);
|
|
49
|
-
if (res.checks.dns && res.checks.dns.mx_records && res.checks.dns.mx_records.length > 0) {
|
|
50
|
-
const mx = res.checks.dns.mx_records.filter(Boolean);
|
|
51
|
-
if (mx.length > 0)
|
|
52
|
-
info(`MX: ${mx.slice(0, 3).join(', ')}${mx.length > 3 ? ` (+${mx.length - 3} more)` : ''}`);
|
|
53
|
-
}
|
|
54
|
-
if (res.checks.microsoft)
|
|
55
|
-
info(`Microsoft: ${res.checks.microsoft.verdict}`);
|
|
56
|
-
}
|