@mintlify/previewing 4.0.1189 → 4.0.1190

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.
@@ -0,0 +1,4 @@
1
+ export declare const addDevTimingLog: (message: string, detail?: string) => void;
2
+ export declare const startDevTiming: (label: string) => ((status?: string) => void);
3
+ export declare const timeDev: <Result>(label: string, callback: () => Promise<Result>) => Promise<Result>;
4
+ export declare const timeDevSync: <Result>(label: string, callback: () => Result) => Result;
@@ -0,0 +1,62 @@
1
+ import { createElement } from 'react';
2
+ import { addLog, removeLog, replaceLog } from '../logging-state.js';
3
+ import { InfoLog } from '../logs.js';
4
+ // steps faster than this are not worth reading about
5
+ const MIN_LOGGED_DURATION_MS = 100;
6
+ const isDevTimingEnabled = () => process.env.DEV_TIMING === 'true';
7
+ const getElapsedMs = (startTime) => {
8
+ return Number((process.hrtime.bigint() - startTime) / 1000000n);
9
+ };
10
+ const formatDuration = (durationMs) => {
11
+ return durationMs < 1000 ? `${durationMs}ms` : `${(durationMs / 1000).toFixed(1)}s`;
12
+ };
13
+ export const addDevTimingLog = (message, detail) => {
14
+ if (!isDevTimingEnabled()) {
15
+ return;
16
+ }
17
+ addLog(createElement(InfoLog, { message, detail }));
18
+ };
19
+ export const startDevTiming = (label) => {
20
+ if (!isDevTimingEnabled()) {
21
+ return () => { };
22
+ }
23
+ const startTime = process.hrtime.bigint();
24
+ const pendingLog = createElement(InfoLog, { message: label, detail: '...' });
25
+ addLog(pendingLog);
26
+ return (status) => {
27
+ const durationMs = getElapsedMs(startTime);
28
+ if (!status && durationMs < MIN_LOGGED_DURATION_MS) {
29
+ removeLog(pendingLog);
30
+ return;
31
+ }
32
+ const finishedLog = createElement(InfoLog, {
33
+ message: `${label}${status ? ` ${status}` : ''}`,
34
+ detail: `in ${formatDuration(durationMs)}`,
35
+ });
36
+ replaceLog(pendingLog, finishedLog);
37
+ };
38
+ };
39
+ export const timeDev = async (label, callback) => {
40
+ const finish = startDevTiming(label);
41
+ try {
42
+ const result = await callback();
43
+ finish();
44
+ return result;
45
+ }
46
+ catch (error) {
47
+ finish('failed');
48
+ throw error;
49
+ }
50
+ };
51
+ export const timeDevSync = (label, callback) => {
52
+ const finish = startDevTiming(label);
53
+ try {
54
+ const result = callback();
55
+ finish();
56
+ return result;
57
+ }
58
+ catch (error) {
59
+ finish('failed');
60
+ throw error;
61
+ }
62
+ };
@@ -5,10 +5,11 @@ import isOnline from 'is-online';
5
5
  import { CLIENT_PATH, DOT_MINTLIFY, CMD_EXEC_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, } from '../constants.js';
6
6
  import { addLog, clearLogs } from '../logging-state.js';
7
7
  import { ErrorLog, SpinnerLog } from '../logs.js';
8
+ import { timeDev, timeDevSync } from './dev-timing.js';
8
9
  import { run } from './run.js';
9
10
  import { silentUpdateClient } from './update.js';
10
11
  const dev = async (argv) => {
11
- const hasInternet = await isOnline();
12
+ const hasInternet = await timeDev('check internet', () => isOnline());
12
13
  const localSchema = argv['local-schema'];
13
14
  const clientVersion = argv['client-version'];
14
15
  const localClientVersion = argv['local-client-version'];
@@ -16,10 +17,10 @@ const dev = async (argv) => {
16
17
  const groups = argv.groups;
17
18
  const cliVersion = argv.cliVersion;
18
19
  const disableOpenApi = argv.disableOpenapi;
19
- await fse.ensureDir(DOT_MINTLIFY);
20
- const versionString = (await pathExists(VERSION_PATH))
21
- ? fse.readFileSync(VERSION_PATH, 'utf8')
22
- : null;
20
+ await timeDev('ensure .mintlify directory', () => fse.ensureDir(DOT_MINTLIFY));
21
+ const versionString = await timeDev('read local client version', async () => {
22
+ return (await pathExists(VERSION_PATH)) ? fse.readFileSync(VERSION_PATH, 'utf8') : null;
23
+ });
23
24
  if (!versionString && !localClientVersion && !hasInternet) {
24
25
  clearLogs();
25
26
  addLog(_jsx(ErrorLog, { message: `running ${packageName} dev after updating requires an internet connection.` }));
@@ -27,12 +28,12 @@ const dev = async (argv) => {
27
28
  process.exit(1);
28
29
  }
29
30
  addLog(_jsx(SpinnerLog, { message: "preparing local preview..." }));
30
- const { needsUpdate, error } = await silentUpdateClient({
31
+ const { needsUpdate, error } = await timeDev('update local client', () => silentUpdateClient({
31
32
  versionString,
32
33
  clientVersion,
33
34
  localClientVersion,
34
35
  cliVersion,
35
- });
36
+ }));
36
37
  if (error) {
37
38
  clearLogs();
38
39
  addLog(_jsx(ErrorLog, { message: error }));
@@ -40,17 +41,21 @@ const dev = async (argv) => {
40
41
  process.exit(1);
41
42
  }
42
43
  // clear preexisting prebuild files
43
- fse.emptyDirSync(NEXT_PUBLIC_PATH);
44
- fse.emptyDirSync(NEXT_PROPS_PATH);
45
- process.chdir(CLIENT_PATH);
44
+ timeDevSync('clear prebuild output', () => {
45
+ fse.emptyDirSync(NEXT_PUBLIC_PATH);
46
+ fse.emptyDirSync(NEXT_PROPS_PATH);
47
+ });
48
+ timeDevSync('switch to local client directory', () => {
49
+ process.chdir(CLIENT_PATH);
50
+ });
46
51
  let fileImportsMap;
47
52
  try {
48
- const result = await prebuild(CMD_EXEC_PATH, {
53
+ const result = await timeDev('prebuild content', () => prebuild(CMD_EXEC_PATH, {
49
54
  localSchema,
50
55
  groups,
51
56
  disableOpenApi,
52
57
  allowSourceRefs: true,
53
- });
58
+ }));
54
59
  fileImportsMap = result?.fileImportsMap;
55
60
  }
56
61
  catch (err) {
@@ -60,6 +65,6 @@ const dev = async (argv) => {
60
65
  await new Promise((resolve) => setTimeout(resolve, 50));
61
66
  process.exit(1);
62
67
  }
63
- await run({ ...argv, needsUpdate, fileImportsMap });
68
+ await timeDev('start preview runtime', () => run({ ...argv, needsUpdate, fileImportsMap }));
64
69
  };
65
70
  export default dev;
@@ -4,9 +4,10 @@ import express from 'express';
4
4
  import { createServer } from 'http';
5
5
  import { Server as SocketServer } from 'socket.io';
6
6
  import { CMD_EXEC_PATH, NEXT_PUBLIC_PATH } from '../constants.js';
7
- import { addLog, removeLastLog } from '../logging-state.js';
7
+ import { addLog, removeSpinnerLogs } from '../logging-state.js';
8
8
  import { LaunchLog, UpdateLog } from '../logs.js';
9
9
  import { maybeFixMissingWindowsEnvVar } from '../util.js';
10
+ import { addDevTimingLog, startDevTiming, timeDev } from './dev-timing.js';
10
11
  import listener, { initializeDocsConfigHashCache, initializeFrontmatterHashCache, initializeImportCache, } from './listener/index.js';
11
12
  import { refreshTrackedReferencedFiles } from './listener/referencedFiles.js';
12
13
  import { getLocalNetworkIp } from './network.js';
@@ -48,7 +49,7 @@ export const run = async (argv) => {
48
49
  const app = express();
49
50
  const server = createServer(app);
50
51
  const io = new SocketServer(server);
51
- const requestHandler = await setupNext();
52
+ const requestHandler = await timeDev('setup Next handler', () => setupNext());
52
53
  const localIp = getLocalNetworkIp();
53
54
  const apiUrl = argv.apiUrl ?? process.env.MINTLIFY_API_URL ?? 'http://localhost:5000';
54
55
  const accessToken = argv.accessToken;
@@ -120,8 +121,10 @@ export const run = async (argv) => {
120
121
  const onChange = () => {
121
122
  io.emit('reload');
122
123
  };
124
+ const finishServerListenTiming = startDevTiming('server ready');
123
125
  server.listen(currentPort, () => {
124
- removeLastLog();
126
+ finishServerListenTiming();
127
+ removeSpinnerLogs();
125
128
  if (argv.needsUpdate) {
126
129
  addLog(_jsx(UpdateLog, { updateCommand: `${argv.packageName} update` }));
127
130
  }
@@ -144,9 +147,10 @@ export const run = async (argv) => {
144
147
  process.on('SIGINT', onExit);
145
148
  process.on('SIGTERM', onExit);
146
149
  });
147
- await initializeImportCache(CMD_EXEC_PATH, argv.fileImportsMap);
148
- await initializeFrontmatterHashCache();
149
- await initializeDocsConfigHashCache();
150
- await refreshTrackedReferencedFiles();
150
+ await timeDev('initialize import cache', () => initializeImportCache(CMD_EXEC_PATH, argv.fileImportsMap));
151
+ await timeDev('initialize frontmatter cache', () => initializeFrontmatterHashCache());
152
+ await timeDev('initialize docs config cache', () => initializeDocsConfigHashCache());
153
+ await timeDev('refresh referenced files', () => refreshTrackedReferencedFiles());
154
+ addDevTimingLog('watching for file changes');
151
155
  listener(onChange);
152
156
  };
@@ -5,19 +5,20 @@ import isOnline from 'is-online';
5
5
  import { CLIENT_PATH, DOT_MINTLIFY, CMD_EXEC_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, } from '../constants.js';
6
6
  import { addLog, clearLogs } from '../logging-state.js';
7
7
  import { ErrorLog, SpinnerLog, SuccessLog } from '../logs.js';
8
+ import { timeDev, timeDevSync } from './dev-timing.js';
8
9
  import { silentUpdateClient } from './update.js';
9
10
  const validateBuild = async (argv) => {
10
- const hasInternet = await isOnline();
11
+ const hasInternet = await timeDev('check internet', () => isOnline());
11
12
  const localSchema = argv['local-schema'];
12
13
  const clientVersion = argv['client-version'];
13
14
  const packageName = argv.packageName;
14
15
  const groups = argv.groups;
15
16
  const cliVersion = argv.cliVersion;
16
17
  const disableOpenApi = argv.disableOpenapi;
17
- await fse.ensureDir(DOT_MINTLIFY);
18
- const versionString = (await pathExists(VERSION_PATH))
19
- ? fse.readFileSync(VERSION_PATH, 'utf8')
20
- : null;
18
+ await timeDev('ensure .mintlify directory', () => fse.ensureDir(DOT_MINTLIFY));
19
+ const versionString = await timeDev('read local client version', async () => {
20
+ return (await pathExists(VERSION_PATH)) ? fse.readFileSync(VERSION_PATH, 'utf8') : null;
21
+ });
21
22
  if (!versionString && !hasInternet) {
22
23
  clearLogs();
23
24
  addLog(_jsx(ErrorLog, { message: `running ${packageName} validate-build after updating requires an internet connection.` }));
@@ -25,12 +26,12 @@ const validateBuild = async (argv) => {
25
26
  process.exit(1);
26
27
  }
27
28
  addLog(_jsx(SpinnerLog, { message: "validating build..." }));
28
- const { error } = await silentUpdateClient({
29
+ const { error } = await timeDev('update local client', () => silentUpdateClient({
29
30
  versionString,
30
31
  clientVersion,
31
32
  cliVersion,
32
33
  localClientVersion: undefined,
33
- });
34
+ }));
34
35
  if (error) {
35
36
  clearLogs();
36
37
  addLog(_jsx(ErrorLog, { message: error }));
@@ -38,11 +39,15 @@ const validateBuild = async (argv) => {
38
39
  process.exit(1);
39
40
  }
40
41
  // clear preexisting prebuild files
41
- fse.emptyDirSync(NEXT_PUBLIC_PATH);
42
- fse.emptyDirSync(NEXT_PROPS_PATH);
43
- process.chdir(CLIENT_PATH);
42
+ timeDevSync('clear prebuild output', () => {
43
+ fse.emptyDirSync(NEXT_PUBLIC_PATH);
44
+ fse.emptyDirSync(NEXT_PROPS_PATH);
45
+ });
46
+ timeDevSync('switch to local client directory', () => {
47
+ process.chdir(CLIENT_PATH);
48
+ });
44
49
  try {
45
- await prebuild(CMD_EXEC_PATH, { localSchema, groups, disableOpenApi, strict: true });
50
+ await timeDev('prebuild content', () => prebuild(CMD_EXEC_PATH, { localSchema, groups, disableOpenApi, strict: true }));
46
51
  clearLogs();
47
52
  addLog(_jsx(SuccessLog, { message: "build validation passed" }));
48
53
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -8,4 +8,7 @@ export declare const addRawErrorLog: (message: string) => void;
8
8
  export declare const clearErrorLogs: () => void;
9
9
  export declare const clearLogs: () => void;
10
10
  export declare const removeLastLog: () => void;
11
+ export declare const removeLog: (target: React.ReactNode) => void;
12
+ export declare const replaceLog: (target: React.ReactNode, next: React.ReactNode) => void;
13
+ export declare const removeSpinnerLogs: () => void;
11
14
  export declare const getCurrentErrorLogs: () => React.ReactNode[];
@@ -1,6 +1,6 @@
1
1
  import { render } from 'ink';
2
2
  import React from 'react';
3
- import { Logs } from './logs.js';
3
+ import { Logs, SpinnerLog } from './logs.js';
4
4
  let currentLogs = [];
5
5
  let currentChangeLogs = [];
6
6
  let currentErrorLogs = [];
@@ -57,6 +57,23 @@ export const removeLastLog = () => {
57
57
  currentLogs = currentLogs.slice(0, -1);
58
58
  setLogsCallback?.(currentLogs);
59
59
  };
60
+ export const removeLog = (target) => {
61
+ ensureLoggingInstance();
62
+ currentLogs = currentLogs.filter((log) => log !== target);
63
+ setLogsCallback?.(currentLogs);
64
+ };
65
+ export const replaceLog = (target, next) => {
66
+ ensureLoggingInstance();
67
+ const index = currentLogs.indexOf(target);
68
+ currentLogs =
69
+ index === -1 ? [...currentLogs, next] : currentLogs.map((log, i) => (i === index ? next : log));
70
+ setLogsCallback?.(currentLogs);
71
+ };
72
+ export const removeSpinnerLogs = () => {
73
+ ensureLoggingInstance();
74
+ currentLogs = currentLogs.filter((log) => !(React.isValidElement(log) && log.type === SpinnerLog));
75
+ setLogsCallback?.(currentLogs);
76
+ };
60
77
  export const getCurrentErrorLogs = () => {
61
78
  return currentErrorLogs;
62
79
  };
package/dist/logs.d.ts CHANGED
@@ -3,8 +3,9 @@ export declare const LaunchLog: ({ localUrl, networkUrl }: {
3
3
  localUrl: string;
4
4
  networkUrl?: string;
5
5
  }) => import("react/jsx-runtime").JSX.Element | null;
6
- export declare const InfoLog: ({ message }: {
6
+ export declare const InfoLog: ({ message, detail }: {
7
7
  message: string;
8
+ detail?: string;
8
9
  }) => import("react/jsx-runtime").JSX.Element | null;
9
10
  export declare const SuccessLog: ({ message }: {
10
11
  message: string;
package/dist/logs.js CHANGED
@@ -11,12 +11,12 @@ export const LaunchLog = ({ localUrl, networkUrl }) => {
11
11
  }
12
12
  return (_jsxs(Box, { flexDirection: "column", alignItems: "flex-start", children: [_jsxs(Text, { children: [_jsx(Text, { color: "green", bold: true, children: "\u2713" }), ' ', _jsx(Text, { children: "preview ready" })] }), _jsx(EmptyLineLog, {}), _jsxs(Text, { children: ['\u00A0'.repeat(2), "local", '\u00A0'.repeat(3), "\u2192", '\u00A0'.repeat(1), localUrl] }), networkUrl && (_jsxs(Text, { children: ['\u00A0'.repeat(2), "network", '\u00A0'.repeat(1), "\u2192", '\u00A0'.repeat(1), networkUrl] })), _jsx(EmptyLineLog, {}), _jsxs(Text, { dimColor: true, children: ["press ", _jsx(Text, { bold: true, children: "ctrl+c" }), " to exit the preview"] }), _jsx(EmptyLineLog, {})] }));
13
13
  };
14
- export const InfoLog = ({ message }) => {
14
+ export const InfoLog = ({ message, detail }) => {
15
15
  if (process.env.CLI_TEST_MODE === 'true') {
16
- console.log(`info ${message}`);
16
+ console.log(`info ${message}${detail ? ` ${detail}` : ''}`);
17
17
  return null;
18
18
  }
19
- return (_jsxs(Box, { children: [_jsx(Text, { color: "blue", bold: true, children: "info" }), _jsxs(Text, { children: [" ", message] })] }));
19
+ return (_jsxs(Box, { children: [_jsx(Text, { color: "blue", bold: true, children: "info" }), _jsxs(Text, { children: [" ", message] }), detail && _jsxs(Text, { dimColor: true, children: [" ", detail] })] }));
20
20
  };
21
21
  export const SuccessLog = ({ message }) => {
22
22
  if (process.env.CLI_TEST_MODE === 'true') {