@mintlify/previewing 4.0.850 → 4.0.852

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.
@@ -18,10 +18,12 @@ describe('silentUpdateClient', () => {
18
18
  it('has latest client version already', async () => {
19
19
  const versionString = '0.0.100';
20
20
  const clientVersion = undefined;
21
+ const localClientVersion = undefined;
21
22
  const cliVersion = undefined;
22
23
  const { needsUpdate, error } = await silentUpdateClient({
23
24
  versionString,
24
25
  clientVersion,
26
+ localClientVersion,
25
27
  cliVersion,
26
28
  });
27
29
  expect(tryDownloadTargetMintSpy).not.toHaveBeenCalled();
@@ -31,10 +33,12 @@ describe('silentUpdateClient', () => {
31
33
  it('has no client version and downloads latest', async () => {
32
34
  const versionString = null;
33
35
  const clientVersion = undefined;
36
+ const localClientVersion = undefined;
34
37
  const cliVersion = undefined;
35
38
  const { needsUpdate, error } = await silentUpdateClient({
36
39
  versionString,
37
40
  clientVersion,
41
+ localClientVersion,
38
42
  cliVersion,
39
43
  });
40
44
  expect(tryDownloadTargetMintSpy).toHaveBeenCalledWith({
@@ -47,10 +51,12 @@ describe('silentUpdateClient', () => {
47
51
  it('always downloads latest for locally linked cli', async () => {
48
52
  const versionString = null;
49
53
  const clientVersion = undefined;
54
+ const localClientVersion = undefined;
50
55
  const cliVersion = LOCAL_LINKED_CLI_VERSION;
51
56
  const { needsUpdate, error } = await silentUpdateClient({
52
57
  versionString,
53
58
  clientVersion,
59
+ localClientVersion,
54
60
  cliVersion,
55
61
  });
56
62
  expect(tryDownloadTargetMintSpy).toHaveBeenCalledWith({
@@ -63,10 +69,12 @@ describe('silentUpdateClient', () => {
63
69
  it('compatible client version is latest and downloads latest', async () => {
64
70
  const versionString = null;
65
71
  const clientVersion = undefined;
72
+ const localClientVersion = undefined;
66
73
  const cliVersion = '4.2.0';
67
74
  const { needsUpdate, error } = await silentUpdateClient({
68
75
  versionString,
69
76
  clientVersion,
77
+ localClientVersion,
70
78
  cliVersion,
71
79
  });
72
80
  expect(tryDownloadTargetMintSpy).toHaveBeenCalledWith({
@@ -80,10 +88,12 @@ describe('silentUpdateClient', () => {
80
88
  vi.mocked(client.getCompatibleClientVersion).mockResolvedValueOnce('0.0.99');
81
89
  const versionString = '0.0.99';
82
90
  const clientVersion = undefined;
91
+ const localClientVersion = undefined;
83
92
  const cliVersion = '4.2.0';
84
93
  const { needsUpdate, error } = await silentUpdateClient({
85
94
  versionString,
86
95
  clientVersion,
96
+ localClientVersion,
87
97
  cliVersion,
88
98
  });
89
99
  expect(tryDownloadTargetMintSpy).not.toHaveBeenCalled();
@@ -94,10 +104,12 @@ describe('silentUpdateClient', () => {
94
104
  vi.mocked(client.getCompatibleClientVersion).mockResolvedValueOnce('0.0.99');
95
105
  const versionString = '0.0.98';
96
106
  const clientVersion = undefined;
107
+ const localClientVersion = undefined;
97
108
  const cliVersion = '4.2.0';
98
109
  const { needsUpdate, error } = await silentUpdateClient({
99
110
  versionString,
100
111
  clientVersion,
112
+ localClientVersion,
101
113
  cliVersion,
102
114
  });
103
115
  expect(tryDownloadTargetMintSpy).toHaveBeenCalledWith({
@@ -111,10 +123,12 @@ describe('silentUpdateClient', () => {
111
123
  vi.mocked(client.getCompatibleClientVersion).mockResolvedValueOnce(undefined);
112
124
  const versionString = '0.0.98';
113
125
  const clientVersion = undefined;
126
+ const localClientVersion = undefined;
114
127
  const cliVersion = '4.2.0';
115
128
  const { needsUpdate, error } = await silentUpdateClient({
116
129
  versionString,
117
130
  clientVersion,
131
+ localClientVersion,
118
132
  cliVersion,
119
133
  });
120
134
  expect(tryDownloadTargetMintSpy).not.toHaveBeenCalled();
@@ -126,10 +140,12 @@ describe('silentUpdateClient', () => {
126
140
  vi.mocked(client.tryDownloadTargetMint).mockResolvedValueOnce('some error');
127
141
  const versionString = null;
128
142
  const clientVersion = undefined;
143
+ const localClientVersion = undefined;
129
144
  const cliVersion = '4.2.0';
130
145
  const { needsUpdate, error } = await silentUpdateClient({
131
146
  versionString,
132
147
  clientVersion,
148
+ localClientVersion,
133
149
  cliVersion,
134
150
  });
135
151
  expect(tryDownloadTargetMintSpy).toHaveBeenCalledWith({
@@ -11,6 +11,7 @@ const dev = async (argv) => {
11
11
  const hasInternet = await isOnline();
12
12
  const localSchema = argv['local-schema'];
13
13
  const clientVersion = argv['client-version'];
14
+ const localClientVersion = argv['local-client-version'];
14
15
  const packageName = argv.packageName;
15
16
  const groups = argv.groups;
16
17
  const cliVersion = argv.cliVersion;
@@ -19,7 +20,7 @@ const dev = async (argv) => {
19
20
  const versionString = (await pathExists(VERSION_PATH))
20
21
  ? fse.readFileSync(VERSION_PATH, 'utf8')
21
22
  : null;
22
- if (!versionString && !hasInternet) {
23
+ if (!versionString && !localClientVersion && !hasInternet) {
23
24
  clearLogs();
24
25
  addLog(_jsx(ErrorLog, { message: `running ${packageName} dev after updating requires an internet connection.` }));
25
26
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -29,6 +30,7 @@ const dev = async (argv) => {
29
30
  const { needsUpdate, error } = await silentUpdateClient({
30
31
  versionString,
31
32
  clientVersion,
33
+ localClientVersion,
32
34
  cliVersion,
33
35
  });
34
36
  if (error) {
@@ -24,7 +24,20 @@ import { CLIENT_PATH, NEXT_CONFIG_PATH, NEXT_ROUTER_SERVER_PATH, NEXT_SIDE_EFFEC
24
24
  */
25
25
  export const setupNext = async () => {
26
26
  const hostname = process.env.HOSTNAME || 'localhost';
27
- const { config } = await JSON.parse(fse.readFileSync(NEXT_CONFIG_PATH, 'utf8'));
27
+ let config;
28
+ try {
29
+ const configFile = fse.readFileSync(NEXT_CONFIG_PATH, 'utf8');
30
+ config = JSON.parse(configFile).config;
31
+ }
32
+ catch (err) {
33
+ if (err instanceof Error &&
34
+ 'code' in err &&
35
+ err.code === 'ENOENT' &&
36
+ NEXT_CONFIG_PATH.includes('.next/required-server-files.json')) {
37
+ throw new Error(`Client not built. Run: cd <path>/apps/client && STANDALONE_BUILD=true NEXT_PUBLIC_ENV=cli yarn build`);
38
+ }
39
+ throw err;
40
+ }
28
41
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(config);
29
42
  // The server.js provided by next.js's standalone build does a similar import of this file.
30
43
  // Not sure what side effects are being created, but want to change as little as possible.
@@ -1,6 +1,7 @@
1
- export declare const silentUpdateClient: ({ versionString, clientVersion, cliVersion }: {
1
+ export declare const silentUpdateClient: ({ versionString, clientVersion, localClientVersion, cliVersion, }: {
2
2
  versionString: string | null;
3
3
  clientVersion: string | undefined;
4
+ localClientVersion: string | undefined;
4
5
  cliVersion: string | undefined;
5
6
  }) => Promise<{
6
7
  needsUpdate: boolean;
@@ -1,30 +1,160 @@
1
- import { getLatestClientVersion, tryDownloadTargetMint, getCompatibleClientVersion } from "./client.js";
2
- import { LOCAL_LINKED_CLI_VERSION } from "../constants.js";
3
- export const silentUpdateClient = async ({ versionString, clientVersion, cliVersion }) => {
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { spawn } from 'child_process';
3
+ import fse from 'fs-extra';
4
+ import path from 'path';
5
+ import { LOCAL_LINKED_CLI_VERSION, MINT_PATH, DOT_MINTLIFY, CLIENT_PATH } from '../constants.js';
6
+ import { clearLogs, addLog } from '../logging-state.js';
7
+ import { SpinnerLog } from '../logs.js';
8
+ import { getLatestClientVersion, tryDownloadTargetMint, getCompatibleClientVersion, } from './client.js';
9
+ const MINT_BACKUP_PATH = path.join(DOT_MINTLIFY, 'mint-backup');
10
+ const isCurrentlySymlinked = async () => {
11
+ if (!(await fse.pathExists(MINT_PATH)))
12
+ return false;
13
+ const stats = await fse.lstat(MINT_PATH);
14
+ return stats.isSymbolicLink();
15
+ };
16
+ const buildClient = async () => {
17
+ return new Promise((resolve) => {
18
+ clearLogs();
19
+ addLog(_jsx(SpinnerLog, { message: "building local client (this may take a few minutes)..." }));
20
+ const buildProcess = spawn('yarn', ['build'], {
21
+ cwd: CLIENT_PATH,
22
+ env: {
23
+ ...process.env,
24
+ STANDALONE_BUILD: 'true',
25
+ NEXT_PUBLIC_ENV: 'cli',
26
+ NEXT_PUBLIC_IS_LOCAL_CLIENT: 'true',
27
+ },
28
+ stdio: 'pipe',
29
+ shell: true,
30
+ });
31
+ let stderr = '';
32
+ buildProcess.stderr.on('data', (data) => {
33
+ stderr += data.toString();
34
+ });
35
+ buildProcess.on('close', (code) => {
36
+ if (code === 0) {
37
+ resolve(undefined);
38
+ }
39
+ else {
40
+ resolve(`Client build failed (exit code ${code}): ${stderr.slice(-500)}`);
41
+ }
42
+ });
43
+ buildProcess.on('error', (err) => {
44
+ resolve(`Client build error: ${err.message}`);
45
+ });
46
+ });
47
+ };
48
+ const restoreFromBackup = async () => {
49
+ try {
50
+ if (await isCurrentlySymlinked()) {
51
+ await fse.remove(MINT_PATH);
52
+ }
53
+ if (await fse.pathExists(MINT_BACKUP_PATH)) {
54
+ await fse.move(MINT_BACKUP_PATH, MINT_PATH);
55
+ }
56
+ return undefined;
57
+ }
58
+ catch (err) {
59
+ return err instanceof Error ? err.message : 'unknown error';
60
+ }
61
+ };
62
+ const symlinkLocalClient = async (targetPath) => {
63
+ try {
64
+ const resolvedPath = path.resolve(targetPath);
65
+ if (!(await fse.pathExists(resolvedPath))) {
66
+ return `Path does not exist: ${resolvedPath}`;
67
+ }
68
+ const stats = await fse.stat(resolvedPath);
69
+ if (!stats.isDirectory()) {
70
+ return `Path is not a directory: ${resolvedPath}`;
71
+ }
72
+ if (await fse.pathExists(MINT_PATH)) {
73
+ const existingStats = await fse.lstat(MINT_PATH);
74
+ if (existingStats.isSymbolicLink()) {
75
+ await fse.remove(MINT_PATH);
76
+ }
77
+ else {
78
+ if (await fse.pathExists(MINT_BACKUP_PATH)) {
79
+ await fse.remove(MINT_BACKUP_PATH);
80
+ }
81
+ await fse.move(MINT_PATH, MINT_BACKUP_PATH);
82
+ }
83
+ }
84
+ await fse.ensureDir(path.dirname(MINT_PATH));
85
+ await fse.symlink(resolvedPath, MINT_PATH);
86
+ const buildError = await buildClient();
87
+ if (buildError) {
88
+ return buildError;
89
+ }
90
+ return undefined;
91
+ }
92
+ catch (err) {
93
+ return err instanceof Error ? err.message : 'unknown error';
94
+ }
95
+ };
96
+ export const silentUpdateClient = async ({ versionString, clientVersion, localClientVersion, cliVersion, }) => {
97
+ // Handle local client symlink
98
+ if (localClientVersion) {
99
+ const error = await symlinkLocalClient(localClientVersion);
100
+ return { needsUpdate: false, error };
101
+ }
102
+ // If currently symlinked but not using local client, restore from backup
103
+ if (await isCurrentlySymlinked()) {
104
+ const restoreError = await restoreFromBackup();
105
+ if (restoreError) {
106
+ return { needsUpdate: false, error: restoreError };
107
+ }
108
+ // Re-read version string after restore
109
+ const newVersionString = (await fse.pathExists(path.join(MINT_PATH, 'mint-version.txt')))
110
+ ? fse.readFileSync(path.join(MINT_PATH, 'mint-version.txt'), 'utf8')
111
+ : null;
112
+ // Continue with normal update logic using restored version
113
+ return silentUpdateClientInternal({
114
+ versionString: newVersionString,
115
+ clientVersion,
116
+ cliVersion,
117
+ });
118
+ }
119
+ return silentUpdateClientInternal({ versionString, clientVersion, cliVersion });
120
+ };
121
+ const silentUpdateClientInternal = async ({ versionString, clientVersion, cliVersion, }) => {
4
122
  const latestClientVersion = await getLatestClientVersion();
5
123
  const hasLatestClientVersion = latestClientVersion && versionString && versionString.trim() === latestClientVersion.trim();
6
124
  if (clientVersion) {
7
125
  // always download specific client version if provided
8
- const error = await tryDownloadTargetMint({ targetVersion: clientVersion, existingVersion: versionString });
126
+ const error = await tryDownloadTargetMint({
127
+ targetVersion: clientVersion,
128
+ existingVersion: versionString,
129
+ });
9
130
  return { needsUpdate: false, error };
10
131
  }
11
132
  else if ((!versionString || cliVersion === LOCAL_LINKED_CLI_VERSION) && latestClientVersion) {
12
133
  // if no version exists, download latest
13
- const error = await tryDownloadTargetMint({ targetVersion: latestClientVersion, existingVersion: null });
134
+ const error = await tryDownloadTargetMint({
135
+ targetVersion: latestClientVersion,
136
+ existingVersion: null,
137
+ });
14
138
  return { needsUpdate: false, error };
15
139
  }
16
140
  else if (cliVersion && !hasLatestClientVersion) {
17
141
  // if not on latest, check whether to download latest or max
18
142
  const maxClientVersion = await getCompatibleClientVersion({ cliVersion });
19
143
  const hasMaxClientVersion = maxClientVersion && versionString && versionString.trim() === maxClientVersion.trim();
20
- if (maxClientVersion === "latest" && latestClientVersion) {
144
+ if (maxClientVersion === 'latest' && latestClientVersion) {
21
145
  // if latest, download latest
22
- const error = await tryDownloadTargetMint({ targetVersion: latestClientVersion, existingVersion: versionString });
146
+ const error = await tryDownloadTargetMint({
147
+ targetVersion: latestClientVersion,
148
+ existingVersion: versionString,
149
+ });
23
150
  return { needsUpdate: false, error };
24
151
  }
25
152
  else if (maxClientVersion && !hasMaxClientVersion) {
26
153
  // if maxxed out, needs update
27
- const error = await tryDownloadTargetMint({ targetVersion: maxClientVersion, existingVersion: versionString });
154
+ const error = await tryDownloadTargetMint({
155
+ targetVersion: maxClientVersion,
156
+ existingVersion: versionString,
157
+ });
28
158
  return { needsUpdate: true, error };
29
159
  }
30
160
  else {