@mintlify/cli 4.0.1069 → 4.0.1070

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/cli",
3
- "version": "4.0.1069",
3
+ "version": "4.0.1070",
4
4
  "description": "The Mintlify CLI",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -62,6 +62,7 @@
62
62
  "inquirer": "12.3.0",
63
63
  "js-yaml": "4.1.0",
64
64
  "mdast-util-mdx-jsx": "3.2.0",
65
+ "openid-client": "^6.8.2",
65
66
  "posthog-node": "5.17.2",
66
67
  "react": "19.2.3",
67
68
  "semver": "7.7.2",
@@ -88,5 +89,5 @@
88
89
  "vitest": "2.1.9",
89
90
  "vitest-mock-process": "1.0.4"
90
91
  },
91
- "gitHead": "10c9be1d7e8d3ccf3f86df9498a1e334090b401e"
92
+ "gitHead": "f7c3aa2f0d1ea8c6368ac8467fc07dbccdf6bd51"
92
93
  }
package/src/cli.tsx CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  readLocalOpenApiFile,
36
36
  } from './helpers.js';
37
37
  import { init } from './init.js';
38
+ import { login } from './login.js';
38
39
  import { mdxLinter } from './mdxLinter.js';
39
40
  import { migrateMdx } from './migrateMdx.js';
40
41
  import { scrapeSite, scrapePage, scrapeOpenApi } from './scrape.js';
@@ -355,6 +356,15 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
355
356
  await terminate(0);
356
357
  }
357
358
  )
359
+ .command(
360
+ 'login',
361
+ false,
362
+ () => undefined,
363
+ async () => {
364
+ await login();
365
+ await terminate(0);
366
+ }
367
+ )
358
368
  .command(
359
369
  'update',
360
370
  'update the CLI to the latest version',
package/src/constants.ts CHANGED
@@ -7,3 +7,8 @@ export const CMD_EXEC_PATH = process.cwd();
7
7
  export const CONFIG_DIR = path.join(HOME_DIR, '.config', 'mintlify');
8
8
  export const CLI_CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
9
9
  export const TELEMETRY_ASYNC_TIMEOUT_MS = 10_000;
10
+
11
+ export const DASHBOARD_URL = process.env.MINTLIFY_DASHBOARD_URL ?? 'http://localhost:3000';
12
+ export const TOKEN_ENDPOINT =
13
+ 'https://test.stytch.com/v1/public/project-test-2d86347b-dfdb-4609-be69-12d8146220bd/oauth2/token';
14
+ export const STYTCH_CLIENT_ID = 'connected-app-test-b597afb3-304a-420f-bc13-dacca566c59f';
package/src/login.tsx ADDED
@@ -0,0 +1,62 @@
1
+ import { input } from '@inquirer/prompts';
2
+ import { addLog } from '@mintlify/previewing';
3
+ import { Text } from 'ink';
4
+ import {
5
+ calculatePKCECodeChallenge,
6
+ randomNonce,
7
+ randomPKCECodeVerifier,
8
+ randomState,
9
+ } from 'openid-client';
10
+
11
+ import { DASHBOARD_URL, STYTCH_CLIENT_ID, TOKEN_ENDPOINT } from './constants.js';
12
+
13
+ interface TokenResponse {
14
+ access_token: string;
15
+ id_token: string;
16
+ refresh_token: string;
17
+ token_type: 'bearer';
18
+ expires_in: number;
19
+ request_id: string;
20
+ status_code: number;
21
+ }
22
+
23
+ export async function login(): Promise<void> {
24
+ const codeVerifier = randomPKCECodeVerifier();
25
+ const codeChallenge = await calculatePKCECodeChallenge(codeVerifier);
26
+ const nonce = randomNonce();
27
+ const clientState = randomState();
28
+
29
+ const state = Buffer.from(JSON.stringify({ nonce, clientState })).toString('base64url');
30
+
31
+ const authorizeUrl = new URL('/api/cli/oauth/authorize', DASHBOARD_URL);
32
+ authorizeUrl.searchParams.set('state', state);
33
+ authorizeUrl.searchParams.set('code_challenge', codeChallenge);
34
+
35
+ addLog(<Text>Opening browser to log in to Mintlify... {authorizeUrl.toString()}</Text>);
36
+
37
+ const code = await input({ message: 'Paste the code from your browser:' });
38
+
39
+ const res = await fetch(TOKEN_ENDPOINT, {
40
+ method: 'POST',
41
+ headers: { 'Content-Type': 'application/json' },
42
+ body: JSON.stringify({
43
+ client_id: STYTCH_CLIENT_ID,
44
+ grant_type: 'authorization_code',
45
+ code,
46
+ code_verifier: codeVerifier,
47
+ redirect_uri: `${DASHBOARD_URL}/api/cli/oauth/callback`,
48
+ }),
49
+ });
50
+
51
+ const body = await res.json().catch(() => ({}));
52
+
53
+ if (!res.ok) {
54
+ addLog(
55
+ <Text color="red">Login failed: {body.error_message ?? body.error ?? 'unknown error'}</Text>
56
+ );
57
+ return;
58
+ }
59
+
60
+ const token = body as TokenResponse;
61
+ addLog(<Text color="green">Logged in successfully.</Text>);
62
+ }