@mintlify/previewing 4.0.1017 → 4.0.1019

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/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { LOCAL_LINKED_CLI_VERSION } from './constants.js';
2
2
  import { getLatestClientVersion, downloadTargetMint, getVersionMap } from './local-preview/client.js';
3
+ import { exportSite } from './local-preview/export.js';
3
4
  import dev from './local-preview/index.js';
4
5
  import validateBuild from './local-preview/validate-build.js';
5
6
  import { getClientVersion } from './util.js';
6
7
  export * from './logs.js';
7
8
  export * from './logging-state.js';
8
- export { dev, validateBuild, getClientVersion, getLatestClientVersion, downloadTargetMint, getVersionMap, LOCAL_LINKED_CLI_VERSION, };
9
+ export { dev, exportSite, validateBuild, getClientVersion, getLatestClientVersion, downloadTargetMint, getVersionMap, LOCAL_LINKED_CLI_VERSION, };
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { LOCAL_LINKED_CLI_VERSION } from './constants.js';
2
2
  import { getLatestClientVersion, downloadTargetMint, getVersionMap, } from './local-preview/client.js';
3
+ import { exportSite } from './local-preview/export.js';
3
4
  import dev from './local-preview/index.js';
4
5
  import validateBuild from './local-preview/validate-build.js';
5
6
  import { getClientVersion } from './util.js';
6
7
  export * from './logs.js';
7
8
  export * from './logging-state.js';
8
- export { dev, validateBuild, getClientVersion, getLatestClientVersion, downloadTargetMint, getVersionMap, LOCAL_LINKED_CLI_VERSION, };
9
+ export { dev, exportSite, validateBuild, getClientVersion, getLatestClientVersion, downloadTargetMint, getVersionMap, LOCAL_LINKED_CLI_VERSION, };
@@ -0,0 +1,2 @@
1
+ import { ArgumentsCamelCase } from 'yargs';
2
+ export declare const exportSite: (argv: ArgumentsCamelCase) => Promise<void>;
@@ -0,0 +1,208 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { getAllPathsInDocsNav } from '@mintlify/common';
3
+ import { prebuild } from '@mintlify/prebuild';
4
+ import AdmZip from 'adm-zip';
5
+ import express from 'express';
6
+ import fse, { pathExists } from 'fs-extra';
7
+ import { createServer } from 'http';
8
+ import isOnline from 'is-online';
9
+ import os from 'os';
10
+ import path from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ import { CLIENT_PATH, DOT_MINTLIFY, CMD_EXEC_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, } from '../constants.js';
13
+ import { addLog, clearLogs } from '../logging-state.js';
14
+ import { ErrorLog, SpinnerLog, SuccessLog } from '../logs.js';
15
+ import { setupNext } from './setupNext.js';
16
+ import { silentUpdateClient } from './update.js';
17
+ const CONCURRENCY = 10;
18
+ const EXPORT_SCRIPTS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'export-scripts');
19
+ async function withExportConsoleSilenced(task) {
20
+ const originalConsole = {
21
+ log: console.log,
22
+ warn: console.warn,
23
+ };
24
+ const noop = (..._args) => undefined;
25
+ console.log = noop;
26
+ console.warn = noop;
27
+ try {
28
+ return await task();
29
+ }
30
+ finally {
31
+ console.log = originalConsole.log;
32
+ console.warn = originalConsole.warn;
33
+ }
34
+ }
35
+ async function fatal(message) {
36
+ clearLogs();
37
+ addLog(_jsx(ErrorLog, { message: message }));
38
+ await new Promise((resolve) => setTimeout(resolve, 50));
39
+ process.exit(1);
40
+ }
41
+ async function collectRoutes() {
42
+ const routes = new Set(['/']);
43
+ const docsConfigPath = path.join(CMD_EXEC_PATH, 'docs.json');
44
+ if (!(await pathExists(docsConfigPath))) {
45
+ return [...routes];
46
+ }
47
+ const config = await fse.readJson(docsConfigPath);
48
+ if (config.navigation) {
49
+ for (const navPath of getAllPathsInDocsNav(config.navigation)) {
50
+ routes.add(`/${navPath}`);
51
+ }
52
+ }
53
+ return [...routes];
54
+ }
55
+ async function generatePages(baseUrl, routes, outputDir) {
56
+ const queue = [...routes];
57
+ let failedPageCount = 0;
58
+ async function worker() {
59
+ while (queue.length > 0) {
60
+ const route = queue.shift();
61
+ try {
62
+ const res = await fetch(`${baseUrl}${route}`);
63
+ if (!res.ok) {
64
+ failedPageCount += 1;
65
+ addLog(_jsx(ErrorLog, { message: `failed to generate ${route} (status ${res.status})` }));
66
+ continue;
67
+ }
68
+ const filePath = route === '/'
69
+ ? path.join(outputDir, 'index.html')
70
+ : path.join(outputDir, route, 'index.html');
71
+ await fse.ensureDir(path.dirname(filePath));
72
+ await fse.writeFile(filePath, await res.text(), 'utf8');
73
+ }
74
+ catch (err) {
75
+ failedPageCount += 1;
76
+ addLog(_jsx(ErrorLog, { message: `failed to generate ${route}: ${err instanceof Error ? err.message : 'unknown error'}` }));
77
+ }
78
+ }
79
+ }
80
+ await Promise.all(Array.from({ length: Math.min(CONCURRENCY, routes.length) }, () => worker()));
81
+ return failedPageCount;
82
+ }
83
+ async function startServer() {
84
+ const app = express();
85
+ const requestHandler = await setupNext();
86
+ app.use('/', express.static(NEXT_PUBLIC_PATH));
87
+ app.all('*', (req, res) => requestHandler(req, res));
88
+ const server = createServer(app);
89
+ const port = await new Promise((resolve, reject) => {
90
+ server.once('error', reject);
91
+ server.listen(0, () => {
92
+ const addr = server.address();
93
+ if (!addr || typeof addr === 'string') {
94
+ reject(new Error('failed to determine listening port'));
95
+ return;
96
+ }
97
+ resolve(addr.port);
98
+ });
99
+ });
100
+ return { server, port };
101
+ }
102
+ async function bundleStaticAssets(tmpDir) {
103
+ const nextStaticSrc = path.join(CLIENT_PATH, '.next', 'static');
104
+ if (await pathExists(nextStaticSrc)) {
105
+ await fse.copy(nextStaticSrc, path.join(tmpDir, '_next', 'static'));
106
+ }
107
+ if (await pathExists(NEXT_PUBLIC_PATH)) {
108
+ const publicFiles = await fse.readdir(NEXT_PUBLIC_PATH);
109
+ for (const file of publicFiles) {
110
+ await fse.copy(path.join(NEXT_PUBLIC_PATH, file), path.join(tmpDir, file), {
111
+ overwrite: false,
112
+ });
113
+ }
114
+ }
115
+ await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'serve.js'), path.join(tmpDir, 'serve.js'));
116
+ await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'start-docs.sh'), path.join(tmpDir, 'Start Docs.command'));
117
+ await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'start-docs.bat'), path.join(tmpDir, 'Start Docs.bat'));
118
+ }
119
+ async function closeServer(server) {
120
+ await new Promise((resolve) => {
121
+ server.close(() => resolve());
122
+ });
123
+ }
124
+ async function generateExportArchive(routes, outputPath) {
125
+ const { server, port } = await startServer();
126
+ let tmpDir;
127
+ try {
128
+ clearLogs();
129
+ addLog(_jsx(SpinnerLog, { message: `generating ${routes.length} pages...` }));
130
+ tmpDir = await fse.mkdtemp(path.join(os.tmpdir(), 'mint-export-'));
131
+ const exportDir = tmpDir;
132
+ const failedPageCount = await withExportConsoleSilenced(async () => {
133
+ return generatePages(`http://localhost:${port}`, routes, exportDir);
134
+ });
135
+ if (failedPageCount > 0) {
136
+ throw new Error(`failed to export: ${failedPageCount} page(s) could not be generated.`);
137
+ }
138
+ addLog(_jsx(SpinnerLog, { message: "collecting static assets..." }));
139
+ await bundleStaticAssets(exportDir);
140
+ addLog(_jsx(SpinnerLog, { message: "creating zip archive..." }));
141
+ const zip = new AdmZip();
142
+ zip.addLocalFolder(exportDir);
143
+ zip.writeZip(outputPath);
144
+ clearLogs();
145
+ addLog(_jsx(SuccessLog, { message: `exported to ${outputPath}` }));
146
+ }
147
+ finally {
148
+ if (tmpDir) {
149
+ await fse.remove(tmpDir);
150
+ }
151
+ await closeServer(server);
152
+ }
153
+ }
154
+ export const exportSite = async (argv) => {
155
+ const hasInternet = await isOnline();
156
+ const clientVersion = argv['client-version'];
157
+ const groups = argv.groups;
158
+ const cliVersion = argv.cliVersion;
159
+ const disableOpenApi = argv.disableOpenapi;
160
+ const outputPath = path.resolve(argv.output);
161
+ await fse.ensureDir(DOT_MINTLIFY);
162
+ const versionString = (await pathExists(VERSION_PATH))
163
+ ? fse.readFileSync(VERSION_PATH, 'utf8')
164
+ : null;
165
+ if (!versionString && !hasInternet) {
166
+ await fatal('export requires an internet connection on first run.');
167
+ }
168
+ addLog(_jsx(SpinnerLog, { message: "preparing export..." }));
169
+ const { error } = await silentUpdateClient({
170
+ versionString,
171
+ clientVersion,
172
+ cliVersion,
173
+ localClientVersion: undefined,
174
+ });
175
+ if (error)
176
+ await fatal(error);
177
+ try {
178
+ fse.emptyDirSync(NEXT_PUBLIC_PATH);
179
+ fse.emptyDirSync(NEXT_PROPS_PATH);
180
+ }
181
+ catch (err) {
182
+ await fatal(err instanceof Error && err.message ? err.message : 'failed to prepare export directories');
183
+ }
184
+ process.chdir(CLIENT_PATH);
185
+ addLog(_jsx(SpinnerLog, { message: "running prebuild..." }));
186
+ try {
187
+ await withExportConsoleSilenced(async () => {
188
+ await prebuild(CMD_EXEC_PATH, { groups, disableOpenApi });
189
+ });
190
+ }
191
+ catch (err) {
192
+ await fatal(err instanceof Error && err.message ? err.message : 'prebuild step failed');
193
+ }
194
+ let routes = [];
195
+ try {
196
+ routes = await collectRoutes();
197
+ }
198
+ catch (err) {
199
+ await fatal(err instanceof Error && err.message ? err.message : 'failed to collect routes');
200
+ }
201
+ addLog(_jsx(SpinnerLog, { message: "starting local server..." }));
202
+ try {
203
+ await generateExportArchive(routes, outputPath);
204
+ }
205
+ catch (err) {
206
+ await fatal(err instanceof Error && err.message ? err.message : 'export failed');
207
+ }
208
+ };