@mintlify/cli 4.0.1098 → 4.0.1100
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/__test__/analytics/client.test.ts +28 -20
- package/__test__/analytics/format.test.ts +9 -14
- package/__test__/authenticatedFetch.test.ts +182 -0
- package/__test__/keyring.test.ts +7 -0
- package/__test__/telemetry.test.ts +2 -2
- package/bin/analytics/client.js +3 -20
- package/bin/analytics/index.js +24 -39
- package/bin/analytics/output.js +3 -2
- package/bin/authenticatedFetch.js +46 -0
- package/bin/cli.js +5 -5
- package/bin/keyring.js +6 -0
- package/bin/login.js +42 -2
- package/bin/middlewares/subdomainMiddleware.js +28 -0
- package/bin/{telemetry/middleware.js → middlewares/telemetryMiddleware.js} +1 -1
- package/bin/status.js +10 -12
- package/bin/tokenRefresh.js +50 -0
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/analytics/client.ts +3 -20
- package/src/analytics/index.tsx +28 -43
- package/src/analytics/output.ts +4 -2
- package/src/authenticatedFetch.ts +42 -0
- package/src/cli.tsx +3 -3
- package/src/keyring.ts +5 -0
- package/src/login.tsx +48 -2
- package/src/middlewares/subdomainMiddleware.ts +16 -0
- package/src/{telemetry/middleware.ts → middlewares/telemetryMiddleware.ts} +1 -1
- package/src/status.tsx +9 -10
- package/src/tokenRefresh.ts +48 -0
package/bin/cli.js
CHANGED
|
@@ -27,9 +27,9 @@ import { getAccessToken } from './keyring.js';
|
|
|
27
27
|
import { login } from './login.js';
|
|
28
28
|
import { logout } from './logout.js';
|
|
29
29
|
import { mdxLinter } from './mdxLinter.js';
|
|
30
|
+
import { createTelemetryMiddleware } from './middlewares/telemetryMiddleware.js';
|
|
30
31
|
import { checkOpenApiFile, getOpenApiFilenamesFromDocsConfig } from './openApiCheck.js';
|
|
31
|
-
import { status,
|
|
32
|
-
import { createTelemetryMiddleware } from './telemetry/middleware.js';
|
|
32
|
+
import { status, getCliSubdomains } from './status.js';
|
|
33
33
|
import { trackTelemetryPreferenceChange } from './telemetry/track.js';
|
|
34
34
|
import { update } from './update.js';
|
|
35
35
|
import { addWorkflow } from './workflow.js';
|
|
@@ -89,7 +89,7 @@ export const cli = ({ packageName = 'mint' }) => {
|
|
|
89
89
|
.usage('usage: mintlify dev [options]')
|
|
90
90
|
.example('mintlify dev', 'run with default settings (opens in browser)')
|
|
91
91
|
.example('mintlify dev --no-open', 'run without opening in browser'), (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
|
92
|
-
var _a
|
|
92
|
+
var _a;
|
|
93
93
|
yield autoUpgradeIfNeeded();
|
|
94
94
|
const port = yield checkPort(argv);
|
|
95
95
|
const { cli: cliVersion } = getVersions();
|
|
@@ -99,9 +99,9 @@ export const cli = ({ packageName = 'mint' }) => {
|
|
|
99
99
|
accessToken = (_a = (yield getAccessToken())) !== null && _a !== void 0 ? _a : undefined;
|
|
100
100
|
const configuredSubdomain = getConfigValue('subdomain');
|
|
101
101
|
subdomain =
|
|
102
|
-
configuredSubdomain !== null && configuredSubdomain !== void 0 ? configuredSubdomain : (accessToken ? (
|
|
102
|
+
configuredSubdomain !== null && configuredSubdomain !== void 0 ? configuredSubdomain : (accessToken ? (yield getCliSubdomains(accessToken))[0] : undefined);
|
|
103
103
|
}
|
|
104
|
-
catch (
|
|
104
|
+
catch (_b) { }
|
|
105
105
|
if (port != undefined) {
|
|
106
106
|
yield dev(Object.assign(Object.assign({}, argv), { port,
|
|
107
107
|
packageName,
|
package/bin/keyring.js
CHANGED
|
@@ -38,6 +38,12 @@ export function getAccessToken() {
|
|
|
38
38
|
return keytar.getPassword(SERVICE, ACCESS_TOKEN_ACCOUNT);
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
export function getRefreshToken() {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
const keytar = yield getKeytar();
|
|
44
|
+
return keytar.getPassword(SERVICE, REFRESH_TOKEN_ACCOUNT);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
41
47
|
export function clearCredentials() {
|
|
42
48
|
return __awaiter(this, void 0, void 0, function* () {
|
|
43
49
|
const keytar = yield getKeytar();
|
package/bin/login.js
CHANGED
|
@@ -8,15 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
import { input } from '@inquirer/prompts';
|
|
12
|
-
import { addLog, ErrorLog, SuccessLog } from '@mintlify/previewing';
|
|
11
|
+
import { input, search } from '@inquirer/prompts';
|
|
12
|
+
import { addLog, ErrorLog, InfoLog, SuccessLog } from '@mintlify/previewing';
|
|
13
13
|
import chalk from 'chalk';
|
|
14
14
|
import { Box, Text } from 'ink';
|
|
15
15
|
import open from 'open';
|
|
16
16
|
import { calculatePKCECodeChallenge, randomNonce, randomPKCECodeVerifier, randomState, } from 'openid-client';
|
|
17
17
|
import { startCallbackServer } from './callbackServer.js';
|
|
18
|
+
import { setConfigValue } from './config.js';
|
|
18
19
|
import { DASHBOARD_URL, STYTCH_CLIENT_ID, TOKEN_ENDPOINT } from './constants.js';
|
|
19
20
|
import { storeCredentials } from './keyring.js';
|
|
21
|
+
import { getCliSubdomains } from './status.js';
|
|
20
22
|
import { trackLoginAttempt, trackLoginFailed, trackLoginSuccess } from './telemetry/track.js';
|
|
21
23
|
export function login() {
|
|
22
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -80,5 +82,43 @@ export function login() {
|
|
|
80
82
|
yield storeCredentials(token.access_token, token.refresh_token);
|
|
81
83
|
void trackLoginSuccess();
|
|
82
84
|
addLog(_jsx(SuccessLog, { message: "logged in successfully" }));
|
|
85
|
+
yield promptSubdomainSelection(token.access_token);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function isPromptCancellationError(error) {
|
|
89
|
+
return error instanceof Error && error.name === 'ExitPromptError';
|
|
90
|
+
}
|
|
91
|
+
function promptSubdomainSelection(accessToken) {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
const subdomains = yield getCliSubdomains(accessToken);
|
|
94
|
+
if (subdomains.length === 0)
|
|
95
|
+
return;
|
|
96
|
+
if (subdomains.length === 1) {
|
|
97
|
+
yield setConfigValue('subdomain', subdomains[0]);
|
|
98
|
+
addLog(_jsx(InfoLog, { message: `default project set to ${subdomains[0]}` }));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
yield new Promise((resolve) => setTimeout(resolve, 50));
|
|
102
|
+
let chosen;
|
|
103
|
+
try {
|
|
104
|
+
chosen = yield search({
|
|
105
|
+
message: 'Select a default project',
|
|
106
|
+
source: (term) => {
|
|
107
|
+
const results = term
|
|
108
|
+
? subdomains.filter((s) => s.toLowerCase().includes(term.toLowerCase()))
|
|
109
|
+
: subdomains;
|
|
110
|
+
return results.map((s) => ({ name: s, value: s }));
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (isPromptCancellationError(error)) {
|
|
116
|
+
addLog(_jsx(InfoLog, { message: `No project set. To set a default project, run ${chalk.bold('mintlify config set subdomain <subdomain>')}` }));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
yield setConfigValue('subdomain', chosen);
|
|
122
|
+
addLog(_jsx(InfoLog, { message: `default project set to ${chosen}` }));
|
|
83
123
|
});
|
|
84
124
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { getConfigValue } from '../config.js';
|
|
11
|
+
import { getAccessToken } from '../keyring.js';
|
|
12
|
+
import { getCliSubdomains } from '../status.js';
|
|
13
|
+
export function subdomainMiddleware(argv) {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
if (argv.subdomain)
|
|
16
|
+
return;
|
|
17
|
+
const fromConfig = getConfigValue('subdomain');
|
|
18
|
+
if (fromConfig) {
|
|
19
|
+
argv.subdomain = fromConfig;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const accessToken = yield getAccessToken();
|
|
23
|
+
if (!accessToken)
|
|
24
|
+
return;
|
|
25
|
+
const subdomains = yield getCliSubdomains(accessToken);
|
|
26
|
+
argv.subdomain = subdomains[0];
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { getConfigValue } from '../config.js';
|
|
11
11
|
import { getVersions } from '../helpers.js';
|
|
12
|
-
import { trackCommand } from '
|
|
12
|
+
import { trackCommand } from '../telemetry/track.js';
|
|
13
13
|
const SCRAPE_SUBCOMMANDS = new Set(['page', 'site', 'openapi']);
|
|
14
14
|
export function getSanitizedCommandForTelemetry(_) {
|
|
15
15
|
const parts = _.filter((p) => typeof p === 'string');
|
package/bin/status.js
CHANGED
|
@@ -11,6 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
import { addLog, ErrorLog } from '@mintlify/previewing';
|
|
12
12
|
import { Box, Text } from 'ink';
|
|
13
13
|
import { z } from 'zod';
|
|
14
|
+
import { authenticatedFetch } from './authenticatedFetch.js';
|
|
14
15
|
import { getConfigValue } from './config.js';
|
|
15
16
|
import { API_URL } from './constants.js';
|
|
16
17
|
import { getCliVersion } from './helpers.js';
|
|
@@ -18,23 +19,22 @@ import { getAccessToken } from './keyring.js';
|
|
|
18
19
|
const StatusResponseSchema = z.object({
|
|
19
20
|
user: z.object({ email: z.string() }),
|
|
20
21
|
org: z.object({ name: z.string() }),
|
|
21
|
-
|
|
22
|
+
subdomains: z.array(z.string()).default([]),
|
|
22
23
|
});
|
|
23
|
-
export function
|
|
24
|
+
export function getCliSubdomains(accessToken) {
|
|
24
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
var _a;
|
|
26
26
|
try {
|
|
27
27
|
const res = yield fetch(`${API_URL}/api/cli/status`, {
|
|
28
28
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
29
29
|
});
|
|
30
30
|
if (!res.ok)
|
|
31
|
-
return
|
|
31
|
+
return [];
|
|
32
32
|
const json = yield res.json().catch(() => null);
|
|
33
33
|
const parsed = StatusResponseSchema.safeParse(json);
|
|
34
|
-
return parsed.success ?
|
|
34
|
+
return parsed.success ? parsed.data.subdomains : [];
|
|
35
35
|
}
|
|
36
|
-
catch (
|
|
37
|
-
return
|
|
36
|
+
catch (_a) {
|
|
37
|
+
return [];
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
}
|
|
@@ -47,9 +47,7 @@ export function status() {
|
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
try {
|
|
50
|
-
const res = yield
|
|
51
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
52
|
-
});
|
|
50
|
+
const res = yield authenticatedFetch(`${API_URL}/api/cli/status`);
|
|
53
51
|
if (!res.ok) {
|
|
54
52
|
addLog(_jsx(ErrorLog, { message: "not logged in. Run `mint login` to authenticate." }));
|
|
55
53
|
return;
|
|
@@ -60,9 +58,9 @@ export function status() {
|
|
|
60
58
|
addLog(_jsx(ErrorLog, { message: "unexpected response from server. please try again." }));
|
|
61
59
|
return;
|
|
62
60
|
}
|
|
63
|
-
const { user, org,
|
|
61
|
+
const { user, org, subdomains } = parsed.data;
|
|
64
62
|
const version = getCliVersion();
|
|
65
|
-
const subdomain = (_b = (_a = getConfigValue('subdomain')) !== null && _a !== void 0 ? _a :
|
|
63
|
+
const subdomain = (_b = (_a = getConfigValue('subdomain')) !== null && _a !== void 0 ? _a : subdomains[0]) !== null && _b !== void 0 ? _b : null;
|
|
66
64
|
addLog(_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [version && (_jsxs(Box, { children: [_jsx(Box, { minWidth: 16, children: _jsx(Text, { dimColor: true, children: "Version" }) }), _jsx(Text, { children: version })] })), _jsxs(Box, { children: [_jsx(Box, { minWidth: 16, children: _jsx(Text, { dimColor: true, children: "Email" }) }), _jsx(Text, { children: user.email })] }), _jsxs(Box, { children: [_jsx(Box, { minWidth: 16, children: _jsx(Text, { dimColor: true, children: "Organization" }) }), _jsx(Text, { children: org.name })] }), subdomain && (_jsxs(Box, { children: [_jsx(Box, { minWidth: 16, children: _jsx(Text, { dimColor: true, children: "Subdomain" }) }), _jsx(Text, { children: subdomain })] }))] }));
|
|
67
65
|
}
|
|
68
66
|
catch (e) {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { STYTCH_CLIENT_ID, TOKEN_ENDPOINT } from './constants.js';
|
|
11
|
+
import { getRefreshToken, storeCredentials } from './keyring.js';
|
|
12
|
+
let inflightRefresh = null;
|
|
13
|
+
export function refreshAccessToken() {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
if (inflightRefresh)
|
|
16
|
+
return inflightRefresh;
|
|
17
|
+
inflightRefresh = doRefresh().finally(() => {
|
|
18
|
+
inflightRefresh = null;
|
|
19
|
+
});
|
|
20
|
+
return inflightRefresh;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function doRefresh() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
try {
|
|
26
|
+
const refreshToken = yield getRefreshToken();
|
|
27
|
+
if (!refreshToken)
|
|
28
|
+
return null;
|
|
29
|
+
const res = yield fetch(TOKEN_ENDPOINT, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
client_id: STYTCH_CLIENT_ID,
|
|
34
|
+
grant_type: 'refresh_token',
|
|
35
|
+
refresh_token: refreshToken,
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
if (!res.ok)
|
|
39
|
+
return null;
|
|
40
|
+
const body = (yield res.json().catch(() => null));
|
|
41
|
+
if (!(body === null || body === void 0 ? void 0 : body.access_token) || !body.refresh_token)
|
|
42
|
+
return null;
|
|
43
|
+
yield storeCredentials(body.access_token, body.refresh_token);
|
|
44
|
+
return body.access_token;
|
|
45
|
+
}
|
|
46
|
+
catch (_a) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|