@pagesmith/core 0.3.0 → 0.4.0

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 (72) hide show
  1. package/README.md +9 -4
  2. package/REFERENCE.md +5 -2
  3. package/dist/ai/index.d.mts +5 -3
  4. package/dist/ai/index.d.mts.map +1 -1
  5. package/dist/ai/index.mjs +300 -206
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/assets/index.d.mts +10 -1
  8. package/dist/assets/index.d.mts.map +1 -1
  9. package/dist/assets/index.mjs +2 -2
  10. package/dist/{assets-DXiWF_KI.mjs → assets-CAPOqQ_P.mjs} +42 -5
  11. package/dist/assets-CAPOqQ_P.mjs.map +1 -0
  12. package/dist/{content-config-Bfe4W9us.d.mts → content-config-DJXUOcNG.d.mts} +49 -17
  13. package/dist/{content-config-Bfe4W9us.d.mts.map → content-config-DJXUOcNG.d.mts.map} +1 -1
  14. package/dist/{content-layer-DPK1EmfY.mjs → content-layer-B5enqWeJ.mjs} +123 -28
  15. package/dist/content-layer-B5enqWeJ.mjs.map +1 -0
  16. package/dist/content-layer-CpHYUYNN.d.mts +121 -0
  17. package/dist/content-layer-CpHYUYNN.d.mts.map +1 -0
  18. package/dist/create/index.d.mts.map +1 -1
  19. package/dist/create/index.mjs +26 -28
  20. package/dist/create/index.mjs.map +1 -1
  21. package/dist/css/index.d.mts +1 -1
  22. package/dist/{heading-BpDXnl-7.d.mts → heading-Dhvzlay-.d.mts} +1 -1
  23. package/dist/{heading-BpDXnl-7.d.mts.map → heading-Dhvzlay-.d.mts.map} +1 -1
  24. package/dist/{index-Bg9srb5U.d.mts → index-B7NRZAxd.d.mts} +1 -1
  25. package/dist/{index-Bg9srb5U.d.mts.map → index-B7NRZAxd.d.mts.map} +1 -1
  26. package/dist/{index-BBYkDxwI.d.mts → index-C0QFHYwb.d.mts} +1 -1
  27. package/dist/{index-BBYkDxwI.d.mts.map → index-C0QFHYwb.d.mts.map} +1 -1
  28. package/dist/{index-CbOKbkjJ.d.mts → index-CJkBs8YQ.d.mts} +2 -2
  29. package/dist/index-CJkBs8YQ.d.mts.map +1 -0
  30. package/dist/{index-YXQxMV6J.d.mts → index-DCznbvaV.d.mts} +2 -2
  31. package/dist/{index-YXQxMV6J.d.mts.map → index-DCznbvaV.d.mts.map} +1 -1
  32. package/dist/index.d.mts +15 -99
  33. package/dist/index.d.mts.map +1 -1
  34. package/dist/index.mjs +13 -9
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/loaders/index.d.mts +2 -2
  37. package/dist/markdown/index.d.mts +2 -2
  38. package/dist/markdown/index.mjs +1 -1
  39. package/dist/{markdown-CyrHoDhP.mjs → markdown-BmDJgYeB.mjs} +23 -1
  40. package/dist/{markdown-CyrHoDhP.mjs.map → markdown-BmDJgYeB.mjs.map} +1 -1
  41. package/dist/mcp/index.d.mts +23 -0
  42. package/dist/mcp/index.d.mts.map +1 -0
  43. package/dist/mcp/index.mjs +2 -0
  44. package/dist/mcp/server.d.mts +13 -0
  45. package/dist/mcp/server.d.mts.map +1 -0
  46. package/dist/mcp/server.mjs +2 -0
  47. package/dist/runtime/index.mjs +1 -1
  48. package/dist/schemas/index.d.mts +3 -3
  49. package/dist/server-D3DHoh5f.mjs +202 -0
  50. package/dist/server-D3DHoh5f.mjs.map +1 -0
  51. package/dist/ssg-utils/index.d.mts +61 -0
  52. package/dist/ssg-utils/index.d.mts.map +1 -0
  53. package/dist/ssg-utils/index.mjs +118 -0
  54. package/dist/ssg-utils/index.mjs.map +1 -0
  55. package/dist/{types-Cn52sdoq.d.mts → types-B-V5qemH.d.mts} +1 -1
  56. package/dist/{types-Cn52sdoq.d.mts.map → types-B-V5qemH.d.mts.map} +1 -1
  57. package/dist/vite/index.d.mts +69 -34
  58. package/dist/vite/index.d.mts.map +1 -1
  59. package/dist/vite/index.mjs +294 -226
  60. package/dist/vite/index.mjs.map +1 -1
  61. package/docs/agents/AGENTS.md.template +9 -0
  62. package/docs/agents/changelog-notes.md +15 -0
  63. package/docs/agents/errors.md +96 -0
  64. package/docs/agents/migration.md +25 -0
  65. package/docs/agents/recipes.md +26 -0
  66. package/docs/agents/usage.md +58 -0
  67. package/docs/llms-full.txt +53 -0
  68. package/docs/llms.txt +29 -0
  69. package/package.json +56 -4
  70. package/dist/assets-DXiWF_KI.mjs.map +0 -1
  71. package/dist/content-layer-DPK1EmfY.mjs.map +0 -1
  72. package/dist/index-CbOKbkjJ.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/vite/ssg.ts","../../src/vite/shared-assets.ts","../../src/vite/ssg-plugin.ts","../../src/vite/index.ts"],"sourcesContent":["/**\n * Pre-rendering utility for Vite-based SSG sites.\n *\n * Call after running both the client and SSR Vite builds.\n * Loads the SSR module, renders each route, injects into the\n * client HTML template, and writes static files.\n */\n\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { pathToFileURL } from 'url'\n\nexport type PrerenderOptions = {\n /** Absolute path to the client build output directory (e.g., `dist/`) */\n outDir: string\n /** Absolute path to the built SSR entry module (e.g., `dist/.server/entry-server.js`) */\n serverEntry: string\n /** Routes to pre-render (e.g., `['/', '/about', '/posts/hello-world']`) */\n routes: string[]\n /** HTML placeholder to replace with rendered content (default: `'<!--ssr-outlet-->'`) */\n placeholder?: string\n /** Remove the server build directory after pre-rendering (default: true) */\n cleanup?: boolean\n}\n\n/**\n * Pre-render routes to static HTML files.\n *\n * Expects the SSR entry to export a `render(url: string): string` function.\n *\n * @example\n * ```ts\n * import { build } from 'vite'\n * import { prerenderRoutes } from '@pagesmith/core/vite'\n *\n * // 1. Client build\n * await build({ build: { outDir: 'dist' } })\n *\n * // 2. SSR build\n * await build({ build: { ssr: 'src/entry-server.tsx', outDir: 'dist/.server' } })\n *\n * // 3. Pre-render\n * await prerenderRoutes({\n * outDir: resolve('dist'),\n * serverEntry: resolve('dist/.server/entry-server.js'),\n * routes: ['/', '/about', '/posts/hello-world'],\n * })\n * ```\n */\nexport async function prerenderRoutes(options: PrerenderOptions): Promise<{ pages: number }> {\n const placeholder = options.placeholder ?? '<!--ssr-outlet-->'\n const cleanup = options.cleanup ?? true\n\n // Load SSR module\n if (!existsSync(options.serverEntry)) {\n throw new Error(`SSR entry not found: ${options.serverEntry}`)\n }\n\n const mod = await import(pathToFileURL(options.serverEntry).href)\n const render: (url: string) => string | Promise<string> = mod.render ?? mod.default?.render\n\n if (typeof render !== 'function') {\n throw new Error(\n `SSR entry must export a 'render(url: string)' function. ` +\n `Found exports: ${Object.keys(mod).join(', ')}`,\n )\n }\n\n // Read client HTML template\n const templatePath = resolve(options.outDir, 'index.html')\n const template = readFileSync(templatePath, 'utf-8')\n\n if (!template.includes(placeholder)) {\n throw new Error(\n `HTML template does not contain placeholder \"${placeholder}\". ` +\n `Add it to your index.html where SSR content should be injected.`,\n )\n }\n\n // Pre-render each route\n for (const route of options.routes) {\n const rendered = await render(route)\n const html = template.replace(placeholder, rendered)\n\n const routePath = route === '/' ? '' : route.replace(/^\\//, '')\n const outPath = resolve(options.outDir, routePath, 'index.html')\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, html)\n }\n\n // Clean up server build\n if (cleanup) {\n const serverDir = dirname(options.serverEntry)\n rmSync(serverDir, { recursive: true, force: true })\n }\n\n return { pages: options.routes.length }\n}\n","import { existsSync, readFileSync } from 'fs'\nimport { dirname, join } from 'path'\nimport { fileURLToPath } from 'url'\nimport type { Plugin } from 'vite'\n\n/**\n * Vite plugin that serves shared font assets during development.\n * In production, fonts are copied to the output directory by the build script.\n */\nexport function sharedAssetsPlugin(): Plugin {\n const pkgDir = join(dirname(fileURLToPath(import.meta.url)), '..', '..')\n const assetsDir = join(pkgDir, 'assets')\n\n return {\n name: 'pagesmith:shared-assets',\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const url = req.url ?? ''\n\n // Serve fonts.css\n if (url === '/assets/fonts.css' || url.endsWith('/assets/fonts.css')) {\n const filePath = join(assetsDir, 'fonts.css')\n if (existsSync(filePath)) {\n res.writeHead(200, { 'Content-Type': 'text/css', 'Cache-Control': 'no-cache' })\n res.end(readFileSync(filePath, 'utf-8'))\n return\n }\n }\n\n // Serve font files\n if (url.includes('/assets/fonts/') && url.endsWith('.woff2')) {\n const fileName = url.split('/assets/fonts/').pop()\n if (fileName) {\n const filePath = join(assetsDir, 'fonts', fileName)\n if (existsSync(filePath)) {\n res.writeHead(200, {\n 'Content-Type': 'font/woff2',\n 'Cache-Control': 'public, max-age=31536000',\n })\n res.end(readFileSync(filePath))\n return\n }\n }\n }\n\n next()\n })\n },\n }\n}\n","/**\n * Vite plugin for static site generation with @pagesmith/core.\n *\n * Handles both development (on-the-fly SSR via middleware) and\n * production (post-build SSG + pagefind indexing).\n *\n * The SSR entry module must export:\n * - `getRoutes(config)` — returns route paths to pre-render\n * - `render(url, config)` — renders a route to an HTML string\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { pagesmithSsg } from '@pagesmith/core/vite'\n *\n * export default defineConfig({\n * base: '/my-site/',\n * plugins: [pagesmithSsg({ entry: './src/entry-server.tsx' })],\n * })\n * ```\n */\n\nimport {\n copyFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from 'fs'\nimport { basename, dirname, extname, join, resolve } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport { copyPublicFiles } from '../assets'\n\nexport type SsgPluginOptions = {\n /** Path to the SSR entry module (e.g., './src/entry-server.tsx') */\n entry: string\n /** Run pagefind after build (default: true) */\n pagefind?: boolean\n /** Content roots used for copying companion assets. */\n contentDirs?: string[]\n}\n\nexport type SsgRenderConfig = {\n /** Base path without trailing slash (e.g., '/my-site') */\n base: string\n /** Absolute path to the project root */\n root: string\n /** Path to the built CSS asset */\n cssPath: string\n /** Path to the built JS asset (undefined in dev for inline-script examples) */\n jsPath?: string\n /** Whether search is enabled (false in dev) */\n searchEnabled: boolean\n /** Whether running in dev mode */\n isDev: boolean\n}\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.ico': 'image/x-icon',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ttf': 'font/ttf',\n '.txt': 'text/plain; charset=utf-8',\n '.xml': 'application/xml; charset=utf-8',\n}\n\nconst WS_RELOAD_SCRIPT = `<script type=\"module\">\nimport 'vite/modulepreload-polyfill'\nif (import.meta.hot) {\n import.meta.hot.on('full-reload', () => location.reload())\n}\n</script>`\n\nconst CONTENT_ASSET_EXTS = new Set([\n '.svg',\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.webp',\n '.avif',\n '.ico',\n])\n\nfunction resolveContentDirs(projectRoot: string, contentDirs: string[] = []): string[] {\n return contentDirs.map((dir) => resolve(projectRoot, dir))\n}\n\nfunction isAssetReference(ref: string): boolean {\n if (!ref.startsWith('./')) return false\n const path = ref.split(/[?#]/u, 1)[0] ?? ref\n return CONTENT_ASSET_EXTS.has(extname(path).toLowerCase())\n}\n\nfunction rewriteContentAssetRefs(html: string, base: string): string {\n const basePrefix = base.replace(/\\/+$/u, '')\n\n return html.replace(\n /(src|href|srcset)=(?:\"([^\"]+)\"|'([^']+)')/g,\n (match, attr: string, doubleRef: string | undefined, singleRef: string | undefined) => {\n const ref = doubleRef ?? singleRef ?? ''\n if (!isAssetReference(ref)) return match\n const pathname = ref.split(/[?#]/u, 1)[0] ?? ref\n const suffix = ref.slice(pathname.length)\n const quote = doubleRef !== undefined ? '\"' : \"'\"\n return `${attr}=${quote}${basePrefix}/assets/${pathname.split('/').pop() ?? pathname}${suffix}${quote}`\n },\n )\n}\n\nfunction collectContentAssets(contentDirs: string[]): Map<string, string> {\n const assets = new Map<string, string>()\n\n function walk(dir: string): void {\n if (!existsSync(dir)) return\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.')) continue\n\n const fullPath = join(dir, entry.name)\n\n if (entry.isDirectory()) {\n walk(fullPath)\n continue\n }\n\n const ext = extname(entry.name).toLowerCase()\n if (!CONTENT_ASSET_EXTS.has(ext)) continue\n\n if (assets.has(entry.name) && assets.get(entry.name) !== fullPath) {\n console.warn(\n `pagesmith:ssg duplicate companion asset basename \"${entry.name}\" detected; using ${fullPath}`,\n )\n }\n\n assets.set(entry.name, fullPath)\n }\n }\n\n for (const dir of contentDirs) {\n walk(dir)\n }\n\n return assets\n}\n\nfunction copyContentAssetsToOutDir(outDir: string, assets: Map<string, string>): void {\n if (assets.size === 0) return\n\n const assetsDir = join(outDir, 'assets')\n mkdirSync(assetsDir, { recursive: true })\n\n for (const [fileName, sourcePath] of assets) {\n copyFileSync(sourcePath, join(assetsDir, fileName))\n }\n}\n\nexport function pagesmithSsg(options: SsgPluginOptions): Plugin[] {\n const enablePagefind = options.pagefind !== false\n let config: ResolvedConfig\n let projectRoot: string\n let base: string // e.g., '/my-site'\n let outDir: string\n let contentDirs: string[] = []\n let contentAssets = new Map<string, string>()\n\n // ── Dev plugin: SSR middleware ──\n const devPlugin: Plugin = {\n name: 'pagesmith:ssg-dev',\n apply: 'serve',\n\n config() {\n // Disable Vite's built-in SPA HTML serving so the SSG middleware\n // can handle all HTML requests via server-side rendering.\n return { appType: 'custom' }\n },\n\n configResolved(resolved) {\n config = resolved\n projectRoot = resolved.root\n base = resolved.base.replace(/\\/+$/, '')\n outDir = resolve(projectRoot, resolved.build.outDir)\n contentDirs = resolveContentDirs(projectRoot, options.contentDirs)\n },\n\n configureServer(server: ViteDevServer) {\n async function refreshContentArtifacts(): Promise<void> {\n contentAssets = collectContentAssets(contentDirs)\n }\n\n void refreshContentArtifacts().catch((error) => {\n console.warn(\n `pagesmith:ssg failed to prepare companion assets: ${error instanceof Error ? error.message : String(error)}`,\n )\n })\n\n if (contentDirs.length > 0) {\n server.watcher.add(contentDirs)\n\n const refresh = () => {\n void refreshContentArtifacts().catch((error) => {\n console.warn(\n `pagesmith:ssg failed to refresh companion assets: ${error instanceof Error ? error.message : String(error)}`,\n )\n })\n }\n\n server.watcher.on('add', refresh)\n server.watcher.on('change', refresh)\n server.watcher.on('unlink', refresh)\n }\n\n // Register middleware directly — appType: 'custom' disables Vite's\n // built-in HTML serving, so we handle all HTML requests via SSR.\n server.middlewares.use(async (req, res, next) => {\n const url = req.url ?? '/'\n const pathname = url.split(/[?#]/u, 1)[0] ?? url\n\n if (pathname.includes('/assets/')) {\n const assetName = pathname.split('/assets/').pop()\n const assetPath = assetName ? contentAssets.get(assetName) : undefined\n\n if (assetPath) {\n const ext = extname(assetPath).toLowerCase()\n res.writeHead(200, {\n 'Content-Type': MIME[ext] ?? 'application/octet-stream',\n 'Cache-Control': 'no-cache',\n })\n res.end(readFileSync(assetPath))\n return\n }\n }\n\n // Only handle HTML navigation requests (not assets, not files with extensions)\n const accept = req.headers.accept ?? ''\n const pathExt = extname(pathname)\n if (pathExt && pathExt !== '.html') return next()\n if (!pathExt && !accept.includes('text/html')) return next()\n\n // Redirect root to base\n if (base && (url === '/' || url === '')) {\n res.writeHead(302, { Location: `${base}/` })\n res.end()\n return\n }\n\n // Must start with base path\n if (base && !url.startsWith(base)) return next()\n\n try {\n // Load SSR module on-the-fly (Vite transforms TSX etc.)\n const ssrMod = await server.ssrLoadModule(resolve(projectRoot, options.entry))\n const renderFn: (url: string, cfg: SsgRenderConfig) => Promise<string> | string =\n ssrMod.render\n\n if (typeof renderFn !== 'function') {\n return next()\n }\n\n const renderConfig: SsgRenderConfig = {\n base,\n root: projectRoot,\n cssPath: `${base}/src/theme.css`, // Vite transforms this in dev\n jsPath: undefined,\n searchEnabled: false,\n isDev: true,\n }\n\n let html = await renderFn(url, renderConfig)\n html = rewriteContentAssetRefs(html, base)\n\n // Inject Vite's client + HMR script for live reload\n html = html.replace(\n '</head>',\n `<script type=\"module\" src=\"/@vite/client\"></script>\\n` +\n `<link rel=\"stylesheet\" href=\"${base}/src/theme.css\">\\n` +\n `</head>`,\n )\n\n // Let Vite transform the HTML (resolves module URLs, etc.)\n html = await server.transformIndexHtml(url, html)\n\n const status = html.includes('doc-not-found') ? 404 : 200\n res.writeHead(status, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(html)\n } catch (err: any) {\n server.ssrFixStacktrace(err)\n console.error(`SSR error for ${url}:`, err.message)\n next(err)\n }\n })\n },\n }\n\n // ── Build plugin: SSG post-build ──\n const buildPlugin: Plugin = {\n name: 'pagesmith:ssg-build',\n apply: 'build',\n\n configResolved(resolved) {\n config = resolved\n projectRoot = resolved.root\n base = resolved.base.replace(/\\/+$/, '')\n outDir = resolve(projectRoot, resolved.build.outDir)\n contentDirs = resolveContentDirs(projectRoot, options.contentDirs)\n },\n\n async closeBundle() {\n // Skip SSG during the SSR build itself (detected by ssr option)\n if (config.build.ssr) return\n\n console.log('\\nSSG: Starting static site generation...')\n\n contentAssets = collectContentAssets(contentDirs)\n\n // Copy font assets from @pagesmith/core\n const corePkgDir = dirname(fileURLToPath(import.meta.resolve('@pagesmith/core/package.json')))\n const coreFontsDir = join(corePkgDir, 'assets', 'fonts')\n const outFontsDir = join(outDir, 'assets', 'fonts')\n mkdirSync(outFontsDir, { recursive: true })\n for (const file of readdirSync(coreFontsDir)) {\n if (file.endsWith('.woff2')) {\n copyFileSync(join(coreFontsDir, file), join(outFontsDir, file))\n }\n }\n copyFileSync(join(corePkgDir, 'assets', 'fonts.css'), join(outDir, 'assets', 'fonts.css'))\n\n // Copy public/ files (favicon etc.)\n const publicDir = join(projectRoot, 'public')\n copyPublicFiles(publicDir, outDir)\n\n // Discover built asset paths from the client build output\n const builtIndex = join(outDir, 'index.html')\n let cssPath = `${base}/assets/style.css`\n let jsPath: string | undefined\n if (existsSync(builtIndex)) {\n const html = readFileSync(builtIndex, 'utf-8')\n const cssMatch = html.match(/href=\"([^\"]*\\.css)\"/)\n const jsMatch = html.match(/src=\"([^\"]*\\.js)\"/)\n if (cssMatch) cssPath = cssMatch[1]\n if (jsMatch) jsPath = jsMatch[1]\n }\n\n // SSR build — use child process to avoid nested Vite resolution issues\n console.log('SSG: Building SSR bundle...')\n const { execFileSync } = await import('child_process')\n const serverDir = join(outDir, '.server')\n const ssrEntry = resolve(projectRoot, options.entry)\n // Write a temp build script that externalizes node_modules and skips the SSG plugin\n const buildScript = `\n import { build } from 'vite-plus';\n await build({\n root: ${JSON.stringify(projectRoot)},\n logLevel: 'warn',\n mode: ${JSON.stringify(config.mode)},\n build: {\n ssr: ${JSON.stringify(ssrEntry)},\n outDir: ${JSON.stringify(serverDir)},\n emptyOutDir: true,\n },\n });\n `\n execFileSync(process.execPath, ['--input-type=module', '-e', buildScript], {\n stdio: 'inherit',\n cwd: projectRoot,\n })\n\n // Load SSR module — derive output filename from the configured entry path\n const entryBaseName = basename(options.entry).replace(/\\.(c|m)?[jt]sx?$/u, '.js')\n const serverEntry = join(serverDir, entryBaseName)\n const ssrMod = await import(pathToFileURL(serverEntry).href)\n\n const renderConfig: SsgRenderConfig = {\n base,\n root: projectRoot,\n cssPath,\n jsPath,\n searchEnabled: true,\n isDev: false,\n }\n\n // Get routes and render\n const routes: string[] = await ssrMod.getRoutes(renderConfig)\n console.log(`SSG: Rendering ${routes.length} pages...`)\n\n for (const route of routes) {\n const html = rewriteContentAssetRefs(await ssrMod.render(route, renderConfig), base)\n const routePath = route === '/' ? '' : route.replace(/^\\//, '')\n const outputPath = join(outDir, routePath, 'index.html')\n mkdirSync(dirname(outputPath), { recursive: true })\n writeFileSync(outputPath, `<!DOCTYPE html>\\n${html}`)\n\n if (route === '/404') {\n writeFileSync(join(outDir, '404.html'), `<!DOCTYPE html>\\n${html}`)\n }\n }\n\n copyContentAssetsToOutDir(outDir, contentAssets)\n\n // Cleanup SSR build\n rmSync(serverDir, { recursive: true, force: true })\n\n // Run pagefind\n if (enablePagefind) {\n console.log('SSG: Indexing with Pagefind...')\n try {\n const pagefindMain = fileURLToPath(import.meta.resolve('pagefind'))\n const pagefindBin = join(dirname(pagefindMain), '..', 'lib', 'runner', 'bin.cjs')\n const { execFileSync } = await import('child_process')\n execFileSync(process.execPath, [pagefindBin, '--site', outDir], { stdio: 'inherit' })\n } catch {\n console.warn('SSG: Pagefind not found, skipping search indexing')\n }\n }\n\n console.log(`SSG: Done — ${routes.length} pages generated`)\n },\n }\n\n return [devPlugin, buildPlugin]\n}\n","export { prerenderRoutes } from './ssg'\nexport type { PrerenderOptions } from './ssg'\nexport { sharedAssetsPlugin } from './shared-assets.js'\nexport { pagesmithSsg } from './ssg-plugin.js'\nexport type { SsgPluginOptions, SsgRenderConfig } from './ssg-plugin.js'\n\nimport { existsSync, mkdirSync, writeFileSync } from 'fs'\nimport { dirname, relative, resolve } from 'path'\nimport { uneval } from 'devalue'\nimport { createContentLayer } from '../content-layer'\nimport { resolveLoader } from '../loaders'\nimport type { Heading } from '../schemas/heading'\nimport type { CollectionDef, CollectionMap, InferCollectionData } from '../schemas/collection'\nimport type { ContentLayerConfig } from '../schemas/content-config'\nimport { toSlug } from '../utils/slug'\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {}\n\ntype PagesmithResolvedConfig = {\n root: string\n}\n\ntype PagesmithModuleGraph = {\n getModuleById(id: string): unknown\n invalidateModule(module: unknown): void\n}\n\ntype PagesmithDevServer = {\n moduleGraph: PagesmithModuleGraph\n ws: {\n send(payload: { type: string }): void\n }\n}\n\nexport type PagesmithVitePlugin = {\n name: string\n enforce?: 'pre' | 'post'\n configResolved?: (config: PagesmithResolvedConfig) => void\n buildStart?: () => void\n resolveId?: (id: string) => string | void\n load?: (id: string) => Promise<string | void> | string | void\n handleHotUpdate?: (context: { file: string; server: PagesmithDevServer }) => void\n}\n\nexport type BaseContentModuleEntry = {\n id: string\n contentSlug: string\n}\n\nexport type MarkdownContentModuleEntry<TCollection extends CollectionDef<any, any, any>> = Simplify<\n BaseContentModuleEntry & {\n html: string\n headings: Heading[]\n frontmatter: InferCollectionData<TCollection>\n }\n>\n\nexport type DataContentModuleEntry<TCollection extends CollectionDef<any, any, any>> = Simplify<\n BaseContentModuleEntry & {\n data: InferCollectionData<TCollection>\n }\n>\n\ntype LoaderKindFromCollection<TCollection extends CollectionDef<any, any, any>> =\n TCollection['loader'] extends 'markdown'\n ? 'markdown'\n : TCollection['loader'] extends { kind: infer TKind }\n ? TKind\n : 'data'\n\nexport type ContentCollectionModule<TCollection extends CollectionDef<any, any, any>> =\n LoaderKindFromCollection<TCollection> extends 'markdown'\n ? MarkdownContentModuleEntry<TCollection>[]\n : DataContentModuleEntry<TCollection>[]\n\nexport type ContentModuleMap<TCollections extends CollectionMap> = {\n [TName in keyof TCollections]: ContentCollectionModule<TCollections[TName]>\n}\n\nexport type PagesmithContentPluginOptions<TCollections extends CollectionMap> = Omit<\n ContentLayerConfig,\n 'collections'\n> & {\n collections: TCollections\n /**\n * Shared content root used to compute `id` and `contentSlug`.\n * Defaults to the deepest common parent directory across all collection directories.\n */\n contentRoot?: string\n /**\n * Root virtual module id.\n * Per-collection modules are exposed as `${moduleId}/<collection-name>`.\n */\n moduleId?: string\n /**\n * Path to the content config module used for generated typings.\n * Defaults to `./content.config.ts`.\n */\n configPath?: string\n /**\n * Generate module declarations for the virtual modules.\n * Defaults to `src/pagesmith-content.d.ts` when `src/` exists, otherwise `pagesmith-content.d.ts`.\n */\n dts?: boolean | string | { path?: string }\n}\n\nconst DEFAULT_MODULE_ID = 'virtual:content'\n\nfunction stripExtension(filePath: string): string {\n return filePath.replace(/\\.(c|m)?[jt]sx?$/u, '')\n}\n\nfunction normalizePath(value: string): string {\n return value.replace(/\\\\/g, '/')\n}\n\nfunction isPathWithin(parent: string, candidate: string): boolean {\n const rel = normalizePath(relative(parent, candidate))\n return rel === '' || (!rel.startsWith('..') && !rel.startsWith('/'))\n}\n\nfunction commonDirectory(paths: string[]): string {\n const normalized = paths.map((path) => normalizePath(resolve(path)))\n if (normalized.length === 0) return process.cwd()\n if (normalized.length === 1) return normalized[0]\n\n const segments = normalized.map((path) => path.split('/').filter(Boolean))\n const shared: string[] = []\n const first = segments[0]!\n\n for (let index = 0; index < first.length; index += 1) {\n const segment = first[index]\n if (segments.every((parts) => parts[index] === segment)) {\n shared.push(segment)\n continue\n }\n break\n }\n\n if (shared.length === 0) {\n return resolve('/')\n }\n\n return resolve(`/${shared.join('/')}`)\n}\n\nfunction resolveDtsPath(\n projectRoot: string,\n dts: PagesmithContentPluginOptions<any>['dts'],\n): string {\n if (dts === false) {\n return ''\n }\n\n if (typeof dts === 'string') {\n return resolve(projectRoot, dts)\n }\n\n if (typeof dts === 'object' && dts?.path) {\n return resolve(projectRoot, dts.path)\n }\n\n const srcPath = resolve(projectRoot, 'src')\n if (existsSync(srcPath)) {\n return resolve(srcPath, 'pagesmith-content.d.ts')\n }\n\n return resolve(projectRoot, 'pagesmith-content.d.ts')\n}\n\nfunction createDtsSource(\n moduleId: string,\n collectionNames: string[],\n dtsPath: string,\n configPath: string,\n): string {\n const configImportPath = normalizePath(\n stripExtension(relative(dirname(dtsPath), configPath)).replace(/^[^.]/u, './$&'),\n )\n\n const moduleLines = collectionNames\n .map(\n (name) => `declare module '${moduleId}/${name}' {\n const collection: import('@pagesmith/core/vite').ContentCollectionModule<\n __PagesmithCollections['${name.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}']\n >\n export default collection\n}`,\n )\n .join('\\n\\n')\n\n return `// Generated by @pagesmith/core/vite. Do not edit manually.\ntype __PagesmithCollections = typeof import('${configImportPath}').default\n\ndeclare module '${moduleId}' {\n const content: import('@pagesmith/core/vite').ContentModuleMap<__PagesmithCollections>\n export default content\n}\n\n${moduleLines}\n`\n}\n\nasync function serializeCollection(\n layer: ReturnType<typeof createContentLayer>,\n collectionName: string,\n collectionDef: CollectionDef<any, any, any>,\n contentRoot: string,\n): Promise<string> {\n const entries = await layer.getCollection(collectionName)\n const loader = resolveLoader(collectionDef.loader)\n const sortedEntries = [...entries].sort((left, right) =>\n left.filePath.localeCompare(right.filePath),\n )\n\n const payload = await Promise.all(\n sortedEntries.map(async (entry) => {\n const contentSlug = toSlug(entry.filePath, contentRoot)\n const base = {\n id: contentSlug,\n contentSlug,\n }\n\n if (loader.kind === 'markdown') {\n const rendered = await entry.render()\n return {\n ...base,\n html: rendered.html,\n headings: rendered.headings,\n frontmatter: entry.data,\n }\n }\n\n return {\n ...base,\n data: entry.data,\n }\n }),\n )\n\n return `const collection = ${uneval(payload)};\\nexport default collection;\\n`\n}\n\nfunction createRootModuleSource(moduleId: string, collectionNames: string[]): string {\n const imports = collectionNames\n .map((name, index) => `import collection${index} from '${moduleId}/${name}'`)\n .join('\\n')\n const contentMap = collectionNames\n .map((name, index) => `${JSON.stringify(name)}: collection${index}`)\n .join(', ')\n\n return `${imports}\\n\\nexport default { ${contentMap} };\\n`\n}\n\nfunction resolvePluginOptions<TCollections extends CollectionMap>(\n collectionsOrOptions: TCollections | PagesmithContentPluginOptions<TCollections>,\n maybeOptions: Omit<PagesmithContentPluginOptions<TCollections>, 'collections'> = {},\n): PagesmithContentPluginOptions<TCollections> {\n if ('collections' in collectionsOrOptions) {\n return collectionsOrOptions as PagesmithContentPluginOptions<TCollections>\n }\n\n return {\n ...maybeOptions,\n collections: collectionsOrOptions,\n }\n}\n\nexport function pagesmithContent<TCollections extends CollectionMap>(\n collections: TCollections,\n options?: Omit<PagesmithContentPluginOptions<TCollections>, 'collections'>,\n): PagesmithVitePlugin\nexport function pagesmithContent<TCollections extends CollectionMap>(\n options: PagesmithContentPluginOptions<TCollections>,\n): PagesmithVitePlugin\nexport function pagesmithContent<TCollections extends CollectionMap>(\n collectionsOrOptions: TCollections | PagesmithContentPluginOptions<TCollections>,\n maybeOptions: Omit<PagesmithContentPluginOptions<TCollections>, 'collections'> = {},\n): PagesmithVitePlugin {\n const options = resolvePluginOptions(collectionsOrOptions, maybeOptions)\n const collectionNames = Object.keys(options.collections)\n const moduleId = options.moduleId ?? DEFAULT_MODULE_ID\n const resolvedPrefix = `\\0${moduleId}/`\n const resolvedRootId = `\\0${moduleId}`\n\n let projectRoot = process.cwd()\n let layerRoot = projectRoot\n let contentRoot = projectRoot\n let configPath = resolve(projectRoot, options.configPath ?? 'content.config.ts')\n let dtsPath = resolveDtsPath(projectRoot, options.dts)\n let layer: ReturnType<typeof createContentLayer> | null = null\n\n function getLayer(): ReturnType<typeof createContentLayer> {\n if (!layer) {\n throw new Error(\n 'pagesmith-content: ContentLayer not initialized. configResolved has not run yet.',\n )\n }\n return layer\n }\n\n const ensureDeclarations = (): void => {\n if (options.dts === false) return\n\n const source = createDtsSource(moduleId, collectionNames, dtsPath, configPath)\n mkdirSync(dirname(dtsPath), { recursive: true })\n writeFileSync(dtsPath, source)\n }\n\n return {\n name: 'pagesmith-content',\n enforce: 'pre',\n\n configResolved(config) {\n projectRoot = resolve(config.root)\n layerRoot = resolve(projectRoot, options.root ?? '.')\n configPath = resolve(projectRoot, options.configPath ?? 'content.config.ts')\n dtsPath = resolveDtsPath(projectRoot, options.dts)\n\n const collectionDirectories = collectionNames.map((name) =>\n resolve(layerRoot, options.collections[name]!.directory),\n )\n contentRoot = options.contentRoot\n ? resolve(layerRoot, options.contentRoot)\n : commonDirectory(collectionDirectories)\n\n layer = createContentLayer({\n ...options,\n root: layerRoot,\n })\n\n ensureDeclarations()\n },\n\n buildStart() {\n ensureDeclarations()\n },\n\n resolveId(id) {\n if (id === moduleId) {\n return resolvedRootId\n }\n\n for (const name of collectionNames) {\n if (id === `${moduleId}/${name}`) {\n return `${resolvedPrefix}${name}`\n }\n }\n },\n\n async load(id) {\n if (id === resolvedRootId) {\n return createRootModuleSource(moduleId, collectionNames)\n }\n\n if (!id.startsWith(resolvedPrefix)) return\n\n const collectionName = id.slice(resolvedPrefix.length)\n const collectionDef = options.collections[collectionName]\n if (!collectionDef) return\n\n return serializeCollection(getLayer(), collectionName, collectionDef, contentRoot)\n },\n\n handleHotUpdate({ file, server }) {\n const resolvedFile = resolve(file)\n const touchesConfig = resolvedFile === configPath\n\n // Determine which collection(s) the changed file belongs to\n const affectedCollections = collectionNames.filter((name) =>\n isPathWithin(resolve(layerRoot, options.collections[name]!.directory), resolvedFile),\n )\n\n const touchesContent = affectedCollections.length > 0\n\n if (!touchesConfig && !touchesContent) return\n\n if (touchesConfig) {\n ensureDeclarations()\n }\n\n const rootModule = server.moduleGraph.getModuleById(resolvedRootId)\n if (rootModule) {\n server.moduleGraph.invalidateModule(rootModule)\n }\n\n if (touchesContent) {\n // Only invalidate affected collections instead of all\n for (const name of affectedCollections) {\n const moduleNode = server.moduleGraph.getModuleById(`${resolvedPrefix}${name}`)\n if (moduleNode) {\n server.moduleGraph.invalidateModule(moduleNode)\n }\n getLayer()\n .invalidateCollection(name)\n .catch((err) => {\n console.warn(`[pagesmith] Failed to invalidate collection \"${name}\":`, err)\n })\n }\n } else {\n // Config change: invalidate all collection modules\n for (const name of collectionNames) {\n const moduleNode = server.moduleGraph.getModuleById(`${resolvedPrefix}${name}`)\n if (moduleNode) {\n server.moduleGraph.invalidateModule(moduleNode)\n }\n }\n getLayer().invalidateAll()\n }\n\n server.ws.send({ type: 'full-reload' })\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["normalizePath"],"sources":["../../src/vite/ssg.ts","../../src/vite/shared-assets.ts","../../src/vite/ssg-render.ts","../../src/vite/ssg-hmr.ts","../../src/vite/ssg-pagefind.ts","../../src/vite/ssg-plugin.ts","../../src/vite/dts.ts","../../src/vite/content-plugin.ts"],"sourcesContent":["/**\n * Pre-rendering utility for Vite-based SSG sites.\n *\n * Call after running both the client and SSR Vite builds.\n * Loads the SSR module, renders each route, injects into the\n * client HTML template, and writes static files.\n */\n\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { pathToFileURL } from 'url'\n\nexport type PrerenderOptions = {\n /** Absolute path to the client build output directory (e.g., `dist/`) */\n outDir: string\n /** Absolute path to the built SSR entry module (e.g., `dist/.server/entry-server.js`) */\n serverEntry: string\n /** Routes to pre-render (e.g., `['/', '/about', '/posts/hello-world']`) */\n routes: string[]\n /** HTML placeholder to replace with rendered content (default: `'<!--ssr-outlet-->'`) */\n placeholder?: string\n /** Remove the server build directory after pre-rendering (default: true) */\n cleanup?: boolean\n}\n\n/**\n * Pre-render routes to static HTML files.\n *\n * Expects the SSR entry to export a `render(url: string): string` function.\n *\n * @example\n * ```ts\n * import { build } from 'vite'\n * import { prerenderRoutes } from '@pagesmith/core/vite'\n *\n * // 1. Client build\n * await build({ build: { outDir: 'dist' } })\n *\n * // 2. SSR build\n * await build({ build: { ssr: 'src/entry-server.tsx', outDir: 'dist/.server' } })\n *\n * // 3. Pre-render\n * await prerenderRoutes({\n * outDir: resolve('dist'),\n * serverEntry: resolve('dist/.server/entry-server.js'),\n * routes: ['/', '/about', '/posts/hello-world'],\n * })\n * ```\n */\nexport async function prerenderRoutes(options: PrerenderOptions): Promise<{ pages: number }> {\n const placeholder = options.placeholder ?? '<!--ssr-outlet-->'\n const cleanup = options.cleanup ?? true\n\n // Load SSR module\n if (!existsSync(options.serverEntry)) {\n throw new Error(`SSR entry not found: ${options.serverEntry}`)\n }\n\n const mod = await import(pathToFileURL(options.serverEntry).href)\n const render: (url: string) => string | Promise<string> = mod.render ?? mod.default?.render\n\n if (typeof render !== 'function') {\n throw new Error(\n `SSR entry must export a 'render(url: string)' function. ` +\n `Found exports: ${Object.keys(mod).join(', ')}`,\n )\n }\n\n // Read client HTML template\n const templatePath = resolve(options.outDir, 'index.html')\n const template = readFileSync(templatePath, 'utf-8')\n\n if (!template.includes(placeholder)) {\n throw new Error(\n `HTML template does not contain placeholder \"${placeholder}\". ` +\n `Add it to your index.html where SSR content should be injected.`,\n )\n }\n\n // Pre-render each route\n for (const route of options.routes) {\n const rendered = await render(route)\n const html = template.replace(placeholder, rendered)\n\n const routePath = route === '/' ? '' : route.replace(/^\\//, '')\n const outPath = resolve(options.outDir, routePath, 'index.html')\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, html)\n }\n\n // Clean up server build\n if (cleanup) {\n const serverDir = dirname(options.serverEntry)\n rmSync(serverDir, { recursive: true, force: true })\n }\n\n return { pages: options.routes.length }\n}\n","import { existsSync, readFileSync } from 'fs'\nimport { dirname, join } from 'path'\nimport { fileURLToPath } from 'url'\nimport type { Plugin } from 'vite'\n\n/**\n * Vite plugin that serves shared font assets during development.\n * In production, fonts are copied to the output directory by the build script.\n */\nexport function sharedAssetsPlugin(): Plugin {\n const pkgDir = join(dirname(fileURLToPath(import.meta.url)), '..', '..')\n const assetsDir = join(pkgDir, 'assets')\n\n return {\n name: 'pagesmith:shared-assets',\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const url = req.url ?? ''\n\n // Serve fonts.css\n if (url === '/assets/fonts.css' || url.endsWith('/assets/fonts.css')) {\n const filePath = join(assetsDir, 'fonts.css')\n if (existsSync(filePath)) {\n res.writeHead(200, { 'Content-Type': 'text/css', 'Cache-Control': 'no-cache' })\n res.end(readFileSync(filePath, 'utf-8'))\n return\n }\n }\n\n // Serve font files\n if (url.includes('/assets/fonts/') && url.endsWith('.woff2')) {\n const fileName = url.split('/assets/fonts/').pop()\n if (fileName) {\n const filePath = join(assetsDir, 'fonts', fileName)\n if (existsSync(filePath)) {\n res.writeHead(200, {\n 'Content-Type': 'font/woff2',\n 'Cache-Control': 'public, max-age=31536000',\n })\n res.end(readFileSync(filePath))\n return\n }\n }\n }\n\n next()\n })\n },\n }\n}\n","/**\n * Route collection, pre-rendering, and content asset handling for the SSG plugin.\n *\n * Provides:\n * - Content companion asset discovery and copying\n * - HTML asset reference rewriting\n * - SSR bundle building via child process\n * - Route pre-rendering to static HTML files\n * - Font and public file copying\n */\n\nimport {\n copyFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from 'fs'\nimport { basename, dirname, extname, join, resolve } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\nimport type { ResolvedConfig } from 'vite'\nimport { collectContentAssets, CONTENT_ASSET_EXTS, copyPublicFiles } from '../assets'\nimport type { SsgRenderConfig } from './ssg-plugin'\n\nexport const MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.ico': 'image/x-icon',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ttf': 'font/ttf',\n '.txt': 'text/plain; charset=utf-8',\n '.xml': 'application/xml; charset=utf-8',\n}\n\n// ── Content directory helpers ──\n\nexport function resolveContentDirs(projectRoot: string, contentDirs: string[] = []): string[] {\n return contentDirs.map((dir) => resolve(projectRoot, dir))\n}\n\nfunction isAssetReference(ref: string): boolean {\n if (!ref.startsWith('./')) return false\n const path = ref.split(/[?#]/u, 1)[0] ?? ref\n return CONTENT_ASSET_EXTS.has(extname(path).toLowerCase())\n}\n\nexport function rewriteContentAssetRefs(html: string, base: string): string {\n const basePrefix = base.replace(/\\/+$/u, '')\n\n return html.replace(\n /(src|href|srcset)=(?:\"([^\"]+)\"|'([^']+)')/g,\n (match, attr: string, doubleRef: string | undefined, singleRef: string | undefined) => {\n const ref = doubleRef ?? singleRef ?? ''\n if (!isAssetReference(ref)) return match\n const pathname = ref.split(/[?#]/u, 1)[0] ?? ref\n const suffix = ref.slice(pathname.length)\n const quote = doubleRef !== undefined ? '\"' : \"'\"\n return `${attr}=${quote}${basePrefix}/assets/${pathname.split('/').pop() ?? pathname}${suffix}${quote}`\n },\n )\n}\n\nfunction copyContentAssetsToOutDir(outDir: string, assets: Map<string, string>): void {\n if (assets.size === 0) return\n\n const assetsDir = join(outDir, 'assets')\n mkdirSync(assetsDir, { recursive: true })\n\n for (const [fileName, sourcePath] of assets) {\n copyFileSync(sourcePath, join(assetsDir, fileName))\n }\n}\n\n// ── Build-time rendering ──\n\nexport type SsgBuildContext = {\n /** Vite resolved config */\n config: ResolvedConfig\n /** Absolute path to the project root */\n projectRoot: string\n /** Base path without trailing slash (e.g., '/my-site') */\n base: string\n /** Absolute path to the build output directory */\n outDir: string\n /** Resolved content directories (absolute paths) */\n contentDirs: string[]\n /** Path to the SSR entry module */\n entry: string\n}\n\n/**\n * Run the full SSG build: SSR bundle, route pre-rendering, asset copying.\n *\n * Returns the number of pages rendered.\n */\nexport async function renderStaticSite(context: SsgBuildContext): Promise<number> {\n const { config, projectRoot, base, outDir, contentDirs, entry } = context\n\n console.log('\\nSSG: Starting static site generation...')\n\n const contentAssets = collectContentAssets(contentDirs)\n\n // Copy font assets from @pagesmith/core\n copyFontAssets(outDir)\n\n // Copy public/ files (favicon etc.)\n const publicDir = join(projectRoot, 'public')\n copyPublicFiles(publicDir, outDir)\n\n // Discover built asset paths from the client build output\n const { cssPath, jsPath } = discoverBuiltAssets(outDir, base)\n\n // SSR build — use child process to avoid nested Vite resolution issues\n console.log('SSG: Building SSR bundle...')\n await buildSsrBundle(config, projectRoot, outDir, entry)\n\n // Load SSR module — derive output filename from the configured entry path\n const entryBaseName = basename(entry).replace(/\\.(c|m)?[jt]sx?$/u, '.js')\n const serverDir = join(outDir, '.server')\n const serverEntry = join(serverDir, entryBaseName)\n const ssrMod = await import(pathToFileURL(serverEntry).href)\n\n const renderConfig: SsgRenderConfig = {\n base,\n root: projectRoot,\n cssPath,\n jsPath,\n searchEnabled: true,\n isDev: false,\n }\n\n // Get routes and render with bounded concurrency\n const routes: string[] = await ssrMod.getRoutes(renderConfig)\n console.log(`SSG: Rendering ${routes.length} pages...`)\n\n const concurrency = Math.min(routes.length, 8)\n let routeIndex = 0\n\n async function renderWorker(): Promise<void> {\n while (routeIndex < routes.length) {\n const i = routeIndex++\n const route = routes[i]\n const html = rewriteContentAssetRefs(await ssrMod.render(route, renderConfig), base)\n const routePath = route === '/' ? '' : route.replace(/^\\//, '')\n const outputPath = join(outDir, routePath, 'index.html')\n mkdirSync(dirname(outputPath), { recursive: true })\n writeFileSync(outputPath, `<!DOCTYPE html>\\n${html}`)\n\n if (route === '/404') {\n writeFileSync(join(outDir, '404.html'), `<!DOCTYPE html>\\n${html}`)\n }\n }\n }\n\n const workers = Array.from({ length: concurrency }, () => renderWorker())\n await Promise.all(workers)\n\n copyContentAssetsToOutDir(outDir, contentAssets)\n\n // Cleanup SSR build\n rmSync(serverDir, { recursive: true, force: true })\n\n return routes.length\n}\n\nfunction copyFontAssets(outDir: string): void {\n const corePkgDir = dirname(fileURLToPath(import.meta.resolve('@pagesmith/core/package.json')))\n const coreFontsDir = join(corePkgDir, 'assets', 'fonts')\n const outFontsDir = join(outDir, 'assets', 'fonts')\n mkdirSync(outFontsDir, { recursive: true })\n for (const file of readdirSync(coreFontsDir)) {\n if (file.endsWith('.woff2')) {\n copyFileSync(join(coreFontsDir, file), join(outFontsDir, file))\n }\n }\n copyFileSync(join(corePkgDir, 'assets', 'fonts.css'), join(outDir, 'assets', 'fonts.css'))\n}\n\nfunction discoverBuiltAssets(\n outDir: string,\n base: string,\n): { cssPath: string; jsPath: string | undefined } {\n const builtIndex = join(outDir, 'index.html')\n let cssPath = `${base}/assets/style.css`\n let jsPath: string | undefined\n if (existsSync(builtIndex)) {\n const html = readFileSync(builtIndex, 'utf-8')\n const cssMatch = html.match(/href=\"([^\"]*\\.css)\"/)\n const jsMatch = html.match(/src=\"([^\"]*\\.js)\"/)\n if (cssMatch) cssPath = cssMatch[1]\n if (jsMatch) jsPath = jsMatch[1]\n }\n return { cssPath, jsPath }\n}\n\nasync function buildSsrBundle(\n config: ResolvedConfig,\n projectRoot: string,\n outDir: string,\n entry: string,\n): Promise<void> {\n const { execFileSync } = await import('child_process')\n const serverDir = join(outDir, '.server')\n const ssrEntry = resolve(projectRoot, entry)\n // Write a temp build script that externalizes node_modules and skips the SSG plugin\n const buildScript = `\n import { build } from 'vite';\n await build({\n root: ${JSON.stringify(projectRoot)},\n logLevel: 'warn',\n mode: ${JSON.stringify(config.mode)},\n build: {\n ssr: ${JSON.stringify(ssrEntry)},\n outDir: ${JSON.stringify(serverDir)},\n emptyOutDir: true,\n },\n });\n `\n execFileSync(process.execPath, ['--input-type=module', '-e', buildScript], {\n stdio: 'inherit',\n cwd: projectRoot,\n })\n}\n","/**\n * Dev-server middleware for the SSG plugin.\n *\n * Handles on-the-fly SSR rendering during development, including:\n * - Content companion asset serving from content directories\n * - HTML navigation request handling via server-side rendering\n * - Vite HMR client injection for live reload\n */\n\nimport { extname, resolve } from 'path'\nimport { readFileSync } from 'fs'\nimport type { ViteDevServer } from 'vite'\nimport type { SsgRenderConfig } from './ssg-plugin'\nimport { collectContentAssets } from '../assets'\nimport { MIME, rewriteContentAssetRefs } from './ssg-render'\n\nconst WS_RELOAD_SCRIPT = `<script type=\"module\">\nimport 'vite/modulepreload-polyfill'\nif (import.meta.hot) {\n import.meta.hot.on('full-reload', () => location.reload())\n}\n</script>`\n\nexport type SsgDevContext = {\n /** Absolute path to the project root */\n projectRoot: string\n /** Base path without trailing slash (e.g., '/my-site') */\n base: string\n /** Resolved content directories (absolute paths) */\n contentDirs: string[]\n /** Path to the SSR entry module */\n entry: string\n}\n\n/**\n * Configure the Vite dev server with SSR middleware for on-the-fly rendering.\n *\n * Sets up:\n * - File watcher for content companion assets\n * - Middleware for serving companion assets from `/assets/` paths\n * - Middleware for SSR-rendering HTML navigation requests\n */\nexport function configureSsgDevServer(server: ViteDevServer, context: SsgDevContext): void {\n const { projectRoot, base, contentDirs, entry } = context\n let contentAssets = new Map<string, string>()\n\n async function refreshContentArtifacts(): Promise<void> {\n contentAssets = collectContentAssets(contentDirs)\n }\n\n void refreshContentArtifacts().catch((error) => {\n console.warn(\n `pagesmith:ssg failed to prepare companion assets: ${error instanceof Error ? error.message : String(error)}`,\n )\n })\n\n if (contentDirs.length > 0) {\n server.watcher.add(contentDirs)\n\n const refresh = () => {\n void refreshContentArtifacts().catch((error) => {\n console.warn(\n `pagesmith:ssg failed to refresh companion assets: ${error instanceof Error ? error.message : String(error)}`,\n )\n })\n }\n\n server.watcher.on('add', refresh)\n server.watcher.on('change', refresh)\n server.watcher.on('unlink', refresh)\n }\n\n // Register middleware directly — appType: 'custom' disables Vite's\n // built-in HTML serving, so we handle all HTML requests via SSR.\n server.middlewares.use(async (req, res, next) => {\n const url = req.url ?? '/'\n const pathname = url.split(/[?#]/u, 1)[0] ?? url\n\n if (pathname.includes('/assets/')) {\n const assetName = pathname.split('/assets/').pop()\n const assetPath = assetName ? contentAssets.get(assetName) : undefined\n\n if (assetPath) {\n const ext = extname(assetPath).toLowerCase()\n res.writeHead(200, {\n 'Content-Type': MIME[ext] ?? 'application/octet-stream',\n 'Cache-Control': 'no-cache',\n })\n res.end(readFileSync(assetPath))\n return\n }\n }\n\n // Only handle HTML navigation requests (not assets, not files with extensions)\n const accept = req.headers.accept ?? ''\n const pathExt = extname(pathname)\n if (pathExt && pathExt !== '.html') return next()\n if (!pathExt && !accept.includes('text/html')) return next()\n\n // Redirect root to base\n if (base && (url === '/' || url === '')) {\n res.writeHead(302, { Location: `${base}/` })\n res.end()\n return\n }\n\n // Must start with base path\n if (base && !url.startsWith(base)) return next()\n\n try {\n // Load SSR module on-the-fly (Vite transforms TSX etc.)\n const ssrMod = await server.ssrLoadModule(resolve(projectRoot, entry))\n const renderFn: (url: string, cfg: SsgRenderConfig) => Promise<string> | string =\n ssrMod.render\n\n if (typeof renderFn !== 'function') {\n return next()\n }\n\n const renderConfig: SsgRenderConfig = {\n base,\n root: projectRoot,\n cssPath: `${base}/src/theme.css`, // Vite transforms this in dev\n jsPath: undefined,\n searchEnabled: false,\n isDev: true,\n }\n\n let html = await renderFn(url, renderConfig)\n html = rewriteContentAssetRefs(html, base)\n\n // Inject Vite's client + HMR script for live reload\n html = html.replace(\n '</head>',\n `<script type=\"module\" src=\"/@vite/client\"></script>\\n` +\n `<link rel=\"stylesheet\" href=\"${base}/src/theme.css\">\\n` +\n `</head>`,\n )\n\n // Let Vite transform the HTML (resolves module URLs, etc.)\n html = await server.transformIndexHtml(url, html)\n\n const status = html.includes('doc-not-found') ? 404 : 200\n res.writeHead(status, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(html)\n } catch (err: unknown) {\n server.ssrFixStacktrace(err as Error)\n console.error(`SSR error for ${url}:`, err instanceof Error ? err.message : String(err))\n next(err)\n }\n })\n}\n","/**\n * Pagefind search indexing for the SSG plugin.\n *\n * Runs the Pagefind CLI to index the generated static site output,\n * producing the search index used by the docs theme.\n */\n\nimport { dirname, join } from 'path'\nimport { fileURLToPath } from 'url'\n\n/**\n * Run Pagefind indexing on the built site output directory.\n *\n * Resolves the Pagefind binary from the installed package and invokes it\n * via a child process. Logs a warning and continues if Pagefind is not\n * installed.\n */\nexport async function runPagefindIndexing(outDir: string): Promise<void> {\n console.log('SSG: Indexing with Pagefind...')\n try {\n const pagefindMain = fileURLToPath(import.meta.resolve('pagefind'))\n const pagefindBin = join(dirname(pagefindMain), '..', 'lib', 'runner', 'bin.cjs')\n const { execFileSync } = await import('child_process')\n execFileSync(process.execPath, [pagefindBin, '--site', outDir], { stdio: 'inherit' })\n } catch {\n console.warn('SSG: Pagefind not found, skipping search indexing')\n }\n}\n","/**\n * Vite plugin for static site generation with @pagesmith/core.\n *\n * Handles both development (on-the-fly SSR via middleware) and\n * production (post-build SSG + pagefind indexing).\n *\n * The SSR entry module must export:\n * - `getRoutes(config)` — returns route paths to pre-render\n * - `render(url, config)` — renders a route to an HTML string\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { pagesmithSsg } from '@pagesmith/core/vite'\n *\n * export default defineConfig({\n * base: '/my-site/',\n * plugins: [pagesmithSsg({ entry: './src/entry-server.tsx' })],\n * })\n * ```\n */\n\nimport { resolve } from 'path'\nimport type { Plugin, ResolvedConfig } from 'vite'\nimport { configureSsgDevServer } from './ssg-hmr'\nimport { resolveContentDirs, renderStaticSite } from './ssg-render'\nimport { runPagefindIndexing } from './ssg-pagefind'\n\nexport type SsgPluginOptions = {\n /** Path to the SSR entry module (e.g., './src/entry-server.tsx') */\n entry: string\n /** Run pagefind after build (default: true) */\n pagefind?: boolean\n /** Content roots used for copying companion assets. */\n contentDirs?: string[]\n}\n\nexport type SsgRenderConfig = {\n /** Base path without trailing slash (e.g., '/my-site') */\n base: string\n /** Absolute path to the project root */\n root: string\n /** Path to the built CSS asset */\n cssPath: string\n /** Path to the built JS asset (undefined in dev for inline-script examples) */\n jsPath?: string\n /** Whether search is enabled (false in dev) */\n searchEnabled: boolean\n /** Whether running in dev mode */\n isDev: boolean\n}\n\nexport function pagesmithSsg(options: SsgPluginOptions): Plugin[] {\n const enablePagefind = options.pagefind !== false\n let config: ResolvedConfig\n let projectRoot: string\n let base: string // e.g., '/my-site'\n let outDir: string\n let contentDirs: string[] = []\n\n // ── Dev plugin: SSR middleware ──\n const devPlugin: Plugin = {\n name: 'pagesmith:ssg-dev',\n apply: 'serve',\n\n config() {\n // Disable Vite's built-in SPA HTML serving so the SSG middleware\n // can handle all HTML requests via server-side rendering.\n return { appType: 'custom' }\n },\n\n configResolved(resolved) {\n config = resolved\n projectRoot = resolved.root\n base = resolved.base.replace(/\\/+$/, '')\n outDir = resolve(projectRoot, resolved.build.outDir)\n contentDirs = resolveContentDirs(projectRoot, options.contentDirs)\n },\n\n configureServer(server) {\n configureSsgDevServer(server, {\n projectRoot,\n base,\n contentDirs,\n entry: options.entry,\n })\n },\n }\n\n // ── Build plugin: SSG post-build ──\n const buildPlugin: Plugin = {\n name: 'pagesmith:ssg-build',\n apply: 'build',\n\n configResolved(resolved) {\n config = resolved\n projectRoot = resolved.root\n base = resolved.base.replace(/\\/+$/, '')\n outDir = resolve(projectRoot, resolved.build.outDir)\n contentDirs = resolveContentDirs(projectRoot, options.contentDirs)\n },\n\n async closeBundle() {\n // Skip SSG during the SSR build itself (detected by ssr option)\n if (config.build.ssr) return\n\n const pageCount = await renderStaticSite({\n config,\n projectRoot,\n base,\n outDir,\n contentDirs,\n entry: options.entry,\n })\n\n if (enablePagefind) {\n await runPagefindIndexing(outDir)\n }\n\n console.log(`SSG: Done — ${pageCount} pages generated`)\n },\n }\n\n return [devPlugin, buildPlugin]\n}\n","import { existsSync } from 'fs'\nimport { dirname, relative, resolve } from 'path'\nimport type { PagesmithContentPluginOptions } from './content-plugin'\n\nfunction stripExtension(filePath: string): string {\n return filePath.replace(/\\.(c|m)?[jt]sx?$/u, '')\n}\n\nfunction normalizePath(value: string): string {\n return value.replace(/\\\\/g, '/')\n}\n\nexport function resolveDtsPath(\n projectRoot: string,\n dts: PagesmithContentPluginOptions<any>['dts'],\n): string {\n if (dts === false) {\n return ''\n }\n\n if (typeof dts === 'string') {\n return resolve(projectRoot, dts)\n }\n\n if (typeof dts === 'object' && dts?.path) {\n return resolve(projectRoot, dts.path)\n }\n\n const srcPath = resolve(projectRoot, 'src')\n if (existsSync(srcPath)) {\n return resolve(srcPath, 'pagesmith-content.d.ts')\n }\n\n return resolve(projectRoot, 'pagesmith-content.d.ts')\n}\n\nexport function createDtsSource(\n moduleId: string,\n collectionNames: string[],\n dtsPath: string,\n configPath: string,\n): string {\n const configImportPath = normalizePath(\n stripExtension(relative(dirname(dtsPath), configPath)).replace(/^[^.]/u, './$&'),\n )\n\n const moduleLines = collectionNames\n .map(\n (name) => `declare module '${moduleId}/${name}' {\n const collection: import('@pagesmith/core/vite').ContentCollectionModule<\n __PagesmithCollections['${name.replaceAll('\\\\', '\\\\\\\\').replaceAll(\"'\", \"\\\\'\")}']\n >\n export default collection\n}`,\n )\n .join('\\n\\n')\n\n return `// Generated by @pagesmith/core/vite. Do not edit manually.\ntype __PagesmithCollections = typeof import('${configImportPath}').default\n\ndeclare module '${moduleId}' {\n const content: import('@pagesmith/core/vite').ContentModuleMap<__PagesmithCollections>\n export default content\n}\n\n${moduleLines}\n`\n}\n","import { mkdirSync, writeFileSync } from 'fs'\nimport { dirname, relative, resolve } from 'path'\nimport { uneval } from 'devalue'\nimport { createContentLayer } from '../content-layer'\nimport { resolveLoader } from '../loaders'\nimport type { Heading } from '../schemas/heading'\nimport type { CollectionDef, CollectionMap, InferCollectionData } from '../schemas/collection'\nimport type { ContentLayerConfig } from '../schemas/content-config'\nimport { toSlug } from '../utils/slug'\nimport { createDtsSource, resolveDtsPath } from './dts'\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {}\n\ntype PagesmithResolvedConfig = {\n root: string\n}\n\ntype PagesmithModuleGraph = {\n getModuleById(id: string): unknown\n invalidateModule(module: unknown): void\n}\n\ntype PagesmithDevServer = {\n moduleGraph: PagesmithModuleGraph\n ws: {\n send(payload: { type: string }): void\n }\n}\n\nexport type PagesmithVitePlugin = {\n name: string\n enforce?: 'pre' | 'post'\n configResolved?: (config: PagesmithResolvedConfig) => void\n buildStart?: () => void\n resolveId?: (id: string) => string | void\n load?: (id: string) => Promise<string | void> | string | void\n handleHotUpdate?: (context: { file: string; server: PagesmithDevServer }) => void\n}\n\nexport type BaseContentModuleEntry = {\n id: string\n contentSlug: string\n}\n\nexport type MarkdownContentModuleEntry<TCollection extends CollectionDef<any, any, any>> = Simplify<\n BaseContentModuleEntry & {\n html: string\n headings: Heading[]\n frontmatter: InferCollectionData<TCollection>\n }\n>\n\nexport type DataContentModuleEntry<TCollection extends CollectionDef<any, any, any>> = Simplify<\n BaseContentModuleEntry & {\n data: InferCollectionData<TCollection>\n }\n>\n\ntype LoaderKindFromCollection<TCollection extends CollectionDef<any, any, any>> =\n TCollection['loader'] extends 'markdown'\n ? 'markdown'\n : TCollection['loader'] extends { kind: infer TKind }\n ? TKind\n : 'data'\n\nexport type ContentCollectionModule<TCollection extends CollectionDef<any, any, any>> =\n LoaderKindFromCollection<TCollection> extends 'markdown'\n ? MarkdownContentModuleEntry<TCollection>[]\n : DataContentModuleEntry<TCollection>[]\n\nexport type ContentModuleMap<TCollections extends CollectionMap> = {\n [TName in keyof TCollections]: ContentCollectionModule<TCollections[TName]>\n}\n\nexport type PagesmithContentPluginOptions<TCollections extends CollectionMap> = Omit<\n ContentLayerConfig,\n 'collections'\n> & {\n collections: TCollections\n /**\n * Shared content root used to compute `id` and `contentSlug`.\n * Defaults to the deepest common parent directory across all collection directories.\n */\n contentRoot?: string\n /**\n * Root virtual module id.\n * Per-collection modules are exposed as `${moduleId}/<collection-name>`.\n */\n moduleId?: string\n /**\n * Path to the content config module used for generated typings.\n * Defaults to `./content.config.ts`.\n */\n configPath?: string\n /**\n * Generate module declarations for the virtual modules.\n * Defaults to `src/pagesmith-content.d.ts` when `src/` exists, otherwise `pagesmith-content.d.ts`.\n */\n dts?: boolean | string | { path?: string }\n}\n\nconst DEFAULT_MODULE_ID = 'virtual:content'\n\nfunction normalizePath(value: string): string {\n return value.replace(/\\\\/g, '/')\n}\n\nfunction isPathWithin(parent: string, candidate: string): boolean {\n const rel = normalizePath(relative(parent, candidate))\n return rel === '' || (!rel.startsWith('..') && !rel.startsWith('/'))\n}\n\nfunction commonDirectory(paths: string[]): string {\n const normalized = paths.map((path) => normalizePath(resolve(path)))\n if (normalized.length === 0) return process.cwd()\n if (normalized.length === 1) return normalized[0]\n\n const segments = normalized.map((path) => path.split('/').filter(Boolean))\n const shared: string[] = []\n const first = segments[0]!\n\n for (let index = 0; index < first.length; index += 1) {\n const segment = first[index]\n if (segments.every((parts) => parts[index] === segment)) {\n shared.push(segment)\n continue\n }\n break\n }\n\n if (shared.length === 0) {\n return resolve('/')\n }\n\n return resolve(`/${shared.join('/')}`)\n}\n\nasync function serializeCollection(\n layer: ReturnType<typeof createContentLayer>,\n collectionName: string,\n collectionDef: CollectionDef<any, any, any>,\n contentRoot: string,\n): Promise<string> {\n const entries = await layer.getCollection(collectionName)\n const loader = resolveLoader(collectionDef.loader)\n const sortedEntries = [...entries].sort((left, right) =>\n left.filePath.localeCompare(right.filePath),\n )\n\n const payload = await Promise.all(\n sortedEntries.map(async (entry) => {\n const contentSlug = toSlug(entry.filePath, contentRoot)\n const base = {\n id: contentSlug,\n contentSlug,\n }\n\n if (loader.kind === 'markdown') {\n const rendered = await entry.render()\n return {\n ...base,\n html: rendered.html,\n headings: rendered.headings,\n frontmatter: entry.data,\n }\n }\n\n return {\n ...base,\n data: entry.data,\n }\n }),\n )\n\n return `const collection = ${uneval(payload)};\\nexport default collection;\\n`\n}\n\nfunction createRootModuleSource(moduleId: string, collectionNames: string[]): string {\n const imports = collectionNames\n .map((name, index) => `import collection${index} from '${moduleId}/${name}'`)\n .join('\\n')\n const contentMap = collectionNames\n .map((name, index) => `${JSON.stringify(name)}: collection${index}`)\n .join(', ')\n\n return `${imports}\\n\\nexport default { ${contentMap} };\\n`\n}\n\nfunction resolvePluginOptions<TCollections extends CollectionMap>(\n collectionsOrOptions: TCollections | PagesmithContentPluginOptions<TCollections>,\n maybeOptions: Omit<PagesmithContentPluginOptions<TCollections>, 'collections'> = {},\n): PagesmithContentPluginOptions<TCollections> {\n if ('collections' in collectionsOrOptions) {\n return collectionsOrOptions as PagesmithContentPluginOptions<TCollections>\n }\n\n return {\n ...maybeOptions,\n collections: collectionsOrOptions,\n }\n}\n\nexport function pagesmithContent<TCollections extends CollectionMap>(\n collections: TCollections,\n options?: Omit<PagesmithContentPluginOptions<TCollections>, 'collections'>,\n): PagesmithVitePlugin\nexport function pagesmithContent<TCollections extends CollectionMap>(\n options: PagesmithContentPluginOptions<TCollections>,\n): PagesmithVitePlugin\nexport function pagesmithContent<TCollections extends CollectionMap>(\n collectionsOrOptions: TCollections | PagesmithContentPluginOptions<TCollections>,\n maybeOptions: Omit<PagesmithContentPluginOptions<TCollections>, 'collections'> = {},\n): PagesmithVitePlugin {\n const options = resolvePluginOptions(collectionsOrOptions, maybeOptions)\n const collectionNames = Object.keys(options.collections)\n const moduleId = options.moduleId ?? DEFAULT_MODULE_ID\n const resolvedPrefix = `\\0${moduleId}/`\n const resolvedRootId = `\\0${moduleId}`\n\n let projectRoot = process.cwd()\n let layerRoot = projectRoot\n let contentRoot = projectRoot\n let configPath = resolve(projectRoot, options.configPath ?? 'content.config.ts')\n let dtsPath = resolveDtsPath(projectRoot, options.dts)\n let layer: ReturnType<typeof createContentLayer> | null = null\n\n function getLayer(): ReturnType<typeof createContentLayer> {\n if (!layer) {\n throw new Error(\n 'pagesmith-content: ContentLayer not initialized. configResolved has not run yet.',\n )\n }\n return layer\n }\n\n const ensureDeclarations = (): void => {\n if (options.dts === false) return\n\n const source = createDtsSource(moduleId, collectionNames, dtsPath, configPath)\n mkdirSync(dirname(dtsPath), { recursive: true })\n writeFileSync(dtsPath, source)\n }\n\n return {\n name: 'pagesmith-content',\n enforce: 'pre',\n\n configResolved(config) {\n projectRoot = resolve(config.root)\n layerRoot = resolve(projectRoot, options.root ?? '.')\n configPath = resolve(projectRoot, options.configPath ?? 'content.config.ts')\n dtsPath = resolveDtsPath(projectRoot, options.dts)\n\n const collectionDirectories = collectionNames.map((name) =>\n resolve(layerRoot, options.collections[name]!.directory),\n )\n contentRoot = options.contentRoot\n ? resolve(layerRoot, options.contentRoot)\n : commonDirectory(collectionDirectories)\n\n layer = createContentLayer({\n ...options,\n root: layerRoot,\n })\n\n ensureDeclarations()\n },\n\n buildStart() {\n ensureDeclarations()\n },\n\n resolveId(id) {\n if (id === moduleId) {\n return resolvedRootId\n }\n\n for (const name of collectionNames) {\n if (id === `${moduleId}/${name}`) {\n return `${resolvedPrefix}${name}`\n }\n }\n },\n\n async load(id) {\n if (id === resolvedRootId) {\n return createRootModuleSource(moduleId, collectionNames)\n }\n\n if (!id.startsWith(resolvedPrefix)) return\n\n const collectionName = id.slice(resolvedPrefix.length)\n const collectionDef = options.collections[collectionName]\n if (!collectionDef) return\n\n return serializeCollection(getLayer(), collectionName, collectionDef, contentRoot)\n },\n\n handleHotUpdate({ file, server }) {\n const resolvedFile = resolve(file)\n const touchesConfig = resolvedFile === configPath\n\n const affectedCollections = collectionNames.filter((name) =>\n isPathWithin(resolve(layerRoot, options.collections[name]!.directory), resolvedFile),\n )\n\n const touchesContent = affectedCollections.length > 0\n\n if (!touchesConfig && !touchesContent) return\n\n if (touchesConfig) {\n ensureDeclarations()\n }\n\n const rootModule = server.moduleGraph.getModuleById(resolvedRootId)\n if (rootModule) {\n server.moduleGraph.invalidateModule(rootModule)\n }\n\n if (touchesContent) {\n for (const name of affectedCollections) {\n const moduleNode = server.moduleGraph.getModuleById(`${resolvedPrefix}${name}`)\n if (moduleNode) {\n server.moduleGraph.invalidateModule(moduleNode)\n }\n getLayer()\n .invalidateCollection(name)\n .catch((err) => {\n console.warn(`[pagesmith] Failed to invalidate collection \"${name}\":`, err)\n })\n }\n } else {\n for (const name of collectionNames) {\n const moduleNode = server.moduleGraph.getModuleById(`${resolvedPrefix}${name}`)\n if (moduleNode) {\n server.moduleGraph.invalidateModule(moduleNode)\n }\n }\n getLayer().invalidateAll()\n }\n\n server.ws.send({ type: 'full-reload' })\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ # Project AI Pointers (Template)
2
+
3
+ ## @pagesmith/core
4
+
5
+ Use the installed package guidance, not copied snippets:
6
+
7
+ - `node_modules/@pagesmith/core/docs/agents/usage.md`
8
+ - `node_modules/@pagesmith/core/docs/agents/recipes.md`
9
+ - `node_modules/@pagesmith/core/REFERENCE.md`
@@ -0,0 +1,15 @@
1
+ # @pagesmith/core Changelog Notes
2
+
3
+ ## v0.3.0
4
+
5
+ - Added `TypedContentLayer` for type-safe `getCollection<K>()` and `getEntry<K>()` with full Zod schema inference
6
+ - Added `layer.watch()` for file-watching with automatic cache invalidation
7
+ - Added MCP server (`@pagesmith/core/mcp`) with `core_list_collections`, `core_get_entry`, `core_validate` tools
8
+ - Added explicit MCP subpath packaging (`@pagesmith/core/mcp`) and Vite SSG helpers split into focused modules
9
+ - Refactored `@pagesmith/core/vite` into thin barrel exports with dedicated plugin modules
10
+ - Hardened MCP Zod schema introspection to use public Zod APIs (removes dependency on internal `_zod` structure)
11
+ - Optimized `getEntry()` miss-path behavior to avoid redundant collection reloads after first load
12
+ - Added `docs/agents/migration.md` with pre-1.0 upgrade guidance
13
+ - AI installer split into focused modules for maintainability
14
+ - AI exports removed from main barrel — use `@pagesmith/core/ai` subpath or CLI `npx pagesmith init --ai`
15
+ - Scripts converted from JavaScript to TypeScript (using `node --strip-types`)
@@ -0,0 +1,96 @@
1
+ # Pagesmith Error Catalog
2
+
3
+ Machine-readable error solutions for AI agents. Each section maps a common error pattern to its fix.
4
+
5
+ ## Schema Validation Errors
6
+
7
+ ### Required field missing
8
+ **Pattern:** `Required at "<field>"`
9
+ **Fix:** Add the missing field to your frontmatter. Check the collection schema for required fields.
10
+ **Example:**
11
+ ```yaml
12
+ ---
13
+ title: My Page # ← required by BaseFrontmatterSchema
14
+ description: A summary # ← required by BaseFrontmatterSchema
15
+ ---
16
+ ```
17
+
18
+ ### Invalid date format
19
+ **Pattern:** `Expected date, received string` or `Invalid date`
20
+ **Fix:** Use ISO 8601 format: `YYYY-MM-DD` or `YYYY-MM-DDTHH:mm:ss`.
21
+ **Example:** `publishedDate: 2024-01-15`
22
+
23
+ ### Unknown field
24
+ **Pattern:** `Unrecognized key(s) in object: "<field>"`
25
+ **Fix:** The schema uses `.strict()`. Remove the unrecognized field or update the schema to include it.
26
+
27
+ ### Type mismatch
28
+ **Pattern:** `Expected <type>, received <type>`
29
+ **Fix:** Ensure the frontmatter value matches the schema type. Common mismatches:
30
+ - `tags` must be an array: `tags: [a, b]` not `tags: a, b`
31
+ - `draft` must be boolean: `draft: true` not `draft: "true"`
32
+ - `order` must be number: `order: 1` not `order: "1"`
33
+
34
+ ## Content Validation Errors
35
+
36
+ ### Missing heading
37
+ **Pattern:** `No h1 heading found`
38
+ **Fix:** Add a top-level `# Heading` to your markdown content, or set `title` in frontmatter (some setups auto-generate h1 from title).
39
+
40
+ ### Heading level skip
41
+ **Pattern:** `Heading level skipped from h<n> to h<m>`
42
+ **Fix:** Don't skip heading levels. After `## Section`, use `### Subsection`, not `#### Deep`.
43
+
44
+ ### Bare URL
45
+ **Pattern:** `Bare URL found`
46
+ **Fix:** Wrap URLs in markdown links: `[Link text](https://example.com)` instead of bare `https://example.com`.
47
+
48
+ ### Missing code language
49
+ **Pattern:** `Code block without language specifier`
50
+ **Fix:** Add a language to fenced code blocks: ` ```js ` instead of ` ``` `.
51
+
52
+ ### Unknown code language
53
+ **Pattern:** `Unknown language "<lang>"`
54
+ **Fix:** Use a supported language identifier. Common mappings: `ts` for TypeScript, `js` for JavaScript, `sh`/`bash` for Shell. See Expressive Code language list.
55
+
56
+ ## Plugin Validation Errors
57
+
58
+ ### Plugin threw
59
+ **Pattern:** `Validator "<name>" threw: <message>`
60
+ **Fix:** A custom or plugin validator encountered an unexpected error. Check the plugin's documentation for the specific error message. The validator name identifies which plugin failed.
61
+
62
+ ## Load Errors
63
+
64
+ ### File not found
65
+ **Pattern:** `Failed to load <path>: ENOENT`
66
+ **Fix:** The file was deleted or moved. Update your content directory or remove the reference.
67
+
68
+ ### Invalid YAML frontmatter
69
+ **Pattern:** `Failed to load <path>: YAMLException`
70
+ **Fix:** Check frontmatter YAML syntax. Common issues:
71
+ - Missing `---` delimiters
72
+ - Unquoted special characters (`:`, `#`, `[`, `{`)
73
+ - Incorrect indentation
74
+
75
+ ### Invalid JSON
76
+ **Pattern:** `Failed to load <path>: JSON` or `Unexpected token`
77
+ **Fix:** Validate your JSON/JSON5 file syntax. Use a JSON linter.
78
+
79
+ ## MCP Server Errors
80
+
81
+ ### Config not found
82
+ **Pattern:** `No pagesmith.config.json5 file found`
83
+ **Fix:** Run `npx pagesmith init` to create a config file, or pass `--config <path>` to specify the location.
84
+
85
+ ### Entry not found
86
+ **Pattern:** `Entry not found: <collection>/<slug>`
87
+ **Fix:** Verify the collection name and slug. Use `core_list_entries` to see available entries.
88
+
89
+ ## Quick Diagnostic Workflow
90
+
91
+ When encountering an error:
92
+
93
+ 1. **Identify the source** — check the `source` field: `schema`, `content`, `plugin`, or `custom`
94
+ 2. **Match the pattern** — find the error pattern above
95
+ 3. **Apply the fix** — follow the specific fix instructions
96
+ 4. **Re-validate** — use `core_validate` MCP tool or rebuild to confirm the fix
@@ -0,0 +1,25 @@
1
+ # @pagesmith/core Migration Notes (Pre-1.0)
2
+
3
+ `@pagesmith/core` is pre-1.0. Minor releases can include breaking changes while API boundaries settle.
4
+
5
+ ## Upgrade checklist
6
+
7
+ 1. Prefer subpath imports from the package export map:
8
+ - `@pagesmith/core/vite`
9
+ - `@pagesmith/core/mcp`
10
+ - `@pagesmith/core/ssg-utils`
11
+ 2. Keep Vite integration scripts aligned with current examples (`vite dev`, `vite build`) in downstream projects.
12
+ 3. Re-run validation and tests after upgrade:
13
+ - `vp check`
14
+ - `vp test`
15
+
16
+ ## Behavior updates to note
17
+
18
+ - `getEntry(collection, slug)` now short-circuits misses once a collection is loaded, avoiding redundant reload work.
19
+ - MCP schema introspection uses public Zod APIs, so custom schema wrappers should continue to use standard `zod` object/optional/nullable wrappers.
20
+ - Vite integration is organized around thin barrel exports and focused plugin modules (`content-plugin`, `ssg-plugin`).
21
+
22
+ ## Related docs
23
+
24
+ - `docs/agents/changelog-notes.md`
25
+ - `REFERENCE.md`
@@ -0,0 +1,26 @@
1
+ # @pagesmith/core Agent Recipes
2
+
3
+ ## Create a collection
4
+
5
+ 1. Add a directory under `content/`.
6
+ 2. Define schema with `z` from `@pagesmith/core`.
7
+ 3. Register with `defineCollection`.
8
+ 4. Expose via `defineCollections` or `defineConfig`.
9
+
10
+ ## Add Vite integration
11
+
12
+ 1. Import `pagesmithContent` and `pagesmithSsg` from `@pagesmith/core/vite`.
13
+ 2. Register content plugin before SSG output steps.
14
+ 3. Ensure SSR entry exports `getRoutes` and `render`.
15
+
16
+ ## Update markdown behavior
17
+
18
+ 1. Update config through markdown options (`remarkPlugins`, `rehypePlugins`, `shiki`).
19
+ 2. Keep plugin order consistent with pipeline expectations.
20
+ 3. Validate with rendered output and built-in validators.
21
+
22
+ ## Update AI pointers in consuming project
23
+
24
+ Add one pointer line to root `CLAUDE.md` or `AGENTS.md`:
25
+
26
+ `Use node_modules/@pagesmith/core/docs/agents/usage.md as the canonical @pagesmith/core guide.`
@@ -0,0 +1,58 @@
1
+ # @pagesmith/core Usage For AI Agents
2
+
3
+ Use this file as the primary instruction source for `@pagesmith/core`.
4
+
5
+ ## When to pick @pagesmith/core
6
+
7
+ - Custom site or app architecture.
8
+ - Framework-specific rendering (React, Solid, Svelte, EJS, Handlebars).
9
+ - Need full control over layout, routing, rendering, and content loading.
10
+
11
+ ## Required integration shape
12
+
13
+ 1. Define collections with `defineCollection` or `defineCollections`.
14
+ 2. Use `defineConfig` + `createContentLayer` for content loading.
15
+ 3. For Vite flows, use `@pagesmith/core/vite` plugins (`pagesmithContent`, `pagesmithSsg`).
16
+ 4. Use `entry.render()` when HTML is needed (lazy render path).
17
+
18
+ ## Non-negotiable rules
19
+
20
+ - Keep schema validation in collection schemas (`z` from `@pagesmith/core`).
21
+ - Prefer folder-based content entries if pages use sibling assets.
22
+ - Keep markdown behavior aligned with core markdown pipeline and validators.
23
+ - Do not add ad-hoc code-block copy button JS; Expressive Code already handles this.
24
+
25
+ ## Reference docs
26
+
27
+ - API reference: `node_modules/@pagesmith/core/REFERENCE.md`
28
+ - Recipes: `node_modules/@pagesmith/core/docs/agents/recipes.md`
29
+ - Version notes: `node_modules/@pagesmith/core/docs/agents/changelog-notes.md`
30
+ - Migration notes: `node_modules/@pagesmith/core/docs/agents/migration.md`
31
+
32
+ ## MCP Introspection Workflows
33
+
34
+ ### Discover and validate all collections
35
+
36
+ ```
37
+ 1. Call core_list_collections → get all collection names and schema fields
38
+ 2. For each collection, call core_validate → get validation results
39
+ 3. Fix any issues found using the error catalog
40
+ ```
41
+
42
+ ### Find and update content
43
+
44
+ ```
45
+ 1. Call core_search_entries with query → find matching entries
46
+ 2. Call core_get_entry with collection and slug → get full content
47
+ 3. Edit the source file at the returned filePath
48
+ 4. Call core_validate to confirm the change is valid
49
+ ```
50
+
51
+ ### Audit content quality
52
+
53
+ ```
54
+ 1. Call core_list_collections → enumerate all collections
55
+ 2. For each, call core_list_entries → get all entries
56
+ 3. Call core_validate → collect all issues
57
+ 4. Group issues by source (schema/content/plugin) for prioritized fixing
58
+ ```
@@ -0,0 +1,53 @@
1
+ # @pagesmith/core Full AI Reference
2
+
3
+ This file is the package-shipped source of truth for AI assistants using `@pagesmith/core`.
4
+
5
+ ## Priority order
6
+
7
+ 1. `docs/agents/usage.md` for package rules and integration contract.
8
+ 2. `docs/agents/recipes.md` for implementation patterns.
9
+ 3. `REFERENCE.md` for complete API details.
10
+
11
+ ## Key rules
12
+
13
+ - Use `@pagesmith/core` for custom-site scenarios; do not force docs conventions from `@pagesmith/docs`.
14
+ - Prefer `defineCollection`, `defineConfig`, and `createContentLayer`.
15
+ - Prefer folder-based markdown entries when pages reference sibling assets.
16
+ - Keep content validation in collection schemas and validators, not scattered in app code.
17
+ - Treat Expressive Code as the source for code-block UI; do not add separate copy-button scripts.
18
+
19
+ ## Exposed files
20
+
21
+ - `node_modules/@pagesmith/core/docs/llms.txt`
22
+ - `node_modules/@pagesmith/core/docs/llms-full.txt`
23
+ - `node_modules/@pagesmith/core/docs/agents/usage.md`
24
+ - `node_modules/@pagesmith/core/docs/agents/recipes.md`
25
+ - `node_modules/@pagesmith/core/docs/agents/errors.md`
26
+ - `node_modules/@pagesmith/core/docs/agents/changelog-notes.md`
27
+ - `node_modules/@pagesmith/core/docs/agents/migration.md`
28
+ - `node_modules/@pagesmith/core/docs/agents/AGENTS.md.template`
29
+
30
+ ## Pointer snippet for consuming projects
31
+
32
+ Add this snippet to project-level memory files:
33
+
34
+ `Read node_modules/@pagesmith/core/docs/agents/usage.md before suggesting or editing @pagesmith/core setup.`
35
+
36
+ ## Validation
37
+
38
+ `ValidationIssue` includes an optional `source` field (`'schema' | 'content' | 'plugin' | 'custom'`) that identifies which validation phase produced the issue. Use this to categorize and prioritize fixes.
39
+
40
+ ## MCP tools
41
+
42
+ The core MCP server (`@pagesmith/core/mcp`) exposes:
43
+
44
+ - `core_list_collections` — list all collections with loader type, directory, and schema fields
45
+ - `core_list_entries` — list entries in a collection (paginated, limit/offset)
46
+ - `core_get_entry` — load a single entry with rendered HTML, headings, and read time
47
+ - `core_validate` — run validation on one or all collections
48
+ - `core_search_entries` — search entries by title, description, tags, slug (case-insensitive, max 20)
49
+
50
+ Shared utilities exported from `@pagesmith/core/mcp`:
51
+ - `getPackageVersion(moduleDir)` — read version from package.json
52
+ - `resolvePackageDocPath(moduleDir, relativePath)` — resolve doc file path
53
+ - `asTextResource(uri, path)` — load file as MCP text resource
package/docs/llms.txt ADDED
@@ -0,0 +1,29 @@
1
+ # @pagesmith/core
2
+
3
+ Version-matched AI context for the installed `@pagesmith/core` package.
4
+
5
+ ## Use this package when
6
+
7
+ - You need a custom content architecture, custom layouts, or framework-specific rendering.
8
+ - You want typed content collections with explicit schemas and runtime control.
9
+
10
+ ## Canonical usage guidance
11
+
12
+ - `node_modules/@pagesmith/core/docs/agents/usage.md`
13
+ - `node_modules/@pagesmith/core/docs/agents/recipes.md`
14
+ - `node_modules/@pagesmith/core/docs/agents/errors.md`
15
+ - `node_modules/@pagesmith/core/docs/agents/migration.md`
16
+ - `node_modules/@pagesmith/core/REFERENCE.md`
17
+
18
+ ## Project memory pointer
19
+
20
+ In the consuming project, add this to `CLAUDE.md` or `AGENTS.md`:
21
+
22
+ `For @pagesmith/core usage rules, read node_modules/@pagesmith/core/docs/agents/usage.md`
23
+
24
+ ## Recent changes
25
+
26
+ - `ValidationIssue` now includes an optional `source` field (`'schema' | 'content' | 'plugin' | 'custom'`) to identify which validation phase produced the issue.
27
+ - New `core_search_entries` MCP tool: search entries across collections by title, description, tags, and slug (case-insensitive, max 20 results).
28
+ - `@pagesmith/core/mcp` now exports shared MCP utilities (`getPackageVersion`, `resolvePackageDocPath`, `asTextResource`) alongside the server factory.
29
+ - Error catalog added at `agents/errors.md` with machine-readable patterns and fixes for schema, content, plugin, load, and MCP errors.