raw-markdown.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. /** Development responses for published Markdown and the documentation index. */
  2. import type { Connect } from 'vite'
  3. import { rawMarkdownRoute } from '../scripts/project-doc-site.ts'
  4. /**
  5. * Serve published source text while preserving Vite's Markdown module imports.
  6. * Explicit `dsh-raw=1` fetches return 404 for unpublished Markdown routes.
  7. *
  8. * @param base Site URL prefix with leading and trailing slashes.
  9. * @param index Render the current llms.txt index.
  10. * @returns Middleware for the Vite development server.
  11. */
  12. export function rawMarkdownMiddleware(base: string, index: () => string): Connect.NextHandleFunction {
  13. return (req, res, next) => {
  14. if (req.url === undefined || (req.method !== 'GET' && req.method !== 'HEAD')) {
  15. next()
  16. return
  17. }
  18. let url: URL
  19. try {
  20. url = new URL(req.url, 'http://docs.local')
  21. } catch (_error) {
  22. // Malformed targets belong to Vite's request handling, not raw-route lookup.
  23. next()
  24. return
  25. }
  26. if (!url.pathname.startsWith(base)) {
  27. next()
  28. return
  29. }
  30. const path = url.pathname.slice(base.length)
  31. const explicit = path.endsWith('.md') && url.searchParams.get('dsh-raw') === '1'
  32. const destination = req.headers['sec-fetch-dest']
  33. // Script imports always belong to Vite, including imports carrying a query.
  34. if (destination !== undefined && destination !== 'document' && !(destination === 'empty' && explicit)) {
  35. next()
  36. return
  37. }
  38. const content = path === 'llms.txt' ? index() : path.endsWith('.md') ? rawMarkdownRoute(path) : undefined
  39. if (content === undefined) {
  40. if (!explicit) {
  41. next()
  42. return
  43. }
  44. res.statusCode = 404
  45. res.end()
  46. return
  47. }
  48. res.setHeader('Content-Type', `${path === 'llms.txt' ? 'text/plain' : 'text/markdown'}; charset=utf-8`)
  49. res.end(req.method === 'HEAD' ? undefined : content)
  50. }
  51. }