Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
FROM node:24-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
FROM oven/bun:1.3 AS base

# --- deps ---
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
COPY package.json bun.lock ./
COPY packages/chronicle/package.json ./packages/chronicle/
RUN pnpm install --frozen-lockfile --filter @raystack/chronicle
RUN bun install --frozen-lockfile

# --- build CLI ---
FROM base AS builder
WORKDIR /app/packages/chronicle
COPY --from=deps /app /app
COPY packages/chronicle ./
RUN pnpm build:cli
RUN bun build-cli.ts

# --- runner ---
FROM base AS runner
Expand All @@ -27,15 +24,13 @@ RUN chmod +x bin/chronicle.js
RUN ln -s /app/packages/chronicle/bin/chronicle.js /usr/local/bin/chronicle

RUN mkdir -p /app/content && ln -s /app/content /app/packages/chronicle/content
RUN chown -R node:node /app

VOLUME /app/content
USER node

ENV CHRONICLE_CONTENT_DIR=./content
WORKDIR /app/packages/chronicle

EXPOSE 3000

ENTRYPOINT ["chronicle"]
CMD ["dev", "--port", "3000"]
CMD ["serve", "--port", "3000"]
937 changes: 937 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "chronicle",
"private": true,
"packageManager": "pnpm@10.6.2",
"workspaces": ["packages/*", "examples/*"],
"engines": {
"node": ">=22"
}
Expand Down
16 changes: 16 additions & 0 deletions packages/chronicle/build-cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import path from 'path'

const result = await Bun.build({
entrypoints: ['src/cli/index.ts'],
outdir: 'dist/cli',
target: 'node',
format: 'esm',
define: {
PACKAGE_ROOT: JSON.stringify(path.resolve(import.meta.dir)),
},
})

if (!result.success) {
for (const log of result.logs) console.error(log)
process.exit(1)
}
7 changes: 1 addition & 6 deletions packages/chronicle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
"chronicle": "./bin/chronicle.js"
},
"scripts": {
"build:cli": "tsup"
},
"engines": {
"node": ">=22"
"build:cli": "bun build-cli.ts"
},
"devDependencies": {
"@biomejs/biome": "^2.3.13",
Expand All @@ -22,8 +19,6 @@
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"openapi-types": "^12.1.3",
"tsup": "^8.5.1",
"tsx": "^4.21.0",
"typescript": "5.9.3"
},
"dependencies": {
Expand Down
8 changes: 4 additions & 4 deletions packages/chronicle/src/app/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { notFound } from 'next/navigation'
import type { MDXContent } from 'mdx/types'
import { loadConfig } from '../../lib/config'
import { source, buildPageTree } from '../../lib/source'
import { getTheme } from '../../themes/registry'
import { mdxComponents } from '../../components/mdx'
import { loadConfig } from '@/lib/config'
import { source, buildPageTree } from '@/lib/source'
import { getTheme } from '@/themes/registry'
import { mdxComponents } from '@/components/mdx'

interface PageProps {
params: Promise<{ slug?: string[] }>
Expand Down
4 changes: 2 additions & 2 deletions packages/chronicle/src/app/api/apis-proxy/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextRequest, NextResponse } from "next/server";
import { loadConfig } from "../../../lib/config";
import { loadApiSpecs } from "../../../lib/openapi";
import { loadConfig } from "@/lib/config";
import { loadApiSpecs } from "@/lib/openapi";

export async function POST(request: NextRequest) {
const { specName, method, path, headers, body } = await request.json();
Expand Down
3 changes: 3 additions & 0 deletions packages/chronicle/src/app/api/health/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function GET() {
return Response.json({ status: 'ok' })
}
8 changes: 4 additions & 4 deletions packages/chronicle/src/app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { source } from '../../../lib/source'
import { source } from '@/lib/source'
import { createSearchAPI, type AdvancedIndex } from 'fumadocs-core/search/server'
import type { StructuredData } from 'fumadocs-core/mdx-plugins'
import type { OpenAPIV3 } from 'openapi-types'
import { loadConfig } from '../../../lib/config'
import { loadApiSpecs, type ApiSpec } from '../../../lib/openapi'
import { getSpecSlug } from '../../../lib/api-routes'
import { loadConfig } from '@/lib/config'
import { loadApiSpecs, type ApiSpec } from '@/lib/openapi'
import { getSpecSlug } from '@/lib/api-routes'

interface PageData {
title?: string
Expand Down
10 changes: 5 additions & 5 deletions packages/chronicle/src/app/apis/[[...slug]]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { loadConfig } from '../../../lib/config'
import { loadApiSpecs } from '../../../lib/openapi'
import { buildApiPageTree } from '../../../lib/api-routes'
import { getTheme } from '../../../themes/registry'
import { Search } from '../../../components/ui/search'
import { loadConfig } from '@/lib/config'
import { loadApiSpecs } from '@/lib/openapi'
import { buildApiPageTree } from '@/lib/api-routes'
import { getTheme } from '@/themes/registry'
import { Search } from '@/components/ui/search'
import styles from './layout.module.css'

export default function ApiLayout({ children }: { children: React.ReactNode }) {
Expand Down
8 changes: 4 additions & 4 deletions packages/chronicle/src/app/apis/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { notFound } from 'next/navigation'
import type { OpenAPIV3 } from 'openapi-types'
import { Flex, Headline, Text } from '@raystack/apsara'
import { loadConfig } from '../../../lib/config'
import { loadApiSpecs } from '../../../lib/openapi'
import { buildApiRoutes, findApiOperation } from '../../../lib/api-routes'
import { EndpointPage } from '../../../components/api'
import { loadConfig } from '@/lib/config'
import { loadApiSpecs } from '@/lib/openapi'
import { buildApiRoutes, findApiOperation } from '@/lib/api-routes'
import { EndpointPage } from '@/components/api'

interface PageProps {
params: Promise<{ slug?: string[] }>
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '@raystack/apsara/normalize.css'
import '@raystack/apsara/style.css'
import type { Metadata } from 'next'
import { loadConfig } from '../lib/config'
import { loadConfig } from '@/lib/config'
import { Providers } from './providers'

const config = loadConfig()
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/cli/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from 'commander'
import { spawn } from 'child_process'
import path from 'path'
import chalk from 'chalk'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '../utils'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '@/cli/utils'

declare const PACKAGE_ROOT: string

Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/cli/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from 'commander'
import { spawn } from 'child_process'
import path from 'path'
import chalk from 'chalk'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '../utils'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '@/cli/utils'

declare const PACKAGE_ROOT: string

Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/cli/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fs from 'fs'
import path from 'path'
import chalk from 'chalk'
import { stringify } from 'yaml'
import type { ChronicleConfig } from '../../types'
import type { ChronicleConfig } from '@/types'

function createConfig(): ChronicleConfig {
return {
Expand Down
52 changes: 52 additions & 0 deletions packages/chronicle/src/cli/commands/serve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Command } from 'commander'
import { spawn } from 'child_process'
import path from 'path'
import chalk from 'chalk'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '@/cli/utils'

declare const PACKAGE_ROOT: string

const nextBin = path.join(PACKAGE_ROOT, 'node_modules', '.bin', process.platform === 'win32' ? 'next.cmd' : 'next')

export const serveCommand = new Command('serve')
.description('Build and start production server')
.option('-p, --port <port>', 'Port number', '3000')
.option('-c, --content <path>', 'Content directory')
.action((options) => {
const contentDir = resolveContentDir(options.content)
loadCLIConfig(contentDir)

const env = {
...process.env,
CHRONICLE_CONTENT_DIR: contentDir,
}

console.log(chalk.cyan('Building for production...'))
console.log(chalk.gray(`Content: ${contentDir}`))

const buildChild = spawn(nextBin, ['build'], {
stdio: 'inherit',
cwd: PACKAGE_ROOT,
env,
})

process.once('SIGINT', () => buildChild.kill('SIGINT'))
process.once('SIGTERM', () => buildChild.kill('SIGTERM'))

buildChild.on('close', (code) => {
if (code !== 0) {
console.log(chalk.red('Build failed'))
process.exit(code ?? 1)
}

console.log(chalk.cyan('Starting production server...'))

const startChild = spawn(nextBin, ['start', '-p', options.port], {
stdio: 'inherit',
cwd: PACKAGE_ROOT,
env,
})

attachLifecycleHandlers(startChild)
})
})
2 changes: 1 addition & 1 deletion packages/chronicle/src/cli/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from 'commander'
import { spawn } from 'child_process'
import path from 'path'
import chalk from 'chalk'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '../utils'
import { resolveContentDir, loadCLIConfig, attachLifecycleHandlers } from '@/cli/utils'

declare const PACKAGE_ROOT: string

Expand Down
2 changes: 2 additions & 0 deletions packages/chronicle/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { initCommand } from './commands/init'
import { devCommand } from './commands/dev'
import { buildCommand } from './commands/build'
import { startCommand } from './commands/start'
import { serveCommand } from './commands/serve'

const program = new Command()

Expand All @@ -15,5 +16,6 @@ program.addCommand(initCommand)
program.addCommand(devCommand)
program.addCommand(buildCommand)
program.addCommand(startCommand)
program.addCommand(serveCommand)

program.parse()
2 changes: 1 addition & 1 deletion packages/chronicle/src/cli/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs'
import path from 'path'
import { parse } from 'yaml'
import chalk from 'chalk'
import type { ChronicleConfig } from '../../types'
import type { ChronicleConfig } from '@/types'

export interface CLIConfig {
config: ChronicleConfig
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/code-snippets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
generatePython,
generateGo,
generateTypeScript,
} from "../../lib/snippet-generators";
} from "@/lib/snippet-generators";
import styles from "./code-snippets.module.css";

interface CodeSnippetsProps {
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/endpoint-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { FieldSection } from './field-section'
import { KeyValueEditor, type KeyValueEntry } from './key-value-editor'
import { CodeSnippets } from './code-snippets'
import { ResponsePanel } from './response-panel'
import { flattenSchema, generateExampleJson, type SchemaField } from '../../lib/schema'
import { flattenSchema, generateExampleJson, type SchemaField } from '@/lib/schema'
import styles from './endpoint-page.module.css'

interface EndpointPageProps {
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/field-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Flex, Text, Accordion, InputField, Switch, Select, IconButton } from '@raystack/apsara'
import { TrashIcon, PlusIcon } from '@heroicons/react/24/outline'
import type { SchemaField } from '../../lib/schema'
import type { SchemaField } from '@/lib/schema'
import styles from './field-row.module.css'

interface FieldRowProps {
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/api/field-section.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import { Flex, Text, Tabs, CodeBlock } from '@raystack/apsara'
import type { SchemaField } from '../../lib/schema'
import type { SchemaField } from '@/lib/schema'
import { FieldRow } from './field-row'
import { JsonEditor } from './json-editor'
import styles from './field-section.module.css'
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/mdx/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Image } from './image'
import { Link } from './link'
import { MdxTable, MdxThead, MdxTbody, MdxTr, MdxTh, MdxTd } from './table'
import { MdxPre } from './code'
import { Callout } from '../common/callout'
import { Callout } from '@/components/common/callout'

export const mdxComponents: MDXComponents = {
img: Image,
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/ui/breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import { Breadcrumb } from '@raystack/apsara'
import type { PageTree, PageTreeItem } from '../../types'
import type { PageTree, PageTreeItem } from '@/types'

interface BreadcrumbsProps {
slug: string[]
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/ui/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Flex, Link, Text } from "@raystack/apsara";
import type { FooterConfig } from "../../types";
import type { FooterConfig } from "@/types";
import styles from "./footer.module.css";

interface FooterProps {
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/components/ui/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useDocsSearch } from "fumadocs-core/search/client";
import type { SortedResult } from "fumadocs-core/search";
import { DocumentIcon, HashtagIcon } from "@heroicons/react/24/outline";
import { isMacOs } from "react-device-detect";
import { MethodBadge } from "../api/method-badge";
import { MethodBadge } from "@/components/api/method-badge";
import styles from "./search.module.css";

function SearchShortcutKey({ className }: { className?: string }) {
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/lib/api-routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenAPIV3 } from 'openapi-types'
import slugify from 'slugify'
import type { PageTree, PageTreeItem } from '../types/content'
import type { PageTree, PageTreeItem } from '@/types/content'
import type { ApiSpec } from './openapi'

export function getSpecSlug(spec: ApiSpec): string {
Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'
import { parse } from 'yaml'
import type { ChronicleConfig } from '../types'
import type { ChronicleConfig } from '@/types'

const CONFIG_FILE = 'chronicle.yaml'

Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/lib/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs'
import path from 'path'
import { parse as parseYaml } from 'yaml'
import type { OpenAPIV2, OpenAPIV3 } from 'openapi-types'
import type { ApiConfig, ApiServerConfig, ApiAuthConfig } from '../types/config'
import type { ApiConfig, ApiServerConfig, ApiAuthConfig } from '@/types/config'

type JsonObject = Record<string, unknown>

Expand Down
2 changes: 1 addition & 1 deletion packages/chronicle/src/lib/source.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { docs } from '../../.source/server'
import { loader } from 'fumadocs-core/source'
import type { PageTree, PageTreeItem, Frontmatter } from '../types'
import type { PageTree, PageTreeItem, Frontmatter } from '@/types'

export const source = loader({
baseUrl: '/',
Expand Down
Loading