@raystack/chronicle 0.1.0-canary.5a730d4 → 0.1.0-canary.67113f8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/cli/index.js +217 -412
  2. package/package.json +13 -10
  3. package/src/cli/commands/build.ts +30 -48
  4. package/src/cli/commands/dev.ts +24 -13
  5. package/src/cli/commands/init.ts +38 -123
  6. package/src/cli/commands/serve.ts +35 -50
  7. package/src/cli/commands/start.ts +20 -16
  8. package/src/cli/index.ts +14 -14
  9. package/src/cli/utils/config.ts +25 -26
  10. package/src/cli/utils/index.ts +3 -2
  11. package/src/cli/utils/resolve.ts +7 -3
  12. package/src/cli/utils/scaffold.ts +14 -16
  13. package/src/components/mdx/details.module.css +0 -2
  14. package/src/components/mdx/image.tsx +5 -20
  15. package/src/components/mdx/index.tsx +18 -4
  16. package/src/components/mdx/link.tsx +24 -20
  17. package/src/components/ui/breadcrumbs.tsx +8 -42
  18. package/src/components/ui/footer.tsx +2 -3
  19. package/src/components/ui/search.tsx +116 -72
  20. package/src/lib/api-routes.ts +6 -8
  21. package/src/lib/config.ts +31 -29
  22. package/src/lib/get-llm-text.ts +10 -0
  23. package/src/lib/head.tsx +26 -22
  24. package/src/lib/mdx-loader.ts +21 -0
  25. package/src/lib/openapi.ts +8 -8
  26. package/src/lib/page-context.tsx +74 -58
  27. package/src/lib/source.ts +136 -114
  28. package/src/pages/ApiLayout.tsx +22 -18
  29. package/src/pages/ApiPage.tsx +32 -27
  30. package/src/pages/DocsLayout.tsx +7 -7
  31. package/src/pages/DocsPage.tsx +11 -11
  32. package/src/pages/NotFound.tsx +11 -4
  33. package/src/server/App.tsx +35 -27
  34. package/src/server/api/apis-proxy.ts +69 -0
  35. package/src/server/api/health.ts +5 -0
  36. package/src/server/api/page/[...slug].ts +17 -0
  37. package/src/server/api/search.ts +170 -0
  38. package/src/server/api/specs.ts +9 -0
  39. package/src/server/build-search-index.ts +117 -0
  40. package/src/server/entry-client.tsx +47 -55
  41. package/src/server/entry-server.tsx +100 -35
  42. package/src/server/routes/llms.txt.ts +61 -0
  43. package/src/server/routes/og.tsx +75 -0
  44. package/src/server/routes/robots.txt.ts +11 -0
  45. package/src/server/routes/sitemap.xml.ts +40 -0
  46. package/src/server/utils/safe-path.ts +17 -0
  47. package/src/server/vite-config.ts +90 -44
  48. package/src/themes/default/Layout.tsx +78 -47
  49. package/src/themes/default/Page.module.css +0 -12
  50. package/src/themes/default/Page.tsx +9 -11
  51. package/src/themes/default/Toc.tsx +25 -39
  52. package/src/themes/default/index.ts +7 -9
  53. package/src/themes/paper/ChapterNav.tsx +63 -43
  54. package/src/themes/paper/Layout.module.css +1 -1
  55. package/src/themes/paper/Layout.tsx +24 -12
  56. package/src/themes/paper/Page.module.css +16 -4
  57. package/src/themes/paper/Page.tsx +56 -62
  58. package/src/themes/paper/ReadingProgress.tsx +160 -139
  59. package/src/themes/paper/index.ts +5 -5
  60. package/src/themes/registry.ts +7 -7
  61. package/src/types/content.ts +5 -21
  62. package/src/types/globals.d.ts +3 -0
  63. package/src/types/theme.ts +4 -3
  64. package/src/cli/__tests__/config.test.ts +0 -25
  65. package/src/cli/__tests__/scaffold.test.ts +0 -10
  66. package/src/pages/__tests__/head.test.tsx +0 -57
  67. package/src/server/__tests__/entry-server.test.tsx +0 -35
  68. package/src/server/__tests__/handlers.test.ts +0 -77
  69. package/src/server/__tests__/og.test.ts +0 -23
  70. package/src/server/__tests__/router.test.ts +0 -72
  71. package/src/server/__tests__/vite-config.test.ts +0 -25
  72. package/src/server/dev.ts +0 -156
  73. package/src/server/entry-prod.ts +0 -127
  74. package/src/server/handlers/apis-proxy.ts +0 -52
  75. package/src/server/handlers/health.ts +0 -3
  76. package/src/server/handlers/llms.ts +0 -58
  77. package/src/server/handlers/og.ts +0 -87
  78. package/src/server/handlers/robots.ts +0 -11
  79. package/src/server/handlers/search.ts +0 -140
  80. package/src/server/handlers/sitemap.ts +0 -39
  81. package/src/server/handlers/specs.ts +0 -9
  82. package/src/server/index.html +0 -12
  83. package/src/server/prod.ts +0 -18
  84. package/src/server/router.ts +0 -42
  85. package/src/themes/default/font.ts +0 -4
@@ -1,11 +0,0 @@
1
- import { loadConfig } from '@/lib/config'
2
-
3
- export function handleRobots(): Response {
4
- const config = loadConfig()
5
- const sitemap = config.url ? `\nSitemap: ${config.url}/sitemap.xml` : ''
6
- const body = `User-agent: *\nAllow: /${sitemap}`
7
-
8
- return new Response(body, {
9
- headers: { 'Content-Type': 'text/plain' },
10
- })
11
- }
@@ -1,140 +0,0 @@
1
- import fs from 'fs/promises'
2
- import path from 'path'
3
- import matter from 'gray-matter'
4
- import MiniSearch from 'minisearch'
5
- import type { OpenAPIV3 } from 'openapi-types'
6
- import { loadConfig } from '@/lib/config'
7
- import { loadApiSpecs, type ApiSpec } from '@/lib/openapi'
8
- import { getSpecSlug } from '@/lib/api-routes'
9
-
10
- interface SearchDocument {
11
- id: string
12
- url: string
13
- title: string
14
- content: string
15
- type: 'page' | 'api'
16
- }
17
-
18
- let searchIndex: MiniSearch<SearchDocument> | null = null
19
-
20
- function getContentDir(): string {
21
- return process.env.CHRONICLE_CONTENT_DIR || path.join(process.cwd(), 'content')
22
- }
23
-
24
- async function scanContent(): Promise<SearchDocument[]> {
25
- const contentDir = getContentDir()
26
- const docs: SearchDocument[] = []
27
-
28
- async function scan(dir: string, prefix: string[] = []) {
29
- let entries
30
- try { entries = await fs.readdir(dir, { withFileTypes: true }) }
31
- catch { return }
32
-
33
- for (const entry of entries) {
34
- if (entry.name.startsWith('.') || entry.name === 'node_modules') continue
35
- const fullPath = path.join(dir, entry.name)
36
-
37
- if (entry.isDirectory()) {
38
- await scan(fullPath, [...prefix, entry.name])
39
- continue
40
- }
41
-
42
- if (!entry.name.endsWith('.mdx') && !entry.name.endsWith('.md')) continue
43
-
44
- const raw = await fs.readFile(fullPath, 'utf-8')
45
- const { data: fm, content } = matter(raw)
46
- const baseName = entry.name.replace(/\.(mdx|md)$/, '')
47
- const slugs = baseName === 'index' ? prefix : [...prefix, baseName]
48
- const url = slugs.length === 0 ? '/' : '/' + slugs.join('/')
49
-
50
- docs.push({
51
- id: url,
52
- url,
53
- title: fm.title ?? baseName,
54
- content: content.slice(0, 5000),
55
- type: 'page',
56
- })
57
- }
58
- }
59
-
60
- await scan(contentDir)
61
- return docs
62
- }
63
-
64
- function buildApiDocs(): SearchDocument[] {
65
- const config = loadConfig()
66
- if (!config.api?.length) return []
67
-
68
- const docs: SearchDocument[] = []
69
- const specs = loadApiSpecs(config.api)
70
-
71
- for (const spec of specs) {
72
- const specSlug = getSpecSlug(spec)
73
- const paths = spec.document.paths ?? {}
74
- for (const [pathStr, pathItem] of Object.entries(paths)) {
75
- if (!pathItem) continue
76
- for (const method of ['get', 'post', 'put', 'delete', 'patch'] as const) {
77
- const op = pathItem[method] as OpenAPIV3.OperationObject | undefined
78
- if (!op?.operationId) continue
79
- const url = `/apis/${specSlug}/${encodeURIComponent(op.operationId)}`
80
- docs.push({
81
- id: url,
82
- url,
83
- title: `${method.toUpperCase()} ${op.summary ?? op.operationId}`,
84
- content: op.description ?? '',
85
- type: 'api',
86
- })
87
- }
88
- }
89
- }
90
-
91
- return docs
92
- }
93
-
94
- async function getIndex(): Promise<MiniSearch<SearchDocument>> {
95
- if (searchIndex) return searchIndex
96
-
97
- const [contentDocs, apiDocs] = await Promise.all([
98
- scanContent(),
99
- Promise.resolve(buildApiDocs()),
100
- ])
101
-
102
- searchIndex = new MiniSearch<SearchDocument>({
103
- fields: ['title', 'content'],
104
- storeFields: ['url', 'title', 'type'],
105
- searchOptions: {
106
- boost: { title: 2 },
107
- fuzzy: 0.2,
108
- prefix: true,
109
- },
110
- })
111
-
112
- searchIndex.addAll([...contentDocs, ...apiDocs])
113
- return searchIndex
114
- }
115
-
116
- export async function handleSearch(req: Request): Promise<Response> {
117
- const url = new URL(req.url)
118
- const query = url.searchParams.get('query') ?? ''
119
- const index = await getIndex()
120
-
121
- if (!query) {
122
- const contentDocs = await scanContent()
123
- const suggestions = contentDocs.slice(0, 8).map((d) => ({
124
- id: d.id,
125
- url: d.url,
126
- type: d.type,
127
- content: d.title,
128
- }))
129
- return Response.json(suggestions)
130
- }
131
-
132
- const results = index.search(query).map((r) => ({
133
- id: r.id,
134
- url: r.url,
135
- type: r.type,
136
- content: r.title,
137
- }))
138
-
139
- return Response.json(results)
140
- }
@@ -1,39 +0,0 @@
1
- import { loadConfig } from '@/lib/config'
2
- import { getPages } from '@/lib/source'
3
- import { loadApiSpecs } from '@/lib/openapi'
4
- import { buildApiRoutes } from '@/lib/api-routes'
5
-
6
- export async function handleSitemap(): Promise<Response> {
7
- const config = loadConfig()
8
- if (!config.url) {
9
- return new Response('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"/>', {
10
- headers: { 'Content-Type': 'application/xml' },
11
- })
12
- }
13
-
14
- const baseUrl = config.url.replace(/\/$/, '')
15
-
16
- const pages = await getPages()
17
- const docPages = pages.map((page) => {
18
- const lastmod = page.frontmatter.lastModified
19
- ? `<lastmod>${new Date(page.frontmatter.lastModified).toISOString()}</lastmod>`
20
- : ''
21
- return `<url><loc>${baseUrl}/${page.slugs.join('/')}</loc>${lastmod}</url>`
22
- })
23
-
24
- const apiPages = config.api?.length
25
- ? buildApiRoutes(loadApiSpecs(config.api)).map((route) =>
26
- `<url><loc>${baseUrl}/apis/${route.slug.join('/')}</loc></url>`
27
- )
28
- : []
29
-
30
- const xml = `<?xml version="1.0" encoding="UTF-8"?>
31
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
32
- <url><loc>${baseUrl}</loc></url>
33
- ${[...docPages, ...apiPages].join('\n')}
34
- </urlset>`
35
-
36
- return new Response(xml, {
37
- headers: { 'Content-Type': 'application/xml' },
38
- })
39
- }
@@ -1,9 +0,0 @@
1
- import { loadConfig } from '@/lib/config'
2
- import { loadApiSpecs } from '@/lib/openapi'
3
-
4
- export function handleSpecs(): Response {
5
- const config = loadConfig()
6
- const specs = config.api?.length ? loadApiSpecs(config.api) : []
7
-
8
- return Response.json(specs)
9
- }
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <!--head-outlet-->
7
- </head>
8
- <body>
9
- <div id="root"><!--ssr-outlet--></div>
10
- <script type="module" src="/src/server/entry-client.tsx"></script>
11
- </body>
12
- </html>
@@ -1,18 +0,0 @@
1
- import path from 'path'
2
- import chalk from 'chalk'
3
-
4
- export interface ProdServerOptions {
5
- port: number
6
- root: string
7
- distDir: string
8
- }
9
-
10
- export async function startProdServer(options: ProdServerOptions) {
11
- const { port, distDir } = options
12
-
13
- const serverEntry = path.resolve(distDir, 'server/entry-prod.js')
14
- const { startServer } = await import(serverEntry)
15
-
16
- console.log(chalk.cyan('Starting production server...'))
17
- return startServer({ port, distDir })
18
- }
@@ -1,42 +0,0 @@
1
- import { handleHealth } from './handlers/health'
2
- import { handleSearch } from './handlers/search'
3
- import { handleApisProxy } from './handlers/apis-proxy'
4
- import { handleOg } from './handlers/og'
5
- import { handleLlms } from './handlers/llms'
6
- import { handleSitemap } from './handlers/sitemap'
7
- import { handleRobots } from './handlers/robots'
8
- import { handleSpecs } from './handlers/specs'
9
-
10
- export type RouteHandler = (req: Request) => Response | Promise<Response>
11
-
12
- interface Route {
13
- pattern: URLPattern
14
- handler: RouteHandler
15
- }
16
-
17
- const routes: Route[] = []
18
-
19
- function addRoute(path: string, handler: RouteHandler) {
20
- routes.push({
21
- pattern: new URLPattern({ pathname: path }),
22
- handler,
23
- })
24
- }
25
-
26
- addRoute('/api/health', handleHealth)
27
- addRoute('/api/search', handleSearch)
28
- addRoute('/api/apis-proxy', handleApisProxy)
29
- addRoute('/api/specs', handleSpecs)
30
- addRoute('/og', handleOg)
31
- addRoute('/llms.txt', handleLlms)
32
- addRoute('/sitemap.xml', handleSitemap)
33
- addRoute('/robots.txt', handleRobots)
34
-
35
- export function matchRoute(url: string): RouteHandler | null {
36
- for (const route of routes) {
37
- if (route.pattern.test(url)) {
38
- return route.handler
39
- }
40
- }
41
- return null
42
- }
@@ -1,4 +0,0 @@
1
- export const inter = {
2
- className: 'chronicle-inter',
3
- style: { fontFamily: "'Inter', system-ui, -apple-system, sans-serif" },
4
- }