@mintlify/cli 4.0.1085 → 4.0.1087

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/workflow.js CHANGED
@@ -13,7 +13,7 @@ import { addLog, addLogs, SuccessLog } from '@mintlify/previewing';
13
13
  import fse from 'fs-extra';
14
14
  import { Text } from 'ink';
15
15
  import path from 'path';
16
- import { CMD_EXEC_PATH } from './constants.js';
16
+ import { CMD_EXEC_PATH } from './helpers.js';
17
17
  export function slugify(name) {
18
18
  return name
19
19
  .toLowerCase()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mintlify/cli",
3
- "version": "4.0.1085",
3
+ "version": "4.0.1087",
4
4
  "description": "The Mintlify CLI",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -93,5 +93,5 @@
93
93
  "vitest": "2.1.9",
94
94
  "vitest-mock-process": "1.0.4"
95
95
  },
96
- "gitHead": "78f288690da1e848e93ed14655df3bf08262b647"
96
+ "gitHead": "2098cd9c9868b0e8e7118290c5c768ecf90d54ff"
97
97
  }
@@ -6,8 +6,7 @@ import { Text } from 'ink';
6
6
 
7
7
  import { checkDocsColors, type AccessibilityCheckResult } from './accessibility.js';
8
8
  import { ContrastResult } from './accessibility.js';
9
- import { CMD_EXEC_PATH } from './constants.js';
10
- import { checkForDocsJson } from './helpers.js';
9
+ import { CMD_EXEC_PATH, checkForDocsJson } from './helpers.js';
11
10
 
12
11
  export type TerminateCode = 0 | 1;
13
12
 
@@ -1,3 +1,4 @@
1
+ import { API_URL } from '../constants.js';
1
2
  import type {
2
3
  BucketThreadsResponse,
3
4
  BucketsResponse,
@@ -10,8 +11,6 @@ import type {
10
11
  VisitorsResponse,
11
12
  } from './types.js';
12
13
 
13
- const API_BASE = process.env.MINTLIFY_API_URL ?? 'http://localhost:5000';
14
-
15
14
  type Params = Record<string, string | number | undefined>;
16
15
 
17
16
  async function getAuthHeaders(): Promise<Record<string, string>> {
@@ -32,7 +31,7 @@ async function getAuthHeaders(): Promise<Record<string, string>> {
32
31
  }
33
32
 
34
33
  async function request<T>(path: string, params: Params = {}): Promise<T> {
35
- const url = new URL(`${API_BASE}/api/cli/analytics${path}`);
34
+ const url = new URL(`${API_URL}/api/cli/analytics${path}`);
36
35
  for (const [key, value] of Object.entries(params)) {
37
36
  if (value !== undefined) url.searchParams.set(key, String(value));
38
37
  }
@@ -0,0 +1,64 @@
1
+ import { CALLBACK_PORT, DASHBOARD_URL } from './constants.js';
2
+
3
+ export async function startCallbackServer(): Promise<{
4
+ codePromise: Promise<string>;
5
+ close: () => void;
6
+ }> {
7
+ const { default: http } = await import('http');
8
+
9
+ let resolveCode: (code: string) => void;
10
+ let rejectCode: (err: Error) => void;
11
+ let closed = false;
12
+
13
+ const codePromise = new Promise<string>((res, rej) => {
14
+ resolveCode = res;
15
+ rejectCode = rej;
16
+ });
17
+
18
+ const server = http.createServer((req, res) => {
19
+ res.setHeader('Access-Control-Allow-Origin', DASHBOARD_URL);
20
+ res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
21
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
22
+
23
+ if (req.method === 'OPTIONS') {
24
+ res.writeHead(204);
25
+ res.end();
26
+ return;
27
+ }
28
+
29
+ if (req.method === 'POST') {
30
+ let body = '';
31
+ req.on('data', (chunk) => {
32
+ body += chunk;
33
+ });
34
+ req.on('end', () => {
35
+ try {
36
+ const { code } = JSON.parse(body) as { code: string };
37
+ res.writeHead(200, { 'Content-Type': 'application/json' });
38
+ res.end(JSON.stringify({ ok: true }));
39
+ closed = true;
40
+ server.close();
41
+ resolveCode(code);
42
+ } catch {
43
+ res.writeHead(400);
44
+ res.end(JSON.stringify({ error: 'invalid body' }));
45
+ }
46
+ });
47
+ } else {
48
+ res.writeHead(405);
49
+ res.end();
50
+ }
51
+ });
52
+
53
+ server.listen(CALLBACK_PORT, 'localhost');
54
+
55
+ const close = () => {
56
+ if (!closed) {
57
+ closed = true;
58
+ server.close();
59
+ rejectCode(new Error('Login cancelled'));
60
+ }
61
+ };
62
+
63
+ return { codePromise, close };
64
+ }
package/src/cli.tsx CHANGED
@@ -22,8 +22,8 @@ import { accessibilityCheck } from './accessibilityCheck.js';
22
22
  import { analyticsBuilder } from './analytics/index.js';
23
23
  import { setTelemetryEnabled } from './config.js';
24
24
  import { getConfigValue, setConfigValue, clearConfigValue } from './config.js';
25
- import { CMD_EXEC_PATH } from './constants.js';
26
25
  import {
26
+ CMD_EXEC_PATH,
27
27
  checkPort,
28
28
  checkNodeVersion,
29
29
  autoUpgradeIfNeeded,
@@ -317,7 +317,7 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
317
317
  )
318
318
  .command(
319
319
  'status',
320
- false,
320
+ 'View current authentication status',
321
321
  () => undefined,
322
322
  async () => {
323
323
  await status();
@@ -326,7 +326,7 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
326
326
  )
327
327
  .command(
328
328
  'logout',
329
- false,
329
+ 'logout of your mintlify account',
330
330
  () => undefined,
331
331
  async () => {
332
332
  await logout();
@@ -335,7 +335,7 @@ export const cli = ({ packageName = 'mint' }: { packageName?: string }) => {
335
335
  )
336
336
  .command(
337
337
  'login',
338
- false,
338
+ 'authenticate your account to mintlify',
339
339
  () => undefined,
340
340
  async () => {
341
341
  await login();
package/src/constants.ts CHANGED
@@ -1,14 +1,33 @@
1
+ import { LOCAL_LINKED_CLI_VERSION } from '@mintlify/previewing';
1
2
  import os from 'os';
2
3
  import path from 'path';
3
4
 
5
+ import { getCliVersion } from './helpers.js';
6
+
4
7
  export const HOME_DIR = os.homedir();
5
- export const CMD_EXEC_PATH = process.cwd();
6
8
 
7
9
  export const CONFIG_DIR = path.join(HOME_DIR, '.config', 'mintlify');
8
10
  export const CLI_CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
9
11
  export const TELEMETRY_ASYNC_TIMEOUT_MS = 10_000;
10
12
 
11
- export const DASHBOARD_URL = process.env.MINTLIFY_DASHBOARD_URL ?? 'http://localhost:3000';
12
- export const TOKEN_ENDPOINT =
13
+ export const CALLBACK_PORT = 11582;
14
+
15
+ const IS_LOCAL_BUILD =
16
+ process.env.CLI_TEST_MODE === 'true' ? true : getCliVersion() == LOCAL_LINKED_CLI_VERSION;
17
+
18
+ export const API_URL =
19
+ process.env.MINTLIFY_API_URL ??
20
+ (IS_LOCAL_BUILD ? 'http://localhost:5000' : 'https://leaves.mintlify.com');
21
+ export const DASHBOARD_URL =
22
+ process.env.MINTLIFY_DASHBOARD_URL ??
23
+ (IS_LOCAL_BUILD ? 'http://localhost:3000' : 'https://dashboard.mintlify.com');
24
+
25
+ const DEV_TOKEN_ENDPOINT =
13
26
  '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';
27
+ const DEV_STYTCH_CLIENT_ID = 'connected-app-test-b597afb3-304a-420f-bc13-dacca566c59f';
28
+ const PROD_TOKEN_ENDPOINT =
29
+ 'https://api.stytch.com/v1/public/project-live-731b7a04-9ac3-4923-90b8-0806d4aa29d4/oauth2/token';
30
+ const PROD_STYTCH_CLIENT_ID = 'connected-app-live-d813eedd-dbb0-434b-a1f9-2ce69e5efc49';
31
+
32
+ export const TOKEN_ENDPOINT = IS_LOCAL_BUILD ? DEV_TOKEN_ENDPOINT : PROD_TOKEN_ENDPOINT;
33
+ export const STYTCH_CLIENT_ID = IS_LOCAL_BUILD ? DEV_STYTCH_CLIENT_ID : PROD_STYTCH_CLIENT_ID;
package/src/helpers.tsx CHANGED
@@ -23,9 +23,10 @@ import path from 'path';
23
23
  import type { ArgumentsCamelCase } from 'yargs';
24
24
  import yargs from 'yargs';
25
25
 
26
- import { CMD_EXEC_PATH } from './constants.js';
27
26
  import { shutdownPostHog } from './telemetry/client.js';
28
27
 
28
+ export const CMD_EXEC_PATH = process.cwd();
29
+
29
30
  export const checkPort = async (argv: ArgumentsCamelCase): Promise<number | undefined> => {
30
31
  const initialPort = typeof argv.port === 'number' ? argv.port : 3000;
31
32
  if (initialPort === (await detect(initialPort))) return initialPort;
package/src/login.tsx CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  randomState,
11
11
  } from 'openid-client';
12
12
 
13
+ import { startCallbackServer } from './callbackServer.js';
13
14
  import { DASHBOARD_URL, STYTCH_CLIENT_ID, TOKEN_ENDPOINT } from './constants.js';
14
15
  import { storeCredentials } from './keyring.js';
15
16
 
@@ -36,6 +37,8 @@ export async function login(): Promise<void> {
36
37
  authorizeUrl.searchParams.set('code_challenge', codeChallenge);
37
38
  const url = authorizeUrl.toString();
38
39
 
40
+ const { codePromise, close: closeServer } = await startCallbackServer();
41
+
39
42
  addLog(
40
43
  <Box flexDirection="column" gap={1} paddingY={1}>
41
44
  <Text bold>
@@ -60,7 +63,7 @@ export async function login(): Promise<void> {
60
63
  // Let ink finish rendering before inquirer takes over stdout
61
64
  await new Promise((resolve) => setTimeout(resolve, 50));
62
65
 
63
- const code = await input({
66
+ const inputPromise = input({
64
67
  message: '█',
65
68
  theme: {
66
69
  prefix: chalk.dim(' │'),
@@ -70,6 +73,19 @@ export async function login(): Promise<void> {
70
73
  },
71
74
  });
72
75
 
76
+ let code: string;
77
+ try {
78
+ code = await Promise.race([codePromise, inputPromise]);
79
+ } catch {
80
+ closeServer();
81
+ inputPromise.cancel();
82
+ addLog(<Text color="red">✖ Login cancelled.</Text>);
83
+ return;
84
+ }
85
+
86
+ closeServer();
87
+ inputPromise.cancel();
88
+
73
89
  const res = await fetch(TOKEN_ENDPOINT, {
74
90
  method: 'POST',
75
91
  headers: { 'Content-Type': 'application/json' },
@@ -95,6 +111,5 @@ export async function login(): Promise<void> {
95
111
 
96
112
  const token = body as TokenResponse;
97
113
  await storeCredentials(token.access_token, token.refresh_token);
98
-
99
114
  addLog(<Text color="green">✔ Logged in successfully.</Text>);
100
115
  }
package/src/status.tsx CHANGED
@@ -2,10 +2,9 @@ import { addLog } from '@mintlify/previewing';
2
2
  import { Text } from 'ink';
3
3
  import { z } from 'zod';
4
4
 
5
+ import { API_URL } from './constants.js';
5
6
  import { getAccessToken } from './keyring.js';
6
7
 
7
- const API_URL = process.env.MINTLIFY_API_URL ?? 'http://localhost:5000';
8
-
9
8
  const StatusResponseSchema = z.object({
10
9
  user: z.object({ email: z.string() }),
11
10
  org: z.object({ name: z.string() }),
@@ -1,6 +1,6 @@
1
1
  import { PostHog } from 'posthog-node';
2
2
 
3
- import { TELEMETRY_ASYNC_TIMEOUT_MS } from '../constants.js';
3
+ const TELEMETRY_ASYNC_TIMEOUT_MS = 10_000;
4
4
 
5
5
  const POSTHOG_API_KEY = 'phc_eNuN6Ojnk9O7uWfC17z12AK85fNR0BY6IiGVy0Gfwzw';
6
6
  const POSTHOG_HOST = 'https://ph.mintlify.com';
package/src/workflow.tsx CHANGED
@@ -4,7 +4,7 @@ import fse from 'fs-extra';
4
4
  import { Text } from 'ink';
5
5
  import path from 'path';
6
6
 
7
- import { CMD_EXEC_PATH } from './constants.js';
7
+ import { CMD_EXEC_PATH } from './helpers.js';
8
8
 
9
9
  export function slugify(name: string): string {
10
10
  return name