@raystack/chronicle 0.1.0-canary.e11f924 → 0.1.0-canary.f0d9bde
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/dist/cli/index.js +878 -9684
- package/package.json +17 -12
- package/src/cli/__tests__/config.test.ts +25 -0
- package/src/cli/__tests__/scaffold.test.ts +10 -0
- package/src/cli/commands/build.ts +66 -19
- package/src/cli/commands/dev.ts +9 -22
- package/src/cli/commands/init.ts +107 -11
- package/src/cli/commands/serve.ts +36 -35
- package/src/cli/commands/start.ts +11 -21
- package/src/cli/utils/config.ts +2 -2
- package/src/cli/utils/index.ts +1 -1
- package/src/cli/utils/resolve.ts +6 -0
- package/src/cli/utils/scaffold.ts +20 -0
- package/src/components/mdx/code.tsx +10 -1
- package/src/components/mdx/details.module.css +1 -24
- package/src/components/mdx/details.tsx +2 -3
- package/src/components/mdx/image.tsx +5 -19
- package/src/components/mdx/index.tsx +3 -3
- package/src/components/mdx/link.tsx +10 -11
- package/src/components/ui/footer.tsx +3 -2
- package/src/components/ui/search.module.css +7 -0
- package/src/components/ui/search.tsx +62 -87
- package/src/lib/config.ts +9 -0
- package/src/lib/head.tsx +45 -0
- package/src/lib/page-context.tsx +95 -0
- package/src/lib/source.ts +92 -21
- package/src/{app/apis/[[...slug]]/layout.tsx → pages/ApiLayout.tsx} +10 -7
- package/src/pages/ApiPage.tsx +68 -0
- package/src/pages/DocsLayout.tsx +18 -0
- package/src/pages/DocsPage.tsx +43 -0
- package/src/pages/NotFound.tsx +10 -0
- package/src/pages/__tests__/head.test.tsx +57 -0
- package/src/server/App.tsx +59 -0
- package/src/server/__tests__/entry-server.test.tsx +35 -0
- package/src/server/__tests__/handlers.test.ts +77 -0
- package/src/server/__tests__/og.test.ts +23 -0
- package/src/server/__tests__/router.test.ts +72 -0
- package/src/server/__tests__/vite-config.test.ts +25 -0
- package/src/server/adapters/vercel.ts +133 -0
- package/src/server/build-search-index.ts +107 -0
- package/src/server/dev.ts +158 -0
- package/src/server/entry-client.tsx +74 -0
- package/src/server/entry-prod.ts +98 -0
- package/src/server/entry-server.tsx +35 -0
- package/src/server/entry-vercel.ts +28 -0
- package/src/server/handlers/apis-proxy.ts +57 -0
- package/src/{app/api/health/route.ts → server/handlers/health.ts} +1 -1
- package/src/server/handlers/llms.ts +58 -0
- package/src/server/handlers/og.ts +87 -0
- package/src/server/handlers/robots.ts +11 -0
- package/src/server/handlers/search.ts +172 -0
- package/src/server/handlers/sitemap.ts +39 -0
- package/src/server/handlers/specs.ts +9 -0
- package/src/server/index.html +12 -0
- package/src/server/prod.ts +18 -0
- package/src/server/request-handler.ts +64 -0
- package/src/server/router.ts +42 -0
- package/src/server/utils/safe-path.ts +14 -0
- package/src/server/vite-config.ts +71 -0
- package/src/themes/default/Layout.tsx +9 -10
- package/src/themes/default/Page.module.css +60 -0
- package/src/themes/default/font.ts +4 -6
- package/src/themes/paper/ChapterNav.tsx +5 -6
- package/src/themes/paper/Page.tsx +8 -9
- package/src/types/config.ts +11 -0
- package/src/types/content.ts +1 -0
- package/tsconfig.json +29 -0
- package/next.config.mjs +0 -10
- package/source.config.ts +0 -50
- package/src/app/[[...slug]]/layout.tsx +0 -15
- package/src/app/[[...slug]]/page.tsx +0 -57
- package/src/app/api/apis-proxy/route.ts +0 -59
- package/src/app/api/search/route.ts +0 -90
- package/src/app/apis/[[...slug]]/page.tsx +0 -57
- package/src/app/layout.tsx +0 -26
- package/src/app/llms-full.txt/route.ts +0 -18
- package/src/app/llms.txt/route.ts +0 -15
- package/src/app/providers.tsx +0 -8
- package/src/cli/utils/process.ts +0 -7
- package/src/lib/get-llm-text.ts +0 -10
- /package/src/{app/apis/[[...slug]]/layout.module.css → pages/ApiLayout.module.css} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raystack/chronicle",
|
|
3
|
-
"version": "0.1.0-canary.
|
|
3
|
+
"version": "0.1.0-canary.f0d9bde",
|
|
4
4
|
"description": "Config-driven documentation framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"dist",
|
|
10
10
|
"src",
|
|
11
11
|
"templates",
|
|
12
|
-
"
|
|
13
|
-
"source.config.ts"
|
|
12
|
+
"tsconfig.json"
|
|
14
13
|
],
|
|
15
14
|
"bin": {
|
|
16
15
|
"chronicle": "./bin/chronicle.js"
|
|
@@ -27,7 +26,6 @@
|
|
|
27
26
|
"@types/react": "^19.2.10",
|
|
28
27
|
"@types/react-dom": "^19.2.3",
|
|
29
28
|
"@types/semver": "^7.7.1",
|
|
30
|
-
"openapi-types": "^12.1.3",
|
|
31
29
|
"semver": "^7.7.4",
|
|
32
30
|
"typescript": "5.9.3"
|
|
33
31
|
},
|
|
@@ -37,26 +35,33 @@
|
|
|
37
35
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
38
36
|
"@codemirror/view": "^6.39.14",
|
|
39
37
|
"@heroicons/react": "^2.2.0",
|
|
38
|
+
"@mdx-js/rollup": "^3.1.1",
|
|
40
39
|
"@raystack/apsara": "^0.56.0",
|
|
41
|
-
"@
|
|
40
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
42
41
|
"chalk": "^5.6.2",
|
|
43
42
|
"class-variance-authority": "^0.7.1",
|
|
44
43
|
"codemirror": "^6.0.2",
|
|
45
44
|
"commander": "^14.0.2",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
45
|
+
"glob": "^11.0.0",
|
|
46
|
+
"gray-matter": "^4.0.3",
|
|
48
47
|
"lodash": "^4.17.23",
|
|
49
48
|
"mermaid": "^11.13.0",
|
|
50
|
-
"
|
|
49
|
+
"openapi-types": "^12.1.3",
|
|
51
50
|
"react": "^19.0.0",
|
|
52
|
-
"react-device-detect": "^2.2.3",
|
|
53
51
|
"react-dom": "^19.0.0",
|
|
54
|
-
"
|
|
52
|
+
"react-router-dom": "^7.13.1",
|
|
55
53
|
"remark-directive": "^4.0.0",
|
|
54
|
+
"remark-gfm": "^4.0.1",
|
|
55
|
+
"@shikijs/rehype": "^4.0.2",
|
|
56
|
+
"remark-frontmatter": "^5.0.0",
|
|
57
|
+
"remark-mdx-frontmatter": "^5.2.0",
|
|
58
|
+
"satori": "^0.25.0",
|
|
59
|
+
"sirv": "^3.0.1",
|
|
56
60
|
"slugify": "^1.6.6",
|
|
57
61
|
"unified": "^11.0.5",
|
|
58
62
|
"unist-util-visit": "^5.1.0",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
63
|
+
"minisearch": "^7.2.0",
|
|
64
|
+
"vite": "^8.0.0",
|
|
65
|
+
"yaml": "^2.8.2"
|
|
61
66
|
}
|
|
62
67
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { resolveContentDir } from '../utils/config'
|
|
3
|
+
|
|
4
|
+
describe('resolveContentDir', () => {
|
|
5
|
+
it('returns flag value when provided', () => {
|
|
6
|
+
const result = resolveContentDir('/custom/path')
|
|
7
|
+
expect(result).toBe('/custom/path')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('returns env var when set', () => {
|
|
11
|
+
const original = process.env.CHRONICLE_CONTENT_DIR
|
|
12
|
+
process.env.CHRONICLE_CONTENT_DIR = '/env/content'
|
|
13
|
+
const result = resolveContentDir()
|
|
14
|
+
expect(result).toContain('env/content')
|
|
15
|
+
process.env.CHRONICLE_CONTENT_DIR = original
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('defaults to content directory', () => {
|
|
19
|
+
const original = process.env.CHRONICLE_CONTENT_DIR
|
|
20
|
+
delete process.env.CHRONICLE_CONTENT_DIR
|
|
21
|
+
const result = resolveContentDir()
|
|
22
|
+
expect(result).toContain('content')
|
|
23
|
+
process.env.CHRONICLE_CONTENT_DIR = original
|
|
24
|
+
})
|
|
25
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { detectPackageManager } from '../utils/scaffold'
|
|
3
|
+
|
|
4
|
+
describe('detectPackageManager', () => {
|
|
5
|
+
it('returns a string', () => {
|
|
6
|
+
const result = detectPackageManager()
|
|
7
|
+
expect(typeof result).toBe('string')
|
|
8
|
+
expect(['npm', 'bun', 'pnpm', 'yarn']).toContain(result)
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -1,33 +1,80 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
2
|
import path from 'path'
|
|
4
|
-
import { fileURLToPath } from 'url'
|
|
5
|
-
import { createRequire } from 'module'
|
|
6
3
|
import chalk from 'chalk'
|
|
7
|
-
import { resolveContentDir
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
4
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
5
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
12
6
|
|
|
13
7
|
export const buildCommand = new Command('build')
|
|
14
8
|
.description('Build for production')
|
|
15
9
|
.option('-c, --content <path>', 'Content directory')
|
|
16
|
-
.
|
|
10
|
+
.option('-o, --outDir <path>', 'Output directory', 'dist')
|
|
11
|
+
.option('--adapter <adapter>', 'Deploy adapter (vercel)')
|
|
12
|
+
.action(async (options) => {
|
|
17
13
|
const contentDir = resolveContentDir(options.content)
|
|
18
|
-
|
|
14
|
+
const outDir = path.resolve(options.outDir)
|
|
15
|
+
|
|
16
|
+
const VALID_ADAPTERS = ['vercel']
|
|
17
|
+
if (options.adapter && !VALID_ADAPTERS.includes(options.adapter)) {
|
|
18
|
+
console.error(chalk.red(`Unknown adapter: ${options.adapter}. Valid adapters: ${VALID_ADAPTERS.join(', ')}`))
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
23
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
19
24
|
|
|
20
25
|
console.log(chalk.cyan('Building for production...'))
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
|
|
27
|
+
const { build } = await import('vite')
|
|
28
|
+
const { createViteConfig } = await import('@/server/vite-config')
|
|
29
|
+
|
|
30
|
+
const baseConfig = await createViteConfig({ root: PACKAGE_ROOT, contentDir })
|
|
31
|
+
|
|
32
|
+
// Build client bundle
|
|
33
|
+
console.log(chalk.gray('Building client...'))
|
|
34
|
+
await build({
|
|
35
|
+
...baseConfig,
|
|
36
|
+
build: {
|
|
37
|
+
outDir: path.join(outDir, 'client'),
|
|
38
|
+
ssrManifest: true,
|
|
39
|
+
rolldownOptions: {
|
|
40
|
+
input: path.resolve(PACKAGE_ROOT, 'src/server/index.html'),
|
|
41
|
+
},
|
|
29
42
|
},
|
|
30
43
|
})
|
|
31
44
|
|
|
32
|
-
|
|
45
|
+
// Build server bundle
|
|
46
|
+
const serverEntry = options.adapter === 'vercel'
|
|
47
|
+
? path.resolve(PACKAGE_ROOT, 'src/server/entry-vercel.ts')
|
|
48
|
+
: path.resolve(PACKAGE_ROOT, 'src/server/entry-prod.ts')
|
|
49
|
+
|
|
50
|
+
console.log(chalk.gray('Building server...'))
|
|
51
|
+
await build({
|
|
52
|
+
...baseConfig,
|
|
53
|
+
ssr: {
|
|
54
|
+
noExternal: true,
|
|
55
|
+
},
|
|
56
|
+
build: {
|
|
57
|
+
outDir: path.join(outDir, 'server'),
|
|
58
|
+
ssr: serverEntry,
|
|
59
|
+
target: 'node22',
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// Generate search index
|
|
64
|
+
console.log(chalk.gray('Building search index...'))
|
|
65
|
+
const { generateSearchIndex } = await import('@/server/build-search-index')
|
|
66
|
+
const docCount = await generateSearchIndex(contentDir, path.join(outDir, 'server'))
|
|
67
|
+
console.log(chalk.gray(` Indexed ${docCount} documents`))
|
|
68
|
+
|
|
69
|
+
console.log(chalk.green('Build complete →'), outDir)
|
|
70
|
+
|
|
71
|
+
// Run Vercel adapter post-build
|
|
72
|
+
if (options.adapter === 'vercel') {
|
|
73
|
+
const { buildVercelOutput } = await import('@/server/adapters/vercel')
|
|
74
|
+
await buildVercelOutput({
|
|
75
|
+
distDir: outDir,
|
|
76
|
+
contentDir,
|
|
77
|
+
projectRoot: process.cwd(),
|
|
78
|
+
})
|
|
79
|
+
}
|
|
33
80
|
})
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -1,34 +1,21 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import { fileURLToPath } from 'url'
|
|
5
|
-
import { createRequire } from 'module'
|
|
6
2
|
import chalk from 'chalk'
|
|
7
|
-
import { resolveContentDir
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
3
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
4
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
12
5
|
|
|
13
6
|
export const devCommand = new Command('dev')
|
|
14
7
|
.description('Start development server')
|
|
15
8
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
16
9
|
.option('-c, --content <path>', 'Content directory')
|
|
17
|
-
.action((options) => {
|
|
10
|
+
.action(async (options) => {
|
|
18
11
|
const contentDir = resolveContentDir(options.content)
|
|
19
|
-
|
|
12
|
+
const port = parseInt(options.port, 10)
|
|
20
13
|
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
15
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
stdio: 'inherit',
|
|
26
|
-
cwd: PACKAGE_ROOT,
|
|
27
|
-
env: {
|
|
28
|
-
...process.env,
|
|
29
|
-
CHRONICLE_CONTENT_DIR: contentDir,
|
|
30
|
-
},
|
|
31
|
-
})
|
|
17
|
+
console.log(chalk.cyan('Starting dev server...'))
|
|
32
18
|
|
|
33
|
-
|
|
19
|
+
const { startDevServer } = await import('@/server/dev')
|
|
20
|
+
await startDevServer({ port, root: PACKAGE_ROOT, contentDir })
|
|
34
21
|
})
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
+
import { execSync } from 'child_process'
|
|
2
3
|
import fs from 'fs'
|
|
3
4
|
import path from 'path'
|
|
4
5
|
import chalk from 'chalk'
|
|
5
6
|
import { stringify } from 'yaml'
|
|
6
7
|
import type { ChronicleConfig } from '@/types'
|
|
8
|
+
import { detectPackageManager, getChronicleVersion } from '@/cli/utils/scaffold'
|
|
7
9
|
|
|
8
10
|
function createConfig(): ChronicleConfig {
|
|
9
11
|
return {
|
|
@@ -14,6 +16,29 @@ function createConfig(): ChronicleConfig {
|
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
function createPackageJson(name: string): Record<string, unknown> {
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
private: true,
|
|
23
|
+
type: 'module',
|
|
24
|
+
scripts: {
|
|
25
|
+
dev: 'chronicle dev',
|
|
26
|
+
build: 'chronicle build',
|
|
27
|
+
start: 'chronicle start',
|
|
28
|
+
},
|
|
29
|
+
dependencies: {
|
|
30
|
+
'@raystack/chronicle': `^${getChronicleVersion()}`,
|
|
31
|
+
},
|
|
32
|
+
devDependencies: {
|
|
33
|
+
'@raystack/tools-config': '0.56.0',
|
|
34
|
+
'openapi-types': '^12.1.3',
|
|
35
|
+
typescript: '5.9.3',
|
|
36
|
+
'@types/react': '^19.2.10',
|
|
37
|
+
'@types/node': '^25.1.0',
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
17
42
|
const sampleMdx = `---
|
|
18
43
|
title: Welcome
|
|
19
44
|
description: Getting started with your documentation
|
|
@@ -27,32 +52,103 @@ This is your documentation home page.
|
|
|
27
52
|
|
|
28
53
|
export const initCommand = new Command('init')
|
|
29
54
|
.description('Initialize a new Chronicle project')
|
|
30
|
-
.option('-
|
|
55
|
+
.option('-c, --content <path>', 'Content directory name', 'content')
|
|
31
56
|
.action((options) => {
|
|
32
|
-
const
|
|
57
|
+
const projectDir = process.cwd()
|
|
58
|
+
const dirName = path.basename(projectDir) || 'docs'
|
|
59
|
+
const contentDir = path.join(projectDir, options.content)
|
|
33
60
|
|
|
34
61
|
// Create content directory
|
|
35
62
|
if (!fs.existsSync(contentDir)) {
|
|
36
63
|
fs.mkdirSync(contentDir, { recursive: true })
|
|
37
|
-
console.log(chalk.green('
|
|
64
|
+
console.log(chalk.green('\u2713'), 'Created', contentDir)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create or update package.json
|
|
68
|
+
const packageJsonPath = path.join(projectDir, 'package.json')
|
|
69
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
70
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(createPackageJson(dirName), null, 2) + '\n')
|
|
71
|
+
console.log(chalk.green('\u2713'), 'Created', packageJsonPath)
|
|
72
|
+
} else {
|
|
73
|
+
const existing = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
|
|
74
|
+
const template = createPackageJson(dirName)
|
|
75
|
+
let updated = false
|
|
76
|
+
|
|
77
|
+
if (existing.type !== 'module') {
|
|
78
|
+
existing.type = 'module'
|
|
79
|
+
updated = true
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!existing.scripts) existing.scripts = {}
|
|
83
|
+
for (const [key, value] of Object.entries(template.scripts as Record<string, string>)) {
|
|
84
|
+
if (!existing.scripts[key]) {
|
|
85
|
+
existing.scripts[key] = value
|
|
86
|
+
updated = true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!existing.dependencies) existing.dependencies = {}
|
|
91
|
+
for (const [key, value] of Object.entries(template.dependencies as Record<string, string>)) {
|
|
92
|
+
if (!existing.dependencies[key]) {
|
|
93
|
+
existing.dependencies[key] = value
|
|
94
|
+
updated = true
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!existing.devDependencies) existing.devDependencies = {}
|
|
99
|
+
for (const [key, value] of Object.entries(template.devDependencies as Record<string, string>)) {
|
|
100
|
+
if (!existing.devDependencies[key]) {
|
|
101
|
+
existing.devDependencies[key] = value
|
|
102
|
+
updated = true
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (updated) {
|
|
107
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(existing, null, 2) + '\n')
|
|
108
|
+
console.log(chalk.green('\u2713'), 'Updated', packageJsonPath)
|
|
109
|
+
} else {
|
|
110
|
+
console.log(chalk.yellow('\u26a0'), packageJsonPath, 'already has all required entries')
|
|
111
|
+
}
|
|
38
112
|
}
|
|
39
113
|
|
|
40
114
|
// Create chronicle.yaml
|
|
41
|
-
const configPath = path.join(
|
|
115
|
+
const configPath = path.join(projectDir, 'chronicle.yaml')
|
|
42
116
|
if (!fs.existsSync(configPath)) {
|
|
43
117
|
fs.writeFileSync(configPath, stringify(createConfig()))
|
|
44
|
-
console.log(chalk.green('
|
|
118
|
+
console.log(chalk.green('\u2713'), 'Created', configPath)
|
|
45
119
|
} else {
|
|
46
|
-
console.log(chalk.yellow('
|
|
120
|
+
console.log(chalk.yellow('\u26a0'), configPath, 'already exists')
|
|
47
121
|
}
|
|
48
122
|
|
|
49
123
|
// Create sample index.mdx
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
124
|
+
const contentFiles = fs.readdirSync(contentDir)
|
|
125
|
+
if (contentFiles.length === 0) {
|
|
126
|
+
const indexPath = path.join(contentDir, 'index.mdx')
|
|
52
127
|
fs.writeFileSync(indexPath, sampleMdx)
|
|
53
|
-
console.log(chalk.green('
|
|
128
|
+
console.log(chalk.green('\u2713'), 'Created', indexPath)
|
|
54
129
|
}
|
|
55
130
|
|
|
56
|
-
|
|
57
|
-
|
|
131
|
+
// Update .gitignore
|
|
132
|
+
const gitignorePath = path.join(projectDir, '.gitignore')
|
|
133
|
+
const gitignoreEntries = ['node_modules', 'dist']
|
|
134
|
+
if (fs.existsSync(gitignorePath)) {
|
|
135
|
+
const existing = fs.readFileSync(gitignorePath, 'utf-8')
|
|
136
|
+
const missing = gitignoreEntries.filter(e => !existing.includes(e))
|
|
137
|
+
if (missing.length > 0) {
|
|
138
|
+
fs.appendFileSync(gitignorePath, `\n${missing.join('\n')}\n`)
|
|
139
|
+
console.log(chalk.green('\u2713'), 'Added', missing.join(', '), 'to .gitignore')
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
fs.writeFileSync(gitignorePath, `${gitignoreEntries.join('\n')}\n`)
|
|
143
|
+
console.log(chalk.green('\u2713'), 'Created .gitignore')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Install dependencies
|
|
147
|
+
const pm = detectPackageManager()
|
|
148
|
+
console.log(chalk.cyan(`\nInstalling dependencies with ${pm}...`))
|
|
149
|
+
execSync(`${pm} install`, { cwd: projectDir, stdio: 'inherit' })
|
|
150
|
+
|
|
151
|
+
const runCmd = pm === 'npm' ? 'npx' : pm === 'bun' ? 'bunx' : `${pm} dlx`
|
|
152
|
+
console.log(chalk.green('\n\u2713 Chronicle initialized!'))
|
|
153
|
+
console.log('\nRun', chalk.cyan(`${runCmd} chronicle dev`), 'to start development server')
|
|
58
154
|
})
|
|
@@ -1,54 +1,55 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
2
|
import path from 'path'
|
|
4
|
-
import { fileURLToPath } from 'url'
|
|
5
|
-
import { createRequire } from 'module'
|
|
6
3
|
import chalk from 'chalk'
|
|
7
|
-
import { resolveContentDir
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
4
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
5
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
12
6
|
|
|
13
7
|
export const serveCommand = new Command('serve')
|
|
14
8
|
.description('Build and start production server')
|
|
15
9
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
16
10
|
.option('-c, --content <path>', 'Content directory')
|
|
17
|
-
.
|
|
11
|
+
.option('-o, --outDir <path>', 'Output directory', 'dist')
|
|
12
|
+
.action(async (options) => {
|
|
18
13
|
const contentDir = resolveContentDir(options.content)
|
|
19
|
-
|
|
14
|
+
const port = parseInt(options.port, 10)
|
|
15
|
+
const outDir = path.resolve(options.outDir)
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
CHRONICLE_CONTENT_DIR: contentDir,
|
|
24
|
-
}
|
|
17
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
18
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
25
19
|
|
|
20
|
+
// Build
|
|
26
21
|
console.log(chalk.cyan('Building for production...'))
|
|
27
|
-
console.log(chalk.gray(`Content: ${contentDir}`))
|
|
28
22
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
cwd: PACKAGE_ROOT,
|
|
32
|
-
env,
|
|
33
|
-
})
|
|
23
|
+
const { build } = await import('vite')
|
|
24
|
+
const { createViteConfig } = await import('@/server/vite-config')
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
process.once('SIGTERM', () => buildChild.kill('SIGTERM'))
|
|
26
|
+
const baseConfig = await createViteConfig({ root: PACKAGE_ROOT, contentDir })
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
await build({
|
|
29
|
+
...baseConfig,
|
|
30
|
+
build: {
|
|
31
|
+
outDir: path.join(outDir, 'client'),
|
|
32
|
+
ssrManifest: true,
|
|
33
|
+
rolldownOptions: {
|
|
34
|
+
input: path.resolve(PACKAGE_ROOT, 'src/server/index.html'),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
})
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
await build({
|
|
40
|
+
...baseConfig,
|
|
41
|
+
ssr: {
|
|
42
|
+
noExternal: true,
|
|
43
|
+
},
|
|
44
|
+
build: {
|
|
45
|
+
outDir: path.join(outDir, 'server'),
|
|
46
|
+
ssr: path.resolve(PACKAGE_ROOT, 'src/server/entry-prod.ts'),
|
|
47
|
+
},
|
|
48
|
+
})
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
cwd: PACKAGE_ROOT,
|
|
49
|
-
env,
|
|
50
|
-
})
|
|
50
|
+
// Start
|
|
51
|
+
console.log(chalk.cyan('Starting production server...'))
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
})
|
|
53
|
+
const { startProdServer } = await import('@/server/prod')
|
|
54
|
+
await startProdServer({ port, root: PACKAGE_ROOT, distDir: outDir })
|
|
54
55
|
})
|
|
@@ -1,34 +1,24 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
2
|
import path from 'path'
|
|
4
|
-
import { fileURLToPath } from 'url'
|
|
5
|
-
import { createRequire } from 'module'
|
|
6
3
|
import chalk from 'chalk'
|
|
7
|
-
import { resolveContentDir
|
|
8
|
-
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
-
const nextCli = require.resolve('next/dist/bin/next')
|
|
4
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
5
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
12
6
|
|
|
13
7
|
export const startCommand = new Command('start')
|
|
14
8
|
.description('Start production server')
|
|
15
9
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
16
10
|
.option('-c, --content <path>', 'Content directory')
|
|
17
|
-
.
|
|
11
|
+
.option('-d, --dist <path>', 'Dist directory', 'dist')
|
|
12
|
+
.action(async (options) => {
|
|
18
13
|
const contentDir = resolveContentDir(options.content)
|
|
19
|
-
|
|
14
|
+
const port = parseInt(options.port, 10)
|
|
15
|
+
const distDir = path.resolve(options.dist)
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
18
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
stdio: 'inherit',
|
|
26
|
-
cwd: PACKAGE_ROOT,
|
|
27
|
-
env: {
|
|
28
|
-
...process.env,
|
|
29
|
-
CHRONICLE_CONTENT_DIR: contentDir,
|
|
30
|
-
},
|
|
31
|
-
})
|
|
20
|
+
console.log(chalk.cyan('Starting production server...'))
|
|
32
21
|
|
|
33
|
-
|
|
22
|
+
const { startProdServer } = await import('@/server/prod')
|
|
23
|
+
await startProdServer({ port, root: PACKAGE_ROOT, distDir })
|
|
34
24
|
})
|
package/src/cli/utils/config.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface CLIConfig {
|
|
|
13
13
|
export function resolveContentDir(contentFlag?: string): string {
|
|
14
14
|
if (contentFlag) return path.resolve(contentFlag)
|
|
15
15
|
if (process.env.CHRONICLE_CONTENT_DIR) return path.resolve(process.env.CHRONICLE_CONTENT_DIR)
|
|
16
|
-
return
|
|
16
|
+
return path.resolve('content')
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function resolveConfigPath(contentDir: string): string | null {
|
|
@@ -28,7 +28,7 @@ export function loadCLIConfig(contentDir: string): CLIConfig {
|
|
|
28
28
|
const configPath = resolveConfigPath(contentDir)
|
|
29
29
|
|
|
30
30
|
if (!configPath) {
|
|
31
|
-
console.log(chalk.red(
|
|
31
|
+
console.log(chalk.red(`Error: chronicle.yaml not found in '${process.cwd()}' or '${contentDir}'`))
|
|
32
32
|
console.log(chalk.gray(`Run 'chronicle init' to create one`))
|
|
33
33
|
process.exit(1)
|
|
34
34
|
}
|
package/src/cli/utils/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './config'
|
|
2
|
-
export * from './
|
|
2
|
+
export * from './resolve'
|
|
@@ -0,0 +1,6 @@
|
|
|
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(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { PACKAGE_ROOT } from './resolve'
|
|
4
|
+
|
|
5
|
+
export function detectPackageManager(): string {
|
|
6
|
+
if (process.env.npm_config_user_agent) {
|
|
7
|
+
return process.env.npm_config_user_agent.split('/')[0]
|
|
8
|
+
}
|
|
9
|
+
const cwd = process.cwd()
|
|
10
|
+
if (fs.existsSync(path.join(cwd, 'bun.lock')) || fs.existsSync(path.join(cwd, 'bun.lockb'))) return 'bun'
|
|
11
|
+
if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm'
|
|
12
|
+
if (fs.existsSync(path.join(cwd, 'yarn.lock'))) return 'yarn'
|
|
13
|
+
return 'npm'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getChronicleVersion(): string {
|
|
17
|
+
const pkgPath = path.join(PACKAGE_ROOT, 'package.json')
|
|
18
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
|
|
19
|
+
return pkg.version
|
|
20
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import type
|
|
3
|
+
import { type ComponentProps, isValidElement, Children } from 'react'
|
|
4
|
+
import { Mermaid } from './mermaid'
|
|
4
5
|
import styles from './code.module.css'
|
|
5
6
|
|
|
6
7
|
type PreProps = ComponentProps<'pre'> & {
|
|
@@ -16,6 +17,14 @@ export function MdxCode({ children, className, ...props }: ComponentProps<'code'
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export function MdxPre({ children, title, className, ...props }: PreProps) {
|
|
20
|
+
// Detect mermaid code blocks
|
|
21
|
+
if (isValidElement(children)) {
|
|
22
|
+
const childProps = children.props as { className?: string; children?: string }
|
|
23
|
+
if (childProps.className?.includes('language-mermaid') && typeof childProps.children === 'string') {
|
|
24
|
+
return <Mermaid chart={childProps.children} />
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
return (
|
|
20
29
|
<div className={styles.codeBlock}>
|
|
21
30
|
{title && <div className={styles.codeHeader}>{title}</div>}
|
|
@@ -4,32 +4,9 @@
|
|
|
4
4
|
margin: var(--rs-space-5) 0;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.
|
|
8
|
-
padding: var(--rs-space-4) var(--rs-space-5);
|
|
9
|
-
cursor: pointer;
|
|
7
|
+
.trigger {
|
|
10
8
|
font-weight: 500;
|
|
11
9
|
font-size: var(--rs-font-size-small);
|
|
12
|
-
color: var(--rs-color-text-base-primary);
|
|
13
|
-
background: var(--rs-color-background-base-secondary);
|
|
14
|
-
list-style: none;
|
|
15
|
-
display: flex;
|
|
16
|
-
align-items: center;
|
|
17
|
-
gap: var(--rs-space-3);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.summary::-webkit-details-marker {
|
|
21
|
-
display: none;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.summary::before {
|
|
25
|
-
content: '▶';
|
|
26
|
-
font-size: 10px;
|
|
27
|
-
transition: transform 0.2s ease;
|
|
28
|
-
color: var(--rs-color-text-base-secondary);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.details[open] > .summary::before {
|
|
32
|
-
transform: rotate(90deg);
|
|
33
10
|
}
|
|
34
11
|
|
|
35
12
|
.content {
|