@mintlify/previewing 4.0.526 → 4.0.528

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 @@
1
+ export {};
@@ -0,0 +1,125 @@
1
+ import { prebuild } from '@mintlify/prebuild';
2
+ import fse from 'fs-extra';
3
+ import isOnline from 'is-online';
4
+ import { mockProcessExit } from 'vitest-mock-process';
5
+ import { dev } from '../index.js';
6
+ import { downloadTargetMint, getTargetMintVersion } from '../local-preview/client.js';
7
+ import { run } from '../local-preview/run.js';
8
+ import * as utils from '../util.js';
9
+ const originalChdir = process.chdir;
10
+ vi.mock('fs-extra', () => {
11
+ const mocks = {
12
+ ensureDir: vi.fn().mockResolvedValue(undefined),
13
+ pathExists: vi.fn().mockResolvedValue(true),
14
+ readFileSync: vi.fn().mockReturnValue('1.0.0'),
15
+ emptyDirSync: vi.fn().mockResolvedValue(undefined),
16
+ };
17
+ return {
18
+ ...mocks,
19
+ default: mocks,
20
+ };
21
+ });
22
+ vi.mock('../local-preview/client.js', () => ({
23
+ getTargetMintVersion: vi.fn().mockResolvedValue('1.0.0'),
24
+ downloadTargetMint: vi.fn().mockResolvedValue(undefined),
25
+ }));
26
+ vi.mock('is-online', () => ({
27
+ default: vi.fn().mockResolvedValue(true),
28
+ }));
29
+ vi.mock('@mintlify/prebuild', () => ({
30
+ prebuild: vi.fn().mockResolvedValue(undefined),
31
+ }));
32
+ vi.mock('../local-preview/run.js', () => ({
33
+ run: vi.fn().mockResolvedValue(undefined),
34
+ }));
35
+ vi.mock('../util.js', () => {
36
+ const mockLogger = {
37
+ text: '',
38
+ succeed: vi.fn(),
39
+ fail: vi.fn(),
40
+ warn: vi.fn(),
41
+ start: vi.fn(),
42
+ stop: vi.fn(),
43
+ stopAndPersist: vi.fn(),
44
+ };
45
+ return {
46
+ buildLogger: vi.fn().mockReturnValue(mockLogger),
47
+ maybeFixMissingWindowsEnvVar: vi.fn(),
48
+ };
49
+ });
50
+ const prebuildMock = vi.mocked(prebuild);
51
+ const runMock = vi.mocked(run);
52
+ const buildLoggerMock = vi.mocked(utils.buildLogger);
53
+ const processExitMock = mockProcessExit();
54
+ const downloadTargetMintMock = vi.mocked(downloadTargetMint);
55
+ const emptyYargs = {
56
+ _: [],
57
+ $0: '',
58
+ };
59
+ describe('dev', () => {
60
+ beforeEach(() => {
61
+ process.chdir = vi.fn();
62
+ vi.clearAllMocks();
63
+ });
64
+ afterEach(() => {
65
+ process.chdir = originalChdir;
66
+ });
67
+ it('happy path', async () => {
68
+ await dev(emptyYargs);
69
+ expect(buildLoggerMock).toHaveBeenCalledWith('Preparing local Mintlify instance...');
70
+ expect(prebuildMock).toHaveBeenCalled();
71
+ expect(buildLoggerMock().succeed).toHaveBeenCalledWith('Local Mintlify instance is ready. Launching your site...');
72
+ expect(runMock).toHaveBeenCalled();
73
+ });
74
+ it('prebuild fails', async () => {
75
+ const errorText = 'Some OpenAPI or docs.json schema error';
76
+ prebuildMock.mockRejectedValueOnce(new Error(errorText));
77
+ await dev(emptyYargs);
78
+ expect(buildLoggerMock).toHaveBeenCalledWith('Preparing local Mintlify instance...');
79
+ expect(buildLoggerMock().fail).toHaveBeenCalledWith(errorText);
80
+ expect(processExitMock).toHaveBeenCalledWith(1);
81
+ });
82
+ });
83
+ describe('dev with no internet', () => {
84
+ beforeEach(() => {
85
+ process.chdir = vi.fn();
86
+ vi.clearAllMocks();
87
+ });
88
+ afterEach(() => {
89
+ process.chdir = originalChdir;
90
+ });
91
+ it('fails if no existing version', async () => {
92
+ vi.mocked(isOnline).mockResolvedValueOnce(false);
93
+ vi.mocked(fse.pathExists).mockResolvedValueOnce();
94
+ await dev(emptyYargs).catch(() => { });
95
+ expect(processExitMock).toHaveBeenCalledWith(1);
96
+ expect(buildLoggerMock().fail).toHaveBeenCalledWith('Running mintlify dev afer updating requires an internet connection.');
97
+ });
98
+ it('has existing version but fails to get targetMintVersion', async () => {
99
+ vi.mocked(isOnline).mockResolvedValueOnce(false);
100
+ vi.mocked(getTargetMintVersion).mockResolvedValueOnce(undefined);
101
+ await dev(emptyYargs);
102
+ expect(buildLoggerMock().warn).toHaveBeenCalledWith('Failed to get latest Mintlify client version. Your current version is: 1.0.0, which may not be the latest Mintlify client version.');
103
+ expect(prebuildMock).toHaveBeenCalled();
104
+ expect(buildLoggerMock().succeed).toHaveBeenCalledWith('Local Mintlify instance is ready. Launching your site...');
105
+ expect(runMock).toHaveBeenCalled();
106
+ });
107
+ });
108
+ describe('dev downloads new version', () => {
109
+ beforeEach(() => {
110
+ process.chdir = vi.fn();
111
+ vi.clearAllMocks();
112
+ });
113
+ afterEach(() => {
114
+ process.chdir = originalChdir;
115
+ });
116
+ it('happy path', async () => {
117
+ vi.mocked(getTargetMintVersion).mockResolvedValueOnce('1.0.1');
118
+ await dev(emptyYargs);
119
+ expect(buildLoggerMock).toHaveBeenCalledWith('Preparing local Mintlify instance...');
120
+ expect(downloadTargetMintMock).toHaveBeenCalled();
121
+ expect(prebuildMock).toHaveBeenCalled();
122
+ expect(buildLoggerMock().succeed).toHaveBeenCalledWith('Local Mintlify instance is ready. Launching your site...');
123
+ expect(runMock).toHaveBeenCalled();
124
+ });
125
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,219 @@
1
+ import fse from 'fs-extra';
2
+ import { pipeline } from 'node:stream/promises';
3
+ import tar from 'tar';
4
+ import { mockProcessExit } from 'vitest-mock-process';
5
+ import * as constants from '../constants.js';
6
+ import { downloadTargetMint } from '../local-preview/client.js';
7
+ import * as utils from '../util.js';
8
+ vi.mock('fs-extra', () => {
9
+ const mocks = {
10
+ existsSync: vi.fn().mockReturnValue(true),
11
+ moveSync: vi.fn().mockReturnValue(undefined),
12
+ ensureDirSync: vi.fn().mockReturnValue(undefined),
13
+ removeSync: vi.fn().mockReturnValue(undefined),
14
+ writeFileSync: vi.fn().mockReturnValue(undefined),
15
+ createWriteStream: vi.fn().mockReturnValue({ write: vi.fn(), end: vi.fn() }),
16
+ };
17
+ return {
18
+ ...mocks,
19
+ default: mocks,
20
+ };
21
+ });
22
+ vi.mock('../util.js', () => ({
23
+ buildLogger: vi.fn().mockReturnValue({
24
+ text: '',
25
+ succeed: vi.fn(),
26
+ fail: vi.fn(),
27
+ warn: vi.fn(),
28
+ start: vi.fn(),
29
+ stop: vi.fn(),
30
+ stopAndPersist: vi.fn(),
31
+ }),
32
+ restoreMintlifyLast: vi.fn().mockReturnValue(undefined),
33
+ }));
34
+ vi.mock('node:stream/promises', () => ({
35
+ pipeline: vi.fn(),
36
+ }));
37
+ vi.mock('got', () => {
38
+ const mocks = {
39
+ stream: vi.fn().mockReturnValue({ pipe: vi.fn(), on: vi.fn() }),
40
+ };
41
+ return {
42
+ ...mocks,
43
+ default: mocks,
44
+ };
45
+ });
46
+ vi.mock('tar', () => {
47
+ const mocks = {
48
+ x: vi.fn(),
49
+ };
50
+ return {
51
+ ...mocks,
52
+ default: mocks,
53
+ };
54
+ });
55
+ const buildLoggerMock = vi.mocked(utils.buildLogger);
56
+ const restoreMintlifyLastMock = vi.mocked(utils.restoreMintlifyLast);
57
+ const pipelineMock = vi.mocked(pipeline);
58
+ const GET_TAR_URL_SPY = vi.spyOn(constants, 'GET_TAR_URL');
59
+ const writeFileSyncMock = vi.mocked(fse.writeFileSync);
60
+ const tarMock = vi.mocked(tar);
61
+ const existsSyncMock = vi.mocked(fse.existsSync);
62
+ const moveSyncMock = vi.mocked(fse.moveSync);
63
+ const removeSyncMock = vi.mocked(fse.removeSync);
64
+ const processExitMock = mockProcessExit();
65
+ describe('downloadTargetMint', () => {
66
+ beforeEach(() => {
67
+ vi.clearAllMocks();
68
+ });
69
+ it('downloads and extracts a new version happy path', async () => {
70
+ const logger = buildLoggerMock();
71
+ const targetMintVersion = '1.0.1';
72
+ const versionString = '1.0.0';
73
+ pipelineMock.mockResolvedValue(undefined);
74
+ await downloadTargetMint({
75
+ logger,
76
+ targetVersion: targetMintVersion,
77
+ existingVersion: versionString,
78
+ });
79
+ // Verify backup was created
80
+ expect(existsSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
81
+ expect(moveSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY, constants.DOT_MINTLIFY_LAST, {
82
+ overwrite: true,
83
+ });
84
+ expect(fse.ensureDirSync).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
85
+ // Verify download and extraction
86
+ expect(GET_TAR_URL_SPY).toHaveBeenCalledWith(targetMintVersion);
87
+ expect(pipelineMock).toHaveBeenCalled();
88
+ expect(tarMock.x).toHaveBeenCalled();
89
+ expect(logger.text).toBe('Extracting Mintlify framework...');
90
+ // Verify cleanup
91
+ expect(removeSyncMock).toHaveBeenCalledWith(constants.TAR_PATH);
92
+ expect(removeSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY_LAST);
93
+ expect(writeFileSyncMock).toHaveBeenCalledWith(constants.VERSION_PATH, targetMintVersion);
94
+ // Verify no restore was needed
95
+ expect(restoreMintlifyLastMock).not.toHaveBeenCalled();
96
+ });
97
+ it('downloads and extracts a specific client version happy path', async () => {
98
+ const logger = buildLoggerMock();
99
+ const versionString = '1.0.0';
100
+ const clientVersion = '2.0.0';
101
+ pipelineMock.mockResolvedValue(undefined);
102
+ await downloadTargetMint({
103
+ logger,
104
+ targetVersion: clientVersion,
105
+ existingVersion: versionString,
106
+ });
107
+ // Verify backup was created
108
+ expect(existsSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
109
+ expect(moveSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY, constants.DOT_MINTLIFY_LAST, {
110
+ overwrite: true,
111
+ });
112
+ expect(fse.ensureDirSync).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
113
+ // Verify download and extraction
114
+ expect(GET_TAR_URL_SPY).toHaveBeenCalledWith(clientVersion);
115
+ expect(pipelineMock).toHaveBeenCalled();
116
+ expect(tarMock.x).toHaveBeenCalled();
117
+ expect(logger.text).toBe('Extracting Mintlify framework...');
118
+ // Verify cleanup
119
+ expect(removeSyncMock).toHaveBeenCalledWith(constants.TAR_PATH);
120
+ expect(removeSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY_LAST);
121
+ expect(writeFileSyncMock).toHaveBeenCalledWith(constants.VERSION_PATH, clientVersion);
122
+ // Verify no restore was needed
123
+ expect(restoreMintlifyLastMock).not.toHaveBeenCalled();
124
+ });
125
+ describe('downloadTargetMint with backup version', () => {
126
+ beforeEach(() => {
127
+ vi.clearAllMocks();
128
+ });
129
+ it('fails to download new version', async () => {
130
+ const logger = buildLoggerMock();
131
+ const targetMintVersion = '1.0.1';
132
+ const versionString = '1.0.0';
133
+ pipelineMock.mockRejectedValue(new Error('connection timed out'));
134
+ await downloadTargetMint({
135
+ logger,
136
+ targetVersion: targetMintVersion,
137
+ existingVersion: versionString,
138
+ });
139
+ // Verify backup was created
140
+ expect(existsSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
141
+ expect(moveSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY, constants.DOT_MINTLIFY_LAST, {
142
+ overwrite: true,
143
+ });
144
+ expect(fse.ensureDirSync).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
145
+ // Verify download fail
146
+ expect(logger.warn).toHaveBeenCalledWith('Failed to download Mintlify framework version 1.0.1, Error: connection timed out, falling back to existing version: 1.0.0');
147
+ // Verify use backup version
148
+ expect(restoreMintlifyLastMock).toHaveBeenCalled();
149
+ // Verify no extraction
150
+ expect(tarMock.x).not.toHaveBeenCalled();
151
+ // Verify no cleanup
152
+ expect(removeSyncMock).not.toHaveBeenCalled();
153
+ expect(writeFileSyncMock).not.toHaveBeenCalled();
154
+ });
155
+ it('fails to extract new version', async () => {
156
+ const logger = buildLoggerMock();
157
+ const targetMintVersion = '1.0.1';
158
+ const versionString = '1.0.0';
159
+ pipelineMock.mockResolvedValue(undefined);
160
+ tarMock.x.mockImplementation(() => {
161
+ throw new Error('Zlib error');
162
+ });
163
+ await downloadTargetMint({
164
+ logger,
165
+ targetVersion: targetMintVersion,
166
+ existingVersion: versionString,
167
+ });
168
+ // Verify backup was created
169
+ expect(existsSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
170
+ expect(moveSyncMock).toHaveBeenCalledWith(constants.DOT_MINTLIFY, constants.DOT_MINTLIFY_LAST, {
171
+ overwrite: true,
172
+ });
173
+ expect(fse.ensureDirSync).toHaveBeenCalledWith(constants.DOT_MINTLIFY);
174
+ // Verify download success
175
+ expect(pipelineMock).toHaveBeenCalled();
176
+ // Verify extraction fail
177
+ expect(logger.warn).toHaveBeenCalledWith('Failed to extract Mintlify framework version 1.0.1, Error: Zlib error, using existing version: 1.0.0');
178
+ // Verify use backup version
179
+ expect(restoreMintlifyLastMock).toHaveBeenCalled();
180
+ // Verify no cleanup
181
+ expect(removeSyncMock).not.toHaveBeenCalled();
182
+ expect(writeFileSyncMock).not.toHaveBeenCalled();
183
+ });
184
+ });
185
+ describe('downloadTargetMint without backup version', () => {
186
+ beforeEach(() => {
187
+ vi.clearAllMocks();
188
+ });
189
+ it('fails to download new version with no fallback', async () => {
190
+ const logger = buildLoggerMock();
191
+ const targetMintVersion = '1.0.1';
192
+ const versionString = null;
193
+ pipelineMock.mockRejectedValue(new Error('connection timed out'));
194
+ await downloadTargetMint({
195
+ logger,
196
+ targetVersion: targetMintVersion,
197
+ existingVersion: versionString,
198
+ });
199
+ expect(logger.fail).toHaveBeenCalledWith('Failed to download Mintlify framework version 1.0.1, Error: connection timed out');
200
+ expect(processExitMock).toHaveBeenCalledWith(1);
201
+ });
202
+ it('fails to extract new version with no fallback', async () => {
203
+ const logger = buildLoggerMock();
204
+ const targetMintVersion = '1.0.1';
205
+ const versionString = null;
206
+ pipelineMock.mockResolvedValue(undefined);
207
+ tarMock.x.mockImplementation(() => {
208
+ throw new Error('Zlib error');
209
+ });
210
+ await downloadTargetMint({
211
+ logger,
212
+ targetVersion: targetMintVersion,
213
+ existingVersion: versionString,
214
+ });
215
+ expect(logger.fail).toHaveBeenCalledWith('Failed to extract Mintlify framework version 1.0.1, Error: Zlib error');
216
+ expect(processExitMock).toHaveBeenCalledWith(1);
217
+ });
218
+ });
219
+ });
@@ -1,6 +1,7 @@
1
1
  export declare const INSTALL_PATH: string;
2
2
  export declare const HOME_DIR: string;
3
3
  export declare const DOT_MINTLIFY: string;
4
+ export declare const DOT_MINTLIFY_LAST = ".mintlify-last";
4
5
  export declare const MINT_PATH: string;
5
6
  export declare const VERSION_PATH: string;
6
7
  export declare const CLIENT_PATH: string;
package/dist/constants.js CHANGED
@@ -5,6 +5,7 @@ import * as url from 'url';
5
5
  export const INSTALL_PATH = url.fileURLToPath(new URL('.', import.meta.url));
6
6
  export const HOME_DIR = os.homedir();
7
7
  export const DOT_MINTLIFY = path.join(HOME_DIR, '.mintlify');
8
+ export const DOT_MINTLIFY_LAST = '.mintlify-last';
8
9
  export const MINT_PATH = path.join(DOT_MINTLIFY, 'mint');
9
10
  export const VERSION_PATH = path.join(MINT_PATH, 'mint-version.txt');
10
11
  export const CLIENT_PATH = path.join(MINT_PATH, 'apps', 'client');
@@ -1,5 +1,7 @@
1
1
  import type { Ora as OraType } from 'ora';
2
2
  export declare const getTargetMintVersion: (logger: OraType) => Promise<string | undefined>;
3
- export declare const fallbackMintClient: (logger: OraType, versionString: string) => Promise<void>;
4
- export declare const extractMintClient: (logger: OraType) => Promise<void>;
5
- export declare const downloadTargetMint: (logger: OraType, targetMintVersion: string, versionString: string | null, clientVersion: string | undefined) => Promise<void>;
3
+ export declare const downloadTargetMint: ({ logger, targetVersion, existingVersion, }: {
4
+ logger: OraType;
5
+ targetVersion: string;
6
+ existingVersion: string | null;
7
+ }) => Promise<void>;
@@ -1,90 +1,73 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import fse from 'fs-extra';
11
2
  import got from 'got';
12
3
  import isOnline from 'is-online';
13
4
  import { pipeline } from 'node:stream/promises';
14
5
  import tar from 'tar';
15
- import { DOT_MINTLIFY, VERSION_PATH, MINT_PATH, TAR_PATH, TARGET_MINT_VERSION_URL, GET_TAR_URL, } from '../constants.js';
16
- export const getTargetMintVersion = (logger) => __awaiter(void 0, void 0, void 0, function* () {
17
- const hasInternet = yield isOnline();
6
+ import { DOT_MINTLIFY, DOT_MINTLIFY_LAST, VERSION_PATH, TAR_PATH, TARGET_MINT_VERSION_URL, GET_TAR_URL, } from '../constants.js';
7
+ import { restoreMintlifyLast } from '../util.js';
8
+ export const getTargetMintVersion = async (logger) => {
9
+ const hasInternet = await isOnline();
18
10
  if (!hasInternet) {
19
11
  return undefined;
20
12
  }
21
13
  try {
22
- const response = yield got(TARGET_MINT_VERSION_URL);
14
+ const response = await got(TARGET_MINT_VERSION_URL);
23
15
  return response.body;
24
16
  }
25
17
  catch (error) {
26
18
  logger.text = `Failed to fetch the latest Mintlify version: ${error instanceof Error ? error.message : 'Unknown error'}`;
27
- return undefined;
28
- }
29
- });
30
- export const fallbackMintClient = (logger, versionString) => __awaiter(void 0, void 0, void 0, function* () {
31
- logger.text = `Using version: ${versionString}`;
32
- const oldTarUrl = GET_TAR_URL(versionString);
33
- try {
34
- yield pipeline(got.stream(oldTarUrl), fse.createWriteStream(TAR_PATH));
35
- }
36
- catch (error) {
37
- logger.fail(`Failed to download Mintlify framework version ${versionString}, ${error}`);
38
- process.exit(1);
39
19
  }
40
- try {
41
- yield extractMintClient(logger);
42
- }
43
- catch (error) {
44
- logger.fail(`Failed to extract Mintlify framework version ${versionString}, ${error}`);
45
- process.exit(1);
20
+ return undefined;
21
+ };
22
+ export const downloadTargetMint = async ({ logger, targetVersion, existingVersion, }) => {
23
+ if (fse.existsSync(DOT_MINTLIFY)) {
24
+ fse.moveSync(DOT_MINTLIFY, DOT_MINTLIFY_LAST, { overwrite: true });
46
25
  }
47
- });
48
- export const extractMintClient = (logger) => __awaiter(void 0, void 0, void 0, function* () {
49
- logger.text = 'Extracting Mintlify framework...';
50
- tar.x({
51
- sync: true,
52
- file: TAR_PATH,
53
- cwd: DOT_MINTLIFY,
54
- onwarn: (_code, message, _data) => {
55
- throw new Error(message);
56
- },
57
- });
58
- });
59
- export const downloadTargetMint = (logger, targetMintVersion, versionString, clientVersion) => __awaiter(void 0, void 0, void 0, function* () {
60
- fse.emptyDirSync(MINT_PATH);
26
+ fse.ensureDirSync(DOT_MINTLIFY);
61
27
  logger.text = 'Downloading Mintlify framework...';
62
- const tarUrl = clientVersion ? GET_TAR_URL(clientVersion) : GET_TAR_URL(targetMintVersion);
63
- let currentVersion = clientVersion || targetMintVersion;
28
+ const tarUrl = GET_TAR_URL(targetVersion);
29
+ let currentVersion = targetVersion.trim();
64
30
  try {
65
- yield pipeline(got.stream(tarUrl), fse.createWriteStream(TAR_PATH));
31
+ await pipeline(got.stream(tarUrl), fse.createWriteStream(TAR_PATH));
66
32
  }
67
33
  catch (error) {
68
- if (versionString) {
69
- currentVersion = versionString;
70
- yield fallbackMintClient(logger, versionString);
34
+ if (existingVersion) {
35
+ logger.warn(`Failed to download Mintlify framework version ${currentVersion}, ${error}, falling back to existing version: ${existingVersion}`);
36
+ currentVersion = existingVersion;
37
+ restoreMintlifyLast();
38
+ return;
71
39
  }
72
40
  else {
41
+ logger.fail(`Failed to download Mintlify framework version ${currentVersion}, ${error}`);
73
42
  process.exit(1);
74
43
  }
75
44
  }
76
45
  try {
77
- yield extractMintClient(logger);
46
+ logger.text = 'Extracting Mintlify framework...';
47
+ tar.x({
48
+ sync: true,
49
+ file: TAR_PATH,
50
+ cwd: DOT_MINTLIFY,
51
+ onwarn: (_code, message, _data) => {
52
+ throw new Error(message);
53
+ },
54
+ });
78
55
  }
79
56
  catch (error) {
80
- if (versionString && currentVersion !== versionString) {
81
- currentVersion = versionString;
82
- yield fallbackMintClient(logger, versionString);
57
+ if (existingVersion) {
58
+ logger.warn(`Failed to extract Mintlify framework version ${currentVersion}, ${error}, using existing version: ${existingVersion}`);
59
+ currentVersion = existingVersion;
60
+ restoreMintlifyLast();
61
+ return;
83
62
  }
84
63
  else {
64
+ logger.fail(`Failed to extract Mintlify framework version ${currentVersion}, ${error}`);
85
65
  process.exit(1);
86
66
  }
87
67
  }
88
68
  fse.removeSync(TAR_PATH);
89
- fse.writeFileSync(VERSION_PATH, targetMintVersion);
90
- });
69
+ if (fse.existsSync(DOT_MINTLIFY_LAST)) {
70
+ fse.removeSync(DOT_MINTLIFY_LAST);
71
+ }
72
+ fse.writeFileSync(VERSION_PATH, currentVersion);
73
+ };
@@ -1,59 +1,46 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { prebuild } from '@mintlify/prebuild';
11
- import open from 'better-opn';
12
- import Chalk from 'chalk';
13
- import express from 'express';
14
2
  import fse, { pathExists } from 'fs-extra';
15
- import { createServer } from 'http';
16
3
  import isOnline from 'is-online';
17
- import { pathToFileURL } from 'node:url';
18
- import { Server as SocketServer } from 'socket.io';
19
- import { CLIENT_PATH, DOT_MINTLIFY, CMD_EXEC_PATH, VERSION_PATH, NEXT_CONFIG_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, NEXT_SIDE_EFFECT_PATH, NEXT_ROUTER_SERVER_PATH, } from '../constants.js';
20
- import { buildLogger, maybeFixMissingWindowsEnvVar } from '../util.js';
4
+ import { CLIENT_PATH, DOT_MINTLIFY, CMD_EXEC_PATH, VERSION_PATH, NEXT_PUBLIC_PATH, NEXT_PROPS_PATH, } from '../constants.js';
5
+ import { buildLogger } from '../util.js';
21
6
  import { getTargetMintVersion, downloadTargetMint } from './client.js';
22
- import listener from './listener/index.js';
23
- const dev = (argv) => __awaiter(void 0, void 0, void 0, function* () {
7
+ import { run } from './run.js';
8
+ const dev = async (argv) => {
24
9
  // Note: We wait for specific text in the logger to be sure the server is ready when we e2e test the cli.
25
10
  // If the cli output does not exactly match:
26
11
  // "- Preparing local Mintlify instance...\n✔ Local Mintlify instance is ready. Launching your site...\nYour local preview is available at http://localhost:3000\nPress Ctrl+C any time to stop the local preview."
27
12
  // the test will fail/require an update.
28
13
  const logger = buildLogger('Preparing local Mintlify instance...');
29
- const hasInternet = yield isOnline();
14
+ const hasInternet = await isOnline();
30
15
  const localSchema = argv['local-schema'];
31
16
  const clientVersion = argv['client-version'];
32
- yield fse.ensureDir(DOT_MINTLIFY);
33
- const versionString = (yield pathExists(VERSION_PATH))
17
+ await fse.ensureDir(DOT_MINTLIFY);
18
+ const versionString = (await pathExists(VERSION_PATH))
34
19
  ? fse.readFileSync(VERSION_PATH, 'utf8')
35
20
  : null;
36
21
  if (!versionString && !hasInternet) {
37
22
  logger.fail('Running mintlify dev afer updating requires an internet connection.');
38
23
  process.exit(1);
39
24
  }
40
- const targetMintVersion = yield getTargetMintVersion(logger);
25
+ const targetMintVersion = await getTargetMintVersion(logger);
41
26
  if (!targetMintVersion) {
42
- logger.text =
43
- 'Failed to get latest Mintlify client version. Your current version is: ' +
44
- versionString +
45
- ', which may not be the latest Mintlify client version.';
27
+ logger.stopAndPersist({ symbol: '✓' });
28
+ logger.warn(`Failed to get latest Mintlify client version. Your current version is: ${versionString?.trim()}, which may not be the latest Mintlify client version.`);
46
29
  }
47
30
  const shouldDownload = versionString !== targetMintVersion || clientVersion !== undefined;
48
31
  if (shouldDownload && hasInternet && targetMintVersion) {
49
- yield downloadTargetMint(logger, targetMintVersion, versionString, clientVersion);
32
+ await downloadTargetMint({
33
+ logger,
34
+ targetVersion: clientVersion ?? targetMintVersion,
35
+ existingVersion: versionString,
36
+ });
50
37
  }
51
38
  // clear preexisting prebuild files
52
39
  fse.emptyDirSync(NEXT_PUBLIC_PATH);
53
40
  fse.emptyDirSync(NEXT_PROPS_PATH);
54
41
  process.chdir(CLIENT_PATH);
55
42
  try {
56
- yield prebuild(CMD_EXEC_PATH, { localSchema });
43
+ await prebuild(CMD_EXEC_PATH, { localSchema });
57
44
  }
58
45
  catch (err) {
59
46
  const errorText = err instanceof Error && err.message ? err.message : 'Prebuild step failed';
@@ -61,82 +48,6 @@ const dev = (argv) => __awaiter(void 0, void 0, void 0, function* () {
61
48
  process.exit(1);
62
49
  }
63
50
  logger.succeed('Local Mintlify instance is ready. Launching your site...');
64
- yield run(argv);
65
- });
66
- /**
67
- * When creating a standalone build, next.js outputs a server.js file that can be used as
68
- * an entry point into the server. However, because we want to customize some parts of the
69
- * http server (adding a socket.io server, serving the whole public directory), we
70
- * create the server ourselves, and just reproduce the setup that next.js would do.
71
- *
72
- * Because we need to directly import from node_modules files, this solution seems very hacky,
73
- * but it is arguably no more hacky than using the server.js that ships with the standalone
74
- * build.
75
- *
76
- * This function attempts to replicate the behavior of two next.js files:
77
- * - environment setup from server.js
78
- * - initialization of the request handler from start-server.ts
79
- *
80
- * Links:
81
- * - [standalone build](https://nextjs.org/docs/pages/api-reference/next-config-js/output#automatically-copying-traced-files)
82
- * - [server.js](https://github.com/vercel/next.js/blob/492156b4c5e2559b2a280f7d483cd85a8e8742a9/packages/next/src/build/utils.ts#L2108-L2113) (created programmatically)
83
- * - [start-server.ts](https://github.com/vercel/next.js/blob/492156b4c5e2559b2a280f7d483cd85a8e8742a9/packages/next/src/server/lib/start-server.ts#L296-L308)
84
- *
85
- * @returns the request handler provided by next.js
86
- */
87
- const setupNext = () => __awaiter(void 0, void 0, void 0, function* () {
88
- const hostname = process.env.HOSTNAME || 'localhost';
89
- const { config } = yield JSON.parse(fse.readFileSync(NEXT_CONFIG_PATH, 'utf8'));
90
- process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config);
91
- // The server.js provided by next.js's standalone build does a similar import of this file.
92
- // Not sure what side effects are being created, but want to change as little as possible.
93
- // Also, Windows requires us to use `pathToFileURL` (see #899)
94
- yield import(pathToFileURL(NEXT_SIDE_EFFECT_PATH).href);
95
- const { initialize } = yield import(pathToFileURL(NEXT_ROUTER_SERVER_PATH).href);
96
- const [requestHandler] = yield initialize({
97
- dir: CLIENT_PATH,
98
- dev: false,
99
- hostname,
100
- minimalMode: true,
101
- });
102
- return requestHandler;
103
- });
104
- const run = (argv) => __awaiter(void 0, void 0, void 0, function* () {
105
- const port = argv.port || '3000';
106
- const currentPort = parseInt(port, 10) || 3000;
107
- const app = express();
108
- const server = createServer(app);
109
- const io = new SocketServer(server);
110
- const requestHandler = yield setupNext();
111
- // next-server is bugged, public files added after starting aren't served
112
- app.use('/', express.static(NEXT_PUBLIC_PATH));
113
- app.all('*', (req, res) => requestHandler(req, res));
114
- const onChange = () => {
115
- io.emit('reload');
116
- };
117
- server.listen(currentPort, () => {
118
- console.log(`${Chalk.green(`Your local preview is available at http://localhost:${port}`)}`);
119
- // Note: We wait for this exact text to be sure the server is ready in the cli e2e test,
120
- // if it changes, the test will fail/require an update.
121
- console.log(`${Chalk.green('Press Ctrl+C any time to stop the local preview.')}`);
122
- /**
123
- * We're running into a known bug with the `open` package, where Windows machines error out because process.env.SYSTEMROOT is not set:
124
- * https://github.com/sindresorhus/open/issues/292
125
- *
126
- * Let's use the same workaround that this project did:
127
- * https://github.com/sanity-io/sanity/pull/4221/files#diff-aeb574e1becf61f21fdf87fbea709669c93d604d660dad4b0f9e24527a2fb54bR256-R262
128
- */
129
- maybeFixMissingWindowsEnvVar();
130
- if (argv.open) {
131
- void open(`http://localhost:${port}`);
132
- }
133
- // exit with successful status
134
- const onExit = () => {
135
- process.exit(0);
136
- };
137
- process.on('SIGINT', onExit);
138
- process.on('SIGTERM', onExit);
139
- });
140
- listener(onChange);
141
- });
51
+ await run(argv);
52
+ };
142
53
  export default dev;