@raystack/chronicle 0.1.0-canary.5a2be79 → 0.1.0-canary.5a730d4
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 +391 -9834
- package/package.json +16 -11
- package/src/cli/__tests__/config.test.ts +25 -0
- package/src/cli/__tests__/scaffold.test.ts +10 -0
- package/src/cli/commands/build.ts +38 -18
- package/src/cli/commands/dev.ts +10 -22
- package/src/cli/commands/init.ts +28 -29
- package/src/cli/commands/serve.ts +38 -36
- package/src/cli/commands/start.ts +12 -21
- package/src/cli/utils/config.ts +1 -1
- package/src/cli/utils/index.ts +1 -2
- package/src/cli/utils/resolve.ts +2 -0
- package/src/cli/utils/scaffold.ts +4 -115
- 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 +58 -86
- package/src/lib/config.ts +1 -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/dev.ts +156 -0
- package/src/server/entry-client.tsx +74 -0
- package/src/server/entry-prod.ts +127 -0
- package/src/server/entry-server.tsx +35 -0
- package/src/server/handlers/apis-proxy.ts +52 -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 +140 -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/router.ts +42 -0
- package/src/server/vite-config.ts +65 -0
- package/src/themes/default/Layout.tsx +9 -10
- package/src/themes/default/Page.module.css +56 -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 +2 -3
- 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.5a730d4",
|
|
4
4
|
"description": "Config-driven documentation framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
"dist",
|
|
10
10
|
"src",
|
|
11
11
|
"templates",
|
|
12
|
-
"next.config.mjs",
|
|
13
|
-
"source.config.ts",
|
|
14
12
|
"tsconfig.json"
|
|
15
13
|
],
|
|
16
14
|
"bin": {
|
|
@@ -37,27 +35,34 @@
|
|
|
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
51
|
"react-device-detect": "^2.2.3",
|
|
53
52
|
"react-dom": "^19.0.0",
|
|
54
|
-
"
|
|
53
|
+
"react-router-dom": "^7.13.1",
|
|
55
54
|
"remark-directive": "^4.0.0",
|
|
55
|
+
"remark-gfm": "^4.0.1",
|
|
56
|
+
"@shikijs/rehype": "^4.0.2",
|
|
57
|
+
"remark-frontmatter": "^5.0.0",
|
|
58
|
+
"remark-mdx-frontmatter": "^5.2.0",
|
|
59
|
+
"satori": "^0.25.0",
|
|
60
|
+
"sirv": "^3.0.1",
|
|
56
61
|
"slugify": "^1.6.6",
|
|
57
62
|
"unified": "^11.0.5",
|
|
58
63
|
"unist-util-visit": "^5.1.0",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
64
|
+
"minisearch": "^7.2.0",
|
|
65
|
+
"vite": "^8.0.0",
|
|
66
|
+
"yaml": "^2.8.2"
|
|
62
67
|
}
|
|
63
68
|
}
|
|
@@ -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,32 +1,52 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
2
|
import path from 'path'
|
|
4
|
-
import fs from 'fs'
|
|
5
3
|
import chalk from 'chalk'
|
|
6
|
-
import {
|
|
4
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
5
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
7
6
|
|
|
8
7
|
export const buildCommand = new Command('build')
|
|
9
8
|
.description('Build for production')
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
9
|
+
.option('-c, --content <path>', 'Content directory')
|
|
10
|
+
.option('-o, --outDir <path>', 'Output directory', 'dist')
|
|
11
|
+
.action(async (options) => {
|
|
12
|
+
const contentDir = resolveContentDir(options.content)
|
|
13
|
+
const outDir = path.resolve(options.outDir)
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
16
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
18
17
|
|
|
19
18
|
console.log(chalk.cyan('Building for production...'))
|
|
20
19
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
const { build } = await import('vite')
|
|
21
|
+
const { createViteConfig } = await import('@/server/vite-config')
|
|
22
|
+
|
|
23
|
+
const baseConfig = await createViteConfig({ root: PACKAGE_ROOT, contentDir })
|
|
24
|
+
|
|
25
|
+
// Build client bundle
|
|
26
|
+
console.log(chalk.gray('Building client...'))
|
|
27
|
+
await build({
|
|
28
|
+
...baseConfig,
|
|
29
|
+
build: {
|
|
30
|
+
outDir: path.join(outDir, 'client'),
|
|
31
|
+
ssrManifest: true,
|
|
32
|
+
rolldownOptions: {
|
|
33
|
+
input: path.resolve(PACKAGE_ROOT, 'src/server/index.html'),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Build server bundle (noExternal: true to bundle all deps for portability)
|
|
39
|
+
console.log(chalk.gray('Building server...'))
|
|
40
|
+
await build({
|
|
41
|
+
...baseConfig,
|
|
42
|
+
ssr: {
|
|
43
|
+
noExternal: true,
|
|
44
|
+
},
|
|
45
|
+
build: {
|
|
46
|
+
outDir: path.join(outDir, 'server'),
|
|
47
|
+
ssr: path.resolve(PACKAGE_ROOT, 'src/server/entry-prod.ts'),
|
|
28
48
|
},
|
|
29
49
|
})
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
console.log(chalk.green('Build complete →'), outDir)
|
|
32
52
|
})
|
package/src/cli/commands/dev.ts
CHANGED
|
@@ -1,33 +1,21 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import fs from 'fs'
|
|
5
2
|
import chalk from 'chalk'
|
|
6
|
-
import {
|
|
3
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
4
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
7
5
|
|
|
8
6
|
export const devCommand = new Command('dev')
|
|
9
7
|
.description('Start development server')
|
|
10
8
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
process.exit(1)
|
|
16
|
-
}
|
|
9
|
+
.option('-c, --content <path>', 'Content directory')
|
|
10
|
+
.action(async (options) => {
|
|
11
|
+
const contentDir = resolveContentDir(options.content)
|
|
12
|
+
const port = parseInt(options.port, 10)
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
15
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
19
16
|
|
|
20
17
|
console.log(chalk.cyan('Starting dev server...'))
|
|
21
18
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
cwd: scaffoldPath,
|
|
25
|
-
env: {
|
|
26
|
-
...process.env,
|
|
27
|
-
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
28
|
-
CHRONICLE_CONTENT_DIR: './content',
|
|
29
|
-
},
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
attachLifecycleHandlers(child)
|
|
19
|
+
const { startDevServer } = await import('@/server/dev')
|
|
20
|
+
await startDevServer({ port, root: PACKAGE_ROOT, contentDir })
|
|
33
21
|
})
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -5,8 +5,7 @@ import path from 'path'
|
|
|
5
5
|
import chalk from 'chalk'
|
|
6
6
|
import { stringify } from 'yaml'
|
|
7
7
|
import type { ChronicleConfig } from '@/types'
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import { detectPackageManager, getChronicleVersion } from '@/cli/utils/scaffold'
|
|
10
9
|
|
|
11
10
|
function createConfig(): ChronicleConfig {
|
|
12
11
|
return {
|
|
@@ -21,13 +20,14 @@ function createPackageJson(name: string): Record<string, unknown> {
|
|
|
21
20
|
return {
|
|
22
21
|
name,
|
|
23
22
|
private: true,
|
|
23
|
+
type: 'module',
|
|
24
24
|
scripts: {
|
|
25
25
|
dev: 'chronicle dev',
|
|
26
26
|
build: 'chronicle build',
|
|
27
27
|
start: 'chronicle start',
|
|
28
28
|
},
|
|
29
29
|
dependencies: {
|
|
30
|
-
'@raystack/chronicle':
|
|
30
|
+
'@raystack/chronicle': `^${getChronicleVersion()}`,
|
|
31
31
|
},
|
|
32
32
|
devDependencies: {
|
|
33
33
|
'@raystack/tools-config': '0.56.0',
|
|
@@ -58,23 +58,27 @@ export const initCommand = new Command('init')
|
|
|
58
58
|
const dirName = path.basename(projectDir) || 'docs'
|
|
59
59
|
const contentDir = path.join(projectDir, options.content)
|
|
60
60
|
|
|
61
|
-
// Create content directory
|
|
61
|
+
// Create content directory
|
|
62
62
|
if (!fs.existsSync(contentDir)) {
|
|
63
63
|
fs.mkdirSync(contentDir, { recursive: true })
|
|
64
|
-
console.log(chalk.green('
|
|
64
|
+
console.log(chalk.green('\u2713'), 'Created', contentDir)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// Create or update package.json
|
|
67
|
+
// Create or update package.json
|
|
68
68
|
const packageJsonPath = path.join(projectDir, 'package.json')
|
|
69
69
|
if (!fs.existsSync(packageJsonPath)) {
|
|
70
70
|
fs.writeFileSync(packageJsonPath, JSON.stringify(createPackageJson(dirName), null, 2) + '\n')
|
|
71
|
-
console.log(chalk.green('
|
|
71
|
+
console.log(chalk.green('\u2713'), 'Created', packageJsonPath)
|
|
72
72
|
} else {
|
|
73
73
|
const existing = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
|
|
74
74
|
const template = createPackageJson(dirName)
|
|
75
75
|
let updated = false
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
if (existing.type !== 'module') {
|
|
78
|
+
existing.type = 'module'
|
|
79
|
+
updated = true
|
|
80
|
+
}
|
|
81
|
+
|
|
78
82
|
if (!existing.scripts) existing.scripts = {}
|
|
79
83
|
for (const [key, value] of Object.entries(template.scripts as Record<string, string>)) {
|
|
80
84
|
if (!existing.scripts[key]) {
|
|
@@ -83,7 +87,6 @@ export const initCommand = new Command('init')
|
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
// Merge missing dependencies
|
|
87
90
|
if (!existing.dependencies) existing.dependencies = {}
|
|
88
91
|
for (const [key, value] of Object.entries(template.dependencies as Record<string, string>)) {
|
|
89
92
|
if (!existing.dependencies[key]) {
|
|
@@ -92,7 +95,6 @@ export const initCommand = new Command('init')
|
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
// Merge missing devDependencies
|
|
96
98
|
if (!existing.devDependencies) existing.devDependencies = {}
|
|
97
99
|
for (const [key, value] of Object.entries(template.devDependencies as Record<string, string>)) {
|
|
98
100
|
if (!existing.devDependencies[key]) {
|
|
@@ -103,41 +105,42 @@ export const initCommand = new Command('init')
|
|
|
103
105
|
|
|
104
106
|
if (updated) {
|
|
105
107
|
fs.writeFileSync(packageJsonPath, JSON.stringify(existing, null, 2) + '\n')
|
|
106
|
-
console.log(chalk.green('
|
|
108
|
+
console.log(chalk.green('\u2713'), 'Updated', packageJsonPath)
|
|
107
109
|
} else {
|
|
108
|
-
console.log(chalk.yellow('
|
|
110
|
+
console.log(chalk.yellow('\u26a0'), packageJsonPath, 'already has all required entries')
|
|
109
111
|
}
|
|
110
112
|
}
|
|
111
113
|
|
|
112
|
-
// Create chronicle.yaml
|
|
114
|
+
// Create chronicle.yaml
|
|
113
115
|
const configPath = path.join(projectDir, 'chronicle.yaml')
|
|
114
116
|
if (!fs.existsSync(configPath)) {
|
|
115
117
|
fs.writeFileSync(configPath, stringify(createConfig()))
|
|
116
|
-
console.log(chalk.green('
|
|
118
|
+
console.log(chalk.green('\u2713'), 'Created', configPath)
|
|
117
119
|
} else {
|
|
118
|
-
console.log(chalk.yellow('
|
|
120
|
+
console.log(chalk.yellow('\u26a0'), configPath, 'already exists')
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
// Create sample index.mdx
|
|
123
|
+
// Create sample index.mdx
|
|
122
124
|
const contentFiles = fs.readdirSync(contentDir)
|
|
123
125
|
if (contentFiles.length === 0) {
|
|
124
126
|
const indexPath = path.join(contentDir, 'index.mdx')
|
|
125
127
|
fs.writeFileSync(indexPath, sampleMdx)
|
|
126
|
-
console.log(chalk.green('
|
|
128
|
+
console.log(chalk.green('\u2713'), 'Created', indexPath)
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
//
|
|
131
|
+
// Update .gitignore
|
|
130
132
|
const gitignorePath = path.join(projectDir, '.gitignore')
|
|
131
|
-
const
|
|
133
|
+
const gitignoreEntries = ['node_modules', 'dist']
|
|
132
134
|
if (fs.existsSync(gitignorePath)) {
|
|
133
135
|
const existing = fs.readFileSync(gitignorePath, 'utf-8')
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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')
|
|
137
140
|
}
|
|
138
141
|
} else {
|
|
139
|
-
fs.writeFileSync(gitignorePath, `${
|
|
140
|
-
console.log(chalk.green('
|
|
142
|
+
fs.writeFileSync(gitignorePath, `${gitignoreEntries.join('\n')}\n`)
|
|
143
|
+
console.log(chalk.green('\u2713'), 'Created .gitignore')
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
// Install dependencies
|
|
@@ -145,11 +148,7 @@ export const initCommand = new Command('init')
|
|
|
145
148
|
console.log(chalk.cyan(`\nInstalling dependencies with ${pm}...`))
|
|
146
149
|
execSync(`${pm} install`, { cwd: projectDir, stdio: 'inherit' })
|
|
147
150
|
|
|
148
|
-
// Scaffold .chronicle/ directory
|
|
149
|
-
loadCLIConfig(contentDir)
|
|
150
|
-
scaffoldDir(contentDir)
|
|
151
|
-
|
|
152
151
|
const runCmd = pm === 'npm' ? 'npx' : pm === 'bun' ? 'bunx' : `${pm} dlx`
|
|
153
|
-
console.log(chalk.green('\n
|
|
152
|
+
console.log(chalk.green('\n\u2713 Chronicle initialized!'))
|
|
154
153
|
console.log('\nRun', chalk.cyan(`${runCmd} chronicle dev`), 'to start development server')
|
|
155
154
|
})
|
|
@@ -1,53 +1,55 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
2
|
import path from 'path'
|
|
4
|
-
import fs from 'fs'
|
|
5
3
|
import chalk from 'chalk'
|
|
6
|
-
import {
|
|
4
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
5
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
7
6
|
|
|
8
7
|
export const serveCommand = new Command('serve')
|
|
9
8
|
.description('Build and start production server')
|
|
10
9
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
.option('-c, --content <path>', 'Content directory')
|
|
11
|
+
.option('-o, --outDir <path>', 'Output directory', 'dist')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
const contentDir = resolveContentDir(options.content)
|
|
14
|
+
const port = parseInt(options.port, 10)
|
|
15
|
+
const outDir = path.resolve(options.outDir)
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const env = {
|
|
21
|
-
...process.env,
|
|
22
|
-
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
23
|
-
CHRONICLE_CONTENT_DIR: './content',
|
|
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
22
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
cwd: scaffoldPath,
|
|
31
|
-
env,
|
|
32
|
-
})
|
|
23
|
+
const { build } = await import('vite')
|
|
24
|
+
const { createViteConfig } = await import('@/server/vite-config')
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
process.once('SIGTERM', () => buildChild.kill('SIGTERM'))
|
|
26
|
+
const baseConfig = await createViteConfig({ root: PACKAGE_ROOT, contentDir })
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
+
})
|
|
42
38
|
|
|
43
|
-
|
|
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
|
+
})
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cwd: scaffoldPath,
|
|
48
|
-
env,
|
|
49
|
-
})
|
|
50
|
+
// Start
|
|
51
|
+
console.log(chalk.cyan('Starting production server...'))
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
})
|
|
53
|
+
const { startProdServer } = await import('@/server/prod')
|
|
54
|
+
await startProdServer({ port, root: PACKAGE_ROOT, distDir: outDir })
|
|
53
55
|
})
|
|
@@ -1,33 +1,24 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
2
|
import path from 'path'
|
|
4
|
-
import fs from 'fs'
|
|
5
3
|
import chalk from 'chalk'
|
|
6
|
-
import {
|
|
4
|
+
import { resolveContentDir } from '@/cli/utils/config'
|
|
5
|
+
import { PACKAGE_ROOT } from '@/cli/utils/resolve'
|
|
7
6
|
|
|
8
7
|
export const startCommand = new Command('start')
|
|
9
8
|
.description('Start production server')
|
|
10
9
|
.option('-p, --port <port>', 'Port number', '3000')
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
.option('-c, --content <path>', 'Content directory')
|
|
11
|
+
.option('-d, --dist <path>', 'Dist directory', 'dist')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
const contentDir = resolveContentDir(options.content)
|
|
14
|
+
const port = parseInt(options.port, 10)
|
|
15
|
+
const distDir = path.resolve(options.dist)
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
process.env.CHRONICLE_PROJECT_ROOT = process.cwd()
|
|
18
|
+
process.env.CHRONICLE_CONTENT_DIR = contentDir
|
|
19
19
|
|
|
20
20
|
console.log(chalk.cyan('Starting production server...'))
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
cwd: scaffoldPath,
|
|
25
|
-
env: {
|
|
26
|
-
...process.env,
|
|
27
|
-
CHRONICLE_PROJECT_ROOT: process.cwd(),
|
|
28
|
-
CHRONICLE_CONTENT_DIR: './content',
|
|
29
|
-
},
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
attachLifecycleHandlers(child)
|
|
22
|
+
const { startProdServer } = await import('@/server/prod')
|
|
23
|
+
await startProdServer({ port, root: PACKAGE_ROOT, distDir })
|
|
33
24
|
})
|
package/src/cli/utils/config.ts
CHANGED
|
@@ -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
package/src/cli/utils/resolve.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import { fileURLToPath } from 'url'
|
|
3
3
|
|
|
4
|
+
// After bundling: dist/cli/index.js → ../.. = package root
|
|
5
|
+
// After install: node_modules/@raystack/chronicle/dist/cli/index.js → ../.. = package root
|
|
4
6
|
export const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
@@ -1,33 +1,7 @@
|
|
|
1
|
-
import { execSync } from 'child_process'
|
|
2
|
-
import { createRequire } from 'module'
|
|
3
1
|
import fs from 'fs'
|
|
4
2
|
import path from 'path'
|
|
5
|
-
import chalk from 'chalk'
|
|
6
3
|
import { PACKAGE_ROOT } from './resolve'
|
|
7
4
|
|
|
8
|
-
const COPY_FILES = ['src', 'source.config.ts', 'tsconfig.json']
|
|
9
|
-
|
|
10
|
-
function copyRecursive(src: string, dest: string) {
|
|
11
|
-
const stat = fs.statSync(src)
|
|
12
|
-
if (stat.isDirectory()) {
|
|
13
|
-
fs.mkdirSync(dest, { recursive: true })
|
|
14
|
-
for (const entry of fs.readdirSync(src)) {
|
|
15
|
-
copyRecursive(path.join(src, entry), path.join(dest, entry))
|
|
16
|
-
}
|
|
17
|
-
} else {
|
|
18
|
-
fs.copyFileSync(src, dest)
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function ensureRemoved(targetPath: string) {
|
|
23
|
-
try {
|
|
24
|
-
fs.lstatSync(targetPath)
|
|
25
|
-
fs.rmSync(targetPath, { recursive: true, force: true })
|
|
26
|
-
} catch {
|
|
27
|
-
// nothing exists, proceed
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
5
|
export function detectPackageManager(): string {
|
|
32
6
|
if (process.env.npm_config_user_agent) {
|
|
33
7
|
return process.env.npm_config_user_agent.split('/')[0]
|
|
@@ -39,93 +13,8 @@ export function detectPackageManager(): string {
|
|
|
39
13
|
return 'npm'
|
|
40
14
|
}
|
|
41
15
|
|
|
42
|
-
function
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/** @type {import('next').NextConfig} */
|
|
48
|
-
const nextConfig = {
|
|
49
|
-
reactStrictMode: true,
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export default withMDX(nextConfig)
|
|
53
|
-
`
|
|
54
|
-
fs.writeFileSync(path.join(scaffoldPath, 'next.config.mjs'), config)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function createPackageJson(): Record<string, unknown> {
|
|
58
|
-
return {
|
|
59
|
-
name: 'chronicle-docs',
|
|
60
|
-
private: true,
|
|
61
|
-
dependencies: {
|
|
62
|
-
'@raystack/chronicle': 'latest',
|
|
63
|
-
},
|
|
64
|
-
devDependencies: {
|
|
65
|
-
'@raystack/tools-config': '0.56.0',
|
|
66
|
-
'openapi-types': '^12.1.3',
|
|
67
|
-
typescript: '5.9.3',
|
|
68
|
-
'@types/react': '^19.2.10',
|
|
69
|
-
'@types/node': '^25.1.0',
|
|
70
|
-
},
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function ensureDeps() {
|
|
75
|
-
const cwd = process.cwd()
|
|
76
|
-
const cwdPkgJson = path.join(cwd, 'package.json')
|
|
77
|
-
const cwdNodeModules = path.join(cwd, 'node_modules')
|
|
78
|
-
|
|
79
|
-
if (fs.existsSync(cwdPkgJson) && fs.existsSync(cwdNodeModules)) {
|
|
80
|
-
// Case 1: existing project with deps installed
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Case 2: no package.json — create in cwd and install
|
|
85
|
-
if (!fs.existsSync(cwdPkgJson)) {
|
|
86
|
-
fs.writeFileSync(cwdPkgJson, JSON.stringify(createPackageJson(), null, 2) + '\n')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!fs.existsSync(cwdNodeModules)) {
|
|
90
|
-
const pm = detectPackageManager()
|
|
91
|
-
console.log(chalk.cyan(`Installing dependencies with ${pm}...`))
|
|
92
|
-
execSync(`${pm} install`, { cwd, stdio: 'inherit' })
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export function resolveNextCli(): string {
|
|
97
|
-
const cwdRequire = createRequire(path.join(process.cwd(), 'package.json'))
|
|
98
|
-
return cwdRequire.resolve('next/dist/bin/next')
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function scaffoldDir(contentDir: string): string {
|
|
102
|
-
const scaffoldPath = path.join(process.cwd(), '.chronicle')
|
|
103
|
-
|
|
104
|
-
// Create .chronicle/ if not exists
|
|
105
|
-
if (!fs.existsSync(scaffoldPath)) {
|
|
106
|
-
fs.mkdirSync(scaffoldPath, { recursive: true })
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Copy package files
|
|
110
|
-
for (const name of COPY_FILES) {
|
|
111
|
-
const src = path.join(PACKAGE_ROOT, name)
|
|
112
|
-
const dest = path.join(scaffoldPath, name)
|
|
113
|
-
ensureRemoved(dest)
|
|
114
|
-
copyRecursive(src, dest)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Generate next.config.mjs
|
|
118
|
-
generateNextConfig(scaffoldPath)
|
|
119
|
-
|
|
120
|
-
// Symlink content dir
|
|
121
|
-
const contentLink = path.join(scaffoldPath, 'content')
|
|
122
|
-
ensureRemoved(contentLink)
|
|
123
|
-
fs.symlinkSync(path.resolve(contentDir), contentLink)
|
|
124
|
-
|
|
125
|
-
// Ensure dependencies are available
|
|
126
|
-
ensureDeps()
|
|
127
|
-
|
|
128
|
-
console.log(chalk.gray(`Scaffold: ${scaffoldPath}`))
|
|
129
|
-
|
|
130
|
-
return scaffoldPath
|
|
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
|
|
131
20
|
}
|