@pagesmith/core 0.3.0 → 0.4.1
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.
- package/README.md +28 -4
- package/REFERENCE.md +163 -94
- package/dist/ai/index.d.mts +5 -3
- package/dist/ai/index.d.mts.map +1 -1
- package/dist/ai/index.mjs +300 -206
- package/dist/ai/index.mjs.map +1 -1
- package/dist/assets/index.d.mts +10 -1
- package/dist/assets/index.d.mts.map +1 -1
- package/dist/assets/index.mjs +2 -2
- package/dist/{assets-DXiWF_KI.mjs → assets-CAPOqQ_P.mjs} +42 -5
- package/dist/assets-CAPOqQ_P.mjs.map +1 -0
- package/dist/{content-config-Bfe4W9us.d.mts → content-config-Bu2HH0Yx.d.mts} +49 -17
- package/dist/{content-config-Bfe4W9us.d.mts.map → content-config-Bu2HH0Yx.d.mts.map} +1 -1
- package/dist/{content-layer-DPK1EmfY.mjs → content-layer-CJRrNpZ_.mjs} +192 -36
- package/dist/content-layer-CJRrNpZ_.mjs.map +1 -0
- package/dist/content-layer-Ckt08g2i.d.mts +122 -0
- package/dist/content-layer-Ckt08g2i.d.mts.map +1 -0
- package/dist/create/index.d.mts.map +1 -1
- package/dist/create/index.mjs +31 -30
- package/dist/create/index.mjs.map +1 -1
- package/dist/css/index.d.mts +1 -1
- package/dist/css/index.mjs +1 -1
- package/dist/css-CO3CBqxx.mjs +24 -0
- package/dist/css-CO3CBqxx.mjs.map +1 -0
- package/dist/heading-D4X2L4vd.d.mts +12 -0
- package/dist/heading-D4X2L4vd.d.mts.map +1 -0
- package/dist/{index-BBYkDxwI.d.mts → index-B4YZRIzb.d.mts} +1 -1
- package/dist/{index-BBYkDxwI.d.mts.map → index-B4YZRIzb.d.mts.map} +1 -1
- package/dist/{index-Bg9srb5U.d.mts → index-B7NRZAxd.d.mts} +1 -1
- package/dist/{index-Bg9srb5U.d.mts.map → index-B7NRZAxd.d.mts.map} +1 -1
- package/dist/{index-YXQxMV6J.d.mts → index-CryArLlX.d.mts} +2 -2
- package/dist/{index-YXQxMV6J.d.mts.map → index-CryArLlX.d.mts.map} +1 -1
- package/dist/{index-CbOKbkjJ.d.mts → index-D44syBt-.d.mts} +3 -2
- package/dist/index-D44syBt-.d.mts.map +1 -0
- package/dist/index.d.mts +16 -99
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +15 -11
- package/dist/index.mjs.map +1 -1
- package/dist/loaders/index.d.mts +2 -2
- package/dist/loaders/index.mjs +1 -1
- package/dist/{loaders-Cf-BXf2L.mjs → loaders-DnyWfANR.mjs} +3 -3
- package/dist/loaders-DnyWfANR.mjs.map +1 -0
- package/dist/markdown/index.d.mts +2 -2
- package/dist/markdown/index.mjs +1 -1
- package/dist/{markdown-CyrHoDhP.mjs → markdown-DMHd400a.mjs} +29 -2
- package/dist/markdown-DMHd400a.mjs.map +1 -0
- package/dist/{heading-BpDXnl-7.d.mts → markdown-config-CDvh5aJ-.d.mts} +2 -10
- package/dist/markdown-config-CDvh5aJ-.d.mts.map +1 -0
- package/dist/mcp/index.d.mts +23 -0
- package/dist/mcp/index.d.mts.map +1 -0
- package/dist/mcp/index.mjs +2 -0
- package/dist/mcp/server.d.mts +13 -0
- package/dist/mcp/server.d.mts.map +1 -0
- package/dist/mcp/server.mjs +2 -0
- package/dist/runtime/index.d.mts.map +1 -1
- package/dist/runtime/index.mjs +4 -9
- package/dist/runtime/index.mjs.map +1 -1
- package/dist/schemas/index.d.mts +4 -3
- package/dist/server-BZA_iSen.mjs +203 -0
- package/dist/server-BZA_iSen.mjs.map +1 -0
- package/dist/ssg-utils/index.d.mts +51 -0
- package/dist/ssg-utils/index.d.mts.map +1 -0
- package/dist/ssg-utils/index.mjs +119 -0
- package/dist/ssg-utils/index.mjs.map +1 -0
- package/dist/{types-Cn52sdoq.d.mts → types-B-V5qemH.d.mts} +1 -1
- package/dist/{types-Cn52sdoq.d.mts.map → types-B-V5qemH.d.mts.map} +1 -1
- package/dist/vite/index.d.mts +69 -34
- package/dist/vite/index.d.mts.map +1 -1
- package/dist/vite/index.mjs +296 -228
- package/dist/vite/index.mjs.map +1 -1
- package/docs/agents/AGENTS.md.template +29 -0
- package/docs/agents/changelog-notes.md +15 -0
- package/docs/agents/errors.md +150 -0
- package/docs/agents/migration.md +25 -0
- package/docs/agents/recipes.md +50 -0
- package/docs/agents/usage.md +119 -0
- package/docs/llms-full.txt +111 -0
- package/docs/llms.txt +68 -0
- package/package.json +57 -4
- package/dist/assets-DXiWF_KI.mjs.map +0 -1
- package/dist/content-layer-DPK1EmfY.mjs.map +0 -1
- package/dist/css-BneO430t.mjs +0 -20
- package/dist/css-BneO430t.mjs.map +0 -1
- package/dist/heading-BpDXnl-7.d.mts.map +0 -1
- package/dist/index-CbOKbkjJ.d.mts.map +0 -1
- package/dist/loaders-Cf-BXf2L.mjs.map +0 -1
- package/dist/markdown-CyrHoDhP.mjs.map +0 -1
package/dist/vite/index.mjs.map
CHANGED
|
@@ -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 && !fileName.includes('..') && !fileName.includes('/')) {\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\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 if (err instanceof Error) {\n server.ssrFixStacktrace(err)\n }\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,29 @@
|
|
|
1
|
+
# Project AI Pointers (Template)
|
|
2
|
+
|
|
3
|
+
## @pagesmith/core
|
|
4
|
+
|
|
5
|
+
Install: `npm add @pagesmith/core`
|
|
6
|
+
|
|
7
|
+
Use the installed package guidance — these files are version-matched to what you have installed:
|
|
8
|
+
|
|
9
|
+
### Primary references
|
|
10
|
+
|
|
11
|
+
- `node_modules/@pagesmith/core/REFERENCE.md` — complete API reference: content layer, collections, loaders, markdown, JSX, CSS, Vite plugins
|
|
12
|
+
- `node_modules/@pagesmith/core/docs/agents/usage.md` — agent rules, integration shape, and copy-paste prompts for common workflows
|
|
13
|
+
- `node_modules/@pagesmith/core/docs/agents/errors.md` — error catalog with patterns and fixes
|
|
14
|
+
|
|
15
|
+
### Task-specific files
|
|
16
|
+
|
|
17
|
+
| Task | Read |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Initial Vite setup | `node_modules/@pagesmith/core/REFERENCE.md`, `node_modules/@pagesmith/core/docs/agents/recipes.md` |
|
|
20
|
+
| Defining collections and schemas | `node_modules/@pagesmith/core/REFERENCE.md` |
|
|
21
|
+
| Writing markdown content (code blocks, mermaid, frontmatter) | `node_modules/@pagesmith/core/REFERENCE.md` |
|
|
22
|
+
| Customizing the markdown pipeline | `node_modules/@pagesmith/core/REFERENCE.md`, `node_modules/@pagesmith/core/docs/agents/recipes.md` |
|
|
23
|
+
| Troubleshooting validation errors | `node_modules/@pagesmith/core/docs/agents/errors.md` |
|
|
24
|
+
| Migration and upgrades | `node_modules/@pagesmith/core/docs/agents/migration.md`, `node_modules/@pagesmith/core/docs/agents/changelog-notes.md` |
|
|
25
|
+
|
|
26
|
+
### Docs package (if also using @pagesmith/docs)
|
|
27
|
+
|
|
28
|
+
- `node_modules/@pagesmith/docs/REFERENCE.md`
|
|
29
|
+
- `node_modules/@pagesmith/docs/docs/agents/usage.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,150 @@
|
|
|
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
|
+
|
|
9
|
+
**Pattern:** `Required at "<field>"`
|
|
10
|
+
**Fix:** Add the missing field to your frontmatter. Check the collection schema for required fields.
|
|
11
|
+
**Example:**
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
---
|
|
15
|
+
title: My Page # ← required by BaseFrontmatterSchema
|
|
16
|
+
description: A summary # ← required by BaseFrontmatterSchema
|
|
17
|
+
---
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Invalid date format
|
|
21
|
+
|
|
22
|
+
**Pattern:** `Expected date, received string` or `Invalid date`
|
|
23
|
+
**Fix:** Use ISO 8601 format: `YYYY-MM-DD` or `YYYY-MM-DDTHH:mm:ss`.
|
|
24
|
+
**Example:** `publishedDate: 2024-01-15`
|
|
25
|
+
|
|
26
|
+
### Unknown field
|
|
27
|
+
|
|
28
|
+
**Pattern:** `Unrecognized key(s) in object: "<field>"`
|
|
29
|
+
**Fix:** The schema uses `.strict()`. Remove the unrecognized field or update the schema to include it.
|
|
30
|
+
|
|
31
|
+
### Type mismatch
|
|
32
|
+
|
|
33
|
+
**Pattern:** `Expected <type>, received <type>`
|
|
34
|
+
**Fix:** Ensure the frontmatter value matches the schema type. Common mismatches:
|
|
35
|
+
|
|
36
|
+
- `tags` must be an array: `tags: [a, b]` not `tags: a, b`
|
|
37
|
+
- `draft` must be boolean: `draft: true` not `draft: "true"`
|
|
38
|
+
- `order` must be number: `order: 1` not `order: "1"`
|
|
39
|
+
|
|
40
|
+
## Content Validation Errors
|
|
41
|
+
|
|
42
|
+
### Missing heading
|
|
43
|
+
|
|
44
|
+
**Pattern:** `Document has content but no headings`
|
|
45
|
+
**Fix:** Add a top-level `# Heading` to your markdown content, or set `title` in frontmatter (some setups auto-generate h1 from title).
|
|
46
|
+
|
|
47
|
+
### Heading level skip
|
|
48
|
+
|
|
49
|
+
**Pattern:** `Heading level skip: h<n> -> h<m> ("<text>")`
|
|
50
|
+
**Fix:** Don't skip heading levels. After `## Section`, use `### Subsection`, not `#### Deep`.
|
|
51
|
+
|
|
52
|
+
### Bare URL
|
|
53
|
+
|
|
54
|
+
**Pattern:** `Bare URL found`
|
|
55
|
+
**Fix:** Wrap URLs in markdown links: `[Link text](https://example.com)` instead of bare `https://example.com`.
|
|
56
|
+
|
|
57
|
+
### Missing code language
|
|
58
|
+
|
|
59
|
+
**Pattern:** `Code block has meta properties but no language identifier`
|
|
60
|
+
**Fix:** Add a language identifier to code blocks that use meta properties like `title`, `mark`, etc.
|
|
61
|
+
|
|
62
|
+
### Unknown meta property
|
|
63
|
+
|
|
64
|
+
**Pattern:** `Unknown code block meta property: "<prop>"`
|
|
65
|
+
**Fix:** Use only supported Expressive Code meta properties: `title`, `showLineNumbers`, `startLineNumber`, `wrap`, `frame`, `collapse`, `mark`, `ins`, `del`.
|
|
66
|
+
|
|
67
|
+
### Unknown code language
|
|
68
|
+
|
|
69
|
+
**Pattern:** `Unknown language "<lang>"`
|
|
70
|
+
**Fix:** Use a supported language identifier. Common mappings: `ts` for TypeScript, `js` for JavaScript, `sh`/`bash` for Shell. See Expressive Code language list.
|
|
71
|
+
|
|
72
|
+
## Plugin Validation Errors
|
|
73
|
+
|
|
74
|
+
### Plugin threw
|
|
75
|
+
|
|
76
|
+
**Pattern:** `[<name>] Validator threw: <message>`
|
|
77
|
+
**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.
|
|
78
|
+
|
|
79
|
+
## Load Errors
|
|
80
|
+
|
|
81
|
+
### File not found
|
|
82
|
+
|
|
83
|
+
**Pattern:** `Failed to load <path>: ENOENT`
|
|
84
|
+
**Fix:** The file was deleted or moved. Update your content directory or remove the reference.
|
|
85
|
+
|
|
86
|
+
### Invalid YAML frontmatter
|
|
87
|
+
|
|
88
|
+
**Pattern:** `Failed to load <path>: YAMLException`
|
|
89
|
+
**Fix:** Check frontmatter YAML syntax. Common issues:
|
|
90
|
+
|
|
91
|
+
- Missing `---` delimiters
|
|
92
|
+
- Unquoted special characters (`:`, `#`, `[`, `{`)
|
|
93
|
+
- Incorrect indentation
|
|
94
|
+
|
|
95
|
+
### Invalid JSON
|
|
96
|
+
|
|
97
|
+
**Pattern:** `Failed to load <path>: JSON` or `Unexpected token`
|
|
98
|
+
**Fix:** Validate your JSON/JSON5 file syntax. Use a JSON linter.
|
|
99
|
+
|
|
100
|
+
## MCP Server Errors
|
|
101
|
+
|
|
102
|
+
### Config not found
|
|
103
|
+
|
|
104
|
+
**Pattern:** `No pagesmith.config.json5 file found at <path>`
|
|
105
|
+
**Fix:** Run `npx pagesmith init` to create a config file, or pass `--config <path>` to specify the location.
|
|
106
|
+
|
|
107
|
+
### Entry not found
|
|
108
|
+
|
|
109
|
+
**Pattern:** `Entry not found: <collection>/<slug>`
|
|
110
|
+
**Fix:** Verify the collection name and slug. Use `core_list_entries` to see available entries.
|
|
111
|
+
|
|
112
|
+
## Content Layer Errors
|
|
113
|
+
|
|
114
|
+
### Collection not found
|
|
115
|
+
|
|
116
|
+
**Pattern:** `Collection "<name>" not found. Available: <list>`
|
|
117
|
+
**Fix:** Check the collection name passed to `getCollection()` or `getEntry()`. The error lists all configured collection names — use one of those.
|
|
118
|
+
|
|
119
|
+
### Markdown processing failed
|
|
120
|
+
|
|
121
|
+
**Pattern:** `Markdown processing failed: <message>`
|
|
122
|
+
**Fix:** The unified markdown pipeline threw an error. Common causes:
|
|
123
|
+
|
|
124
|
+
- Invalid remark/rehype plugin configuration
|
|
125
|
+
- Malformed markdown that breaks a parser plugin
|
|
126
|
+
- Shiki theme or language loading failure
|
|
127
|
+
|
|
128
|
+
Check the inner error message for details. If caused by a custom plugin, verify the plugin implementation.
|
|
129
|
+
|
|
130
|
+
### Unknown loader type
|
|
131
|
+
|
|
132
|
+
**Pattern:** `Unknown loader type: <type>`
|
|
133
|
+
**Fix:** The `loader` field in your collection definition uses an unrecognized type string. Supported built-in types: `markdown`, `json`, `json5`, `jsonc`, `yaml`, `toml`. For custom loaders, pass a `Loader` object instead of a string.
|
|
134
|
+
|
|
135
|
+
## Vite Plugin Errors
|
|
136
|
+
|
|
137
|
+
### ContentLayer not initialized
|
|
138
|
+
|
|
139
|
+
**Pattern:** `pagesmith-content: ContentLayer not initialized. configResolved has not run yet.`
|
|
140
|
+
**Fix:** The `pagesmithContent` Vite plugin tried to load content before Vite called `configResolved`. This usually means the plugin was misconfigured or a module tried to import content at config time. Ensure the plugin is registered in `vite.config.ts` and content is only imported from application code (not config files).
|
|
141
|
+
|
|
142
|
+
## Quick Diagnostic Workflow
|
|
143
|
+
|
|
144
|
+
When encountering an error:
|
|
145
|
+
|
|
146
|
+
1. **Identify the source** — each `ValidationIssue` has a `source` field indicating where it originated: `schema` (Zod safeParse), `content` (MDAST-based validators), `plugin` (plugin validators), or `custom` (collection `validate` function)
|
|
147
|
+
2. **Match the pattern** — find the error pattern above
|
|
148
|
+
3. **Apply the fix** — follow the specific fix instructions
|
|
149
|
+
4. **Re-validate** — use `core_validate` MCP tool or rebuild to confirm the fix
|
|
150
|
+
|
|
@@ -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
|
+
- `node_modules/@pagesmith/core/docs/agents/changelog-notes.md`
|
|
25
|
+
- `node_modules/@pagesmith/core/REFERENCE.md`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @pagesmith/core Agent Recipes
|
|
2
|
+
|
|
3
|
+
Short procedural recipes for common content layer workflows. For the full reference, see `node_modules/@pagesmith/core/REFERENCE.md`.
|
|
4
|
+
|
|
5
|
+
## Create a collection
|
|
6
|
+
|
|
7
|
+
1. Add a directory under `content/`.
|
|
8
|
+
2. Define schema with `z` from `@pagesmith/core`.
|
|
9
|
+
3. Register with `defineCollection`.
|
|
10
|
+
4. Expose via `defineCollections` or `defineConfig`.
|
|
11
|
+
|
|
12
|
+
**Read:** `node_modules/@pagesmith/core/REFERENCE.md` (Content Layer API, Collections)
|
|
13
|
+
|
|
14
|
+
## Add Vite integration
|
|
15
|
+
|
|
16
|
+
1. Import `pagesmithContent` and `pagesmithSsg` from `@pagesmith/core/vite`.
|
|
17
|
+
2. Register content plugin before SSG output steps.
|
|
18
|
+
3. Ensure SSR entry exports `getRoutes` and `render`.
|
|
19
|
+
|
|
20
|
+
**Read:** `node_modules/@pagesmith/core/REFERENCE.md` (Vite Plugins)
|
|
21
|
+
|
|
22
|
+
## Write markdown content
|
|
23
|
+
|
|
24
|
+
1. Create markdown files with frontmatter (`title`, `description`, etc.).
|
|
25
|
+
2. Use fenced code blocks with language identifiers.
|
|
26
|
+
3. Use Expressive Code meta for titles, line numbers, and line highlighting.
|
|
27
|
+
4. Use mermaid code blocks for diagrams (` ```mermaid `).
|
|
28
|
+
5. Use GitHub Alerts for callouts (`> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`).
|
|
29
|
+
6. Validate with built-in content validators.
|
|
30
|
+
|
|
31
|
+
**Read:** `node_modules/@pagesmith/core/REFERENCE.md` (Markdown Pipeline, Expressive Code, Validators)
|
|
32
|
+
|
|
33
|
+
## Update markdown behavior
|
|
34
|
+
|
|
35
|
+
1. Update config through markdown options (`remarkPlugins`, `rehypePlugins`, `shiki`).
|
|
36
|
+
2. Keep plugin order consistent with pipeline expectations.
|
|
37
|
+
3. Validate with rendered output and built-in validators.
|
|
38
|
+
|
|
39
|
+
**Read:** `node_modules/@pagesmith/core/REFERENCE.md` (Markdown Pipeline, Custom Plugins)
|
|
40
|
+
|
|
41
|
+
## Update AI pointers in consuming project
|
|
42
|
+
|
|
43
|
+
Add pointer lines to root `CLAUDE.md` or `AGENTS.md`:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
For @pagesmith/core usage and prompts, read node_modules/@pagesmith/core/docs/agents/usage.md
|
|
47
|
+
For the full @pagesmith/core API reference, see node_modules/@pagesmith/core/REFERENCE.md
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or copy `node_modules/@pagesmith/core/docs/agents/AGENTS.md.template` as a starting point.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# @pagesmith/core Usage For AI Agents
|
|
2
|
+
|
|
3
|
+
Use this file as the primary instruction source for `@pagesmith/core`.
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
1. Install: `npm add @pagesmith/core`
|
|
8
|
+
2. Read the full reference: `node_modules/@pagesmith/core/REFERENCE.md`
|
|
9
|
+
3. The `docs/` folder inside the package contains version-matched AI guidance files.
|
|
10
|
+
|
|
11
|
+
## When to pick @pagesmith/core
|
|
12
|
+
|
|
13
|
+
- Custom site or app architecture.
|
|
14
|
+
- Framework-specific rendering (React, Solid, Svelte, EJS, Handlebars).
|
|
15
|
+
- Need full control over layout, routing, rendering, and content loading.
|
|
16
|
+
|
|
17
|
+
## Required integration shape
|
|
18
|
+
|
|
19
|
+
1. Define collections with `defineCollection` or `defineCollections`.
|
|
20
|
+
2. Use `defineConfig` + `createContentLayer` for content loading.
|
|
21
|
+
3. For Vite flows, use `@pagesmith/core/vite` plugins (`pagesmithContent`, `pagesmithSsg`).
|
|
22
|
+
4. Use `entry.render()` when HTML is needed (lazy render path).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Agent Prompts
|
|
27
|
+
|
|
28
|
+
Copy-paste prompts for common workflows. Each prompt tells the agent which package files to read.
|
|
29
|
+
|
|
30
|
+
### Prompt: Initial setup with Vite
|
|
31
|
+
|
|
32
|
+
> Add `@pagesmith/core` content collections to this project. Read `node_modules/@pagesmith/core/REFERENCE.md` for the full API reference and `node_modules/@pagesmith/core/docs/agents/recipes.md` for setup recipes. Install the package, create `content.config.ts` with collection definitions, configure Vite with `pagesmithContent` and `pagesmithSsg`, and update CLAUDE.md / AGENTS.md with Pagesmith pointers.
|
|
33
|
+
|
|
34
|
+
**Files to read:**
|
|
35
|
+
- `node_modules/@pagesmith/core/REFERENCE.md`
|
|
36
|
+
- `node_modules/@pagesmith/core/docs/agents/recipes.md`
|
|
37
|
+
|
|
38
|
+
### Prompt: Define content collections
|
|
39
|
+
|
|
40
|
+
> Create content collections for this project using `@pagesmith/core`. Read `node_modules/@pagesmith/core/REFERENCE.md` for `defineCollection`, `defineCollections`, schema options, loader types, computed fields, filters, and custom validators. Define Zod schemas for each collection and register them with `defineConfig`.
|
|
41
|
+
|
|
42
|
+
**Files to read:**
|
|
43
|
+
- `node_modules/@pagesmith/core/REFERENCE.md` (Content Layer API, Collections, Loaders, Validation sections)
|
|
44
|
+
|
|
45
|
+
### Prompt: Write markdown content
|
|
46
|
+
|
|
47
|
+
> Create markdown content for the collections defined in this project. Read `node_modules/@pagesmith/core/REFERENCE.md` for the markdown pipeline, frontmatter schemas, code block features (Expressive Code), and content validators. Use proper frontmatter, fenced code blocks with language identifiers, mermaid code blocks for diagrams, and GitHub Alerts for callouts.
|
|
48
|
+
|
|
49
|
+
**Files to read:**
|
|
50
|
+
- `node_modules/@pagesmith/core/REFERENCE.md` (Markdown Pipeline, Expressive Code, Frontmatter Schemas, Validators sections)
|
|
51
|
+
|
|
52
|
+
### Prompt: Troubleshooting validation errors
|
|
53
|
+
|
|
54
|
+
> Fix content validation errors in this project. Read `node_modules/@pagesmith/core/docs/agents/errors.md` for the error catalog with patterns and fixes grouped by source (schema, content, plugin, load, MCP).
|
|
55
|
+
|
|
56
|
+
**Files to read:**
|
|
57
|
+
- `node_modules/@pagesmith/core/docs/agents/errors.md`
|
|
58
|
+
- `node_modules/@pagesmith/core/REFERENCE.md` (Validation section)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Package files reference
|
|
63
|
+
|
|
64
|
+
| File | Purpose |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `node_modules/@pagesmith/core/REFERENCE.md` | Complete API reference: content layer, collections, loaders, markdown pipeline, JSX, CSS, Vite plugins |
|
|
67
|
+
| `node_modules/@pagesmith/core/README.md` | User-facing quick start, Vite integration, and API overview |
|
|
68
|
+
| `node_modules/@pagesmith/core/docs/agents/usage.md` | This file — agent rules and prompts |
|
|
69
|
+
| `node_modules/@pagesmith/core/docs/agents/recipes.md` | Step-by-step recipes for common tasks |
|
|
70
|
+
| `node_modules/@pagesmith/core/docs/agents/errors.md` | Error catalog with patterns and fixes |
|
|
71
|
+
| `node_modules/@pagesmith/core/docs/agents/migration.md` | Pre-1.0 upgrade notes |
|
|
72
|
+
| `node_modules/@pagesmith/core/docs/agents/changelog-notes.md` | Version highlights |
|
|
73
|
+
| `node_modules/@pagesmith/core/docs/agents/AGENTS.md.template` | Template for consuming project AGENTS.md |
|
|
74
|
+
| `node_modules/@pagesmith/core/docs/llms.txt` | Compact AI context index |
|
|
75
|
+
| `node_modules/@pagesmith/core/docs/llms-full.txt` | Full AI context with all file pointers |
|
|
76
|
+
|
|
77
|
+
## Non-negotiable rules
|
|
78
|
+
|
|
79
|
+
- Keep schema validation in collection schemas (`z` from `@pagesmith/core`).
|
|
80
|
+
- Prefer folder-based content entries if pages use sibling assets.
|
|
81
|
+
- Keep markdown behavior aligned with core markdown pipeline and validators.
|
|
82
|
+
- Do not add ad-hoc code-block copy button JS; Expressive Code already handles this.
|
|
83
|
+
|
|
84
|
+
## Related package docs
|
|
85
|
+
|
|
86
|
+
- Core reference: `node_modules/@pagesmith/core/REFERENCE.md`
|
|
87
|
+
- Core README: `node_modules/@pagesmith/core/README.md`
|
|
88
|
+
- Docs reference: `node_modules/@pagesmith/docs/REFERENCE.md`
|
|
89
|
+
- Docs README: `node_modules/@pagesmith/docs/README.md`
|
|
90
|
+
- Docs usage: `node_modules/@pagesmith/docs/docs/agents/usage.md`
|
|
91
|
+
|
|
92
|
+
## MCP Introspection Workflows
|
|
93
|
+
|
|
94
|
+
### Discover and validate all collections
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
1. Call core_list_collections → get all collection names and schema fields
|
|
98
|
+
2. For each collection, call core_validate → get validation results
|
|
99
|
+
3. Fix any issues found using the error catalog
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Find and update content
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
1. Call core_search_entries with query → find matching entries
|
|
106
|
+
2. Call core_get_entry with collection and slug → get full content
|
|
107
|
+
3. Edit the source file at the returned filePath
|
|
108
|
+
4. Call core_validate to confirm the change is valid
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Audit content quality
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
1. Call core_list_collections → enumerate all collections
|
|
115
|
+
2. For each, call core_list_entries → get all entries
|
|
116
|
+
3. Call core_validate → collect all issues
|
|
117
|
+
4. Group issues by source (schema/content/plugin) for prioritized fixing
|
|
118
|
+
```
|
|
119
|
+
|