@docsalot/previewing 0.1.0-beta.1 → 0.1.0-beta.10

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/README.md CHANGED
@@ -1,17 +1,13 @@
1
- # @mintlify/previewing
1
+ # @docsalot/previewing
2
2
 
3
- Preview Mintlify docs locally.
3
+ Preview DocsALot docs locally.
4
4
 
5
- ## 🚀 Installation
5
+ ## Installation
6
6
 
7
- ```
8
- npm install @mintlify/previewing
7
+ ```bash
8
+ npm install @docsalot/previewing
9
9
  ```
10
10
 
11
11
  ## Community
12
12
 
13
- Join our Discord community if you have questions or just want to chat:
14
-
15
- [![](https://dcbadge.vercel.app/api/server/ACREKdwjG5)](https://discord.gg/ACREKdwjG5)
16
-
17
- _Built with 💚 by the Mintlify community._
13
+ Discord: https://discord.gg/Dp6EpTv4BU
Binary file
@@ -1,7 +1,8 @@
1
- export declare const TARGET_MINT_VERSION = "v0.0.9";
1
+ export declare const TARGET_CLIENT_VERSION = "v0.1.0-runtime.1";
2
2
  export declare const INSTALL_PATH: string;
3
+ export declare const BUNDLED_CLIENT_TARBALL_PATH: string;
3
4
  export declare const HOME_DIR: string;
4
- export declare const DOT_MINTLIFY: string;
5
+ export declare const DOT_DOCSALOT: string;
5
6
  export declare const VERSION_PATH: string;
6
7
  export declare const CLIENT_PATH: string;
7
8
  export declare const MINT_PATH: string;
package/dist/constants.js CHANGED
@@ -3,19 +3,18 @@
3
3
  import path from "path";
4
4
  import * as url from "url";
5
5
  import os from "os";
6
- // Change this to bump to a newer version of mint's client
7
- export const TARGET_MINT_VERSION = "v0.0.9";
6
+ // Change this to bump to a newer version of the bundled client.
7
+ export const TARGET_CLIENT_VERSION = "v0.1.0-runtime.1";
8
8
  // package installation location
9
9
  export const INSTALL_PATH = url.fileURLToPath(new URL(".", import.meta.url));
10
+ export const BUNDLED_CLIENT_TARBALL_PATH = path.join(INSTALL_PATH, "assets", "client.tar.gz");
10
11
  export const HOME_DIR = os.homedir();
11
- // DOT_MINTLIFY can be overridden via environment variable
12
- // Priority: DOCSALOT_PATH env var > hardcoded local path
13
- // Docker: Set DOCSALOT_PATH=/app/mint-main
14
- const HARDCODED_PATH = '/Users/faizank/workspace/experiments/live_projects/slashml/mint-main';
15
- export const DOT_MINTLIFY = process.env.DOCSALOT_PATH || HARDCODED_PATH;
16
- export const VERSION_PATH = path.join(DOT_MINTLIFY, "mint", "mint-version.txt");
17
- export const CLIENT_PATH = path.join(DOT_MINTLIFY, "client");
18
- export const MINT_PATH = path.join(DOT_MINTLIFY, "mint");
12
+ // DOCSALOT_PATH can be overridden via environment variable.
13
+ // Priority: DOCSALOT_PATH env var > ~/.docsalot
14
+ export const DOT_DOCSALOT = process.env.DOCSALOT_PATH || path.join(HOME_DIR, ".docsalot");
15
+ export const VERSION_PATH = path.join(DOT_DOCSALOT, "mint", "client-version.txt");
16
+ export const CLIENT_PATH = path.join(DOT_DOCSALOT, "client");
17
+ export const MINT_PATH = path.join(DOT_DOCSALOT, "mint");
19
18
  // command execution location
20
19
  export const CMD_EXEC_PATH = process.cwd();
21
20
  export const SUPPORTED_MEDIA_EXTENSIONS = [
@@ -1,11 +1,40 @@
1
1
  import shell from "shelljs";
2
- import { CLIENT_PATH } from "../../constants.js";
3
- import { buildLogger, ensureYarn } from "../../util.js";
2
+ import fse, { pathExists } from "fs-extra";
3
+ import { BUNDLED_CLIENT_TARBALL_PATH, CLIENT_PATH, MINT_PATH, TARGET_CLIENT_VERSION, VERSION_PATH, } from "../../constants.js";
4
+ import { buildLogger } from "../../util.js";
5
+ const bootstrapBundledClient = async (logger) => {
6
+ if (!(await pathExists(BUNDLED_CLIENT_TARBALL_PATH))) {
7
+ logger.fail(`Bundled client tarball is missing at: ${BUNDLED_CLIENT_TARBALL_PATH}`);
8
+ process.exit(1);
9
+ }
10
+ await fse.ensureDir(CLIENT_PATH);
11
+ logger.text = "Extracting bundled DocsALot client...";
12
+ const untarResult = shell.exec(`tar -xzf "${BUNDLED_CLIENT_TARBALL_PATH}" -C "${CLIENT_PATH}" --strip-components 1`, { silent: true });
13
+ if (untarResult.code !== 0) {
14
+ logger.fail("Failed to extract bundled DocsALot client.");
15
+ process.exit(1);
16
+ }
17
+ fse.writeFileSync(VERSION_PATH, TARGET_CLIENT_VERSION);
18
+ };
19
+ const shouldBootstrapClient = async () => {
20
+ const clientExists = await pathExists(CLIENT_PATH);
21
+ if (!clientExists)
22
+ return true;
23
+ if (!(await pathExists(VERSION_PATH)))
24
+ return true;
25
+ const installedVersion = fse.readFileSync(VERSION_PATH, "utf8").trim();
26
+ return installedVersion !== TARGET_CLIENT_VERSION;
27
+ };
4
28
  const installDeps = async () => {
5
- const logger = buildLogger("");
6
- ensureYarn(logger);
7
- shell.cd(CLIENT_PATH);
8
- shell.exec("yarn");
9
- logger.succeed("Dependencies installed.");
29
+ const logger = buildLogger("Preparing local DocsALot runtime...");
30
+ await fse.ensureDir(MINT_PATH);
31
+ const needsBootstrap = await shouldBootstrapClient();
32
+ if (needsBootstrap) {
33
+ await fse.remove(CLIENT_PATH);
34
+ await bootstrapBundledClient(logger);
35
+ logger.succeed("DocsALot runtime installed.");
36
+ return;
37
+ }
38
+ logger.succeed("DocsALot runtime already installed.");
10
39
  };
11
40
  export default installDeps;
@@ -0,0 +1,2 @@
1
+ declare const syncLocalContentCommand: () => Promise<void>;
2
+ export default syncLocalContentCommand;
@@ -0,0 +1,75 @@
1
+ import Chalk from "chalk";
2
+ import mintValidation from "@docsalot/validation";
3
+ import fse from "fs-extra";
4
+ import path from "path";
5
+ import { promises as _promises } from "fs";
6
+ import { CLIENT_PATH, CMD_EXEC_PATH } from "../../constants.js";
7
+ import { categorizeFiles } from "../listener/categorize.js";
8
+ import { generateNav } from "../listener/generate.js";
9
+ import { isFileSizeValid } from "../listener/utils.js";
10
+ import createPage from "../listener/utils/createPage.js";
11
+ import { getConfigPath } from "../listener/utils/mintConfigFile.js";
12
+ const { readFile } = _promises;
13
+ const PROPS_PATH = path.join(CLIENT_PATH, "src", "_props");
14
+ const PUBLIC_PATH = path.join(CLIENT_PATH, "public");
15
+ const writePages = async (contentFilenames, openApiFiles) => {
16
+ const writes = contentFilenames.map(async (filename) => {
17
+ const sourcePath = path.join(CMD_EXEC_PATH, filename);
18
+ const targetPath = path.join(PROPS_PATH, filename);
19
+ const contentStr = (await readFile(sourcePath)).toString();
20
+ const { pageContent } = await createPage(filename, contentStr, CMD_EXEC_PATH, openApiFiles);
21
+ await fse.outputFile(targetPath, pageContent, { flag: "w" });
22
+ });
23
+ await Promise.all(writes);
24
+ };
25
+ const writeSnippets = async (snippets) => {
26
+ const writes = snippets.map(async (filename) => {
27
+ const sourcePath = path.join(CMD_EXEC_PATH, filename);
28
+ const targetPath = path.join(PROPS_PATH, filename);
29
+ await fse.copy(sourcePath, targetPath);
30
+ });
31
+ await Promise.all(writes);
32
+ };
33
+ const writeStaticFiles = async (staticFilenames) => {
34
+ for (const filename of staticFilenames) {
35
+ const sourcePath = path.join(CMD_EXEC_PATH, filename);
36
+ if (!(await isFileSizeValid(sourcePath, 5))) {
37
+ console.error(Chalk.red(`🚨 The file at ${filename} is too big. The maximum file size is 5 mb.`));
38
+ continue;
39
+ }
40
+ const targetPath = path.join(PUBLIC_PATH, filename);
41
+ await fse.copy(sourcePath, targetPath);
42
+ }
43
+ };
44
+ const copyAndValidateLayout = async () => {
45
+ const configPath = await getConfigPath(CMD_EXEC_PATH);
46
+ if (configPath == null) {
47
+ throw new Error("Could not find layout.json in the docs directory.");
48
+ }
49
+ const rawConfig = (await readFile(configPath)).toString();
50
+ const config = JSON.parse(rawConfig);
51
+ const { status, errors, warnings } = mintValidation.validateMintConfig(config);
52
+ errors.forEach((error) => {
53
+ console.error(`🚨 ${Chalk.red(error)}`);
54
+ });
55
+ warnings.forEach((warning) => {
56
+ console.warn(`⚠️ ${Chalk.yellow(warning)}`);
57
+ });
58
+ if (status !== "success") {
59
+ throw new Error("layout.json is invalid. Fix validation errors and try again.");
60
+ }
61
+ await fse.copy(configPath, path.join(PROPS_PATH, "layout.json"));
62
+ };
63
+ const syncLocalContentCommand = async () => {
64
+ await fse.ensureDir(PROPS_PATH);
65
+ await fse.ensureDir(PUBLIC_PATH);
66
+ const { contentFilenames, staticFilenames, openApiFiles, snippets } = await categorizeFiles(CMD_EXEC_PATH);
67
+ await copyAndValidateLayout();
68
+ await writePages(contentFilenames, openApiFiles);
69
+ await writeSnippets(snippets);
70
+ await writeStaticFiles(staticFilenames);
71
+ await fse.outputFile(path.join(PROPS_PATH, "openApiFiles.json"), JSON.stringify(openApiFiles, null, 2), { flag: "w" });
72
+ const generatedNav = await generateNav();
73
+ await fse.outputFile(path.join(PROPS_PATH, "generatedNav.json"), JSON.stringify(generatedNav, null, 2), { flag: "w" });
74
+ };
75
+ export default syncLocalContentCommand;
@@ -2,158 +2,72 @@
2
2
  import Chalk from "chalk";
3
3
  import child_process from "child_process";
4
4
  import open from "open";
5
- import fse, { pathExists } from "fs-extra";
6
- import inquirer from "inquirer";
7
- import { isInternetAvailable } from "is-internet-available";
8
- import path from "path";
5
+ import fse from "fs-extra";
9
6
  import shell from "shelljs";
10
- import { Octokit } from "@octokit/rest";
11
- import { CLIENT_PATH, HOME_DIR, DOT_MINTLIFY, CMD_EXEC_PATH, TARGET_MINT_VERSION, VERSION_PATH, MINT_PATH, } from "../constants.js";
12
- import { buildLogger, ensureYarn } from "../util.js";
7
+ import { HOME_DIR, CLIENT_PATH, CMD_EXEC_PATH, MINT_PATH, } from "../constants.js";
8
+ import { buildLogger } from "../util.js";
13
9
  import listener from "./listener/index.js";
14
10
  import { getConfigPath } from "./listener/utils/mintConfigFile.js";
15
- const nodeModulesExists = async () => {
16
- // return pathExists(path.join(DOT_MINTLIFY, "mint", "client", "node_modules"));
17
- return pathExists(path.join(DOT_MINTLIFY, "client", "node_modules"));
18
- };
19
- const promptForYarn = async () => {
20
- const yarnInstalled = shell.which("yarn");
21
- if (!yarnInstalled) {
22
- await inquirer
23
- .prompt([
24
- {
25
- type: "confirm",
26
- name: "confirm",
27
- message: "yarn must be globally installed. Install yarn?",
28
- default: true,
29
- },
30
- ])
31
- .then(({ confirm }) => {
32
- if (confirm) {
33
- shell.exec("npm install --global yarn");
34
- }
35
- else {
36
- console.log("Installation cancelled.");
37
- }
38
- });
39
- }
40
- };
41
- const downloadTargetMint = async (logger) => {
42
- fse.emptyDirSync(MINT_PATH);
43
- logger.text = "Downloading Mintlify framework...";
44
- const octokit = new Octokit();
45
- const downloadRes = await octokit.repos.downloadTarballArchive({
46
- owner: "mintlify",
47
- repo: "mint",
48
- ref: TARGET_MINT_VERSION,
49
- });
50
- logger.text = "Extracting Mintlify framework...";
51
- const TAR_PATH = path.join(MINT_PATH, "mint.tar.gz");
52
- fse.writeFileSync(TAR_PATH, Buffer.from(downloadRes.data));
53
- // strip-components 1 removes the top level directory from the unzipped content
54
- // which is a folder with the release sha
55
- fse.mkdirSync(path.join(MINT_PATH, "mint-tmp"));
56
- shell.exec("tar -xzf mint.tar.gz -C mint-tmp --strip-components 1", {
57
- silent: true,
58
- });
59
- fse.removeSync(TAR_PATH);
60
- fse.moveSync(path.join(MINT_PATH, "mint-tmp", "client"), path.join(CLIENT_PATH));
61
- fse.writeFileSync(VERSION_PATH, TARGET_MINT_VERSION);
62
- // Delete unnecessary content downloaded from GitHub
63
- fse.removeSync(path.join(MINT_PATH, "mint-tmp"));
64
- logger.text = "Installing dependencies...";
65
- ensureYarn(logger);
66
- shell.cd(CLIENT_PATH);
67
- shell.exec("yarn", { silent: true });
68
- };
69
- const checkForMintJson = async (logger) => {
11
+ import installDepsCommand from "./helper-commands/installDepsCommand.js";
12
+ import syncLocalContentCommand from "./helper-commands/syncLocalContentCommand.js";
13
+ const checkForLayoutJson = async (logger) => {
70
14
  const configPath = await getConfigPath(CMD_EXEC_PATH);
71
15
  if (configPath == null) {
72
- logger.fail("Must be ran in a directory where a mint.json file exists.");
16
+ logger.fail("Must be ran in a directory where a layout.json file exists.");
73
17
  process.exit(1);
74
18
  }
75
19
  return;
76
20
  };
77
21
  const dev = async (argv) => {
78
- buildLogger("DEVS");
79
22
  shell.cd(HOME_DIR);
80
- await promptForYarn();
81
23
  const logger = buildLogger("Preparing local Docsalot instance...");
82
24
  await fse.ensureDir(MINT_PATH);
83
- shell.cd(MINT_PATH);
84
- const internet = await isInternetAvailable();
85
- if (!internet && !(await pathExists(CLIENT_PATH))) {
86
- logger.fail("Running mintlify dev for the first time requires an internet connection.");
87
- process.exit(1);
88
- }
89
- // if (internet) {
90
- // const mintVersionExists = await pathExists(VERSION_PATH);
91
- // let needToDownloadTargetMint = !mintVersionExists;
92
- // if (mintVersionExists) {
93
- // const currVersion = fse.readFileSync(VERSION_PATH, "utf8");
94
- // if (currVersion !== TARGET_MINT_VERSION) {
95
- // needToDownloadTargetMint = true;
96
- // }
97
- // }
98
- // if (needToDownloadTargetMint) {
99
- // await downloadTargetMint(logger);
100
- // }
101
- // }
102
- if (!(await nodeModulesExists())) {
103
- if (!internet) {
104
- logger.fail(`Dependencies are missing and you are offline. Connect to the internet and run
105
-
106
- mintlify install
107
-
108
- `);
109
- }
110
- else {
111
- logger.fail(`Dependencies were not installed correctly, run
112
-
113
- mintlify install
114
-
115
- `);
116
- }
117
- process.exit(1);
118
- }
119
- await checkForMintJson(logger);
120
- shell.cd(CLIENT_PATH);
121
- const relativePath = path.relative(CLIENT_PATH, CMD_EXEC_PATH);
122
- child_process.spawnSync("yarn preconfigure", [relativePath], { shell: true });
25
+ await installDepsCommand();
26
+ await checkForLayoutJson(logger);
27
+ logger.text = "Syncing docs content into local runtime...";
28
+ await syncLocalContentCommand();
123
29
  logger.succeed("Local instance is ready. Launching your site...");
124
30
  run(argv.port || "3000");
125
31
  };
126
32
  const run = (port) => {
127
33
  shell.cd(CLIENT_PATH);
128
- console.log("CLIENT PATH", CLIENT_PATH);
129
- // For Cloud Run/Docker, use dev-host (binds to 0.0.0.0, no file watching)
130
- // For local development, use dev-watch (binds to localhost, with file watching)
131
- const isProduction = process.env.BIND_ALL_INTERFACES === "true";
132
- const devScript = isProduction ? "npm run dev-host" : "npm run dev-watch";
133
- const mintlifyDevProcess = child_process.spawn(devScript, {
34
+ const host = process.env.BIND_ALL_INTERFACES === "true" ? "0.0.0.0" : "127.0.0.1";
35
+ const localAdminToken = process.env.ADMIN_TOKEN || "__docsalot_local_preview__";
36
+ process.env.ADMIN_TOKEN = localAdminToken;
37
+ process.env.DOCSALOT_LOCAL_PREVIEW = "true";
38
+ let browserOpened = false;
39
+ const docsalotDevProcess = child_process.spawn("node server.js", {
134
40
  env: {
135
41
  ...process.env,
136
42
  PORT: port,
43
+ HOSTNAME: host,
44
+ NODE_ENV: "production",
45
+ ADMIN_TOKEN: localAdminToken,
46
+ DOCSALOT_LOCAL_PREVIEW: "true",
137
47
  },
138
48
  cwd: CLIENT_PATH,
139
49
  stdio: "pipe",
140
50
  shell: true,
141
51
  });
142
- mintlifyDevProcess.stdout.on("data", (data) => {
52
+ docsalotDevProcess.stdout.on("data", (data) => {
143
53
  const output = data.toString();
144
54
  console.log(output);
145
- if (output.startsWith("> Ready on http://localhost:")) {
55
+ if (!browserOpened &&
56
+ (output.includes("Ready in") ||
57
+ output.includes("started server") ||
58
+ output.includes("http://localhost:"))) {
59
+ browserOpened = true;
146
60
  console.log(`🌿 ${Chalk.green(`Your local preview is available at http://localhost:${port}`)}`);
147
61
  console.log(`🌿 ${Chalk.green("Press Ctrl+C any time to stop the local preview.")}`);
148
62
  open(`http://localhost:${port}`);
149
63
  }
150
64
  });
151
65
  const onExit = () => {
152
- mintlifyDevProcess.kill("SIGINT");
66
+ docsalotDevProcess.kill("SIGINT");
153
67
  process.exit(0);
154
68
  };
155
69
  process.on("SIGINT", onExit);
156
70
  process.on("SIGTERM", onExit);
157
- listener();
71
+ listener(port);
158
72
  };
159
73
  export default dev;
@@ -3,6 +3,17 @@
3
3
  import path from "path";
4
4
  import { getFileList } from "@docsalot/prebuild";
5
5
  import { getFileExtension, openApiCheck } from "./utils.js";
6
+ const shouldIgnorePath = (filename) => {
7
+ const normalized = filename.replace(/\\/g, "/").toLowerCase();
8
+ return (normalized.startsWith("/node_modules/") ||
9
+ normalized.includes("/node_modules/") ||
10
+ normalized.startsWith("/.git/") ||
11
+ normalized.includes("/.git/") ||
12
+ normalized.startsWith("/.next/") ||
13
+ normalized.includes("/.next/") ||
14
+ normalized.startsWith("/.docsalot/") ||
15
+ normalized.includes("/.docsalot/"));
16
+ };
6
17
  export const categorizeFiles = async (contentDirectoryPath) => {
7
18
  const allFilesInCmdExecutionPath = getFileList(contentDirectoryPath);
8
19
  const contentFilenames = [];
@@ -11,6 +22,9 @@ export const categorizeFiles = async (contentDirectoryPath) => {
11
22
  const openApiFiles = [];
12
23
  const snippets = [];
13
24
  allFilesInCmdExecutionPath.forEach((filename) => {
25
+ if (shouldIgnorePath(filename)) {
26
+ return;
27
+ }
14
28
  promises.push((async () => {
15
29
  const extension = getFileExtension(filename);
16
30
  let isOpenApi = false;
@@ -34,7 +48,9 @@ export const categorizeFiles = async (contentDirectoryPath) => {
34
48
  });
35
49
  }
36
50
  }
37
- else if (!filename.endsWith("mint.json") && !isOpenApi) {
51
+ else if (!filename.endsWith("layout.json") &&
52
+ !filename.endsWith("docs.json") &&
53
+ !isOpenApi) {
38
54
  // all other files
39
55
  staticFilenames.push(filename);
40
56
  }
@@ -64,7 +80,7 @@ const supportedStaticFileExtensions = [
64
80
  export const getCategory = (filePath) => {
65
81
  filePath = filePath.toLowerCase();
66
82
  const parsed = path.parse(filePath);
67
- if (parsed.base === "mint.json" || parsed.base === "layout.json") {
83
+ if (parsed.base === "layout.json") {
68
84
  return "mintConfig";
69
85
  }
70
86
  const fileName = parsed.name;
@@ -27,18 +27,31 @@ const pageMetadataKeys = [
27
27
  const generateDecoratedMintNavigationFromPages = (filenamePageMetadataMap, mintConfigNav) => {
28
28
  const filenames = Object.keys(filenamePageMetadataMap);
29
29
  const createNav = (nav) => {
30
+ if (!nav || !Array.isArray(nav.pages)) {
31
+ return null;
32
+ }
30
33
  return {
31
34
  group: nav.group,
32
35
  version: nav?.version,
33
- pages: nav.pages.map((page) => {
34
- if (typeof page === "string" && filenames.includes(page)) {
35
- return filenamePageMetadataMap[page];
36
+ pages: nav.pages
37
+ .map((page) => {
38
+ if (typeof page === "string") {
39
+ if (filenames.includes(page)) {
40
+ return filenamePageMetadataMap[page];
41
+ }
42
+ // Keep local preview resilient when navigation references missing pages.
43
+ return null;
36
44
  }
37
45
  return createNav(page);
38
- }),
46
+ })
47
+ .filter(Boolean)
48
+ .map((entry) => entry),
39
49
  };
40
50
  };
41
- return mintConfigNav.map((nav) => createNav(nav));
51
+ return (mintConfigNav || [])
52
+ .map((nav) => createNav(nav))
53
+ .filter(Boolean)
54
+ .map((entry) => entry);
42
55
  };
43
56
  const createFilenamePageMetadataMap = async (contentDirectoryPath, contentFilenames, openApiFiles, clientPath, writeFiles = false) => {
44
57
  let pagesAcc = {};
@@ -1,2 +1,2 @@
1
- declare const listener: () => void;
1
+ declare const listener: (port?: string) => void;
2
2
  export default listener;
@@ -1,4 +1,5 @@
1
1
  // @ts-nocheck
2
+ import axios from "axios";
2
3
  import chokidar from "chokidar";
3
4
  import fse from "fs-extra";
4
5
  import pathUtil from "path";
@@ -11,7 +12,49 @@ import { promises as _promises } from "fs";
11
12
  import createPage from "./utils/createPage.js";
12
13
  import { getCategory } from "./categorize.js";
13
14
  const { readFile } = _promises;
14
- const listener = () => {
15
+ const isLocalPreviewMode = process.env.DOCSALOT_LOCAL_PREVIEW === "true";
16
+ const localRevalidateSecret = process.env.ADMIN_TOKEN || "__docsalot_local_preview__";
17
+ const toPagePath = (filename) => {
18
+ const normalized = filename.replace(/\\/g, "/").replace(/^\/+/, "");
19
+ if (!normalized.endsWith(".md") && !normalized.endsWith(".mdx")) {
20
+ return null;
21
+ }
22
+ const withoutExtension = normalized.replace(/\.mdx?$/i, "");
23
+ if (withoutExtension === "index") {
24
+ return "/";
25
+ }
26
+ if (withoutExtension.endsWith("/index")) {
27
+ return "/" + withoutExtension.slice(0, -"/index".length);
28
+ }
29
+ return "/" + withoutExtension;
30
+ };
31
+ const getRevalidatePaths = (category, filename) => {
32
+ const paths = ["/"];
33
+ if (category === "page") {
34
+ const pagePath = toPagePath(filename);
35
+ if (pagePath) {
36
+ paths.push(pagePath);
37
+ }
38
+ }
39
+ return [...new Set(paths)];
40
+ };
41
+ const revalidateLocalPaths = async (port, paths) => {
42
+ if (!isLocalPreviewMode || !port || paths.length === 0) {
43
+ return;
44
+ }
45
+ for (const path of paths) {
46
+ try {
47
+ await axios.post(`http://127.0.0.1:${port}/api/revalidate`, {
48
+ secret: localRevalidateSecret,
49
+ path,
50
+ }, { timeout: 2000 });
51
+ }
52
+ catch {
53
+ // Revalidation is best-effort; avoid failing file sync when server is restarting.
54
+ }
55
+ }
56
+ };
57
+ const listener = (port) => {
15
58
  chokidar
16
59
  .watch(CMD_EXEC_PATH, {
17
60
  ignoreInitial: true,
@@ -38,6 +81,7 @@ const listener = () => {
38
81
  console.log("Static file added: ", filename);
39
82
  break;
40
83
  }
84
+ await revalidateLocalPaths(port, getRevalidatePaths(category, filename));
41
85
  }
42
86
  catch (error) {
43
87
  console.error(error.message);
@@ -63,6 +107,7 @@ const listener = () => {
63
107
  console.log("Static file edited: ", filename);
64
108
  break;
65
109
  }
110
+ await revalidateLocalPaths(port, getRevalidatePaths(category, filename));
66
111
  }
67
112
  catch (error) {
68
113
  console.error(error.message);
@@ -86,7 +131,7 @@ const listener = () => {
86
131
  console.log(`Snippet deleted: ${filename}`);
87
132
  break;
88
133
  case "mintConfig":
89
- console.log("⚠️ mint.json deleted. Please create a new mint.json file as it is mandatory.");
134
+ console.log("⚠️ layout.json deleted. Please create a new layout.json file as it is mandatory.");
90
135
  process.exit(1);
91
136
  case "potentialJsonOpenApiSpec":
92
137
  case "potentialYamlOpenApiSpec":
@@ -97,6 +142,7 @@ const listener = () => {
97
142
  console.log("Static file deleted: ", filename);
98
143
  break;
99
144
  }
145
+ await revalidateLocalPaths(port, getRevalidatePaths(potentialCategory, filename));
100
146
  }
101
147
  catch (error) {
102
148
  console.error(error.message);
@@ -147,9 +193,9 @@ const onUpdateEvent = async (filename) => {
147
193
  break;
148
194
  case "mintConfig":
149
195
  regenerateNav = true;
150
- const mintJsonFileContent = (await readFile(filePath)).toString();
196
+ const layoutJsonFileContent = (await readFile(filePath)).toString();
151
197
  try {
152
- const mintConfig = JSON.parse(mintJsonFileContent);
198
+ const mintConfig = JSON.parse(layoutJsonFileContent);
153
199
  const { status, errors, warnings } = mintValidation.validateMintConfig(mintConfig);
154
200
  errors.forEach((error) => {
155
201
  console.error(`🚨 ${Chalk.red(error)}`);
@@ -163,7 +209,7 @@ const onUpdateEvent = async (filename) => {
163
209
  }
164
210
  catch (error) {
165
211
  if (error.name === "SyntaxError") {
166
- console.error(`🚨 ${Chalk.red("mint.json has invalid JSON. You are likely missing a comma or a bracket. You can paste your mint.json file into https://jsonlint.com/ to get a more specific error message.")}`);
212
+ console.error(`🚨 ${Chalk.red("layout.json has invalid JSON. You are likely missing a comma or a bracket. You can paste your layout.json file into https://jsonlint.com/ to get a more specific error message.")}`);
167
213
  }
168
214
  else {
169
215
  console.error(`🚨 ${Chalk.red(error.message)}`);
@@ -4,10 +4,6 @@ import pathUtil from "path";
4
4
  const { readFile } = _promises;
5
5
  // TODO: Put in prebuild package
6
6
  export const getConfigPath = async (contentDirectoryPath) => {
7
- // Prefer modern config filename, but keep backward compatibility.
8
- if (await pathExists(pathUtil.join(contentDirectoryPath, "mint.json"))) {
9
- return pathUtil.join(contentDirectoryPath, "mint.json");
10
- }
11
7
  if (await pathExists(pathUtil.join(contentDirectoryPath, "layout.json"))) {
12
8
  return pathUtil.join(contentDirectoryPath, "layout.json");
13
9
  }