@raystack/chronicle 0.1.0-canary.5a730d4 → 0.1.0-canary.6511afe

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.
Files changed (82) hide show
  1. package/dist/cli/index.js +165 -414
  2. package/package.json +13 -10
  3. package/src/cli/commands/build.ts +30 -48
  4. package/src/cli/commands/dev.ts +24 -13
  5. package/src/cli/commands/init.ts +38 -123
  6. package/src/cli/commands/serve.ts +35 -50
  7. package/src/cli/commands/start.ts +20 -16
  8. package/src/cli/index.ts +14 -14
  9. package/src/cli/utils/config.ts +25 -26
  10. package/src/cli/utils/index.ts +3 -2
  11. package/src/cli/utils/resolve.ts +7 -3
  12. package/src/cli/utils/scaffold.ts +14 -16
  13. package/src/components/mdx/code.tsx +1 -10
  14. package/src/components/mdx/details.module.css +24 -1
  15. package/src/components/mdx/details.tsx +3 -2
  16. package/src/components/mdx/image.tsx +5 -20
  17. package/src/components/mdx/index.tsx +3 -3
  18. package/src/components/mdx/link.tsx +24 -20
  19. package/src/components/ui/footer.tsx +2 -3
  20. package/src/components/ui/search.tsx +116 -72
  21. package/src/lib/config.ts +31 -29
  22. package/src/lib/get-llm-text.ts +10 -0
  23. package/src/lib/head.tsx +26 -22
  24. package/src/lib/openapi.ts +8 -8
  25. package/src/lib/page-context.tsx +76 -57
  26. package/src/lib/source.ts +144 -96
  27. package/src/pages/ApiLayout.tsx +22 -18
  28. package/src/pages/ApiPage.tsx +32 -27
  29. package/src/pages/DocsLayout.tsx +7 -7
  30. package/src/pages/DocsPage.tsx +11 -11
  31. package/src/pages/NotFound.tsx +11 -4
  32. package/src/server/App.tsx +35 -27
  33. package/src/server/api/apis-proxy.ts +69 -0
  34. package/src/server/api/health.ts +5 -0
  35. package/src/server/api/page/[...slug].ts +18 -0
  36. package/src/server/api/search.ts +170 -0
  37. package/src/server/api/specs.ts +9 -0
  38. package/src/server/build-search-index.ts +117 -0
  39. package/src/server/entry-client.tsx +52 -56
  40. package/src/server/entry-server.tsx +95 -35
  41. package/src/server/routes/llms.txt.ts +61 -0
  42. package/src/server/routes/og.tsx +75 -0
  43. package/src/server/routes/robots.txt.ts +11 -0
  44. package/src/server/routes/sitemap.xml.ts +39 -0
  45. package/src/server/utils/safe-path.ts +17 -0
  46. package/src/server/vite-config.ts +64 -46
  47. package/src/themes/default/Layout.tsx +69 -41
  48. package/src/themes/default/Page.module.css +0 -56
  49. package/src/themes/default/Page.tsx +9 -11
  50. package/src/themes/default/Toc.tsx +30 -28
  51. package/src/themes/default/index.ts +7 -9
  52. package/src/themes/paper/ChapterNav.tsx +59 -39
  53. package/src/themes/paper/Layout.module.css +1 -1
  54. package/src/themes/paper/Layout.tsx +24 -12
  55. package/src/themes/paper/Page.module.css +11 -4
  56. package/src/themes/paper/Page.tsx +67 -47
  57. package/src/themes/paper/ReadingProgress.tsx +160 -139
  58. package/src/themes/paper/index.ts +5 -5
  59. package/src/themes/registry.ts +7 -7
  60. package/src/types/globals.d.ts +4 -0
  61. package/src/cli/__tests__/config.test.ts +0 -25
  62. package/src/cli/__tests__/scaffold.test.ts +0 -10
  63. package/src/pages/__tests__/head.test.tsx +0 -57
  64. package/src/server/__tests__/entry-server.test.tsx +0 -35
  65. package/src/server/__tests__/handlers.test.ts +0 -77
  66. package/src/server/__tests__/og.test.ts +0 -23
  67. package/src/server/__tests__/router.test.ts +0 -72
  68. package/src/server/__tests__/vite-config.test.ts +0 -25
  69. package/src/server/dev.ts +0 -156
  70. package/src/server/entry-prod.ts +0 -127
  71. package/src/server/handlers/apis-proxy.ts +0 -52
  72. package/src/server/handlers/health.ts +0 -3
  73. package/src/server/handlers/llms.ts +0 -58
  74. package/src/server/handlers/og.ts +0 -87
  75. package/src/server/handlers/robots.ts +0 -11
  76. package/src/server/handlers/search.ts +0 -140
  77. package/src/server/handlers/sitemap.ts +0 -39
  78. package/src/server/handlers/specs.ts +0 -9
  79. package/src/server/index.html +0 -12
  80. package/src/server/prod.ts +0 -18
  81. package/src/server/router.ts +0 -42
  82. package/src/themes/default/font.ts +0 -4
package/dist/cli/index.js CHANGED
@@ -21,44 +21,57 @@ var exports_vite_config = {};
21
21
  __export(exports_vite_config, {
22
22
  createViteConfig: () => createViteConfig
23
23
  });
24
- import path5 from "path";
25
24
  import react from "@vitejs/plugin-react";
26
- import mdx from "@mdx-js/rollup";
27
- import remarkDirective from "remark-directive";
28
- import remarkGfm from "remark-gfm";
29
- import remarkFrontmatter from "remark-frontmatter";
30
- import remarkMdxFrontmatter from "remark-mdx-frontmatter";
31
- import rehypeShiki from "@shikijs/rehype";
25
+ import mdx from "fumadocs-mdx/vite";
26
+ import { nitro } from "nitro/vite";
27
+ import path4 from "node:path";
32
28
  async function createViteConfig(options) {
33
- const { root, contentDir, isDev = false } = options;
29
+ const { packageRoot, projectRoot, contentDir, preset } = options;
34
30
  return {
35
- root,
31
+ root: packageRoot,
36
32
  configFile: false,
33
+ plugins: [
34
+ nitro({
35
+ serverDir: path4.resolve(packageRoot, "src/server"),
36
+ ...preset && { preset },
37
+ alias: {
38
+ "@content": path4.resolve(packageRoot, ".content")
39
+ }
40
+ }),
41
+ mdx({}, { index: false }),
42
+ react(),
43
+ {
44
+ name: "chronicle:content-alias",
45
+ resolveId(id) {
46
+ if (id.startsWith("@content/")) {
47
+ return path4.resolve(packageRoot, ".content", id.slice("@content/".length));
48
+ }
49
+ }
50
+ }
51
+ ],
37
52
  resolve: {
38
53
  alias: {
39
- "@": path5.resolve(root, "src"),
40
- "@content": contentDir
54
+ "@": path4.resolve(packageRoot, "src"),
55
+ "@content": path4.resolve(packageRoot, ".content")
56
+ },
57
+ conditions: ["module-sync", "import", "node"],
58
+ dedupe: [
59
+ "react",
60
+ "react-dom",
61
+ "react/jsx-runtime",
62
+ "react/jsx-dev-runtime",
63
+ "react-router"
64
+ ]
65
+ },
66
+ server: {
67
+ fs: {
68
+ allow: [packageRoot, projectRoot, contentDir]
41
69
  }
42
70
  },
43
- plugins: [
44
- mdx({
45
- remarkPlugins: [
46
- remarkFrontmatter,
47
- remarkMdxFrontmatter,
48
- remarkGfm,
49
- remarkDirective
50
- ],
51
- rehypePlugins: [
52
- [rehypeShiki, { themes: { light: "github-light", dark: "github-dark" } }]
53
- ],
54
- mdExtensions: [".md"],
55
- mdxExtensions: [".mdx"]
56
- }),
57
- react()
58
- ],
59
71
  define: {
60
- "process.env.CHRONICLE_CONTENT_DIR": JSON.stringify(contentDir),
61
- "process.env.CHRONICLE_PROJECT_ROOT": JSON.stringify(root)
72
+ __CHRONICLE_CONTENT_DIR__: JSON.stringify(contentDir),
73
+ __CHRONICLE_PROJECT_ROOT__: JSON.stringify(projectRoot),
74
+ __CHRONICLE_PACKAGE_ROOT__: JSON.stringify(packageRoot)
62
75
  },
63
76
  css: {
64
77
  modules: {
@@ -66,12 +79,14 @@ async function createViteConfig(options) {
66
79
  }
67
80
  },
68
81
  ssr: {
69
- noExternal: ["@raystack/apsara"]
82
+ noExternal: ["@raystack/apsara", "dayjs", "fumadocs-core"]
70
83
  },
71
- build: {
72
- rolldownOptions: {
73
- input: isDev ? undefined : {
74
- client: path5.resolve(root, "src/server/index.html")
84
+ environments: {
85
+ client: {
86
+ build: {
87
+ rollupOptions: {
88
+ input: path4.resolve(packageRoot, "src/server/entry-client.tsx")
89
+ }
75
90
  }
76
91
  }
77
92
  }
@@ -79,229 +94,92 @@ async function createViteConfig(options) {
79
94
  }
80
95
  var init_vite_config = () => {};
81
96
 
82
- // src/server/dev.ts
83
- var exports_dev = {};
84
- __export(exports_dev, {
85
- startDevServer: () => startDevServer
86
- });
87
- import { createServer as createViteServer } from "vite";
88
- import { createServer } from "http";
89
- import fsPromises from "fs/promises";
90
- import { createReadStream } from "fs";
91
- import path6 from "path";
92
- import chalk3 from "chalk";
93
- async function startDevServer(options) {
94
- const { port, root, contentDir } = options;
95
- const viteConfig = await createViteConfig({ root, contentDir, isDev: true });
96
- const vite = await createViteServer({
97
- ...viteConfig,
98
- server: { middlewareMode: true },
99
- appType: "custom"
100
- });
101
- const templatePath = path6.resolve(root, "src/server/index.html");
102
- const server = createServer(async (req, res) => {
103
- const url = req.url || "/";
104
- try {
105
- if (url.startsWith("/@") || url.startsWith("/__vite") || url.startsWith("/node_modules/")) {
106
- vite.middlewares(req, res, () => {
107
- res.statusCode = 404;
108
- res.end();
109
- });
110
- return;
111
- }
112
- const contentFile = path6.join(contentDir, decodeURIComponent(url.split("?")[0]));
113
- if (!url.endsWith(".md") && !url.endsWith(".mdx")) {
114
- try {
115
- const stat = await fsPromises.stat(contentFile);
116
- if (stat.isFile()) {
117
- const ext = path6.extname(contentFile).toLowerCase();
118
- const mimeTypes = {
119
- ".png": "image/png",
120
- ".jpg": "image/jpeg",
121
- ".jpeg": "image/jpeg",
122
- ".gif": "image/gif",
123
- ".svg": "image/svg+xml",
124
- ".webp": "image/webp",
125
- ".ico": "image/x-icon",
126
- ".pdf": "application/pdf",
127
- ".json": "application/json",
128
- ".yaml": "text/yaml",
129
- ".yml": "text/yaml",
130
- ".txt": "text/plain"
131
- };
132
- res.setHeader("Content-Type", mimeTypes[ext] || "application/octet-stream");
133
- createReadStream(contentFile).pipe(res);
134
- return;
135
- }
136
- } catch {}
137
- }
138
- if (/\.(js|ts|tsx|css|map)(\?|$)/.test(url)) {
139
- vite.middlewares(req, res, () => {
140
- res.statusCode = 404;
141
- res.end();
142
- });
143
- return;
144
- }
145
- const { matchRoute } = await vite.ssrLoadModule(path6.resolve(root, "src/server/router.ts"));
146
- const routeHandler = matchRoute(new URL(url, `http://localhost:${port}`).href);
147
- if (routeHandler) {
148
- const request = new Request(new URL(url, `http://localhost:${port}`));
149
- const response = await routeHandler(request);
150
- res.statusCode = response.status;
151
- response.headers.forEach((value, key) => res.setHeader(key, value));
152
- const body = await response.text();
153
- res.end(body);
154
- return;
155
- }
156
- const pathname = new URL(url, `http://localhost:${port}`).pathname;
157
- const slug = pathname === "/" ? [] : pathname.slice(1).split("/").filter(Boolean);
158
- const source = await vite.ssrLoadModule(path6.resolve(root, "src/lib/source.ts"));
159
- const { mdxComponents } = await vite.ssrLoadModule(path6.resolve(root, "src/components/mdx/index.tsx"));
160
- const { loadConfig } = await vite.ssrLoadModule(path6.resolve(root, "src/lib/config.ts"));
161
- const config = loadConfig();
162
- const { loadApiSpecs } = await vite.ssrLoadModule(path6.resolve(root, "src/lib/openapi.ts"));
163
- const apiSpecs = config.api?.length ? loadApiSpecs(config.api) : [];
164
- const [tree, sourcePage] = await Promise.all([
165
- source.buildPageTree(),
166
- source.getPage(slug)
167
- ]);
168
- let pageData = null;
169
- let embeddedData = { config, tree, slug, frontmatter: null, filePath: null };
170
- if (sourcePage) {
171
- const component = await source.loadPageComponent(sourcePage);
172
- const React = await import("react");
173
- const MDXBody = component;
174
- pageData = {
175
- slug,
176
- frontmatter: sourcePage.frontmatter,
177
- content: MDXBody ? React.createElement(MDXBody, { components: mdxComponents }) : null
178
- };
179
- embeddedData.frontmatter = sourcePage.frontmatter;
180
- embeddedData.filePath = sourcePage.filePath;
181
- }
182
- let template = await fsPromises.readFile(templatePath, "utf-8");
183
- template = await vite.transformIndexHtml(url, template);
184
- const dataScript = `<script>window.__PAGE_DATA__ = ${JSON.stringify(embeddedData)}</script>`;
185
- template = template.replace("<!--head-outlet-->", `<!--head-outlet-->${dataScript}`);
186
- const { render } = await vite.ssrLoadModule(path6.resolve(root, "src/server/entry-server.tsx"));
187
- const html = render(url, { config, tree, page: pageData, apiSpecs });
188
- const finalHtml = template.replace("<!--ssr-outlet-->", html);
189
- res.setHeader("Content-Type", "text/html");
190
- res.statusCode = 200;
191
- res.end(finalHtml);
192
- } catch (e) {
193
- vite.ssrFixStacktrace(e);
194
- console.error(e);
195
- res.statusCode = 500;
196
- res.end(e.message);
197
- }
198
- });
199
- server.listen(port, () => {
200
- console.log(chalk3.cyan(`
201
- Chronicle dev server running at:`));
202
- console.log(chalk3.green(` http://localhost:${port}
203
- `));
204
- });
205
- const shutdown = () => {
206
- vite.close();
207
- server.close();
208
- process.exit(0);
209
- };
210
- process.on("SIGINT", shutdown);
211
- process.on("SIGTERM", shutdown);
212
- return { server, vite };
213
- }
214
- var init_dev = __esm(() => {
215
- init_vite_config();
216
- });
217
-
218
- // src/server/prod.ts
219
- var exports_prod = {};
220
- __export(exports_prod, {
221
- startProdServer: () => startProdServer
222
- });
223
- import path8 from "path";
224
- import chalk6 from "chalk";
225
- async function startProdServer(options) {
226
- const { port, distDir } = options;
227
- const serverEntry = path8.resolve(distDir, "server/entry-prod.js");
228
- const { startServer } = await import(serverEntry);
229
- console.log(chalk6.cyan("Starting production server..."));
230
- return startServer({ port, distDir });
231
- }
232
- var init_prod = () => {};
233
-
234
97
  // src/cli/index.ts
235
98
  import { Command as Command6 } from "commander";
236
99
 
237
- // src/cli/commands/init.ts
100
+ // src/cli/commands/build.ts
101
+ import chalk2 from "chalk";
238
102
  import { Command } from "commander";
239
- import { execSync } from "child_process";
240
- import fs2 from "fs";
241
- import path3 from "path";
242
- import chalk from "chalk";
243
- import { stringify } from "yaml";
244
103
 
245
- // src/cli/utils/scaffold.ts
246
- import fs from "fs";
247
- import path2 from "path";
104
+ // src/cli/utils/config.ts
105
+ import path from "node:path";
106
+ import chalk from "chalk";
107
+ import { parse } from "yaml";
108
+ function resolveContentDir(contentFlag) {
109
+ if (contentFlag)
110
+ return path.resolve(contentFlag);
111
+ return path.resolve("content");
112
+ }
248
113
 
249
114
  // src/cli/utils/resolve.ts
250
- import path from "path";
115
+ import path2 from "path";
251
116
  import { fileURLToPath } from "url";
252
- var PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
117
+ var PACKAGE_ROOT = path2.resolve(path2.dirname(fileURLToPath(import.meta.url)), "..", "..");
253
118
 
254
119
  // src/cli/utils/scaffold.ts
255
- function detectPackageManager() {
256
- if (process.env.npm_config_user_agent) {
257
- return process.env.npm_config_user_agent.split("/")[0];
258
- }
259
- const cwd = process.cwd();
260
- if (fs.existsSync(path2.join(cwd, "bun.lock")) || fs.existsSync(path2.join(cwd, "bun.lockb")))
261
- return "bun";
262
- if (fs.existsSync(path2.join(cwd, "pnpm-lock.yaml")))
263
- return "pnpm";
264
- if (fs.existsSync(path2.join(cwd, "yarn.lock")))
265
- return "yarn";
266
- return "npm";
267
- }
268
- function getChronicleVersion() {
269
- const pkgPath = path2.join(PACKAGE_ROOT, "package.json");
270
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
271
- return pkg.version;
120
+ import fs from "node:fs/promises";
121
+ import path3 from "node:path";
122
+ async function linkContent(contentDir) {
123
+ const linkPath = path3.join(PACKAGE_ROOT, ".content");
124
+ const target = path3.resolve(contentDir);
125
+ try {
126
+ const existing = await fs.readlink(linkPath);
127
+ if (existing === target)
128
+ return;
129
+ await fs.unlink(linkPath);
130
+ } catch {}
131
+ await fs.symlink(target, linkPath);
272
132
  }
273
133
 
134
+ // src/cli/commands/build.ts
135
+ var buildCommand = new Command("build").description("Build for production").option("-c, --content <path>", "Content directory").option("--preset <preset>", "Deploy preset (vercel, cloudflare, node-server)").action(async (options) => {
136
+ const contentDir = resolveContentDir(options.content);
137
+ await linkContent(contentDir);
138
+ console.log(chalk2.cyan("Building for production..."));
139
+ const { createBuilder } = await import("vite");
140
+ const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
141
+ const config = await createViteConfig2({
142
+ packageRoot: PACKAGE_ROOT,
143
+ projectRoot: process.cwd(),
144
+ contentDir,
145
+ preset: options.preset
146
+ });
147
+ const builder = await createBuilder({ ...config, builder: {} });
148
+ await builder.buildApp();
149
+ console.log(chalk2.green("Build complete"));
150
+ });
151
+
152
+ // src/cli/commands/dev.ts
153
+ import chalk3 from "chalk";
154
+ import { Command as Command2 } from "commander";
155
+ var devCommand = new Command2("dev").description("Start development server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").action(async (options) => {
156
+ const contentDir = resolveContentDir(options.content);
157
+ const port = parseInt(options.port, 10);
158
+ await linkContent(contentDir);
159
+ console.log(chalk3.cyan("Starting dev server..."));
160
+ const { createServer } = await import("vite");
161
+ const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
162
+ const config = await createViteConfig2({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir });
163
+ const server = await createServer({
164
+ ...config,
165
+ server: { ...config.server, port }
166
+ });
167
+ await server.listen();
168
+ server.printUrls();
169
+ });
170
+
274
171
  // src/cli/commands/init.ts
275
- function createConfig() {
276
- return {
277
- title: "My Documentation",
278
- description: "Documentation powered by Chronicle",
279
- theme: { name: "default" },
280
- search: { enabled: true, placeholder: "Search documentation..." }
281
- };
282
- }
283
- function createPackageJson(name) {
284
- return {
285
- name,
286
- private: true,
287
- type: "module",
288
- scripts: {
289
- dev: "chronicle dev",
290
- build: "chronicle build",
291
- start: "chronicle start"
292
- },
293
- dependencies: {
294
- "@raystack/chronicle": `^${getChronicleVersion()}`
295
- },
296
- devDependencies: {
297
- "@raystack/tools-config": "0.56.0",
298
- "openapi-types": "^12.1.3",
299
- typescript: "5.9.3",
300
- "@types/react": "^19.2.10",
301
- "@types/node": "^25.1.0"
302
- }
303
- };
304
- }
172
+ import fs2 from "node:fs";
173
+ import path5 from "node:path";
174
+ import chalk4 from "chalk";
175
+ import { Command as Command3 } from "commander";
176
+ import { stringify } from "yaml";
177
+ var defaultConfig = {
178
+ title: "My Documentation",
179
+ description: "Documentation powered by Chronicle",
180
+ theme: { name: "default" },
181
+ search: { enabled: true, placeholder: "Search documentation..." }
182
+ };
305
183
  var sampleMdx = `---
306
184
  title: Welcome
307
185
  description: Getting started with your documentation
@@ -312,74 +190,28 @@ order: 1
312
190
 
313
191
  This is your documentation home page.
314
192
  `;
315
- var initCommand = new Command("init").description("Initialize a new Chronicle project").option("-c, --content <path>", "Content directory name", "content").action((options) => {
193
+ var initCommand = new Command3("init").description("Initialize a new Chronicle project").option("-c, --content <path>", "Content directory name", "content").action((options) => {
316
194
  const projectDir = process.cwd();
317
- const dirName = path3.basename(projectDir) || "docs";
318
- const contentDir = path3.join(projectDir, options.content);
195
+ const contentDir = path5.join(projectDir, options.content);
319
196
  if (!fs2.existsSync(contentDir)) {
320
197
  fs2.mkdirSync(contentDir, { recursive: true });
321
- console.log(chalk.green("✓"), "Created", contentDir);
198
+ console.log(chalk4.green("✓"), "Created", contentDir);
322
199
  }
323
- const packageJsonPath = path3.join(projectDir, "package.json");
324
- if (!fs2.existsSync(packageJsonPath)) {
325
- fs2.writeFileSync(packageJsonPath, JSON.stringify(createPackageJson(dirName), null, 2) + `
326
- `);
327
- console.log(chalk.green("✓"), "Created", packageJsonPath);
328
- } else {
329
- const existing = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
330
- const template = createPackageJson(dirName);
331
- let updated = false;
332
- if (existing.type !== "module") {
333
- existing.type = "module";
334
- updated = true;
335
- }
336
- if (!existing.scripts)
337
- existing.scripts = {};
338
- for (const [key, value] of Object.entries(template.scripts)) {
339
- if (!existing.scripts[key]) {
340
- existing.scripts[key] = value;
341
- updated = true;
342
- }
343
- }
344
- if (!existing.dependencies)
345
- existing.dependencies = {};
346
- for (const [key, value] of Object.entries(template.dependencies)) {
347
- if (!existing.dependencies[key]) {
348
- existing.dependencies[key] = value;
349
- updated = true;
350
- }
351
- }
352
- if (!existing.devDependencies)
353
- existing.devDependencies = {};
354
- for (const [key, value] of Object.entries(template.devDependencies)) {
355
- if (!existing.devDependencies[key]) {
356
- existing.devDependencies[key] = value;
357
- updated = true;
358
- }
359
- }
360
- if (updated) {
361
- fs2.writeFileSync(packageJsonPath, JSON.stringify(existing, null, 2) + `
362
- `);
363
- console.log(chalk.green("✓"), "Updated", packageJsonPath);
364
- } else {
365
- console.log(chalk.yellow("⚠"), packageJsonPath, "already has all required entries");
366
- }
367
- }
368
- const configPath = path3.join(projectDir, "chronicle.yaml");
200
+ const configPath = path5.join(projectDir, "chronicle.yaml");
369
201
  if (!fs2.existsSync(configPath)) {
370
- fs2.writeFileSync(configPath, stringify(createConfig()));
371
- console.log(chalk.green("✓"), "Created", configPath);
202
+ fs2.writeFileSync(configPath, stringify(defaultConfig));
203
+ console.log(chalk4.green("✓"), "Created", configPath);
372
204
  } else {
373
- console.log(chalk.yellow("⚠"), configPath, "already exists");
205
+ console.log(chalk4.yellow("⚠"), configPath, "already exists");
374
206
  }
375
207
  const contentFiles = fs2.readdirSync(contentDir);
376
208
  if (contentFiles.length === 0) {
377
- const indexPath = path3.join(contentDir, "index.mdx");
209
+ const indexPath = path5.join(contentDir, "index.mdx");
378
210
  fs2.writeFileSync(indexPath, sampleMdx);
379
- console.log(chalk.green("✓"), "Created", indexPath);
211
+ console.log(chalk4.green("✓"), "Created", indexPath);
380
212
  }
381
- const gitignorePath = path3.join(projectDir, ".gitignore");
382
- const gitignoreEntries = ["node_modules", "dist"];
213
+ const gitignorePath = path5.join(projectDir, ".gitignore");
214
+ const gitignoreEntries = ["node_modules", "dist", ".output"];
383
215
  if (fs2.existsSync(gitignorePath)) {
384
216
  const existing = fs2.readFileSync(gitignorePath, "utf-8");
385
217
  const missing = gitignoreEntries.filter((e) => !existing.includes(e));
@@ -388,142 +220,61 @@ var initCommand = new Command("init").description("Initialize a new Chronicle pr
388
220
  ${missing.join(`
389
221
  `)}
390
222
  `);
391
- console.log(chalk.green("✓"), "Added", missing.join(", "), "to .gitignore");
223
+ console.log(chalk4.green("✓"), "Added", missing.join(", "), "to .gitignore");
392
224
  }
393
225
  } else {
394
226
  fs2.writeFileSync(gitignorePath, `${gitignoreEntries.join(`
395
227
  `)}
396
228
  `);
397
- console.log(chalk.green("✓"), "Created .gitignore");
229
+ console.log(chalk4.green("✓"), "Created .gitignore");
398
230
  }
399
- const pm = detectPackageManager();
400
- console.log(chalk.cyan(`
401
- Installing dependencies with ${pm}...`));
402
- execSync(`${pm} install`, { cwd: projectDir, stdio: "inherit" });
403
- const runCmd = pm === "npm" ? "npx" : pm === "bun" ? "bunx" : `${pm} dlx`;
404
- console.log(chalk.green(`
231
+ console.log(chalk4.green(`
405
232
  ✓ Chronicle initialized!`));
406
233
  console.log(`
407
- Run`, chalk.cyan(`${runCmd} chronicle dev`), "to start development server");
408
- });
409
-
410
- // src/cli/commands/dev.ts
411
- import { Command as Command2 } from "commander";
412
- import chalk4 from "chalk";
413
-
414
- // src/cli/utils/config.ts
415
- import path4 from "path";
416
- import { parse } from "yaml";
417
- import chalk2 from "chalk";
418
- function resolveContentDir(contentFlag) {
419
- if (contentFlag)
420
- return path4.resolve(contentFlag);
421
- if (process.env.CHRONICLE_CONTENT_DIR)
422
- return path4.resolve(process.env.CHRONICLE_CONTENT_DIR);
423
- return path4.resolve("content");
424
- }
425
-
426
- // src/cli/commands/dev.ts
427
- var devCommand = new Command2("dev").description("Start development server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").action(async (options) => {
428
- const contentDir = resolveContentDir(options.content);
429
- const port = parseInt(options.port, 10);
430
- process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
431
- process.env.CHRONICLE_CONTENT_DIR = contentDir;
432
- console.log(chalk4.cyan("Starting dev server..."));
433
- const { startDevServer: startDevServer2 } = await Promise.resolve().then(() => (init_dev(), exports_dev));
434
- await startDevServer2({ port, root: PACKAGE_ROOT, contentDir });
234
+ Run`, chalk4.cyan("chronicle dev"), "to start development server");
435
235
  });
436
236
 
437
- // src/cli/commands/build.ts
438
- import { Command as Command3 } from "commander";
439
- import path7 from "path";
237
+ // src/cli/commands/serve.ts
440
238
  import chalk5 from "chalk";
441
- var buildCommand = new Command3("build").description("Build for production").option("-c, --content <path>", "Content directory").option("-o, --outDir <path>", "Output directory", "dist").action(async (options) => {
239
+ import { Command as Command4 } from "commander";
240
+ var serveCommand = new Command4("serve").description("Build and start production server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").option("--preset <preset>", "Deploy preset (vercel, cloudflare, node-server)").action(async (options) => {
442
241
  const contentDir = resolveContentDir(options.content);
443
- const outDir = path7.resolve(options.outDir);
444
- process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
445
- process.env.CHRONICLE_CONTENT_DIR = contentDir;
446
- console.log(chalk5.cyan("Building for production..."));
447
- const { build } = await import("vite");
242
+ const port = parseInt(options.port, 10);
243
+ await linkContent(contentDir);
244
+ const { build, preview } = await import("vite");
448
245
  const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
449
- const baseConfig = await createViteConfig2({ root: PACKAGE_ROOT, contentDir });
450
- console.log(chalk5.gray("Building client..."));
451
- await build({
452
- ...baseConfig,
453
- build: {
454
- outDir: path7.join(outDir, "client"),
455
- ssrManifest: true,
456
- rolldownOptions: {
457
- input: path7.resolve(PACKAGE_ROOT, "src/server/index.html")
458
- }
459
- }
246
+ const config = await createViteConfig2({
247
+ packageRoot: PACKAGE_ROOT,
248
+ projectRoot: process.cwd(),
249
+ contentDir,
250
+ preset: options.preset
460
251
  });
461
- console.log(chalk5.gray("Building server..."));
462
- await build({
463
- ...baseConfig,
464
- ssr: {
465
- noExternal: true
466
- },
467
- build: {
468
- outDir: path7.join(outDir, "server"),
469
- ssr: path7.resolve(PACKAGE_ROOT, "src/server/entry-prod.ts")
470
- }
252
+ console.log(chalk5.cyan("Building for production..."));
253
+ await build(config);
254
+ console.log(chalk5.cyan("Starting production server..."));
255
+ const server = await preview({
256
+ ...config,
257
+ preview: { port }
471
258
  });
472
- console.log(chalk5.green("Build complete →"), outDir);
259
+ server.printUrls();
473
260
  });
474
261
 
475
262
  // src/cli/commands/start.ts
476
- import { Command as Command4 } from "commander";
477
- import path9 from "path";
478
- import chalk7 from "chalk";
479
- var startCommand = new Command4("start").description("Start production server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").option("-d, --dist <path>", "Dist directory", "dist").action(async (options) => {
480
- const contentDir = resolveContentDir(options.content);
481
- const port = parseInt(options.port, 10);
482
- const distDir = path9.resolve(options.dist);
483
- process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
484
- process.env.CHRONICLE_CONTENT_DIR = contentDir;
485
- console.log(chalk7.cyan("Starting production server..."));
486
- const { startProdServer: startProdServer2 } = await Promise.resolve().then(() => (init_prod(), exports_prod));
487
- await startProdServer2({ port, root: PACKAGE_ROOT, distDir });
488
- });
489
-
490
- // src/cli/commands/serve.ts
263
+ import chalk6 from "chalk";
491
264
  import { Command as Command5 } from "commander";
492
- import path10 from "path";
493
- import chalk8 from "chalk";
494
- var serveCommand = new Command5("serve").description("Build and start production server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").option("-o, --outDir <path>", "Output directory", "dist").action(async (options) => {
265
+ var startCommand = new Command5("start").description("Start production server").option("-p, --port <port>", "Port number", "3000").option("-c, --content <path>", "Content directory").action(async (options) => {
495
266
  const contentDir = resolveContentDir(options.content);
496
267
  const port = parseInt(options.port, 10);
497
- const outDir = path10.resolve(options.outDir);
498
- process.env.CHRONICLE_PROJECT_ROOT = process.cwd();
499
- process.env.CHRONICLE_CONTENT_DIR = contentDir;
500
- console.log(chalk8.cyan("Building for production..."));
501
- const { build } = await import("vite");
268
+ await linkContent(contentDir);
269
+ console.log(chalk6.cyan("Starting production server..."));
270
+ const { preview } = await import("vite");
502
271
  const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
503
- const baseConfig = await createViteConfig2({ root: PACKAGE_ROOT, contentDir });
504
- await build({
505
- ...baseConfig,
506
- build: {
507
- outDir: path10.join(outDir, "client"),
508
- ssrManifest: true,
509
- rolldownOptions: {
510
- input: path10.resolve(PACKAGE_ROOT, "src/server/index.html")
511
- }
512
- }
513
- });
514
- await build({
515
- ...baseConfig,
516
- ssr: {
517
- noExternal: true
518
- },
519
- build: {
520
- outDir: path10.join(outDir, "server"),
521
- ssr: path10.resolve(PACKAGE_ROOT, "src/server/entry-prod.ts")
522
- }
272
+ const config = await createViteConfig2({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir });
273
+ const server = await preview({
274
+ ...config,
275
+ preview: { port }
523
276
  });
524
- console.log(chalk8.cyan("Starting production server..."));
525
- const { startProdServer: startProdServer2 } = await Promise.resolve().then(() => (init_prod(), exports_prod));
526
- await startProdServer2({ port, root: PACKAGE_ROOT, distDir: outDir });
277
+ server.printUrls();
527
278
  });
528
279
 
529
280
  // src/cli/index.ts