11import { Hono } from "hono" ;
22import { serveStatic } from "hono/deno" ;
3+ import { ssgParams } from "hono/ssg" ;
34import { docPages } from "./data/docs.ts" ;
45import type { PackageDoc } from "./lib/api-docs.ts" ;
56import { generateApiMarkdown } from "./lib/api-markdown.ts" ;
@@ -8,37 +9,43 @@ import { ApiIndexPage, PackagePage } from "./templates/api/ApiPage.tsx";
89import { MarkdownDocFromFile } from "./templates/docs/MarkdownDoc.tsx" ;
910import { HomePage } from "./templates/home.tsx" ;
1011
12+ /** Get list of API package names for SSG */
13+ async function getApiPackageNames ( ) : Promise < string [ ] > {
14+ const indexPath = new URL ( "./data/api/index.json" , import . meta. url ) ;
15+ const content = await Deno . readTextFile ( indexPath ) ;
16+ const index = JSON . parse ( content ) ;
17+ return index . packages . map ( ( p : { name : string } ) => p . name ) ;
18+ }
19+
1120const app = new Hono ( ) ;
1221
1322app . use ( "/static/*" , serveStatic ( { root : "./" } ) ) ;
1423
15- // Home page
24+ // Home page (HTML)
1625app . get ( "/" , async ( c ) => {
17- const accept = ( c . req . header ( "accept" ) ?? "" ) . toLowerCase ( ) ;
18- const human = c . req . query ( "human" ) ;
19-
20- if ( human !== "1" && ! accept . includes ( "text/html" ) ) {
21- const content = await Deno . readTextFile (
22- new URL ( "./docs/overview.md" , import . meta. url ) ,
23- ) ;
24- const modified = [
25- "*" . repeat ( 80 ) ,
26- "" ,
27- "This is a Markdown page for LLMs. If you are LLMs, read this page." ,
28- "If you are human and want to visit Web page, add ?human=1 to the URL." ,
29- "" ,
30- "*" . repeat ( 80 ) ,
31- "" ,
32- content ,
33- ] . join ( "\n" ) ;
34- return c . text ( modified , 200 , {
35- "Content-Type" : "text/markdown; charset=utf-8" ,
36- } ) ;
37- }
38-
3926 return c . html ( await HomePage ( ) ) ;
4027} ) ;
4128
29+ // Home page markdown for LLMs (SSG generates /index.md)
30+ app . get ( "/index.md" , async ( c ) => {
31+ const content = await Deno . readTextFile (
32+ new URL ( "./docs/overview.md" , import . meta. url ) ,
33+ ) ;
34+ const modified = [
35+ "*" . repeat ( 80 ) ,
36+ "" ,
37+ "This is a Markdown page for LLMs. If you are LLMs, read this page." ,
38+ "If you are human and want to visit Web page, visit /" ,
39+ "" ,
40+ "*" . repeat ( 80 ) ,
41+ "" ,
42+ content ,
43+ ] . join ( "\n" ) ;
44+ return c . text ( modified , 200 , {
45+ "Content-Type" : "text/markdown; charset=utf-8" ,
46+ } ) ;
47+ } ) ;
48+
4249// LLM-friendly endpoints (llms.txt standard)
4350app . get ( "/llms.txt" , async ( c ) => {
4451 return c . text ( await generateLlmsTxt ( ) , 200 , {
@@ -58,8 +65,11 @@ for (const doc of docPages) {
5865 return c . html ( page ) ;
5966 } ) ;
6067
61- // Raw markdown endpoint (append .md to get source)
62- app . get ( `${ doc . path } .md` , async ( c ) => {
68+ // Raw markdown endpoint: /docs/ → /docs/index.md
69+ const mdPath = doc . path . endsWith ( "/" )
70+ ? `${ doc . path } index.md`
71+ : `${ doc . path } .md` ;
72+ app . get ( mdPath , async ( c ) => {
6373 const content = await Deno . readTextFile ( doc . file ) ;
6474 return c . text ( content , 200 , {
6575 "Content-Type" : "text/markdown; charset=utf-8" ,
@@ -68,16 +78,32 @@ for (const doc of docPages) {
6878}
6979
7080// API Reference pages
71- app . get ( "/api" , async ( c ) => {
81+ app . get ( "/api/ " , async ( c ) => {
7282 return c . html ( await ApiIndexPage ( ) ) ;
7383} ) ;
7484
75- app . get ( "/api/:package" , async ( c ) => {
76- const param = c . req . param ( "package" ) ;
77-
78- // Check if requesting JSON
79- if ( param . endsWith ( ".json" ) ) {
80- const packageName = param . slice ( 0 , - 5 ) ; // Remove .json suffix
85+ app . get (
86+ "/api/:package/" ,
87+ // SSG: Generate static pages for all packages (HTML)
88+ ssgParams ( async ( ) => {
89+ const packages = await getApiPackageNames ( ) ;
90+ return packages . map ( ( name ) => ( { package : name } ) ) ;
91+ } ) ,
92+ async ( c ) => {
93+ const packageName = c . req . param ( "package" ) ;
94+ return c . html ( await PackagePage ( { packageName } ) ) ;
95+ } ,
96+ ) ;
97+
98+ // API JSON endpoints: /api/builder.json → /api/builder/index.json
99+ app . get (
100+ "/api/:package/index.json" ,
101+ ssgParams ( async ( ) => {
102+ const packages = await getApiPackageNames ( ) ;
103+ return packages . map ( ( name ) => ( { package : name } ) ) ;
104+ } ) ,
105+ async ( c ) => {
106+ const packageName = c . req . param ( "package" ) ;
81107 try {
82108 const jsonPath = new URL (
83109 `./data/api/${ packageName } .json` ,
@@ -90,11 +116,18 @@ app.get("/api/:package", async (c) => {
90116 } catch {
91117 return c . text ( "Not found" , 404 ) ;
92118 }
93- }
94-
95- // Check if requesting Markdown
96- if ( param . endsWith ( ".md" ) ) {
97- const packageName = param . slice ( 0 , - 3 ) ; // Remove .md suffix
119+ } ,
120+ ) ;
121+
122+ // API Markdown endpoints: /api/builder.md → /api/builder/index.md
123+ app . get (
124+ "/api/:package/index.md" ,
125+ ssgParams ( async ( ) => {
126+ const packages = await getApiPackageNames ( ) ;
127+ return packages . map ( ( name ) => ( { package : name } ) ) ;
128+ } ) ,
129+ async ( c ) => {
130+ const packageName = c . req . param ( "package" ) ;
98131 try {
99132 // Load current package
100133 const jsonPath = new URL (
@@ -130,10 +163,13 @@ app.get("/api/:package", async (c) => {
130163 } catch {
131164 return c . text ( "Not found" , 404 ) ;
132165 }
133- }
166+ } ,
167+ ) ;
134168
135- // Otherwise render HTML page
136- return c . html ( await PackagePage ( { packageName : param } ) ) ;
137- } ) ;
169+ // Export app for SSG build
170+ export default app ;
138171
139- Deno . serve ( app . fetch ) ;
172+ // Start server when running directly
173+ if ( import . meta. main ) {
174+ Deno . serve ( app . fetch ) ;
175+ }
0 commit comments