@mintlify/previewing 4.0.1588 → 4.0.1590

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.
@@ -2,32 +2,23 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { getAllPathsInDecoratedNav, getAllPathsInDocsNav } from '@mintlify/common';
3
3
  import { prebuild } from '@mintlify/prebuild';
4
4
  import AdmZip from 'adm-zip';
5
- import express from 'express';
6
5
  import fse, { pathExists } from 'fs-extra';
7
- import { createServer } from 'http';
8
6
  import os from 'os';
9
7
  import path from 'path';
10
8
  import { fileURLToPath } from 'url';
11
- import { CLIENT_PATH, CMD_EXEC_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, PREVIEW_PATH, configureSharedPreviewPath, } from '../constants.js';
9
+ import { CMD_EXEC_PATH, CONTENT_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, PREVIEW_PATH, configureSharedPreviewPath, } from '../constants.js';
12
10
  import { addLog, clearLogs } from '../logging-state.js';
13
11
  import { ErrorLog, SpinnerLog, SuccessLog, WarningLog } from '../logs.js';
14
12
  import { localizeAssets } from './export-assets.js';
15
- import { applyBasePathToExport, findBasePathConflict, normalizeExportBasePath, } from './export-base-path.js';
13
+ import { findBasePathConflict, normalizeExportBasePath } from './export-base-path.js';
16
14
  import { generateExportLlmsTxt } from './export-llms.js';
15
+ import { createNextRenderer } from './export-next.js';
17
16
  import { writeSearchIndex } from './export-search.js';
17
+ import { createViteRenderer } from './export-vite.js';
18
18
  import { getGroupFilteredRoutes } from './getGroupFilteredRoutes.js';
19
19
  import { isOnline } from './is-online.js';
20
- import { setupNext } from './setupNext.js';
21
20
  import { silentUpdateClient } from './update.js';
22
- const CONCURRENCY = 10;
23
- const RSC_CONTENT_TYPE = 'text/x-component';
24
- const RSC_PAYLOAD_FILE = 'index.txt';
25
21
  const EXPORT_SCRIPTS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'export-scripts');
26
- function resolveRequestRoute(route, rootRoute) {
27
- if (route === '/' && rootRoute)
28
- return rootRoute;
29
- return route;
30
- }
31
22
  function prepareRoutesForExport(routes, groups) {
32
23
  if (!groups?.length || routes.includes('/'))
33
24
  return { routes };
@@ -94,59 +85,6 @@ async function collectRoutes(groups) {
94
85
  }
95
86
  return [...routes];
96
87
  }
97
- export async function generatePages(baseUrl, routes, outputDir, rootRoute) {
98
- const queue = [...routes];
99
- let failedPageCount = 0;
100
- async function worker() {
101
- while (queue.length > 0) {
102
- const route = queue.shift();
103
- try {
104
- const requestRoute = resolveRequestRoute(route, rootRoute);
105
- const [res, rscRes] = await Promise.all([
106
- fetch(`${baseUrl}${requestRoute}`),
107
- fetch(`${baseUrl}${requestRoute}`, { headers: { RSC: '1' } }),
108
- ]);
109
- const isRscPayload = rscRes.headers.get('content-type')?.startsWith(RSC_CONTENT_TYPE);
110
- if (!res.ok || !rscRes.ok || !isRscPayload) {
111
- failedPageCount += 1;
112
- addLog(_jsx(ErrorLog, { message: `failed to generate ${route} (status ${res.ok ? rscRes.status : res.status})` }));
113
- continue;
114
- }
115
- const pageDir = route === '/' ? outputDir : path.join(outputDir, route);
116
- await fse.ensureDir(pageDir);
117
- await Promise.all([
118
- fse.writeFile(path.join(pageDir, 'index.html'), await res.text(), 'utf8'),
119
- fse.writeFile(path.join(pageDir, RSC_PAYLOAD_FILE), await rscRes.text(), 'utf8'),
120
- ]);
121
- }
122
- catch (err) {
123
- failedPageCount += 1;
124
- addLog(_jsx(ErrorLog, { message: `failed to generate ${route}: ${err instanceof Error ? err.message : 'unknown error'}` }));
125
- }
126
- }
127
- }
128
- await Promise.all(Array.from({ length: Math.min(CONCURRENCY, routes.length) }, () => worker()));
129
- return failedPageCount;
130
- }
131
- async function startServer(basePath) {
132
- const app = express();
133
- const requestHandler = await setupNext(basePath ? { assetPrefix: basePath } : undefined);
134
- app.use('/', express.static(NEXT_PUBLIC_PATH));
135
- app.all('*', (req, res) => requestHandler(req, res));
136
- const server = createServer(app);
137
- const port = await new Promise((resolve, reject) => {
138
- server.once('error', reject);
139
- server.listen(0, () => {
140
- const addr = server.address();
141
- if (!addr || typeof addr === 'string') {
142
- reject(new Error('failed to determine listening port'));
143
- return;
144
- }
145
- resolve(addr.port);
146
- });
147
- });
148
- return { server, port };
149
- }
150
88
  export async function writeStaticUserInfo(tmpDir, groups) {
151
89
  if (!groups?.length)
152
90
  return;
@@ -154,11 +92,8 @@ export async function writeStaticUserInfo(tmpDir, groups) {
154
92
  user: { groups },
155
93
  });
156
94
  }
157
- async function bundleStaticAssets(tmpDir, groups, basePath) {
158
- const nextStaticSrc = path.join(CLIENT_PATH, '.next', 'static');
159
- if (await pathExists(nextStaticSrc)) {
160
- await fse.copy(nextStaticSrc, path.join(tmpDir, '_next', 'static'));
161
- }
95
+ async function bundleStaticAssets(tmpDir, groups, basePath, renderer) {
96
+ await renderer.copyAssets(tmpDir);
162
97
  if (await pathExists(NEXT_PUBLIC_PATH)) {
163
98
  const publicFiles = await fse.readdir(NEXT_PUBLIC_PATH);
164
99
  for (const file of publicFiles) {
@@ -170,7 +105,7 @@ async function bundleStaticAssets(tmpDir, groups, basePath) {
170
105
  await writeStaticUserInfo(tmpDir, groups);
171
106
  const serveScript = await fse.readFile(path.join(EXPORT_SCRIPTS_DIR, 'serve.js'), 'utf8');
172
107
  await fse.writeFile(path.join(tmpDir, 'serve.js'), serveScript.replace("const BASE_PATH = '';", `const BASE_PATH = ${JSON.stringify(basePath)};`));
173
- await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'README.md'), path.join(tmpDir, 'README.md'));
108
+ await fse.copy(path.join(EXPORT_SCRIPTS_DIR, renderer.readme), path.join(tmpDir, 'README.md'));
174
109
  await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'start-docs.sh'), path.join(tmpDir, 'Start Docs.command'));
175
110
  await fse.copy(path.join(EXPORT_SCRIPTS_DIR, 'start-docs.bat'), path.join(tmpDir, 'Start Docs.bat'));
176
111
  }
@@ -184,13 +119,10 @@ export async function writeLlmsTxt(tmpDir, routes, basePath = '') {
184
119
  ]);
185
120
  await fse.writeFile(llmsTxtPath, generateExportLlmsTxt(docsConfig, generatedNav, routes, basePath), 'utf8');
186
121
  }
187
- async function closeServer(server) {
188
- await new Promise((resolve) => {
189
- server.close(() => resolve());
190
- });
191
- }
192
- async function generateExportArchive(routes, outputPath, groups, basePath) {
193
- const { server, port } = await startServer(basePath);
122
+ async function generateExportArchive(routes, outputPath, groups, basePath, vite) {
123
+ const renderer = vite
124
+ ? await createViteRenderer({ groups, basePath: basePath || undefined })
125
+ : await createNextRenderer(groups, basePath);
194
126
  const { routes: preparedRoutes, rootRoute } = prepareRoutesForExport(routes, groups);
195
127
  const routesToGenerate = withIndexRouteAliases(preparedRoutes);
196
128
  let tmpDir;
@@ -200,14 +132,13 @@ async function generateExportArchive(routes, outputPath, groups, basePath) {
200
132
  tmpDir = await fse.mkdtemp(path.join(os.tmpdir(), 'mint-export-'));
201
133
  const exportDir = tmpDir;
202
134
  const failedPageCount = await withExportConsoleSilenced(async () => {
203
- return generatePages(`http://localhost:${port}`, routesToGenerate, exportDir, rootRoute);
135
+ return renderer.generatePages(routesToGenerate, exportDir, rootRoute);
204
136
  });
205
137
  if (failedPageCount > 0) {
206
138
  throw new Error(`failed to export: ${failedPageCount} page(s) could not be generated.`);
207
139
  }
208
140
  addLog(_jsx(SpinnerLog, { message: "collecting static assets..." }));
209
- await bundleStaticAssets(exportDir, groups, basePath);
210
- await applyBasePathToExport(exportDir, basePath);
141
+ await bundleStaticAssets(exportDir, groups, basePath, renderer);
211
142
  await writeLlmsTxt(exportDir, routes, basePath);
212
143
  addLog(_jsx(SpinnerLog, { message: "building search index..." }));
213
144
  const [docsConfig, generatedNav] = await Promise.all([
@@ -216,7 +147,11 @@ async function generateExportArchive(routes, outputPath, groups, basePath) {
216
147
  ]);
217
148
  await writeSearchIndex(exportDir, { generatedNav, docsConfig, groups });
218
149
  addLog(_jsx(SpinnerLog, { message: "bundling external assets..." }));
219
- const { failed } = await localizeAssets(exportDir);
150
+ const clientAssetFailures = await renderer.bundleAssets(exportDir);
151
+ const { failed: assetFailures } = await localizeAssets(exportDir, {
152
+ stylesheetDir: renderer.stylesheetDir,
153
+ });
154
+ const failed = [...clientAssetFailures, ...assetFailures];
220
155
  addLog(_jsx(SpinnerLog, { message: "creating zip archive..." }));
221
156
  const zip = new AdmZip();
222
157
  zip.addLocalFolder(exportDir);
@@ -231,11 +166,12 @@ async function generateExportArchive(routes, outputPath, groups, basePath) {
231
166
  if (tmpDir) {
232
167
  await fse.remove(tmpDir);
233
168
  }
234
- await closeServer(server);
169
+ await renderer.close();
235
170
  }
236
171
  }
237
172
  export const exportSite = async (argv) => {
238
- configureSharedPreviewPath();
173
+ const vite = argv.classic !== true;
174
+ configureSharedPreviewPath(vite ? 'vite' : 'next');
239
175
  const hasInternet = await isOnline();
240
176
  const clientVersion = argv['client-version'];
241
177
  const localClientVersion = argv['local-client-version'];
@@ -273,7 +209,8 @@ export const exportSite = async (argv) => {
273
209
  catch (err) {
274
210
  await fatal(err instanceof Error && err.message ? err.message : 'failed to prepare export directories');
275
211
  }
276
- process.chdir(CLIENT_PATH);
212
+ await fse.ensureDir(CONTENT_PATH);
213
+ process.chdir(CONTENT_PATH);
277
214
  addLog(_jsx(SpinnerLog, { message: "running prebuild..." }));
278
215
  try {
279
216
  await withExportConsoleSilenced(async () => {
@@ -294,10 +231,8 @@ export const exportSite = async (argv) => {
294
231
  if (conflictingRoute) {
295
232
  await fatal(`--base-path ${basePath} conflicts with the page ${conflictingRoute}. Pages can't start with the base path, so pick a different one.`);
296
233
  }
297
- addLog(_jsx(SpinnerLog, { message: "starting local server..." }));
298
- process.env.MINT_EXPORT = JSON.stringify({ groups, basePath: basePath || undefined });
299
234
  try {
300
- await generateExportArchive(routes, outputPath, groups, basePath);
235
+ await generateExportArchive(routes, outputPath, groups, basePath, vite);
301
236
  }
302
237
  catch (err) {
303
238
  await fatal(err instanceof Error && err.message ? err.message : 'export failed');
@@ -43,13 +43,6 @@ const startDev = async (argv) => {
43
43
  const cliVersion = argv.cliVersion;
44
44
  const disableOpenApi = argv.disableOpenapi;
45
45
  const disablePrefetch = argv.disablePrefetch;
46
- const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number);
47
- if (CLIENT_FRAMEWORK === 'vite' && (nodeMajor < 20 || (nodeMajor === 20 && nodeMinor < 11))) {
48
- clearLogs();
49
- addLog(_jsx(ErrorLog, { message: `${packageName} dev --beta needs node 20.11 or newer.` }));
50
- await new Promise((resolve) => setTimeout(resolve, 50));
51
- process.exit(1);
52
- }
53
46
  await timeDev('ensure preview directory', () => fse.ensureDir(PREVIEW_PATH));
54
47
  if (!localClientVersion && !clientVersion && CLIENT_FRAMEWORK === 'next') {
55
48
  timeDevSync('seed preview from shared workspace', () => seedPreviewFromShared());
@@ -126,7 +119,7 @@ const startDev = async (argv) => {
126
119
  };
127
120
  const dev = async (argv) => {
128
121
  const port = Number(argv.port ?? 3000);
129
- configurePreviewPath(port, argv.beta === true ? 'vite' : 'next');
122
+ configurePreviewPath(port, argv.classic === true ? 'next' : 'vite');
130
123
  const releasePreviewLock = acquirePreviewLock(port);
131
124
  try {
132
125
  await startDev(argv);
@@ -1,4 +1,13 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ type MintExportConfig = {
3
+ groups?: string[];
4
+ basePath?: string;
5
+ };
2
6
  type RequestListener = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
7
+ export type ExportFetch = (request: Request) => Promise<Response>;
3
8
  export declare const setupVite: () => Promise<RequestListener>;
9
+ export declare const setupViteExport: (mintExport: MintExportConfig) => Promise<{
10
+ fetchPage: ExportFetch;
11
+ assetPrefixes: string[];
12
+ }>;
4
13
  export {};
@@ -2,13 +2,26 @@ import fse from 'fs-extra';
2
2
  import path from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { CLIENT_PATH } from '../constants.js';
5
- export const setupVite = async () => {
5
+ const loadCliEntry = async () => {
6
6
  const entryPath = path.join(CLIENT_PATH, 'dist-cli', 'index.js');
7
7
  if (!(await fse.pathExists(entryPath))) {
8
8
  throw new Error(`Client not built. Run: cd <path>/apps/client-vite && pnpm build:cli`);
9
9
  }
10
- const entry = await import(pathToFileURL(entryPath).href);
10
+ return { entry: await import(pathToFileURL(entryPath).href), entryPath };
11
+ };
12
+ export const setupVite = async () => {
13
+ const { entry, entryPath } = await loadCliEntry();
11
14
  if (!entry.createCliHandler)
12
15
  throw new Error(`${entryPath} does not export createCliHandler`);
13
16
  return entry.createCliHandler();
14
17
  };
18
+ export const setupViteExport = async (mintExport) => {
19
+ const { entry } = await loadCliEntry();
20
+ if (!entry.createCliExportFetch || !entry.exportAssetPrefixes) {
21
+ throw new Error('this client version is too old to export, rerun online to fetch the latest client or export with --classic');
22
+ }
23
+ return {
24
+ fetchPage: await entry.createCliExportFetch(mintExport),
25
+ assetPrefixes: entry.exportAssetPrefixes,
26
+ };
27
+ };