@mintlify/cli 4.0.1068 → 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.1068",
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": "3401569a70e020cc6f08559f5f6feed9715c8324"
92
+ "gitHead": "f7c3aa2f0d1ea8c6368ac8467fc07dbccdf6bd51"
92
93
  }
package/src/cli.tsx CHANGED
@@ -27,16 +27,15 @@ import { accessibilityCheck } from './accessibilityCheck.js';
27
27
  import { setTelemetryEnabled } from './config.js';
28
28
  import {
29
29
  checkPort,
30
- checkForMintJson,
31
30
  checkNodeVersion,
32
- upgradeConfig,
33
- checkForDocsJson,
31
+ autoUpgradeIfNeeded,
34
32
  getVersions,
35
33
  suppressConsoleWarnings,
36
34
  terminate,
37
35
  readLocalOpenApiFile,
38
36
  } from './helpers.js';
39
37
  import { init } from './init.js';
38
+ import { login } from './login.js';
40
39
  import { mdxLinter } from './mdxLinter.js';
41
40
  import { migrateMdx } from './migrateMdx.js';
42
41
  import { scrapeSite, scrapePage, scrapeOpenApi } from './scrape.js';
@@ -109,6 +108,7 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
109
108
  .example('mintlify dev', 'run with default settings (opens in browser)')
110
109
  .example('mintlify dev --no-open', 'run without opening in browser'),
111
110
  async (argv) => {
111
+ await autoUpgradeIfNeeded();
112
112
  const port = await checkPort(argv);
113
113
  const { cli: cliVersion } = getVersions();
114
114
  if (port != undefined) {
@@ -273,11 +273,7 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
273
273
  description: 'also check links inside <Snippet> components',
274
274
  }),
275
275
  async (argv) => {
276
- const hasMintJson = await checkForMintJson();
277
- if (!hasMintJson) {
278
- await checkForDocsJson();
279
- }
280
-
276
+ await autoUpgradeIfNeeded();
281
277
  addLog(<SpinnerLog message="checking for broken links..." />);
282
278
  try {
283
279
  const graph = await buildGraph(undefined, {
@@ -355,33 +351,27 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
355
351
  })
356
352
  .epilog('example: `mintlify rename introduction.mdx overview.mdx`'),
357
353
  async ({ from, to, force }) => {
358
- const hasMintJson = await checkForMintJson();
359
- if (!hasMintJson) {
360
- await checkForDocsJson();
361
- }
354
+ await autoUpgradeIfNeeded();
362
355
  await renameFilesAndUpdateLinksInContent(from, to, force);
363
356
  await terminate(0);
364
357
  }
365
358
  )
366
359
  .command(
367
- 'update',
368
- 'update the CLI to the latest version',
360
+ 'login',
361
+ false,
369
362
  () => undefined,
370
363
  async () => {
371
- await update({ packageName });
364
+ await login();
372
365
  await terminate(0);
373
366
  }
374
367
  )
375
368
  .command(
376
- 'upgrade',
377
- 'upgrade mint.json file to docs.json (current format)',
369
+ 'update',
370
+ 'update the CLI to the latest version',
378
371
  () => undefined,
379
372
  async () => {
380
- const hasMintJson = await checkForMintJson();
381
- if (!hasMintJson) {
382
- await checkForDocsJson();
383
- }
384
- await upgradeConfig();
373
+ await update({ packageName });
374
+ await terminate(0);
385
375
  }
386
376
  )
387
377
  .command(
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/helpers.tsx CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  SpinnerLog,
10
10
  removeLastLog,
11
11
  LOCAL_LINKED_CLI_VERSION,
12
+ WarningLog,
12
13
  } from '@mintlify/previewing';
13
14
  import { upgradeToDocsConfig, validatePathWithinCwd } from '@mintlify/validation';
14
15
  import detect from 'detect-port';
@@ -94,6 +95,19 @@ export const checkForDocsJson = async () => {
94
95
  }
95
96
  };
96
97
 
98
+ export const autoUpgradeIfNeeded = async () => {
99
+ const hasMintJson = await checkForMintJson();
100
+ if (!hasMintJson) return;
101
+
102
+ const docsJsonPath = path.join(CMD_EXEC_PATH, 'docs.json');
103
+ const hasDocsJson = await fse.pathExists(docsJsonPath);
104
+ if (!hasDocsJson) {
105
+ addLog(<WarningLog message="Legacy mint.json detected, auto-upgrading to docs.json" />);
106
+ addLog(<SpinnerLog message="upgrading mint.json to docs.json..." />);
107
+ await upgradeConfig();
108
+ }
109
+ };
110
+
97
111
  export const upgradeConfig = async () => {
98
112
  try {
99
113
  const mintJsonPath = path.join(CMD_EXEC_PATH, 'mint.json');
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
+ }