@raystack/chronicle 0.1.0-canary.0efaef0
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/bin/chronicle.js +2 -0
- package/dist/cli/index.js +276 -0
- package/package.json +71 -0
- package/src/cli/commands/build.ts +34 -0
- package/src/cli/commands/dev.ts +32 -0
- package/src/cli/commands/init.ts +69 -0
- package/src/cli/commands/serve.ts +40 -0
- package/src/cli/commands/start.ts +28 -0
- package/src/cli/index.ts +21 -0
- package/src/cli/utils/config.ts +42 -0
- package/src/cli/utils/index.ts +3 -0
- package/src/cli/utils/resolve.ts +10 -0
- package/src/cli/utils/scaffold.ts +18 -0
- package/src/components/api/code-snippets.module.css +7 -0
- package/src/components/api/code-snippets.tsx +76 -0
- package/src/components/api/endpoint-page.module.css +58 -0
- package/src/components/api/endpoint-page.tsx +283 -0
- package/src/components/api/field-row.module.css +126 -0
- package/src/components/api/field-row.tsx +204 -0
- package/src/components/api/field-section.module.css +24 -0
- package/src/components/api/field-section.tsx +100 -0
- package/src/components/api/index.ts +8 -0
- package/src/components/api/json-editor.module.css +9 -0
- package/src/components/api/json-editor.tsx +61 -0
- package/src/components/api/key-value-editor.module.css +13 -0
- package/src/components/api/key-value-editor.tsx +62 -0
- package/src/components/api/method-badge.module.css +4 -0
- package/src/components/api/method-badge.tsx +29 -0
- package/src/components/api/response-panel.module.css +8 -0
- package/src/components/api/response-panel.tsx +44 -0
- package/src/components/common/breadcrumb.tsx +3 -0
- package/src/components/common/button.tsx +3 -0
- package/src/components/common/callout.module.css +7 -0
- package/src/components/common/callout.tsx +27 -0
- package/src/components/common/code-block.tsx +3 -0
- package/src/components/common/dialog.tsx +3 -0
- package/src/components/common/index.ts +10 -0
- package/src/components/common/input-field.tsx +3 -0
- package/src/components/common/sidebar.tsx +3 -0
- package/src/components/common/switch.tsx +3 -0
- package/src/components/common/table.tsx +3 -0
- package/src/components/common/tabs.tsx +3 -0
- package/src/components/mdx/code.module.css +42 -0
- package/src/components/mdx/code.tsx +27 -0
- package/src/components/mdx/details.module.css +37 -0
- package/src/components/mdx/details.tsx +18 -0
- package/src/components/mdx/image.tsx +9 -0
- package/src/components/mdx/index.tsx +35 -0
- package/src/components/mdx/link.tsx +41 -0
- package/src/components/mdx/mermaid.module.css +9 -0
- package/src/components/mdx/mermaid.tsx +37 -0
- package/src/components/mdx/paragraph.module.css +8 -0
- package/src/components/mdx/paragraph.tsx +19 -0
- package/src/components/mdx/table.tsx +40 -0
- package/src/components/ui/breadcrumbs.tsx +72 -0
- package/src/components/ui/client-theme-switcher.tsx +18 -0
- package/src/components/ui/footer.module.css +27 -0
- package/src/components/ui/footer.tsx +30 -0
- package/src/components/ui/search.module.css +111 -0
- package/src/components/ui/search.tsx +218 -0
- package/src/lib/api-routes.ts +120 -0
- package/src/lib/config.ts +58 -0
- package/src/lib/get-llm-text.ts +10 -0
- package/src/lib/head.tsx +49 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/openapi.ts +188 -0
- package/src/lib/page-context.tsx +117 -0
- package/src/lib/remark-unused-directives.ts +30 -0
- package/src/lib/schema.ts +99 -0
- package/src/lib/snippet-generators.ts +87 -0
- package/src/lib/source.ts +186 -0
- package/src/pages/ApiLayout.module.css +22 -0
- package/src/pages/ApiLayout.tsx +33 -0
- package/src/pages/ApiPage.tsx +73 -0
- package/src/pages/DocsLayout.tsx +18 -0
- package/src/pages/DocsPage.tsx +43 -0
- package/src/pages/NotFound.tsx +17 -0
- package/src/server/App.tsx +67 -0
- package/src/server/api/apis-proxy.ts +69 -0
- package/src/server/api/health.ts +5 -0
- package/src/server/api/page/[...slug].ts +18 -0
- package/src/server/api/search.ts +170 -0
- package/src/server/api/specs.ts +9 -0
- package/src/server/build-search-index.ts +117 -0
- package/src/server/entry-client.tsx +73 -0
- package/src/server/entry-server.tsx +95 -0
- package/src/server/routes/llms.txt.ts +61 -0
- package/src/server/routes/og.tsx +75 -0
- package/src/server/routes/robots.txt.ts +11 -0
- package/src/server/routes/sitemap.xml.ts +39 -0
- package/src/server/utils/safe-path.ts +17 -0
- package/src/server/vite-config.ts +71 -0
- package/src/themes/default/Layout.module.css +81 -0
- package/src/themes/default/Layout.tsx +160 -0
- package/src/themes/default/Page.module.css +46 -0
- package/src/themes/default/Page.tsx +19 -0
- package/src/themes/default/Toc.module.css +48 -0
- package/src/themes/default/Toc.tsx +68 -0
- package/src/themes/default/index.ts +11 -0
- package/src/themes/paper/ChapterNav.module.css +71 -0
- package/src/themes/paper/ChapterNav.tsx +115 -0
- package/src/themes/paper/Layout.module.css +33 -0
- package/src/themes/paper/Layout.tsx +37 -0
- package/src/themes/paper/Page.module.css +181 -0
- package/src/themes/paper/Page.tsx +126 -0
- package/src/themes/paper/ReadingProgress.module.css +132 -0
- package/src/themes/paper/ReadingProgress.tsx +315 -0
- package/src/themes/paper/index.ts +8 -0
- package/src/themes/registry.ts +14 -0
- package/src/types/config.ts +80 -0
- package/src/types/content.ts +36 -0
- package/src/types/globals.d.ts +4 -0
- package/src/types/index.ts +3 -0
- package/src/types/theme.ts +22 -0
- package/tsconfig.json +29 -0
package/bin/chronicle.js
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
18
|
+
|
|
19
|
+
// src/server/vite-config.ts
|
|
20
|
+
var exports_vite_config = {};
|
|
21
|
+
__export(exports_vite_config, {
|
|
22
|
+
createViteConfig: () => createViteConfig
|
|
23
|
+
});
|
|
24
|
+
import react from "@vitejs/plugin-react";
|
|
25
|
+
import mdx from "fumadocs-mdx/vite";
|
|
26
|
+
import { nitro } from "nitro/vite";
|
|
27
|
+
import path4 from "node:path";
|
|
28
|
+
async function createViteConfig(options) {
|
|
29
|
+
const { packageRoot, projectRoot, contentDir, preset } = options;
|
|
30
|
+
return {
|
|
31
|
+
root: packageRoot,
|
|
32
|
+
configFile: false,
|
|
33
|
+
plugins: [
|
|
34
|
+
nitro({
|
|
35
|
+
serverDir: path4.resolve(packageRoot, "src/server"),
|
|
36
|
+
...preset && { preset }
|
|
37
|
+
}),
|
|
38
|
+
mdx({}, { index: false }),
|
|
39
|
+
react()
|
|
40
|
+
],
|
|
41
|
+
resolve: {
|
|
42
|
+
alias: {
|
|
43
|
+
"@": path4.resolve(packageRoot, "src")
|
|
44
|
+
},
|
|
45
|
+
conditions: ["module-sync", "import", "node"],
|
|
46
|
+
dedupe: [
|
|
47
|
+
"react",
|
|
48
|
+
"react-dom",
|
|
49
|
+
"react/jsx-runtime",
|
|
50
|
+
"react/jsx-dev-runtime",
|
|
51
|
+
"react-router"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
server: {
|
|
55
|
+
fs: {
|
|
56
|
+
allow: [packageRoot, projectRoot, contentDir]
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
define: {
|
|
60
|
+
__CHRONICLE_CONTENT_DIR__: JSON.stringify(contentDir),
|
|
61
|
+
__CHRONICLE_PROJECT_ROOT__: JSON.stringify(projectRoot),
|
|
62
|
+
__CHRONICLE_PACKAGE_ROOT__: JSON.stringify(packageRoot)
|
|
63
|
+
},
|
|
64
|
+
css: {
|
|
65
|
+
modules: {
|
|
66
|
+
localsConvention: "camelCase"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
ssr: {
|
|
70
|
+
noExternal: ["@raystack/apsara", "dayjs", "fumadocs-core"]
|
|
71
|
+
},
|
|
72
|
+
environments: {
|
|
73
|
+
client: {
|
|
74
|
+
build: {
|
|
75
|
+
rollupOptions: {
|
|
76
|
+
input: path4.resolve(packageRoot, "src/server/entry-client.tsx")
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
var init_vite_config = () => {};
|
|
84
|
+
|
|
85
|
+
// src/cli/index.ts
|
|
86
|
+
import { Command as Command6 } from "commander";
|
|
87
|
+
|
|
88
|
+
// src/cli/commands/build.ts
|
|
89
|
+
import chalk2 from "chalk";
|
|
90
|
+
import { Command } from "commander";
|
|
91
|
+
|
|
92
|
+
// src/cli/utils/config.ts
|
|
93
|
+
import path from "node:path";
|
|
94
|
+
import chalk from "chalk";
|
|
95
|
+
import { parse } from "yaml";
|
|
96
|
+
function resolveContentDir(contentFlag) {
|
|
97
|
+
if (contentFlag)
|
|
98
|
+
return path.resolve(contentFlag);
|
|
99
|
+
return path.resolve("content");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/cli/utils/resolve.ts
|
|
103
|
+
import path2 from "path";
|
|
104
|
+
import { fileURLToPath } from "url";
|
|
105
|
+
var PACKAGE_ROOT = path2.resolve(path2.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
106
|
+
|
|
107
|
+
// src/cli/utils/scaffold.ts
|
|
108
|
+
import fs from "node:fs/promises";
|
|
109
|
+
import path3 from "node:path";
|
|
110
|
+
async function linkContent(contentDir) {
|
|
111
|
+
const linkPath = path3.join(PACKAGE_ROOT, ".content");
|
|
112
|
+
const target = path3.resolve(contentDir);
|
|
113
|
+
try {
|
|
114
|
+
const existing = await fs.readlink(linkPath);
|
|
115
|
+
if (existing === target)
|
|
116
|
+
return;
|
|
117
|
+
await fs.unlink(linkPath);
|
|
118
|
+
} catch {}
|
|
119
|
+
await fs.symlink(target, linkPath);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/cli/commands/build.ts
|
|
123
|
+
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) => {
|
|
124
|
+
const contentDir = resolveContentDir(options.content);
|
|
125
|
+
await linkContent(contentDir);
|
|
126
|
+
console.log(chalk2.cyan("Building for production..."));
|
|
127
|
+
const { createBuilder } = await import("vite");
|
|
128
|
+
const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
|
|
129
|
+
const config = await createViteConfig2({
|
|
130
|
+
packageRoot: PACKAGE_ROOT,
|
|
131
|
+
projectRoot: process.cwd(),
|
|
132
|
+
contentDir,
|
|
133
|
+
preset: options.preset
|
|
134
|
+
});
|
|
135
|
+
const builder = await createBuilder({ ...config, builder: {} });
|
|
136
|
+
await builder.buildApp();
|
|
137
|
+
console.log(chalk2.green("Build complete"));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// src/cli/commands/dev.ts
|
|
141
|
+
import chalk3 from "chalk";
|
|
142
|
+
import { Command as Command2 } from "commander";
|
|
143
|
+
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) => {
|
|
144
|
+
const contentDir = resolveContentDir(options.content);
|
|
145
|
+
const port = parseInt(options.port, 10);
|
|
146
|
+
await linkContent(contentDir);
|
|
147
|
+
console.log(chalk3.cyan("Starting dev server..."));
|
|
148
|
+
const { createServer } = await import("vite");
|
|
149
|
+
const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
|
|
150
|
+
const config = await createViteConfig2({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir });
|
|
151
|
+
const server = await createServer({
|
|
152
|
+
...config,
|
|
153
|
+
server: { ...config.server, port }
|
|
154
|
+
});
|
|
155
|
+
await server.listen();
|
|
156
|
+
server.printUrls();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// src/cli/commands/init.ts
|
|
160
|
+
import fs2 from "node:fs";
|
|
161
|
+
import path5 from "node:path";
|
|
162
|
+
import chalk4 from "chalk";
|
|
163
|
+
import { Command as Command3 } from "commander";
|
|
164
|
+
import { stringify } from "yaml";
|
|
165
|
+
var defaultConfig = {
|
|
166
|
+
title: "My Documentation",
|
|
167
|
+
description: "Documentation powered by Chronicle",
|
|
168
|
+
theme: { name: "default" },
|
|
169
|
+
search: { enabled: true, placeholder: "Search documentation..." }
|
|
170
|
+
};
|
|
171
|
+
var sampleMdx = `---
|
|
172
|
+
title: Welcome
|
|
173
|
+
description: Getting started with your documentation
|
|
174
|
+
order: 1
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
# Welcome
|
|
178
|
+
|
|
179
|
+
This is your documentation home page.
|
|
180
|
+
`;
|
|
181
|
+
var initCommand = new Command3("init").description("Initialize a new Chronicle project").option("-c, --content <path>", "Content directory name", "content").action((options) => {
|
|
182
|
+
const projectDir = process.cwd();
|
|
183
|
+
const contentDir = path5.join(projectDir, options.content);
|
|
184
|
+
if (!fs2.existsSync(contentDir)) {
|
|
185
|
+
fs2.mkdirSync(contentDir, { recursive: true });
|
|
186
|
+
console.log(chalk4.green("✓"), "Created", contentDir);
|
|
187
|
+
}
|
|
188
|
+
const configPath = path5.join(projectDir, "chronicle.yaml");
|
|
189
|
+
if (!fs2.existsSync(configPath)) {
|
|
190
|
+
fs2.writeFileSync(configPath, stringify(defaultConfig));
|
|
191
|
+
console.log(chalk4.green("✓"), "Created", configPath);
|
|
192
|
+
} else {
|
|
193
|
+
console.log(chalk4.yellow("⚠"), configPath, "already exists");
|
|
194
|
+
}
|
|
195
|
+
const contentFiles = fs2.readdirSync(contentDir);
|
|
196
|
+
if (contentFiles.length === 0) {
|
|
197
|
+
const indexPath = path5.join(contentDir, "index.mdx");
|
|
198
|
+
fs2.writeFileSync(indexPath, sampleMdx);
|
|
199
|
+
console.log(chalk4.green("✓"), "Created", indexPath);
|
|
200
|
+
}
|
|
201
|
+
const gitignorePath = path5.join(projectDir, ".gitignore");
|
|
202
|
+
const gitignoreEntries = ["node_modules", "dist", ".output"];
|
|
203
|
+
if (fs2.existsSync(gitignorePath)) {
|
|
204
|
+
const existing = fs2.readFileSync(gitignorePath, "utf-8");
|
|
205
|
+
const missing = gitignoreEntries.filter((e) => !existing.includes(e));
|
|
206
|
+
if (missing.length > 0) {
|
|
207
|
+
fs2.appendFileSync(gitignorePath, `
|
|
208
|
+
${missing.join(`
|
|
209
|
+
`)}
|
|
210
|
+
`);
|
|
211
|
+
console.log(chalk4.green("✓"), "Added", missing.join(", "), "to .gitignore");
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
fs2.writeFileSync(gitignorePath, `${gitignoreEntries.join(`
|
|
215
|
+
`)}
|
|
216
|
+
`);
|
|
217
|
+
console.log(chalk4.green("✓"), "Created .gitignore");
|
|
218
|
+
}
|
|
219
|
+
console.log(chalk4.green(`
|
|
220
|
+
✓ Chronicle initialized!`));
|
|
221
|
+
console.log(`
|
|
222
|
+
Run`, chalk4.cyan("chronicle dev"), "to start development server");
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// src/cli/commands/serve.ts
|
|
226
|
+
import chalk5 from "chalk";
|
|
227
|
+
import { Command as Command4 } from "commander";
|
|
228
|
+
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) => {
|
|
229
|
+
const contentDir = resolveContentDir(options.content);
|
|
230
|
+
const port = parseInt(options.port, 10);
|
|
231
|
+
await linkContent(contentDir);
|
|
232
|
+
const { build, preview } = await import("vite");
|
|
233
|
+
const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
|
|
234
|
+
const config = await createViteConfig2({
|
|
235
|
+
packageRoot: PACKAGE_ROOT,
|
|
236
|
+
projectRoot: process.cwd(),
|
|
237
|
+
contentDir,
|
|
238
|
+
preset: options.preset
|
|
239
|
+
});
|
|
240
|
+
console.log(chalk5.cyan("Building for production..."));
|
|
241
|
+
await build(config);
|
|
242
|
+
console.log(chalk5.cyan("Starting production server..."));
|
|
243
|
+
const server = await preview({
|
|
244
|
+
...config,
|
|
245
|
+
preview: { port }
|
|
246
|
+
});
|
|
247
|
+
server.printUrls();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// src/cli/commands/start.ts
|
|
251
|
+
import chalk6 from "chalk";
|
|
252
|
+
import { Command as Command5 } from "commander";
|
|
253
|
+
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) => {
|
|
254
|
+
const contentDir = resolveContentDir(options.content);
|
|
255
|
+
const port = parseInt(options.port, 10);
|
|
256
|
+
await linkContent(contentDir);
|
|
257
|
+
console.log(chalk6.cyan("Starting production server..."));
|
|
258
|
+
const { preview } = await import("vite");
|
|
259
|
+
const { createViteConfig: createViteConfig2 } = await Promise.resolve().then(() => (init_vite_config(), exports_vite_config));
|
|
260
|
+
const config = await createViteConfig2({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir });
|
|
261
|
+
const server = await preview({
|
|
262
|
+
...config,
|
|
263
|
+
preview: { port }
|
|
264
|
+
});
|
|
265
|
+
server.printUrls();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// src/cli/index.ts
|
|
269
|
+
var program = new Command6;
|
|
270
|
+
program.name("chronicle").description("Config-driven documentation framework").version("0.1.0");
|
|
271
|
+
program.addCommand(initCommand);
|
|
272
|
+
program.addCommand(devCommand);
|
|
273
|
+
program.addCommand(buildCommand);
|
|
274
|
+
program.addCommand(startCommand);
|
|
275
|
+
program.addCommand(serveCommand);
|
|
276
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@raystack/chronicle",
|
|
3
|
+
"version": "0.1.0-canary.0efaef0",
|
|
4
|
+
"description": "Config-driven documentation framework",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"bin",
|
|
9
|
+
"dist",
|
|
10
|
+
"src",
|
|
11
|
+
"templates",
|
|
12
|
+
"tsconfig.json"
|
|
13
|
+
],
|
|
14
|
+
"bin": {
|
|
15
|
+
"chronicle": "./bin/chronicle.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build:cli": "bun build-cli.ts",
|
|
19
|
+
"lint": "biome lint src/"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@biomejs/biome": "^2.3.13",
|
|
23
|
+
"@raystack/tools-config": "0.56.0",
|
|
24
|
+
"@types/lodash": "^4.17.23",
|
|
25
|
+
"@types/mdx": "^2.0.13",
|
|
26
|
+
"@types/node": "^25.1.0",
|
|
27
|
+
"@types/react": "^19.2.10",
|
|
28
|
+
"@types/react-dom": "^19.2.3",
|
|
29
|
+
"@types/semver": "^7.7.1",
|
|
30
|
+
"semver": "^7.7.4",
|
|
31
|
+
"typescript": "5.9.3"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@codemirror/lang-json": "^6.0.2",
|
|
35
|
+
"@codemirror/state": "^6.5.4",
|
|
36
|
+
"@codemirror/theme-one-dark": "^6.1.3",
|
|
37
|
+
"@codemirror/view": "^6.39.14",
|
|
38
|
+
"@heroicons/react": "^2.2.0",
|
|
39
|
+
"@raystack/apsara": "0.55.1",
|
|
40
|
+
"@shikijs/rehype": "^4.0.2",
|
|
41
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
42
|
+
"chalk": "^5.6.2",
|
|
43
|
+
"class-variance-authority": "^0.7.1",
|
|
44
|
+
"codemirror": "^6.0.2",
|
|
45
|
+
"commander": "^14.0.2",
|
|
46
|
+
"fumadocs-core": "16.6.15",
|
|
47
|
+
"fumadocs-mdx": "^14.2.6",
|
|
48
|
+
"glob": "^11.0.0",
|
|
49
|
+
"gray-matter": "^4.0.3",
|
|
50
|
+
"h3": "^2.0.1-rc.16",
|
|
51
|
+
"lodash": "^4.17.23",
|
|
52
|
+
"mermaid": "^11.13.0",
|
|
53
|
+
"minisearch": "^7.2.0",
|
|
54
|
+
"nitro": "latest",
|
|
55
|
+
"openapi-types": "^12.1.3",
|
|
56
|
+
"react": "^19.0.0",
|
|
57
|
+
"react-dom": "^19.0.0",
|
|
58
|
+
"react-router": "^7.13.1",
|
|
59
|
+
"remark-directive": "^4.0.0",
|
|
60
|
+
"remark-parse": "^11.0.0",
|
|
61
|
+
"remark-frontmatter": "^5.0.0",
|
|
62
|
+
"remark-gfm": "^4.0.1",
|
|
63
|
+
"remark-mdx-frontmatter": "^5.2.0",
|
|
64
|
+
"satori": "^0.25.0",
|
|
65
|
+
"slugify": "^1.6.6",
|
|
66
|
+
"unified": "^11.0.5",
|
|
67
|
+
"unist-util-visit": "^5.1.0",
|
|
68
|
+
"vite": "^8.0.0",
|
|
69
|
+
"yaml": "^2.8.2"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveContentDir } from '@/cli/utils/config';
|
|
4
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve';
|
|
5
|
+
import { linkContent } from '@/cli/utils/scaffold';
|
|
6
|
+
|
|
7
|
+
export const buildCommand = new Command('build')
|
|
8
|
+
.description('Build for production')
|
|
9
|
+
.option('-c, --content <path>', 'Content directory')
|
|
10
|
+
.option(
|
|
11
|
+
'--preset <preset>',
|
|
12
|
+
'Deploy preset (vercel, cloudflare, node-server)'
|
|
13
|
+
)
|
|
14
|
+
.action(async options => {
|
|
15
|
+
const contentDir = resolveContentDir(options.content);
|
|
16
|
+
await linkContent(contentDir);
|
|
17
|
+
|
|
18
|
+
console.log(chalk.cyan('Building for production...'));
|
|
19
|
+
|
|
20
|
+
const { createBuilder } = await import('vite');
|
|
21
|
+
const { createViteConfig } = await import('@/server/vite-config');
|
|
22
|
+
|
|
23
|
+
const config = await createViteConfig({
|
|
24
|
+
packageRoot: PACKAGE_ROOT,
|
|
25
|
+
projectRoot: process.cwd(),
|
|
26
|
+
contentDir,
|
|
27
|
+
preset: options.preset
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const builder = await createBuilder({ ...config, builder: {} });
|
|
31
|
+
await builder.buildApp();
|
|
32
|
+
|
|
33
|
+
console.log(chalk.green('Build complete'));
|
|
34
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { resolveContentDir } from '@/cli/utils/config';
|
|
6
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve';
|
|
7
|
+
import { linkContent } from '@/cli/utils/scaffold';
|
|
8
|
+
|
|
9
|
+
export const devCommand = new Command('dev')
|
|
10
|
+
.description('Start development server')
|
|
11
|
+
.option('-p, --port <port>', 'Port number', '3000')
|
|
12
|
+
.option('-c, --content <path>', 'Content directory')
|
|
13
|
+
.action(async options => {
|
|
14
|
+
const contentDir = resolveContentDir(options.content);
|
|
15
|
+
const port = parseInt(options.port, 10);
|
|
16
|
+
|
|
17
|
+
await linkContent(contentDir);
|
|
18
|
+
|
|
19
|
+
console.log(chalk.cyan('Starting dev server...'));
|
|
20
|
+
|
|
21
|
+
const { createServer } = await import('vite');
|
|
22
|
+
const { createViteConfig } = await import('@/server/vite-config');
|
|
23
|
+
|
|
24
|
+
const config = await createViteConfig({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir });
|
|
25
|
+
const server = await createServer({
|
|
26
|
+
...config,
|
|
27
|
+
server: { ...config.server, port }
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await server.listen();
|
|
31
|
+
server.printUrls();
|
|
32
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { stringify } from 'yaml';
|
|
6
|
+
import type { ChronicleConfig } from '@/types';
|
|
7
|
+
|
|
8
|
+
const defaultConfig: ChronicleConfig = {
|
|
9
|
+
title: 'My Documentation',
|
|
10
|
+
description: 'Documentation powered by Chronicle',
|
|
11
|
+
theme: { name: 'default' },
|
|
12
|
+
search: { enabled: true, placeholder: 'Search documentation...' }
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const sampleMdx = `---
|
|
16
|
+
title: Welcome
|
|
17
|
+
description: Getting started with your documentation
|
|
18
|
+
order: 1
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Welcome
|
|
22
|
+
|
|
23
|
+
This is your documentation home page.
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
export const initCommand = new Command('init')
|
|
27
|
+
.description('Initialize a new Chronicle project')
|
|
28
|
+
.option('-c, --content <path>', 'Content directory name', 'content')
|
|
29
|
+
.action(options => {
|
|
30
|
+
const projectDir = process.cwd();
|
|
31
|
+
const contentDir = path.join(projectDir, options.content);
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(contentDir)) {
|
|
34
|
+
fs.mkdirSync(contentDir, { recursive: true });
|
|
35
|
+
console.log(chalk.green('\u2713'), 'Created', contentDir);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const configPath = path.join(projectDir, 'chronicle.yaml');
|
|
39
|
+
if (!fs.existsSync(configPath)) {
|
|
40
|
+
fs.writeFileSync(configPath, stringify(defaultConfig));
|
|
41
|
+
console.log(chalk.green('\u2713'), 'Created', configPath);
|
|
42
|
+
} else {
|
|
43
|
+
console.log(chalk.yellow('\u26a0'), configPath, 'already exists');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const contentFiles = fs.readdirSync(contentDir);
|
|
47
|
+
if (contentFiles.length === 0) {
|
|
48
|
+
const indexPath = path.join(contentDir, 'index.mdx');
|
|
49
|
+
fs.writeFileSync(indexPath, sampleMdx);
|
|
50
|
+
console.log(chalk.green('\u2713'), 'Created', indexPath);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const gitignorePath = path.join(projectDir, '.gitignore');
|
|
54
|
+
const gitignoreEntries = ['node_modules', 'dist', '.output'];
|
|
55
|
+
if (fs.existsSync(gitignorePath)) {
|
|
56
|
+
const existing = fs.readFileSync(gitignorePath, 'utf-8');
|
|
57
|
+
const missing = gitignoreEntries.filter(e => !existing.includes(e));
|
|
58
|
+
if (missing.length > 0) {
|
|
59
|
+
fs.appendFileSync(gitignorePath, `\n${missing.join('\n')}\n`);
|
|
60
|
+
console.log(chalk.green('\u2713'), 'Added', missing.join(', '), 'to .gitignore');
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
fs.writeFileSync(gitignorePath, `${gitignoreEntries.join('\n')}\n`);
|
|
64
|
+
console.log(chalk.green('\u2713'), 'Created .gitignore');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(chalk.green('\n\u2713 Chronicle initialized!'));
|
|
68
|
+
console.log('\nRun', chalk.cyan('chronicle dev'), 'to start development server');
|
|
69
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveContentDir } from '@/cli/utils/config';
|
|
4
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve';
|
|
5
|
+
import { linkContent } from '@/cli/utils/scaffold';
|
|
6
|
+
|
|
7
|
+
export const serveCommand = new Command('serve')
|
|
8
|
+
.description('Build and start production server')
|
|
9
|
+
.option('-p, --port <port>', 'Port number', '3000')
|
|
10
|
+
.option('-c, --content <path>', 'Content directory')
|
|
11
|
+
.option(
|
|
12
|
+
'--preset <preset>',
|
|
13
|
+
'Deploy preset (vercel, cloudflare, node-server)'
|
|
14
|
+
)
|
|
15
|
+
.action(async options => {
|
|
16
|
+
const contentDir = resolveContentDir(options.content);
|
|
17
|
+
const port = parseInt(options.port, 10);
|
|
18
|
+
await linkContent(contentDir);
|
|
19
|
+
|
|
20
|
+
const { build, preview } = await import('vite');
|
|
21
|
+
const { createViteConfig } = await import('@/server/vite-config');
|
|
22
|
+
|
|
23
|
+
const config = await createViteConfig({
|
|
24
|
+
packageRoot: PACKAGE_ROOT,
|
|
25
|
+
projectRoot: process.cwd(),
|
|
26
|
+
contentDir,
|
|
27
|
+
preset: options.preset
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log(chalk.cyan('Building for production...'));
|
|
31
|
+
await build(config);
|
|
32
|
+
|
|
33
|
+
console.log(chalk.cyan('Starting production server...'));
|
|
34
|
+
const server = await preview({
|
|
35
|
+
...config,
|
|
36
|
+
preview: { port }
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
server.printUrls();
|
|
40
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { resolveContentDir } from '@/cli/utils/config';
|
|
4
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve';
|
|
5
|
+
import { linkContent } from '@/cli/utils/scaffold';
|
|
6
|
+
|
|
7
|
+
export const startCommand = new Command('start')
|
|
8
|
+
.description('Start production server')
|
|
9
|
+
.option('-p, --port <port>', 'Port number', '3000')
|
|
10
|
+
.option('-c, --content <path>', 'Content directory')
|
|
11
|
+
.action(async options => {
|
|
12
|
+
const contentDir = resolveContentDir(options.content);
|
|
13
|
+
const port = parseInt(options.port, 10);
|
|
14
|
+
await linkContent(contentDir);
|
|
15
|
+
|
|
16
|
+
console.log(chalk.cyan('Starting production server...'));
|
|
17
|
+
|
|
18
|
+
const { preview } = await import('vite');
|
|
19
|
+
const { createViteConfig } = await import('@/server/vite-config');
|
|
20
|
+
|
|
21
|
+
const config = await createViteConfig({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir });
|
|
22
|
+
const server = await preview({
|
|
23
|
+
...config,
|
|
24
|
+
preview: { port }
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
server.printUrls();
|
|
28
|
+
});
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { buildCommand } from './commands/build';
|
|
3
|
+
import { devCommand } from './commands/dev';
|
|
4
|
+
import { initCommand } from './commands/init';
|
|
5
|
+
import { serveCommand } from './commands/serve';
|
|
6
|
+
import { startCommand } from './commands/start';
|
|
7
|
+
|
|
8
|
+
const program = new Command();
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('chronicle')
|
|
12
|
+
.description('Config-driven documentation framework')
|
|
13
|
+
.version('0.1.0');
|
|
14
|
+
|
|
15
|
+
program.addCommand(initCommand);
|
|
16
|
+
program.addCommand(devCommand);
|
|
17
|
+
program.addCommand(buildCommand);
|
|
18
|
+
program.addCommand(startCommand);
|
|
19
|
+
program.addCommand(serveCommand);
|
|
20
|
+
|
|
21
|
+
program.parse();
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { parse } from 'yaml';
|
|
5
|
+
import type { ChronicleConfig } from '@/types';
|
|
6
|
+
|
|
7
|
+
export interface CLIConfig {
|
|
8
|
+
config: ChronicleConfig;
|
|
9
|
+
configPath: string;
|
|
10
|
+
contentDir: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function resolveContentDir(contentFlag?: string): string {
|
|
14
|
+
if (contentFlag) return path.resolve(contentFlag);
|
|
15
|
+
return path.resolve('content');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function resolveConfigPath(contentDir: string): string | null {
|
|
19
|
+
const cwdPath = path.join(process.cwd(), 'chronicle.yaml');
|
|
20
|
+
if (fs.existsSync(cwdPath)) return cwdPath;
|
|
21
|
+
const contentPath = path.join(contentDir, 'chronicle.yaml');
|
|
22
|
+
if (fs.existsSync(contentPath)) return contentPath;
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function loadCLIConfig(contentDir: string): CLIConfig {
|
|
27
|
+
const configPath = resolveConfigPath(contentDir);
|
|
28
|
+
|
|
29
|
+
if (!configPath) {
|
|
30
|
+
console.log(
|
|
31
|
+
chalk.red(
|
|
32
|
+
`Error: chronicle.yaml not found in '${process.cwd()}' or '${contentDir}'`
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
console.log(chalk.gray("Run 'chronicle init' to create one"));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const config = parse(fs.readFileSync(configPath, 'utf-8')) as ChronicleConfig;
|
|
40
|
+
|
|
41
|
+
return { config, configPath, contentDir };
|
|
42
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
|
|
4
|
+
// After bundling: dist/cli/index.js → ../.. = package root
|
|
5
|
+
// After install: node_modules/@raystack/chronicle/dist/cli/index.js → ../.. = package root
|
|
6
|
+
export const PACKAGE_ROOT = path.resolve(
|
|
7
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
8
|
+
'..',
|
|
9
|
+
'..'
|
|
10
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { PACKAGE_ROOT } from './resolve';
|
|
4
|
+
|
|
5
|
+
export async function linkContent(contentDir: string): Promise<void> {
|
|
6
|
+
const linkPath = path.join(PACKAGE_ROOT, '.content');
|
|
7
|
+
const target = path.resolve(contentDir);
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const existing = await fs.readlink(linkPath);
|
|
11
|
+
if (existing === target) return;
|
|
12
|
+
await fs.unlink(linkPath);
|
|
13
|
+
} catch {
|
|
14
|
+
// link doesn't exist
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
await fs.symlink(target, linkPath);
|
|
18
|
+
}
|