@mintlify/cli 4.0.1341 → 4.0.1343
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/bin/addDomain.js +90 -0
- package/bin/cli.js +9 -0
- package/bin/constants.js +1 -0
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/addDomain.tsx +136 -0
- package/src/cli.tsx +15 -0
- package/src/constants.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mintlify/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1343",
|
|
4
4
|
"description": "The Mintlify CLI",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@inquirer/prompts": "7.9.0",
|
|
48
|
-
"@mintlify/common": "1.0.
|
|
49
|
-
"@mintlify/link-rot": "3.0.
|
|
48
|
+
"@mintlify/common": "1.0.1045",
|
|
49
|
+
"@mintlify/link-rot": "3.0.1238",
|
|
50
50
|
"@mintlify/models": "0.0.343",
|
|
51
|
-
"@mintlify/prebuild": "1.0.
|
|
52
|
-
"@mintlify/previewing": "4.0.
|
|
53
|
-
"@mintlify/validation": "0.1.
|
|
51
|
+
"@mintlify/prebuild": "1.0.1193",
|
|
52
|
+
"@mintlify/previewing": "4.0.1262",
|
|
53
|
+
"@mintlify/validation": "0.1.800",
|
|
54
54
|
"adm-zip": "0.5.16",
|
|
55
55
|
"chalk": "5.2.0",
|
|
56
56
|
"color": "4.2.3",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"keytar": "7.9.0"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@mintlify/editor": "0.0.
|
|
86
|
+
"@mintlify/editor": "0.0.251",
|
|
87
87
|
"@mintlify/ts-config": "2.0.2",
|
|
88
88
|
"@tsconfig/recommended": "1.0.2",
|
|
89
89
|
"@types/adm-zip": "0.5.7",
|
|
@@ -103,5 +103,5 @@
|
|
|
103
103
|
"vitest": "2.1.9",
|
|
104
104
|
"vitest-mock-process": "1.0.4"
|
|
105
105
|
},
|
|
106
|
-
"gitHead": "
|
|
106
|
+
"gitHead": "8abb137ebdfdba53b385f751c5fb9ac79e76dedc"
|
|
107
107
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getRelativeRecordName } from '@mintlify/common';
|
|
2
|
+
import { addLog, ErrorLog, removeLastLog, SpinnerLog, SuccessLog } from '@mintlify/previewing';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
|
|
5
|
+
import { authenticatedFetch } from './authenticatedFetch.js';
|
|
6
|
+
import { getConfigValue } from './config.js';
|
|
7
|
+
import { API_URL, CUSTOM_DOMAIN_CNAME_TARGET } from './constants.js';
|
|
8
|
+
import { getAccessToken } from './keyring.js';
|
|
9
|
+
import { getCliSubdomains } from './status.js';
|
|
10
|
+
|
|
11
|
+
interface DnsRecord {
|
|
12
|
+
type: string;
|
|
13
|
+
domain: string;
|
|
14
|
+
value: string;
|
|
15
|
+
isConfigured?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface CustomDomainCheckResponse {
|
|
19
|
+
cloudflare?: { dnsRecords?: DnsRecord[] };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const DNS_POLL_INTERVAL_MS = 5_000;
|
|
23
|
+
const DNS_POLL_MAX_ATTEMPTS = 3;
|
|
24
|
+
|
|
25
|
+
const DOMAIN_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i;
|
|
26
|
+
|
|
27
|
+
export async function addDomain(domain: string): Promise<void> {
|
|
28
|
+
if (!DOMAIN_PATTERN.test(domain)) {
|
|
29
|
+
addLog(
|
|
30
|
+
<ErrorLog
|
|
31
|
+
message={`invalid domain "${domain}". Expected a bare hostname, e.g. docs.example.com`}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const accessToken = await getAccessToken();
|
|
38
|
+
if (!accessToken) {
|
|
39
|
+
addLog(<ErrorLog message="not logged in. Run `mint login` to authenticate." />);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const subdomains = await getCliSubdomains(accessToken);
|
|
44
|
+
const configuredSubdomain = getConfigValue('subdomain');
|
|
45
|
+
const subdomain =
|
|
46
|
+
configuredSubdomain && subdomains.includes(configuredSubdomain)
|
|
47
|
+
? configuredSubdomain
|
|
48
|
+
: subdomains[0];
|
|
49
|
+
if (!subdomain) {
|
|
50
|
+
addLog(<ErrorLog message="no subdomain found. Run `mint status` to check your account." />);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const addRes = await authenticatedFetch(
|
|
56
|
+
`${API_URL}/api/cli/deployment/custom-domain/${subdomain}/${domain}`,
|
|
57
|
+
{
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'Content-Type': 'application/json' },
|
|
60
|
+
body: JSON.stringify({ basePath: '' }),
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (!addRes.ok) {
|
|
65
|
+
const body = await addRes.json().catch(() => ({}));
|
|
66
|
+
addLog(<ErrorLog message={`could not add domain: ${body.error ?? 'unknown error'}`} />);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
addLog(<ErrorLog message="could not reach the server" />);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const maxWaitSeconds = ((DNS_POLL_MAX_ATTEMPTS - 1) * DNS_POLL_INTERVAL_MS) / 1000;
|
|
75
|
+
addLog(
|
|
76
|
+
<SpinnerLog message={`waiting for DNS records to generate (up to ${maxWaitSeconds}s)...`} />
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
let dnsRecords: DnsRecord[] = [];
|
|
80
|
+
let recordsReady = false;
|
|
81
|
+
try {
|
|
82
|
+
for (let attempt = 0; attempt < DNS_POLL_MAX_ATTEMPTS; attempt++) {
|
|
83
|
+
const checkRes = await authenticatedFetch(
|
|
84
|
+
`${API_URL}/api/cli/deployment/custom-domain/${subdomain}/${domain}`
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (checkRes.ok) {
|
|
88
|
+
const body = (await checkRes.json()) as CustomDomainCheckResponse;
|
|
89
|
+
dnsRecords = body.cloudflare?.dnsRecords ?? [];
|
|
90
|
+
|
|
91
|
+
const stillGenerating = dnsRecords.some((record) => record.value === 'loading');
|
|
92
|
+
if (dnsRecords.length > 0 && !stillGenerating) {
|
|
93
|
+
recordsReady = true;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (attempt < DNS_POLL_MAX_ATTEMPTS - 1) {
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, DNS_POLL_INTERVAL_MS));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
removeLastLog();
|
|
104
|
+
addLog(<ErrorLog message="domain added, but could not fetch DNS records" />);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
removeLastLog();
|
|
109
|
+
|
|
110
|
+
const readyTxtRecords = dnsRecords.filter(
|
|
111
|
+
(record) => record.type === 'TXT' && record.value !== 'loading'
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
addLog(<SuccessLog message={`domain ${domain} added`} />);
|
|
115
|
+
addLog(
|
|
116
|
+
<Box flexDirection="column" gap={1} paddingY={1}>
|
|
117
|
+
<Text bold>Add these DNS records with your domain provider:</Text>
|
|
118
|
+
<Box flexDirection="column" paddingLeft={3}>
|
|
119
|
+
{readyTxtRecords.map((record) => (
|
|
120
|
+
<Text key={record.domain}>
|
|
121
|
+
TXT {getRelativeRecordName(record.domain, domain)} → {record.value}
|
|
122
|
+
</Text>
|
|
123
|
+
))}
|
|
124
|
+
<Text>
|
|
125
|
+
CNAME {getRelativeRecordName(domain, domain)} → {CUSTOM_DOMAIN_CNAME_TARGET}
|
|
126
|
+
</Text>
|
|
127
|
+
</Box>
|
|
128
|
+
<Text dimColor>Add the TXT records first; add the CNAME once they're validated.</Text>
|
|
129
|
+
{!recordsReady && (
|
|
130
|
+
<Text dimColor>
|
|
131
|
+
Some TXT records are still being generated. Check the dashboard in a moment for the rest.
|
|
132
|
+
</Text>
|
|
133
|
+
)}
|
|
134
|
+
</Box>
|
|
135
|
+
);
|
|
136
|
+
}
|
package/src/cli.tsx
CHANGED
|
@@ -19,6 +19,7 @@ import yargs, { type Argv } from 'yargs';
|
|
|
19
19
|
import { hideBin } from 'yargs/helpers';
|
|
20
20
|
|
|
21
21
|
import { accessibilityCheck } from './accessibilityCheck.js';
|
|
22
|
+
import { addDomain } from './addDomain.js';
|
|
22
23
|
import { comingSoon } from './comingSoon.js';
|
|
23
24
|
import { setTelemetryEnabled } from './config.js';
|
|
24
25
|
import { getConfigValue, setConfigValue, clearConfigValue } from './config.js';
|
|
@@ -470,6 +471,20 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
|
|
|
470
471
|
await terminate(0);
|
|
471
472
|
}
|
|
472
473
|
)
|
|
474
|
+
.command(
|
|
475
|
+
'add-domain <domain>',
|
|
476
|
+
'Add a custom domain to your deployment',
|
|
477
|
+
(yargs: Argv) =>
|
|
478
|
+
yargs.positional('domain', {
|
|
479
|
+
type: 'string',
|
|
480
|
+
demandOption: true,
|
|
481
|
+
description: 'The custom domain to add (e.g. docs.example.com)',
|
|
482
|
+
}),
|
|
483
|
+
async (argv) => {
|
|
484
|
+
await addDomain(argv.domain);
|
|
485
|
+
await terminate(0);
|
|
486
|
+
}
|
|
487
|
+
)
|
|
473
488
|
.command('config', 'Manage CLI configuration', (yargs) =>
|
|
474
489
|
yargs
|
|
475
490
|
.command(
|
package/src/constants.ts
CHANGED
|
@@ -31,3 +31,5 @@ const PROD_STYTCH_CLIENT_ID = 'connected-app-live-d813eedd-dbb0-434b-a1f9-2ce69e
|
|
|
31
31
|
|
|
32
32
|
export const TOKEN_ENDPOINT = IS_LOCAL_BUILD ? DEV_TOKEN_ENDPOINT : PROD_TOKEN_ENDPOINT;
|
|
33
33
|
export const STYTCH_CLIENT_ID = IS_LOCAL_BUILD ? DEV_STYTCH_CLIENT_ID : PROD_STYTCH_CLIENT_ID;
|
|
34
|
+
|
|
35
|
+
export const CUSTOM_DOMAIN_CNAME_TARGET = 'cname.mintlify.builders';
|