seemore 1.0.4 → 1.0.5

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/dist/cli/index.js CHANGED
@@ -14,6 +14,7 @@ var paths_exports = {};
14
14
  __export(paths_exports, {
15
15
  appRoot: () => appRoot,
16
16
  cacheDir: () => cacheDir,
17
+ canonicalise: () => canonicalise,
17
18
  packageRoot: () => packageRoot,
18
19
  resolveContentRoot: () => resolveContentRoot
19
20
  });
@@ -967,6 +968,12 @@ import { gzipSync } from "zlib";
967
968
  import { createFromSource } from "fumadocs-core/search/server";
968
969
  import { structure } from "fumadocs-core/mdx-plugins";
969
970
  var SIZE_WARNING_BYTES = 15e5;
971
+ function toSearchableText(body) {
972
+ return body.replace(/^>\s*\[!\w+\]\s*$/gm, ">").replace(
973
+ /\[\[([^\]|#]*)(?:#[^\]|]*)?(?:\|([^\]]*))?\]\]/g,
974
+ (_match, target, label) => (label || target.split("/").pop() || "").trim()
975
+ );
976
+ }
970
977
  async function buildSearchIndex(ctx) {
971
978
  const loader = await ctx.source.loader.get();
972
979
  const bodies = /* @__PURE__ */ new Map();
@@ -984,7 +991,7 @@ async function buildSearchIndex(ctx) {
984
991
  url: withBase(ctx.config.base, page.url),
985
992
  title: typeof page.data.title === "string" ? page.data.title : page.url,
986
993
  description: typeof page.data.description === "string" ? page.data.description : void 0,
987
- structuredData: structure(body)
994
+ structuredData: structure(toSearchableText(body))
988
995
  };
989
996
  }
990
997
  });
@@ -1008,6 +1015,7 @@ function formatBytes(bytes) {
1008
1015
  }
1009
1016
 
1010
1017
  // src/node/vite/plugin.ts
1018
+ init_paths();
1011
1019
  var VIRTUAL = {
1012
1020
  tree: "virtual:seemore/tree",
1013
1021
  routes: "virtual:seemore/routes",
@@ -1086,6 +1094,27 @@ function seemorePlugin({ ctx, serveSearch = false }) {
1086
1094
  next(error);
1087
1095
  }
1088
1096
  });
1097
+ devServer.middlewares.use((req, res, next) => {
1098
+ const [path = "", query = ""] = (req.url ?? "").split("?");
1099
+ if (path !== "/__seemore/route") return next();
1100
+ const file = new URLSearchParams(query).get("file");
1101
+ if (file === null) {
1102
+ res.statusCode = 400;
1103
+ res.setHeader("Content-Type", "application/json");
1104
+ res.end(JSON.stringify({ error: 'Missing "file" query parameter.' }));
1105
+ return;
1106
+ }
1107
+ const absFile = canonicalise(file);
1108
+ const page = ctx.pages().find((p) => p.absPath === absFile);
1109
+ if (page === void 0) {
1110
+ res.statusCode = 404;
1111
+ res.setHeader("Content-Type", "application/json");
1112
+ res.end(JSON.stringify({ error: `${file} is not part of this site \u2014 excluded, or lost a duplicate slug.` }));
1113
+ return;
1114
+ }
1115
+ res.setHeader("Content-Type", "application/json");
1116
+ res.end(JSON.stringify({ url: withBase(ctx.config.base, page.url) }));
1117
+ });
1089
1118
  },
1090
1119
  /** Called by the watcher after a rescan. */
1091
1120
  api: {
@@ -1290,7 +1319,14 @@ function createViteConfig({ ctx, mode, outDir, ssrOutDir }) {
1290
1319
  resolve: {
1291
1320
  // The app is compiled from seemore's own sources, so its dependencies must resolve
1292
1321
  // from seemore's directory rather than from the user's project.
1293
- dedupe: ["react", "react-dom", "react-router", "fumadocs-core", "fumadocs-ui"]
1322
+ dedupe: ["react", "react-dom", "react-router", "fumadocs-core", "fumadocs-ui"],
1323
+ // In dev the module worker is served through the shared module graph and its fumadocs
1324
+ // chunk comes from the dep optimizer, where `worker.plugins` never runs — the browser
1325
+ // build of `decode-named-character-reference` is inlined into the prebundle and the
1326
+ // worker throws on load. Adding the package's own `worker` condition graph-wide flips
1327
+ // the whole dev graph (main thread included) to its DOM-free build, which behaves the
1328
+ // same; production keeps the targeted worker-bundle swap above.
1329
+ conditions: mode === "dev" ? ["worker"] : []
1294
1330
  },
1295
1331
  server: {
1296
1332
  fs: {
@@ -1552,10 +1588,15 @@ async function runDev(options) {
1552
1588
  const resolvedPort = server.config.server.port ?? DEFAULT_PORT;
1553
1589
  const url = `http://localhost:${resolvedPort}${config.base}`;
1554
1590
  ctx.warnings.flush();
1555
- console.log(`
1591
+ if (options.json === true) {
1592
+ const ready = { url, port: resolvedPort, contentRoot, pageCount: scan2.pages.length };
1593
+ console.log(JSON.stringify(ready));
1594
+ } else {
1595
+ console.log(`
1556
1596
  ${pc3.green("seemore")} ${pc3.bold(url)}`);
1557
- console.log(` ${pc3.dim(`${scan2.pages.length} pages from ${contentRoot}`)}
1597
+ console.log(` ${pc3.dim(`${scan2.pages.length} pages from ${contentRoot}`)}
1558
1598
  `);
1599
+ }
1559
1600
  return {
1560
1601
  server,
1561
1602
  ctx,
@@ -1577,6 +1618,7 @@ Options
1577
1618
  --port <number> dev server port (default 4040)
1578
1619
  --host [host] expose the dev server on the network
1579
1620
  --open / --no-open open a browser on start (default: no)
1621
+ --json print one machine-readable JSON line instead of the summary (dev only)
1580
1622
  --config <path> path to seemore.config.ts
1581
1623
  --out <dir> build output directory (default: dist)
1582
1624
  --base <path> subpath the site is served from, e.g. /my-repo/
@@ -1599,6 +1641,7 @@ async function main(argv = process.argv.slice(2)) {
1599
1641
  host: { type: "string" },
1600
1642
  open: { type: "boolean" },
1601
1643
  "no-open": { type: "boolean" },
1644
+ json: { type: "boolean" },
1602
1645
  config: { type: "string" },
1603
1646
  out: { type: "string" },
1604
1647
  base: { type: "string" },
@@ -1630,7 +1673,8 @@ async function main(argv = process.argv.slice(2)) {
1630
1673
  ...shared,
1631
1674
  port: values.port === void 0 ? void 0 : Number(values.port),
1632
1675
  host: values.host === void 0 ? void 0 : values.host === "" ? true : values.host,
1633
- open: values.open === true && values["no-open"] !== true
1676
+ open: values.open === true && values["no-open"] !== true,
1677
+ json: values.json === true
1634
1678
  });
1635
1679
  }
1636
1680
  main().catch((error) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/node/paths.ts","../../src/cli/index.ts","../../src/cli/build.ts","../../src/node/config/load.ts","../../src/shared/base.ts","../../src/shared/types.ts","../../src/node/config/features.ts","../../src/node/config/schema.ts","../../src/node/content/links.ts","../../src/node/content/slug.ts","../../src/node/content/source.ts","../../src/node/content/scan.ts","../../src/node/content/frontmatter.ts","../../src/node/report.ts","../../src/node/context.ts","../../src/node/prerender/emit.ts","../../src/node/prerender/deploy.ts","../../src/node/prerender/render.ts","../../src/node/vite/config.ts","../../src/node/vite/mdx.ts","../../src/node/vite/remark.ts","../../src/node/vite/plugin.ts","../../src/node/search/build.ts","../../src/node/vite/watcher.ts","../../src/node/social/cards.ts","../../src/shared/og.ts","../../src/cli/dev.ts"],"sourcesContent":["import { existsSync, realpathSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { tmpdir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * The installed seemore package directory.\n *\n * Works from the bundled CLI (`dist/cli/index.js`) and from the sources during tests, which\n * is why it walks for `package.json` rather than assuming a depth.\n */\nexport function packageRoot(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let depth = 0; depth < 10; depth++) {\n if (existsSync(join(dir, 'package.json'))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error('seemore: could not locate its own package root.');\n}\n\n/** The browser layer, which ships as source and is compiled in-process. */\nexport function appRoot(): string {\n return join(packageRoot(), 'src', 'app');\n}\n\n/**\n * Vite's caches go to the OS temp directory, keyed by content root.\n *\n * Dev writes nothing into the user's folder, and that has to include the\n * dependency-optimiser cache Vite would otherwise put in `node_modules/.vite`.\n */\nexport function cacheDir(contentRoot: string): string {\n const key = createHash('sha256').update(resolve(contentRoot)).digest('hex').slice(0, 12);\n return join(tmpdir(), 'seemore', key);\n}\n\n/**\n * `seemore [dir]`, else the folder the command runs in. Nothing is probed: which Markdown\n * becomes the site is decided by where the user stands, never by what happens to exist.\n *\n * The result is canonicalised through the filesystem. Every module id seemore derives from\n * the root — import specifiers, watcher lookups — must use the real spelling, because Vite\n * refuses to *load* a path containing a Windows 8.3 short-name segment (`RUNNER~1`) no\n * matter what the fs allow list says. Real users hit this too: `C:\\Users\\<long name>\\`\n * carries a short alias on any drive with 8.3 names enabled.\n */\nexport function resolveContentRoot(cwd: string, explicit?: string): string {\n return explicit !== undefined ? canonicalise(resolve(cwd, explicit)) : canonicalise(cwd);\n}\n\nfunction canonicalise(dir: string): string {\n try {\n return realpathSync.native(dir);\n } catch {\n // A root that does not exist yet keeps its literal spelling; dev reports the empty corpus.\n return dir;\n }\n}\n","#!/usr/bin/env node\nimport { parseArgs } from 'node:util';\nimport pc from 'picocolors';\nimport { runBuild } from './build.js';\nimport { runDev } from './dev.js';\n\nconst USAGE = `\n${pc.bold('seemore')} — turn a folder of Markdown into a docs site\n\n seemore [dir] start the dev server\n seemore build [dir] build a static site into dist/\n\nOptions\n --port <number> dev server port (default 4040)\n --host [host] expose the dev server on the network\n --open / --no-open open a browser on start (default: no)\n --config <path> path to seemore.config.ts\n --out <dir> build output directory (default: dist)\n --base <path> subpath the site is served from, e.g. /my-repo/\n -h, --help show this message\n -v, --version show the version\n`;\n\n/**\n * `parseArgs` has no notion of an optional value, so a bare `--host` — the documented form,\n * and the one Vite uses for \"listen on every interface\" — is rewritten to `--host=` first.\n */\nfunction normaliseHostFlag(argv: string[]): string[] {\n const index = argv.indexOf('--host');\n if (index === -1) return argv;\n const next = argv[index + 1];\n if (next !== undefined && !next.startsWith('-')) return argv;\n return [...argv.slice(0, index), '--host=', ...argv.slice(index + 1)];\n}\n\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<void> {\n const { values, positionals } = parseArgs({\n args: normaliseHostFlag(argv),\n allowPositionals: true,\n options: {\n port: { type: 'string' },\n host: { type: 'string' },\n open: { type: 'boolean' },\n 'no-open': { type: 'boolean' },\n config: { type: 'string' },\n out: { type: 'string' },\n base: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean', short: 'v' },\n },\n });\n\n if (values.help === true) {\n console.log(USAGE);\n return;\n }\n\n if (values.version === true) {\n const { readFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { packageRoot } = await import('../node/paths.js');\n const pkg = JSON.parse(readFileSync(join(packageRoot(), 'package.json'), 'utf8')) as { version: string };\n console.log(pkg.version);\n return;\n }\n\n const [command, ...rest] = positionals;\n const isBuild = command === 'build';\n const dir = isBuild ? rest[0] : command;\n\n const shared = { cwd: process.cwd(), dir, configPath: values.config, base: values.base };\n\n if (isBuild) {\n await runBuild({ ...shared, outDir: values.out });\n return;\n }\n\n await runDev({\n ...shared,\n port: values.port === undefined ? undefined : Number(values.port),\n host: values.host === undefined ? undefined : values.host === '' ? true : values.host,\n open: values.open === true && values['no-open'] !== true,\n });\n}\n\nmain().catch((error: unknown) => {\n console.error(`\\n${pc.red('seemore')} ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n});\n","import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { tmpdir } from 'node:os';\nimport { isAbsolute, join, relative, resolve } from 'node:path';\nimport pc from 'picocolors';\nimport { build as viteBuild } from 'vite';\nimport { loadConfig } from '../node/config/load.js';\nimport { createContext, type SeemoreContext } from '../node/context.js';\nimport { normaliseBase } from '../shared/base.js';\nimport { resolveContentRoot } from '../node/paths.js';\nimport { applyTemplate, outputPathFor, writeHtml } from '../node/prerender/emit.js';\nimport { writeDeployArtifacts } from '../node/prerender/deploy.js';\nimport { loadPrerenderModule } from '../node/prerender/render.js';\nimport { buildSearchIndex, formatBytes, measureIndex } from '../node/search/build.js';\nimport { generateSocialCards } from '../node/social/cards.js';\nimport { createViteConfig } from '../node/vite/config.js';\n\nexport interface BuildOptions {\n cwd: string;\n dir?: string;\n configPath?: string;\n outDir?: string;\n base?: string;\n}\n\nexport async function runBuild(options: BuildOptions): Promise<{ outDir: string; routes: number }> {\n const contentRoot = resolveContentRoot(options.cwd, options.dir);\n const loaded = await loadConfig({ root: options.cwd, configPath: options.configPath });\n\n const config = { ...loaded.config, base: options.base === undefined ? loaded.config.base : normaliseBase(options.base) };\n warnAboutMissingBase(config.base, loaded.file);\n\n const ctx = createContext({ config, contentRoot });\n const outDir = resolve(options.cwd, options.outDir ?? 'dist');\n assertSafeOutDir(outDir, options.cwd, contentRoot);\n\n const scan = ctx.source.current();\n failOnErrors(ctx.errors(), contentRoot);\n if (scan.pages.length === 0) {\n throw new Error(`No Markdown files found under ${contentRoot}. Point seemore at a folder that has some, or check \\`exclude\\`.`);\n }\n for (const warning of scan.warnings) ctx.warnings.add(warning);\n\n console.log(pc.dim(`seemore ${scan.pages.length} pages from ${relative(options.cwd, contentRoot) || '.'}`));\n\n // 1. The client bundle, which also produces the HTML template every page is injected into.\n await viteBuild(createViteConfig({ ctx, mode: 'build', outDir }));\n const template = readFileSync(join(outDir, 'index.html'), 'utf8');\n\n // 2. The same module graph, evaluated in node.\n const ssrOutDir = mkdtempSync(join(tmpdir(), 'seemore-ssr-'));\n try {\n const prerender = await loadPrerenderModule(ctx, ssrOutDir);\n const urls = prerender.listRoutes();\n // When no page claims `/`, the router generates an index page there — the same component\n // the dev server renders — so the client build's empty shell never ships as the home page.\n const routes = urls.includes('/') ? urls : ['/', ...urls];\n if (routes.length > urls.length) {\n console.log(pc.dim('seemore no index page; generated one listing every page at /'));\n }\n\n for (const url of routes) {\n writeHtml(outDir, outputPathFor(url), applyTemplate(template, await prerender.render(url)));\n }\n\n // 3. The shell an unknown address falls back to, which is also Surge's `200.html`.\n const notFound = applyTemplate(template, await prerender.render('/__seemore_not_found'));\n writeHtml(outDir, '404.html', notFound);\n writeDeployArtifacts(outDir, config.base, notFound);\n\n // 4. The search index, at the same path the dev middleware serves.\n if (config.search.provider === 'static') {\n const index = await buildSearchIndex(ctx);\n mkdirSync(join(outDir, 'api'), { recursive: true });\n writeFileSync(join(outDir, 'api', 'search.json'), index, 'utf8');\n\n const size = measureIndex(index);\n console.log(pc.dim(`seemore search index ${formatBytes(size.gzipped)} gzipped`));\n if (size.warning !== undefined) ctx.warnings.add(size.warning);\n }\n\n if (config.search.provider !== 'static') await warnIfSearchSdkMissing(ctx, config.search.provider);\n\n if (config.features['social.cards']) await generateSocialCards(ctx, outDir);\n\n ctx.warnings.flush();\n console.log(pc.green(`seemore ${routes.length} pages written to ${relative(options.cwd, outDir) || outDir}`));\n\n return { outDir, routes: routes.length };\n } finally {\n rmSync(ssrOutDir, { recursive: true, force: true });\n }\n}\n\n/**\n * The build empties `outDir` before writing, and `outDir` is always outside the Vite root —\n * seemore's root is its own package — so Vite's own guard against that never fires. A typo\n * like `--out .` would delete the project, so it is refused here instead.\n */\nfunction assertSafeOutDir(outDir: string, cwd: string, contentRoot: string): void {\n const contains = (parent: string, child: string): boolean => {\n const rel = relative(parent, child);\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));\n };\n\n for (const [name, dir] of [\n ['the current directory', cwd],\n ['the content directory', contentRoot],\n ] as const) {\n if (contains(outDir, dir)) {\n throw new Error(\n `Refusing to build into ${outDir}: it is, or contains, ${name}, and the build empties its output directory first. Pass --out with a directory of its own.`,\n );\n }\n }\n}\n\n/**\n * The hosted search providers need an SDK that seemore does not depend on. Finding out in the\n * browser means an empty search box; finding out here means a line in the build log.\n */\nasync function warnIfSearchSdkMissing(ctx: SeemoreContext, provider: 'algolia' | 'orama-cloud'): Promise<void> {\n const packageName = provider === 'algolia' ? 'algoliasearch' : '@orama/core';\n try {\n createRequire(join(ctx.config.root, 'noop.js')).resolve(packageName);\n } catch {\n ctx.warnings.add(\n `\\`search.provider\\` is '${provider}', which needs ${packageName}. Run \\`npm install ${packageName}\\` or search will find nothing.`,\n );\n }\n}\n\n/** Failing conditions produce a silently wrong site; warnings produce a visibly wrong page. */\nfunction failOnErrors(errors: string[], contentRoot: string): void {\n if (errors.length === 0) return;\n throw new Error(`seemore found ${errors.length} problem(s) in ${contentRoot}:\\n\\n${errors.join('\\n\\n')}`);\n}\n\n/**\n * `base` is never inferred. Under CI, where getting it wrong ships a broken site,\n * say so — with the exact line to add.\n */\nfunction warnAboutMissingBase(base: string, configFile: string | undefined): void {\n if (base !== '/' || process.env.GITHUB_ACTIONS !== 'true') return;\n const repo = process.env.GITHUB_REPOSITORY?.split('/')[1];\n console.warn(\n pc.yellow(\n `seemore \\`base\\` is not set, and GitHub Pages serves project sites from a subpath.\\n` +\n ` Add this to ${configFile ?? 'seemore.config.ts'}:\\n\\n` +\n ` base: '/${repo ?? 'your-repo'}/',\\n\\n` +\n ` Or pass --base '/${repo ?? 'your-repo'}/'. Ignore this if you deploy to a domain root.`,\n ),\n );\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { createJiti } from 'jiti';\nimport { z } from 'zod';\nimport { normaliseBase } from '../base.js';\nimport { resolveFeatures, type FeatureFlag } from './features.js';\nimport { configSchema, THEMES, type SeemoreConfig, type ResolvedSeemoreConfig, type SearchConfig } from './schema.js';\n\nconst CONFIG_NAMES = ['seemore.config.ts', 'seemore.config.mts', 'seemore.config.js', 'seemore.config.mjs'];\n\nexport interface LoadConfigOptions {\n /** Directory to look in, and the base for relative paths inside the config. */\n root: string;\n /** `--config`; when given, a missing file is an error rather than a fallback to defaults. */\n configPath?: string;\n}\n\n/** Turn a validated config into the fully-resolved shape the rest of seemore consumes. */\nexport function resolveConfig(\n input: SeemoreConfig,\n options: { root: string; configFile?: string },\n): ResolvedSeemoreConfig {\n const parsed = parseOrThrow(input, options.configFile);\n\n const search: SearchConfig = parsed.search === 'static' ? { provider: 'static' } : (parsed.search as SearchConfig);\n\n const features = resolveFeatures(parsed.features as FeatureFlag[], {\n // Nothing to link to without an edit base, so the flag follows the option.\n 'content.action.edit': parsed.editLink !== undefined,\n });\n\n return {\n title: parsed.title,\n description: parsed.description,\n favicon: parsed.favicon,\n base: normaliseBase(parsed.base),\n theme: parsed.theme,\n css: parsed.css === undefined ? undefined : resolveFrom(options.root, parsed.css),\n features,\n nav: parsed.nav,\n footer: parsed.footer,\n editLink: parsed.editLink,\n search,\n exclude: parsed.exclude,\n root: options.root,\n configFile: options.configFile,\n };\n}\n\nexport interface LoadedConfig {\n config: ResolvedSeemoreConfig;\n /** Absolute path of the config file that was used, if any. */\n file?: string;\n}\n\n/**\n * Load `seemore.config.ts` with jiti. Not Vite's `ssrLoadModule`: the config\n * decides `base`, `base` configures Vite, and Vite would have to already exist to load it.\n */\nexport async function loadConfig(options: LoadConfigOptions): Promise<LoadedConfig> {\n const file = findConfigFile(options);\n\n if (file === undefined) {\n return { config: resolveConfig({}, { root: options.root }) };\n }\n\n const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });\n let loaded: unknown;\n try {\n loaded = await jiti.import(file, { default: true });\n } catch (error) {\n throw new Error(`Failed to load ${file}:\\n${error instanceof Error ? error.message : String(error)}`, {\n cause: error,\n });\n }\n\n if (loaded === null || typeof loaded !== 'object') {\n throw new Error(`${file} must export a config object as its default export, got ${typeof loaded}.`);\n }\n\n return {\n config: resolveConfig(loaded as SeemoreConfig, { root: dirname(file), configFile: file }),\n file,\n };\n}\n\nfunction findConfigFile({ root, configPath }: LoadConfigOptions): string | undefined {\n if (configPath !== undefined) {\n const absolute = resolveFrom(root, configPath);\n if (!existsSync(absolute)) {\n throw new Error(`Config file not found: ${absolute}`);\n }\n return absolute;\n }\n\n for (const name of CONFIG_NAMES) {\n const candidate = resolve(root, name);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction resolveFrom(root: string, path: string): string {\n return isAbsolute(path) ? path : resolve(root, path);\n}\n\nfunction parseOrThrow(input: SeemoreConfig, file: string | undefined): z.output<typeof configSchema> {\n const result = configSchema.safeParse(input);\n if (result.success) return result.data;\n\n const where = file === undefined ? 'seemore config' : file;\n const issues = result.error.issues.map((issue) => {\n const field = issue.path.length === 0 ? '(root)' : issue.path.join('.');\n return ` - ${field}: ${explain(issue)}`;\n });\n throw new Error(`Invalid ${where}:\\n${issues.join('\\n')}`);\n}\n\nfunction explain(issue: z.core.$ZodIssue): string {\n // zod's default message for a large enum truncates badly; the valid set is the useful part.\n if (issue.code === 'invalid_value' && issue.path.join('.') === 'theme') {\n return `unknown theme. Valid themes: ${THEMES.join(', ')}.`;\n }\n return issue.message;\n}\n","/**\n * Base-path handling.\n *\n * Internally a base is always normalised to leading + trailing slash (`/sub/`), because a\n * single canonical shape is what makes the \"no absolute-root URL leaks\" test possible. The\n * trailing slash is stripped again only at the point of output.\n */\n\nconst EXTERNAL = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i;\n\n/** `undefined` | `sub` | `/sub` | `/sub/` → `/sub/`. The root base is `/`. */\nexport function normaliseBase(base: string | undefined): string {\n if (base === undefined || base === '') return '/';\n if (EXTERNAL.test(base)) {\n throw new Error(\n `Invalid \\`base\\`: ${JSON.stringify(base)}. \\`base\\` is a path on the host, not a URL — use \"/${base.replace(/^.*?:\\/\\/[^/]*/, '').replace(/^\\/+/, '')}\".`,\n );\n }\n const trimmed = base.replace(/^\\/+/, '').replace(/\\/+$/, '');\n return trimmed === '' ? '/' : `/${trimmed}/`;\n}\n\n/** True for hrefs that a base must never touch: external, protocol-relative, hash, or relative. */\nexport function isExternalHref(href: string): boolean {\n return EXTERNAL.test(href) || href.startsWith('#') || !href.startsWith('/');\n}\n\n/** Prefix a root-relative path with the base. Idempotent; leaves external hrefs alone. */\nexport function withBase(base: string, href: string): string {\n const b = normaliseBase(base);\n if (b === '/' || isExternalHref(href)) return href;\n if (href === '/') return b;\n if (href === b.slice(0, -1) || href.startsWith(b)) return href;\n return b + href.replace(/^\\/+/, '');\n}\n\n/** Inverse of {@link withBase}: turn a browser pathname back into an internal route URL. */\nexport function stripBase(base: string, pathname: string): string {\n const b = normaliseBase(base);\n if (b === '/') return pathname;\n if (pathname === b || pathname === b.slice(0, -1)) return '/';\n if (!pathname.startsWith(b)) return pathname;\n return `/${pathname.slice(b.length)}`;\n}\n\n/** The form React Router wants for `basename`: leading slash, no trailing slash, `/` at root. */\nexport function toBasename(base: string): string {\n const b = normaliseBase(base);\n return b === '/' ? '/' : b.slice(0, -1);\n}\n\n/**\n * Browser pathnames are percent-encoded; route URLs are not.\n *\n * `/guía/página-uno` arrives from `location.pathname` as `/gu%C3%ADa/p%C3%A1gina-uno`, and a\n * lookup against the route map misses — so a correctly prerendered page hydrates into \"Page\n * not found\". `decodeURI`, not `decodeURIComponent`: a literal `%2F` in a filename must stay\n * encoded or it would split into two path segments.\n */\nexport function decodePath(pathname: string): string {\n try {\n return decodeURI(pathname);\n } catch {\n // Malformed escapes are the browser's problem, not ours; match on what we were given.\n return pathname;\n }\n}\n","import type { ComponentType, ReactNode } from 'react';\n\n/**\n * Types shared by the node pipeline and the browser app. This file ships as source, next to\n * `src/app`, so both halves agree on the shape of the virtual modules.\n */\n\nexport const FEATURES = [\n 'navigation.instant.prefetch',\n 'navigation.instant.preview',\n 'navigation.footer',\n 'navigation.top',\n 'navigation.path',\n 'navigation.sections',\n 'navigation.prune',\n 'toc.follow',\n 'toc.integrate',\n 'content.code.copy',\n 'content.action.edit',\n 'search.suggest',\n 'search.highlight',\n 'social.cards',\n] as const;\n\nexport type Feature = (typeof FEATURES)[number];\n/** What a user may write in `features`: a flag, or `!flag` to switch a default-on flag off. */\nexport type FeatureFlag = Feature | `!${Feature}`;\nexport type ResolvedFeatures = Record<Feature, boolean>;\n\nexport interface NavItem {\n text: string;\n link?: string;\n items?: NavItem[];\n}\n\nexport type ClientSearchConfig =\n | { provider: 'static'; from: string }\n | { provider: 'orama-cloud'; endpoint: string; apiKey: string }\n | { provider: 'algolia'; appId: string; apiKey: string; indexName: string };\n\n/** The payload of `virtual:seemore/config`. */\nexport interface ClientConfig {\n title: string;\n description?: string;\n base: string;\n theme: string;\n features: ResolvedFeatures;\n nav?: NavItem[];\n footer?: { text?: string; links?: { text: string; link: string }[] };\n editLink?: { base: string; text: string };\n favicon?: string;\n search: ClientSearchConfig;\n contentRoot: string;\n}\n\n/** One entry of `virtual:seemore/routes`. */\nexport interface RouteEntry {\n url: string;\n /** Virtual path relative to the content root — what an edit link points at. */\n file: string;\n absPath: string;\n title: string;\n description: string | null;\n load: () => Promise<PageModule>;\n}\n\nexport interface TocEntry {\n title: ReactNode;\n url: string;\n depth: number;\n}\n\nexport interface PageModule {\n default: ComponentType<{ components?: Record<string, unknown> }>;\n /** Exported by fumadocs' `rehype-toc`. */\n toc?: TocEntry[];\n}\n","import type { Feature, FeatureFlag, ResolvedFeatures } from '../../shared/types.js';\n\n/**\n * Feature flags.\n *\n * MkDocs Material's model — one flat list of dotted strings — but typed as a union, which\n * their YAML cannot do. Because seemore has default-on features where MkDocs has none, the\n * list is additive over the defaults and a `!` prefix turns a default-on feature off.\n */\n\nexport { FEATURES } from '../../shared/types.js';\nexport type { Feature, FeatureFlag, ResolvedFeatures } from '../../shared/types.js';\n\nexport const FEATURE_DEFAULTS: Record<Feature, boolean> = {\n 'navigation.instant.prefetch': true,\n 'navigation.instant.preview': false,\n 'navigation.footer': true,\n 'navigation.top': true,\n 'navigation.path': false,\n 'navigation.sections': false,\n 'navigation.prune': false,\n 'toc.follow': true,\n 'toc.integrate': false,\n 'content.code.copy': true,\n // Implicitly on when `editLink` is configured; there is nothing to link to otherwise.\n 'content.action.edit': false,\n 'search.suggest': true,\n 'search.highlight': true,\n 'social.cards': false,\n};\n\nexport function isFeatureEnabled(features: ResolvedFeatures, feature: Feature): boolean {\n return features[feature];\n}\n\n/**\n * Rules the flag set must satisfy. MkDocs reports its equivalents in prose and lets the\n * site build wrong; we fail in the config loader with the fix in the message.\n */\ntype Rule =\n | { kind: 'conflict'; a: Feature; b: Feature; why: string }\n | { kind: 'requires'; flag: Feature; needs: Feature; why: string };\n\nconst RULES: Rule[] = [\n {\n kind: 'conflict',\n a: 'toc.integrate',\n b: 'toc.follow',\n why: '`toc.integrate` merges the table of contents into the sidebar, leaving no separate TOC pane for `toc.follow` to scroll.',\n },\n {\n kind: 'requires',\n flag: 'navigation.instant.preview',\n needs: 'navigation.instant.prefetch',\n why: '`navigation.instant.preview` renders the target page in a popover, which is only possible once prefetch has loaded it.',\n },\n];\n\nexport function resolveFeatures(\n input: readonly FeatureFlag[],\n implicit: Partial<ResolvedFeatures> = {},\n): ResolvedFeatures {\n const resolved: ResolvedFeatures = { ...FEATURE_DEFAULTS, ...implicit };\n\n for (const flag of input) {\n const off = flag.startsWith('!');\n const name = (off ? flag.slice(1) : flag) as Feature;\n resolved[name] = !off;\n }\n\n const problems: string[] = [];\n for (const rule of RULES) {\n if (rule.kind === 'conflict') {\n if (!resolved[rule.a] || !resolved[rule.b]) continue;\n const fix = FEATURE_DEFAULTS[rule.b]\n ? `Add '!${rule.b}' to \\`features\\` to switch it off.`\n : `Remove '${rule.b}' from \\`features\\`.`;\n problems.push(`\\`${rule.a}\\` cannot be combined with \\`${rule.b}\\`. ${rule.why} ${fix}`);\n } else if (resolved[rule.flag] && !resolved[rule.needs]) {\n problems.push(\n `\\`${rule.flag}\\` requires \\`${rule.needs}\\`, which is switched off. ${rule.why}`,\n );\n }\n }\n\n if (problems.length > 0) {\n throw new Error(\n `Incompatible \\`features\\` in seemore config:\\n${problems.map((p) => ` - ${p}`).join('\\n')}`,\n );\n }\n\n return resolved;\n}\n","import { z } from 'zod';\nimport { FEATURES, type FeatureFlag, type ResolvedFeatures } from './features.js';\n\n/** The CSS presets fumadocs-ui ships. We do not invent a token system. */\nexport const THEMES = [\n 'neutral',\n 'black',\n 'catppuccin',\n 'dusk',\n 'ocean',\n 'purple',\n 'ruby',\n 'solar',\n 'aspen',\n 'emerald',\n 'vitepress',\n 'shadcn',\n] as const;\n\nexport type Theme = (typeof THEMES)[number];\n\nconst featureFlag = z.enum([...FEATURES, ...FEATURES.map((f) => `!${f}` as const)] as [string, ...string[]]);\n\nconst navItem: z.ZodType<NavItem> = z.lazy(() =>\n z.object({\n text: z.string(),\n link: z.string().optional(),\n items: z.array(navItem).optional(),\n }),\n);\n\nexport interface NavItem {\n text: string;\n link?: string;\n items?: NavItem[];\n}\n\nconst searchSchema = z.union([\n z.literal('static'),\n z.object({ provider: z.literal('static') }),\n z.object({\n provider: z.literal('orama-cloud'),\n endpoint: z.string(),\n apiKey: z.string(),\n }),\n z.object({\n provider: z.literal('algolia'),\n appId: z.string(),\n apiKey: z.string(),\n indexName: z.string(),\n }),\n]);\n\nexport const configSchema = z.object({\n title: z.string().default('Documentation'),\n description: z.string().optional(),\n favicon: z.string().optional(),\n /** Subpath the site is served from, e.g. `/my-repo/`. Never inferred. */\n base: z.string().optional(),\n theme: z.enum(THEMES).default('neutral'),\n /** A CSS file appended after everything else, so it wins. */\n css: z.string().optional(),\n features: z.array(featureFlag).default([]),\n nav: z.array(navItem).optional(),\n footer: z\n .object({\n text: z.string().optional(),\n links: z.array(z.object({ text: z.string(), link: z.string() })).optional(),\n })\n .optional(),\n editLink: z\n .object({\n base: z.string(),\n text: z.string().default('Edit this page'),\n })\n .optional(),\n search: searchSchema.default('static'),\n exclude: z.array(z.string()).default([]),\n});\n\n/** What a user writes in `seemore.config.ts`. */\nexport type SeemoreConfig = Omit<z.input<typeof configSchema>, 'features' | 'theme' | 'search'> & {\n features?: FeatureFlag[];\n theme?: Theme;\n search?: z.input<typeof searchSchema>;\n};\n\nexport type SearchConfig =\n | { provider: 'static' }\n | { provider: 'orama-cloud'; endpoint: string; apiKey: string }\n | { provider: 'algolia'; appId: string; apiKey: string; indexName: string };\n\n/** What the rest of seemore consumes: every optional filled in, every path absolute. */\nexport interface ResolvedSeemoreConfig {\n title: string;\n description?: string;\n favicon?: string;\n /** Always normalised to leading + trailing slash. */\n base: string;\n theme: Theme;\n /** Absolute path, resolved against the config file's directory. */\n css?: string;\n features: ResolvedFeatures;\n nav?: NavItem[];\n footer?: { text?: string; links?: { text: string; link: string }[] };\n editLink?: { base: string; text: string };\n search: SearchConfig;\n exclude: string[];\n /** Directory the config was resolved from — relative paths in it hang off this. */\n root: string;\n /** Absolute path of the config file, when there is one. */\n configFile?: string;\n}\n","import { slug as slugify } from 'github-slugger';\nimport { isExternalHref, withBase } from '../base.js';\nimport type { ContentPage } from './scan.js';\nimport { slugifySegment, toPosix } from './slug.js';\n\nconst CONTENT_EXT = /\\.mdx?$/i;\n\nexport interface ResolvedLink {\n /** The href to emit. Unchanged from the input when nothing needed resolving. */\n href: string;\n warning?: string;\n}\n\nexport interface ResolvedWikilink {\n /** `undefined` when the target does not exist — render the label as plain text. */\n href?: string;\n label: string;\n warning?: string;\n}\n\nexport interface LinkResolver {\n /** Relative `.md`/`.mdx` links → routes. Everything else passes through untouched. */\n resolveHref(href: string, fromFile: string): ResolvedLink;\n /** The inside of a `[[…]]`, i.e. `Target`, `Target|label`, `Target#Heading`, or both. */\n resolveWikilink(target: string, fromFile: string): ResolvedWikilink;\n}\n\nexport function createLinkResolver(pages: readonly ContentPage[], base: string): LinkResolver {\n /** `guide/deep-dive` (extension stripped, original casing) → page. */\n const byPath = new Map<string, ContentPage>();\n /** Lowercased basename, and its slugified form → every page that answers to it. */\n const byName = new Map<string, ContentPage[]>();\n\n const add = (map: Map<string, ContentPage[]>, key: string, page: ContentPage) => {\n const bucket = map.get(key);\n if (bucket) bucket.push(page);\n else map.set(key, [page]);\n };\n\n for (const page of pages) {\n const withoutExt = page.file.replace(CONTENT_EXT, '');\n byPath.set(withoutExt.toLowerCase(), page);\n byPath.set(page.file.toLowerCase(), page);\n // A directory index answers to its directory, so `[[guide]]` finds `guide/index.md`.\n if (page.isIndex) {\n const dir = withoutExt.split('/').slice(0, -1).join('/');\n if (dir !== '') byPath.set(dir.toLowerCase(), page);\n }\n\n const basename = withoutExt.split('/').pop() ?? '';\n add(byName, basename.toLowerCase(), page);\n const slugged = slugifySegment(basename);\n if (slugged !== basename.toLowerCase()) add(byName, slugged, page);\n }\n\n /** Shallowest path first, then alphabetically — stable regardless of scan order. */\n const pick = (candidates: ContentPage[]): ContentPage =>\n [...candidates].sort((a, b) => {\n const depth = a.file.split('/').length - b.file.split('/').length;\n return depth !== 0 ? depth : a.file.localeCompare(b.file);\n })[0]!;\n\n function lookup(target: string): { page?: ContentPage; ambiguous?: ContentPage[] } {\n const cleaned = toPosix(target).replace(/^\\/+/, '').replace(CONTENT_EXT, '');\n const key = cleaned.toLowerCase();\n\n // 1. Exact path match relative to the content root.\n const exact = byPath.get(key);\n if (exact) return { page: exact };\n\n // 2 and 3. Basename match, then slugified basename match.\n const named = byName.get(key) ?? byName.get(slugifySegment(cleaned));\n if (named === undefined || named.length === 0) return {};\n if (named.length === 1) return { page: named[0]! };\n return { page: pick(named), ambiguous: named };\n }\n\n function href(page: ContentPage, hash: string | undefined): string {\n const url = withBase(base, page.url);\n return hash === undefined ? url : `${url}#${slugify(hash)}`;\n }\n\n return {\n resolveHref(raw, fromFile) {\n if (isExternalHref(raw) && !raw.startsWith('.') && !CONTENT_EXT.test(raw.split('#')[0] ?? '')) {\n return { href: raw };\n }\n const [pathPart = '', hashPart] = splitHash(raw);\n if (!CONTENT_EXT.test(pathPart)) return { href: raw };\n\n // A leading slash means \"from the content root\", so the linking file's directory is\n // not the starting point.\n const fromDir = pathPart.startsWith('/') ? [] : toPosix(fromFile).split('/').slice(0, -1);\n const resolved = joinPosix(fromDir, pathPart);\n const page = byPath.get(resolved.toLowerCase());\n\n if (page === undefined) {\n return {\n href: raw,\n warning: `Broken link ${raw} in ${toPosix(fromFile)}: no page at ${resolved}.`,\n };\n }\n return { href: href(page, hashPart) };\n },\n\n resolveWikilink(target, fromFile) {\n const pipe = target.indexOf('|');\n const linkPart = (pipe === -1 ? target : target.slice(0, pipe)).trim();\n const label = (pipe === -1 ? target : target.slice(pipe + 1)).trim();\n const [pathPart = '', hashPart] = splitHash(linkPart);\n\n const { page, ambiguous } = lookup(pathPart);\n if (page === undefined) {\n return {\n label,\n warning: `Dead wikilink [[${target}]] in ${toPosix(fromFile)}: no page matches \"${pathPart}\".`,\n };\n }\n\n const warning =\n ambiguous === undefined\n ? undefined\n : `Ambiguous wikilink [[${target}]] in ${toPosix(fromFile)}: matches ${ambiguous\n .map((c) => c.file)\n .sort()\n .join(', ')}. Using ${page.file}.`;\n\n return { href: href(page, hashPart), label, warning };\n },\n };\n}\n\nfunction splitHash(value: string): [string, string | undefined] {\n const index = value.indexOf('#');\n if (index === -1) return [value, undefined];\n return [value.slice(0, index), value.slice(index + 1)];\n}\n\n/** Resolve `./a`, `../a`, `a` against a directory, without touching the real filesystem. */\nfunction joinPosix(fromDir: readonly string[], relative: string): string {\n const segments = [...fromDir];\n for (const part of toPosix(relative).split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') segments.pop();\n else segments.push(part);\n }\n return segments.join('/').replace(CONTENT_EXT, '');\n}\n","/**\n * Path → URL resolution.\n *\n * One slug algorithm, `github-slugger`, is used for URLs, heading anchors and the search\n * index alike — it is already a fumadocs dependency, so agreeing with it is free.\n */\nimport { slug as slugify } from 'github-slugger';\n\nconst INDEX_NAMES = new Set(['index', 'readme']);\nconst CONTENT_EXT = /\\.mdx?$/i;\n\nexport interface RouteInfo {\n /** Virtual path relative to the content root, posix separators. */\n file: string;\n /** Route URL: leading slash, never a trailing slash. The site root is `/`. */\n url: string;\n /** Slug segments; the site root is the empty array. */\n slugs: string[];\n /** Path of the emitted HTML relative to `dist/`. */\n output: string;\n /** Whether this file stands for its directory rather than for itself. */\n isIndex: boolean;\n}\n\n/** Normalise a possibly-Windows path to a posix virtual path. */\nexport function toPosix(file: string): string {\n return file.replace(/\\\\/g, '/').replace(/^\\.\\//, '').replace(/^\\/+/, '');\n}\n\n/**\n * Slugify a single path segment. Segments that slugify to nothing (`...`, emoji-only) fall\n * back to a lowercased, punctuation-stripped form so that a URL is never empty.\n */\nexport function slugifySegment(segment: string): string {\n const slugged = slugify(segment);\n if (slugged !== '') return slugged;\n const fallback = segment.toLowerCase().replace(/[^\\p{L}\\p{N}]+/gu, '-').replace(/^-+|-+$/g, '');\n return fallback === '' ? 'untitled' : fallback;\n}\n\nexport function toRoute(file: string): RouteInfo {\n const posix = toPosix(file);\n const segments = posix.split('/');\n const basename = segments.pop() ?? '';\n const stem = basename.replace(CONTENT_EXT, '');\n const isIndex = INDEX_NAMES.has(stem.toLowerCase());\n\n const slugs = segments.map(slugifySegment);\n if (!isIndex) slugs.push(slugifySegment(stem));\n\n return {\n file: posix,\n url: slugs.length === 0 ? '/' : `/${slugs.join('/')}`,\n slugs,\n output: [...slugs, 'index.html'].join('/'),\n isIndex,\n };\n}\n\nexport interface ResolvedRoutes {\n routes: RouteInfo[];\n /** Conditions that make the site silently wrong — a build error. */\n errors: string[];\n /** Conditions that are visible on the page itself — a warning. */\n warnings: string[];\n}\n\n/**\n * Resolve a whole corpus at once, because the interesting failures are corpus-level:\n * `index.md` vs `README.md` in one directory, and two different files slugifying alike.\n */\nexport function resolveRoutes(files: string[]): ResolvedRoutes {\n const sorted = [...files].map(toPosix).sort();\n const byUrl = new Map<string, RouteInfo[]>();\n const warnings: string[] = [];\n const errors: string[] = [];\n\n for (const file of sorted) {\n const route = toRoute(file);\n const bucket = byUrl.get(route.url);\n if (bucket) bucket.push(route);\n else byUrl.set(route.url, [route]);\n }\n\n const routes: RouteInfo[] = [];\n for (const [url, candidates] of [...byUrl.entries()].sort(([a], [b]) => (a < b ? -1 : 1))) {\n if (candidates.length === 1) {\n routes.push(candidates[0]!);\n continue;\n }\n\n // `index.md` beating `README.md` is a documented preference, not a collision.\n const indexes = candidates.filter((c) => c.isIndex);\n if (indexes.length === candidates.length) {\n const winner =\n indexes.find((c) => c.file.split('/').pop()?.toLowerCase().startsWith('index')) ?? indexes[0]!;\n const losers = indexes.filter((c) => c !== winner);\n warnings.push(\n `${url} has more than one index file: using ${winner.file}, ignoring ${losers\n .map((l) => l.file)\n .join(', ')}.`,\n );\n routes.push(winner);\n continue;\n }\n\n errors.push(\n `Duplicate route ${url} produced by ${candidates.length} files:\\n` +\n candidates.map((c) => ` - ${c.file}`).join('\\n') +\n `\\nRename one of them, or exclude it with \\`exclude\\` in seemore.config.ts.`,\n );\n }\n\n return { routes, errors, warnings };\n}\n","import { dynamicLoader } from 'fumadocs-core/source';\nimport type { Root } from 'fumadocs-core/page-tree';\nimport { scan, type ContentPage, type ScanOptions, type ScanResult } from './scan.js';\n\nexport interface SeemoreSource {\n /** The most recent scan. Never triggers filesystem work. */\n current(): ScanResult;\n /** Re-read the corpus and let fumadocs decide what changed. */\n refresh(): ScanResult;\n getPageTree(): Promise<Root>;\n /** Serialized for the browser — the payload of `virtual:seemore/tree`. */\n serializeTree(): Promise<unknown>;\n pages(): ContentPage[];\n loader: ReturnType<typeof dynamicLoader>;\n}\n\n/**\n * Wire the scanner to fumadocs' dynamic loader.\n *\n * `cache: 'custom'` puts us in charge of when a scan happens: the watcher calls\n * {@link SeemoreSource.refresh}, and fumadocs recomputes the page tree because the array\n * identity changed. Between refreshes `files()` hands back the same array, so reading the\n * tree is free.\n */\nexport function createSource(options: ScanOptions): SeemoreSource {\n let cached: ScanResult | undefined;\n\n const read = (): ScanResult => (cached ??= scan(options));\n\n const loader = dynamicLoader(\n {\n cache: 'custom',\n files: () => read().files,\n invalidate: () => {\n cached = undefined;\n },\n },\n { baseUrl: '/' },\n );\n\n return {\n loader,\n current: read,\n pages: () => read().pages,\n refresh() {\n loader.invalidate();\n return read();\n },\n async getPageTree() {\n const output = await loader.get();\n return output.getPageTree();\n },\n async serializeTree() {\n const output = await loader.get();\n return output.serializePageTree(output.getPageTree());\n },\n };\n}\n","import { readFileSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { globSync } from 'tinyglobby';\nimport { z } from 'zod';\nimport type { VirtualFile } from 'fumadocs-core/source';\nimport { parseFrontmatter, type FrontmatterData } from './frontmatter.js';\nimport { resolveRoutes, toPosix, type RouteInfo } from './slug.js';\n\n/** Appended to, never replaced by, `config.exclude`. */\nexport const DEFAULT_EXCLUDES = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/out/**',\n '**/vendor/**',\n '**/target/**',\n '**/.seemore/**',\n '**/.*/**',\n '**/.*',\n '**/CHANGELOG.md',\n];\n\n/** fumadocs' `meta.json` shape, validated so a typo reports a file rather than a blank folder. */\nconst metaSchema = z\n .object({\n title: z.string().optional(),\n icon: z.string().optional(),\n root: z.boolean().optional(),\n pages: z.array(z.string()).optional(),\n pagesIndex: z.string().optional(),\n defaultOpen: z.boolean().optional(),\n collapsible: z.boolean().optional(),\n description: z.string().optional(),\n })\n .loose();\n\nexport interface ContentPage extends RouteInfo {\n /** Absolute path on disk — what the generated import map imports. */\n absPath: string;\n data: FrontmatterData & { title: string };\n}\n\nexport interface ScanResult {\n /** What fumadocs' loader consumes. */\n files: VirtualFile[];\n /** What the router, prefetch map and prerender driver consume. */\n pages: ContentPage[];\n errors: string[];\n warnings: string[];\n}\n\nexport interface ScanOptions {\n contentRoot: string;\n exclude?: string[];\n /** Used as the title of a root index page that has no frontmatter title. */\n siteTitle?: string;\n /** Dev keeps drafts so they can be written; the build drops them. */\n includeDrafts?: boolean;\n}\n\nexport function scan(options: ScanOptions): ScanResult {\n const contentRoot = resolve(options.contentRoot);\n const ignore = [...DEFAULT_EXCLUDES, ...(options.exclude ?? [])];\n\n const contentFiles = globSync(['**/*.md', '**/*.mdx'], {\n cwd: contentRoot,\n ignore,\n dot: false,\n absolute: false,\n }).map(toPosix);\n\n const metaFiles = globSync(['**/meta.json'], { cwd: contentRoot, ignore, dot: false, absolute: false }).map(toPosix);\n\n const { routes, errors, warnings } = resolveRoutes(contentFiles);\n\n const pages: ContentPage[] = [];\n for (const route of routes) {\n const absPath = join(contentRoot, route.file);\n let data: FrontmatterData;\n try {\n data = parseFrontmatter(readFileSync(absPath, 'utf8'), route.file).data;\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n continue;\n }\n\n if (data.draft === true && options.includeDrafts !== true) continue;\n\n pages.push({ ...route, absPath, data: { ...data, title: titleFor(route, data, options.siteTitle) } });\n }\n\n const files: VirtualFile[] = pages.map((page) => ({\n type: 'page',\n path: page.file,\n absolutePath: page.absPath,\n // Our slugs, not fumadocs' — one algorithm decides URLs, anchors and the index.\n slugs: page.slugs,\n data: page.data,\n }));\n\n const metaDirs = new Set<string>();\n for (const file of metaFiles) {\n const absPath = join(contentRoot, file);\n try {\n const parsed = metaSchema.safeParse(JSON.parse(readFileSync(absPath, 'utf8')));\n if (!parsed.success) {\n errors.push(\n `Invalid ${file}:\\n${parsed.error.issues.map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`).join('\\n')}`,\n );\n continue;\n }\n metaDirs.add(dirname(file));\n files.push({ type: 'meta', path: file, absolutePath: absPath, data: parsed.data });\n } catch (error) {\n errors.push(`Invalid ${file}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n files.push(...synthesiseOrderMeta(pages, metaDirs));\n\n return { files, pages, errors, warnings };\n}\n\n/**\n * Ordering: a real `meta.json` wins; otherwise frontmatter `order` decides, then\n * title. fumadocs has no native `order`, so we express the intent in the mechanism it does\n * have — a synthetic `meta.json` whose `pages` list ends in the `...` rest marker, leaving\n * anything we did not mention in fumadocs' own alphabetical order.\n */\nfunction synthesiseOrderMeta(pages: ContentPage[], metaDirs: Set<string>): VirtualFile[] {\n const byDir = new Map<string, ContentPage[]>();\n for (const page of pages) {\n const dir = dirname(page.file);\n const bucket = byDir.get(dir);\n if (bucket) bucket.push(page);\n else byDir.set(dir, [page]);\n }\n\n const out: VirtualFile[] = [];\n for (const [dir, dirPages] of byDir) {\n if (metaDirs.has(dir)) continue;\n // Nothing to express unless something wants to move: an explicit `order`, or an index\n // page that would otherwise sort alphabetically into the middle of its own directory.\n if (!dirPages.some((p) => typeof p.data.order === 'number' || p.isIndex)) continue;\n\n const ordered = [...dirPages].sort(compareForOrder).map((p) => basename(p.file).replace(/\\.mdx?$/i, ''));\n\n out.push({\n type: 'meta',\n path: dir === '.' ? 'meta.json' : `${dir}/meta.json`,\n data: { pages: [...ordered, '...'] },\n });\n }\n return out;\n}\n\nfunction compareForOrder(a: ContentPage, b: ContentPage): number {\n // An index page stands for its directory, so it leads unless it asks not to.\n const ao = orderOf(a);\n const bo = orderOf(b);\n if (ao !== bo) return ao - bo;\n return a.data.title.localeCompare(b.data.title);\n}\n\nfunction orderOf(page: ContentPage): number {\n if (typeof page.data.order === 'number') return page.data.order;\n return page.isIndex ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;\n}\n\nfunction titleFor(route: RouteInfo, data: FrontmatterData, siteTitle: string | undefined): string {\n if (typeof data.title === 'string' && data.title !== '') return data.title;\n if (route.url === '/') return siteTitle ?? 'Home';\n return humanise(route.slugs[route.slugs.length - 1] ?? 'Untitled');\n}\n\n/** `getting-started` → `Getting Started`. Good enough to never show a raw slug in a sidebar. */\nfunction humanise(slug: string): string {\n return slug\n .split('-')\n .filter((word) => word !== '')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n","import matter from 'gray-matter';\nimport { z } from 'zod';\n\n/**\n * Frontmatter is validated, not restricted: unknown keys pass through so that a corpus\n * written for another tool still builds. Only the keys seemore acts on are typed.\n */\nexport const frontmatterSchema = z\n .object({\n title: z.string().optional(),\n description: z.string().optional(),\n icon: z.string().optional(),\n /** Sidebar ordering, second only to `meta.json`. */\n order: z.number().optional(),\n /**\n * Excluded from the build. Dev keeps drafts so they can be written, so a link to one\n * works while you write it and warns as a dead link when you build.\n */\n draft: z.boolean().optional(),\n })\n .loose();\n\nexport type FrontmatterData = z.output<typeof frontmatterSchema> & Record<string, unknown>;\n\n/** Split a source file into validated frontmatter and body. `file` is only for messages. */\nexport function parseFrontmatter(source: string, file: string): { data: FrontmatterData; content: string } {\n let parsed;\n try {\n parsed = matter(source);\n } catch (error) {\n throw new Error(\n `Invalid frontmatter in ${file}: ${error instanceof Error ? error.message.split('\\n')[0] : String(error)}`,\n { cause: error },\n );\n }\n\n return { data: validateFrontmatter(parsed.data, file), content: parsed.content };\n}\n\nexport function validateFrontmatter(data: unknown, file: string): FrontmatterData {\n const result = frontmatterSchema.safeParse(data ?? {});\n if (result.success) return result.data as FrontmatterData;\n\n const issues = result.error.issues.map((issue) => {\n const field = issue.path.length === 0 ? '(root)' : issue.path.join('.');\n return ` - ${field}: ${issue.message}`;\n });\n throw new Error(`Invalid frontmatter in ${file}:\\n${issues.join('\\n')}`);\n}\n","import pc from 'picocolors';\n\n/**\n * Warnings are collected and printed once, as a grouped summary, rather than interleaved\n * with progress output — a build that prints forty warnings between chunks is a\n * build whose warnings nobody reads.\n */\nexport interface WarningCollector {\n add(message: string): void;\n list(): string[];\n clear(): void;\n /** Print the grouped summary. Returns the number of warnings printed. */\n flush(log?: (line: string) => void): number;\n}\n\nexport function createWarningCollector(): WarningCollector {\n const seen = new Set<string>();\n\n return {\n add(message) {\n seen.add(message);\n },\n list: () => [...seen],\n clear: () => seen.clear(),\n flush(log = console.warn) {\n const messages = [...seen].sort();\n seen.clear();\n if (messages.length === 0) return 0;\n log('');\n log(pc.yellow(`${messages.length} warning${messages.length === 1 ? '' : 's'}:`));\n for (const message of messages) log(pc.yellow(` - ${message}`));\n log('');\n return messages.length;\n },\n };\n}\n","import { createLinkResolver, type LinkResolver } from './content/links.js';\nimport type { ContentPage, ScanResult } from './content/scan.js';\nimport { createSource, type SeemoreSource } from './content/source.js';\nimport type { ResolvedSeemoreConfig } from './config/schema.js';\nimport { createWarningCollector, type WarningCollector } from './report.js';\n\nexport interface SeemoreContext {\n config: ResolvedSeemoreConfig;\n /** Absolute path of the directory being documented. Usually outside the Vite root. */\n contentRoot: string;\n source: SeemoreSource;\n warnings: WarningCollector;\n pages(): ContentPage[];\n /** Rebuilt on every refresh, so remark plugins must read it late. */\n resolver(): LinkResolver;\n /** Re-read the corpus after a filesystem change. */\n refresh(): ScanResult;\n /** Slug collisions and frontmatter failures found by the most recent scan. */\n errors(): string[];\n}\n\nexport interface CreateContextOptions {\n config: ResolvedSeemoreConfig;\n contentRoot: string;\n /** Dev keeps drafts so they can be written; the build drops them. */\n includeDrafts?: boolean;\n}\n\nexport function createContext(options: CreateContextOptions): SeemoreContext {\n const { config, contentRoot } = options;\n\n const source = createSource({\n contentRoot,\n exclude: config.exclude,\n siteTitle: config.title,\n includeDrafts: options.includeDrafts,\n });\n\n let resolver = createLinkResolver(source.pages(), config.base);\n\n return {\n config,\n contentRoot,\n source,\n warnings: createWarningCollector(),\n pages: () => source.pages(),\n resolver: () => resolver,\n errors: () => source.current().errors,\n refresh() {\n const result = source.refresh();\n resolver = createLinkResolver(result.pages, config.base);\n return result;\n },\n };\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n/** Turn a route URL into the file that serves it. */\nexport function outputPathFor(url: string): string {\n const clean = url.replace(/^\\/+|\\/+$/g, '');\n return clean === '' ? 'index.html' : join(clean, 'index.html');\n}\n\nexport function writeHtml(outDir: string, relativePath: string, html: string): void {\n const target = join(outDir, relativePath);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, html, 'utf8');\n}\n\n/**\n * Inject a rendered page into the client build's `index.html`.\n *\n * The template already carries the hashed script and stylesheet Vite emitted, so the markup\n * and the assets can never drift apart.\n */\nexport function applyTemplate(template: string, { html, head }: { html: string; head: string }): string {\n // Replacer functions, not strings: a page containing `$&` or `` $` `` would otherwise\n // splice the marker — or the whole document head — into its own body.\n return template.replace('<!--seemore-head-->', () => head).replace('<!--seemore-app-->', () => html);\n}\n","import { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/**\n * Host conventions.\n *\n * The portable output is everything else: one real `index.html` per route, plus `404.html`,\n * which every static host honours. These files are additive — small, named conventions that\n * particular hosts look for — not a list of hosts seemore supports.\n */\nexport function writeDeployArtifacts(outDir: string, base: string, shell: string): void {\n const prefix = base === '/' ? '' : base.replace(/\\/+$/, '');\n\n // Netlify and Cloudflare Pages share this format. It applies after the real files they\n // already serve, so it only catches addresses that do not exist.\n writeFileSync(join(outDir, '_redirects'), `${prefix}/* ${prefix}/index.html 200\\n`, 'utf8');\n\n // Surge looks for `200.html` as its SPA fallback.\n writeFileSync(join(outDir, '200.html'), shell, 'utf8');\n\n // GitHub Pages runs the output through Jekyll unless this file exists, and Jekyll drops\n // every file and directory whose name starts with `_`. A `docs/_internal/` folder would\n // build correctly and then 404 once deployed — the exact failure seemore exists to prevent.\n writeFileSync(join(outDir, '.nojekyll'), '', 'utf8');\n}\n","import { pathToFileURL } from 'node:url';\nimport { join } from 'node:path';\nimport { build } from 'vite';\nimport type { SeemoreContext } from '../context.js';\nimport { createViteConfig } from '../vite/config.js';\n\nexport interface RenderResult {\n html: string;\n head: string;\n}\n\nexport interface PrerenderModule {\n render(url: string): Promise<RenderResult>;\n listRoutes(): string[];\n}\n\n/**\n * Build the prerender entry for node and load it.\n *\n * This is a second Vite build rather than a reuse of the client bundle because the client\n * bundle is compiled for the browser; the driver needs the same module graph evaluated in\n * node, with the same virtual modules, so the two can never describe different sites.\n */\nexport async function loadPrerenderModule(ctx: SeemoreContext, ssrOutDir: string): Promise<PrerenderModule> {\n await build(createViteConfig({ ctx, mode: 'build', ssrOutDir }));\n\n const entry = join(ssrOutDir, 'entry.prerender.js');\n const loaded = (await import(pathToFileURL(entry).href)) as Partial<PrerenderModule>;\n\n if (typeof loaded.render !== 'function' || typeof loaded.listRoutes !== 'function') {\n throw new Error(`seemore: the prerender build at ${entry} did not export \\`render\\` and \\`listRoutes\\`.`);\n }\n\n return { render: loaded.render, listRoutes: loaded.listRoutes };\n}\n","import { realpathSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { InlineConfig, Plugin } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tailwindcss from '@tailwindcss/vite';\nimport mdx from '@mdx-js/rollup';\nimport type { SeemoreContext } from '../context.js';\nimport { appRoot, cacheDir, packageRoot } from '../paths.js';\nimport { createRehypePlugins, createRemarkPlugins } from './mdx.js';\nimport { seemorePlugin } from './plugin.js';\nimport { seemoreWatcherPlugin } from './watcher.js';\n\nexport interface ViteConfigOptions {\n ctx: SeemoreContext;\n mode: 'dev' | 'build';\n /** Absolute output directory. Ignored in dev. */\n outDir?: string;\n /** When set, build the prerender entry for node instead of the client bundle. */\n ssrOutDir?: string;\n}\n\nexport function createViteConfig({ ctx, mode, outDir, ssrOutDir }: ViteConfigOptions): InlineConfig {\n const root = appRoot();\n const isSsr = ssrOutDir !== undefined;\n\n const mdxOptions = {\n // `format` is inferred per file, so a plain `.md` never needs MDX syntax.\n remarkPlugins: createRemarkPlugins({\n contentRoot: ctx.contentRoot,\n getResolver: () => ctx.resolver(),\n onWarning: (message) => ctx.warnings.add(message),\n }),\n rehypePlugins: createRehypePlugins(),\n // MDX compiles its own JSX. Vite's builtin transform infers a file's language from its\n // extension and does not know `.md`/`.mdx`, so leaving JSX in the output would fail to\n // parse. Fast Refresh is unaffected: it is a separate transform, applied to these files\n // through the React plugin's `include` below, which is what turns a content edit into an\n // in-place component swap rather than a reload.\n jsx: false,\n };\n\n return {\n root,\n base: ctx.config.base,\n cacheDir: cacheDir(ctx.contentRoot),\n configFile: false,\n envDir: false,\n clearScreen: false,\n logLevel: mode === 'build' ? 'warn' : 'info',\n\n plugins: [\n // Order matters: MDX first, then React, so JSX from MDX is transformed and refreshed.\n { ...mdx(mdxOptions), enforce: 'pre' },\n react({ include: /\\.(?:mdx?|jsx?|tsx?)$/ }),\n // Before Tailwind: our plugin injects the theme preset into the root stylesheet, and\n // Tailwind must see the injected version.\n seemorePlugin({ ctx, serveSearch: mode === 'dev' }),\n tailwindcss(),\n ...(mode === 'dev' ? [seemoreWatcherPlugin(ctx)] : []),\n ],\n\n // Vite bundles workers with the browser export condition, but a worker has no `document`.\n // `decode-named-character-reference` — pulled in through fumadocs' search client, via\n // remark — calls `document.createElement` at module scope in its browser build, so the\n // search worker threw on load. The package ships a DOM-free `worker` entry; use it.\n worker: { plugins: () => [workerConditionPlugin()] },\n\n resolve: {\n // The app is compiled from seemore's own sources, so its dependencies must resolve\n // from seemore's directory rather than from the user's project.\n dedupe: ['react', 'react-dom', 'react-router', 'fumadocs-core', 'fumadocs-ui'],\n },\n\n server: {\n fs: {\n // The content root is normally *outside* the Vite root, and files outside `allow`\n // 404 silently — the single most likely cause of \"the watcher does nothing\".\n allow: withRealPaths([root, packageRoot(), ctx.contentRoot, ctx.config.root, process.cwd()]),\n },\n watch: {\n // Only real exclusions here. Vite merges these into chokidar's ignore *list*, where a\n // leading `!` is a negated matcher that matches everything it is not — so the obvious\n // `!<contentRoot>/**` \"re-include\" would silently ignore the entire project instead.\n // Content outside the Vite root is watched by seemore's own chokidar instance.\n ignored: ['**/node_modules/**', '**/.git/**'],\n },\n },\n\n build: isSsr\n ? {\n ssr: join(root, 'entry.prerender.tsx'),\n outDir: ssrOutDir,\n emptyOutDir: true,\n copyPublicDir: false,\n minify: false,\n rollupOptions: { output: { entryFileNames: 'entry.prerender.js' } },\n }\n : {\n outDir,\n emptyOutDir: true,\n rollupOptions: { input: join(root, 'index.html') },\n // The app bundle is seemore's own, not the user's; warning them about a size they\n // cannot act on is noise.\n chunkSizeWarningLimit: 2_000,\n },\n\n // The prerender bundle is written to a scratch directory outside any `node_modules`, so\n // it has to be self-contained: an externalised `react` there resolves against the scratch\n // directory and is simply not found.\n ssr: isSsr ? { noExternal: true } : undefined,\n };\n}\n\n/**\n * Every path, plus where it actually points.\n *\n * Vite resolves a module to its real path before checking `fs.allow`, so a content root\n * reached through a symlink — `/var` on macOS, or anything under a linked directory — is\n * denied unless both spellings are listed. The failure is a silent 404, so it is worth the\n * two extra entries.\n */\nfunction withRealPaths(paths: string[]): string[] {\n const out = new Set<string>();\n for (const path of paths) {\n out.add(path);\n try {\n out.add(realpathSync.native(path));\n } catch {\n // A path that does not exist yet cannot be resolved, and does not need to be.\n }\n }\n return [...out];\n}\n\n/**\n * Point worker bundles at the DOM-free build of packages that ship two.\n *\n * Resolution goes through Vite so pnpm's layout is respected — these packages are deep\n * transitive dependencies and are not resolvable from seemore's own directory — and only the\n * final `index.dom.js` is swapped for its sibling.\n */\nfunction workerConditionPlugin(): Plugin {\n return {\n name: 'seemore:worker-conditions',\n enforce: 'pre',\n async resolveId(source, importer, options) {\n if (!WORKER_SAFE_ENTRIES.has(source)) return undefined;\n\n const resolved = await this.resolve(source, importer, options);\n if (resolved === null) return undefined;\n\n const domFree = resolved.id.replace(/index\\.dom\\.js$/, 'index.js');\n return domFree === resolved.id ? resolved : { ...resolved, id: domFree };\n },\n };\n}\n\n/**\n * Packages whose browser build touches the DOM at module scope and whose default build does\n * not. `decode-named-character-reference` reaches the worker through remark, by way of\n * fumadocs' search client.\n */\nconst WORKER_SAFE_ENTRIES = new Set(['decode-named-character-reference']);\n","import type { PluggableList } from 'unified';\nimport remarkFrontmatter from 'remark-frontmatter';\nimport {\n rehypeCode,\n rehypeToc,\n remarkAdmonition,\n remarkDirectiveAdmonition,\n remarkGfm,\n remarkHeading,\n remarkImage,\n remarkMdxMermaid,\n remarkSteps,\n} from 'fumadocs-core/mdx-plugins';\nimport {\n remarkSeemoreAlerts,\n remarkSeemoreAssets,\n remarkSeemoreLinks,\n remarkSeemoreWikilinks,\n type SeemoreRemarkOptions,\n} from './remark.js';\n\n/**\n * The remark/rehype chain. Order matters:\n *\n * - headings get their ids before `rehype-toc` reads them;\n * - our link rewriting runs after the fumadocs transforms that can create links;\n * - Shiki runs at build time in `rehype-code`, so no highlighter ships to the browser.\n *\n * `remark-structure` is deliberately absent: search indexing runs node-side over the raw\n * markdown, where it works identically in dev and build without depending on a\n * browser module having been evaluated.\n */\nexport function createRemarkPlugins(options: SeemoreRemarkOptions): PluggableList {\n return [\n // Strips the `---` block so it never renders. Its data already came from the scan.\n [remarkFrontmatter, ['yaml']],\n remarkGfm,\n remarkHeading,\n remarkAdmonition,\n remarkDirectiveAdmonition,\n // After the fumadocs admonition plugins, which handle `:::note`, and before anything that\n // rewrites link or text nodes inside the quote.\n remarkSeemoreAlerts,\n remarkSteps,\n // Before `remark-image`: a reference to a file that is not there becomes a warning and a\n // visibly broken image, rather than a failed build.\n () => remarkSeemoreAssets(options),\n [\n remarkImage,\n {\n onError: (error: Error) => {\n options.onWarning(error.message);\n },\n },\n ],\n // Rewrites ```mermaid fences to <Mermaid chart=\"…\" />. We supply the component.\n remarkMdxMermaid,\n () => remarkSeemoreWikilinks(options),\n () => remarkSeemoreLinks(options),\n ];\n}\n\nexport function createRehypePlugins(): PluggableList {\n return [\n // A fence in a language Shiki has no grammar for (` ```d2 `, anything an AI dreamt up) is\n // plain code on the page, not a dead one: `plaintext` is special-cased by Shiki and\n // never needs loading.\n [rehypeCode, { fallbackLanguage: 'plaintext' }],\n rehypeToc,\n ];\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, relative, resolve } from 'node:path';\nimport { visit } from 'unist-util-visit';\nimport type { Blockquote, Image, Paragraph, PhrasingContent, Root, Text } from 'mdast';\nimport type { Transformer } from 'unified';\nimport type { VFile } from 'vfile';\nimport type { LinkResolver } from '../content/links.js';\nimport { toPosix } from '../content/slug.js';\n\nexport interface SeemoreRemarkOptions {\n contentRoot: string;\n /** Read late: the resolver is replaced on every rescan. */\n getResolver: () => LinkResolver;\n onWarning: (message: string) => void;\n}\n\nconst WIKILINK = /\\[\\[([^\\]\\n]+)\\]\\]/g;\n\n/** GitHub's alert syntax, and the fumadocs callout each kind maps onto. */\nconst ALERTS: Record<string, { type: string; title: string }> = {\n NOTE: { type: 'info', title: 'Note' },\n TIP: { type: 'idea', title: 'Tip' },\n IMPORTANT: { type: 'info', title: 'Important' },\n WARNING: { type: 'warn', title: 'Warning' },\n CAUTION: { type: 'error', title: 'Caution' },\n};\n\nconst ALERT_MARKER = /^\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]\\s*/;\n\n/**\n * GitHub alerts — `> [!NOTE]` — become fumadocs callouts.\n *\n * fumadocs ships `:::note` and directive admonitions, neither of which is what people\n * actually have in their repositories. seemore points at folders that already exist, so the\n * syntax GitHub renders is the syntax that has to work.\n */\nexport function remarkSeemoreAlerts(): Transformer<Root, Root> {\n return (tree) => {\n visit(tree, 'blockquote', (node: Blockquote, index, parent) => {\n if (parent === undefined || index === undefined) return;\n\n const first = node.children[0];\n if (first === undefined || first.type !== 'paragraph') return;\n\n const marker = ALERT_MARKER.exec(textOf(first));\n const alert = marker === null ? undefined : ALERTS[marker[1] ?? ''];\n if (marker === undefined || marker === null || alert === undefined) return;\n\n stripMarker(first, marker[0]);\n\n parent.children[index] = {\n type: 'mdxJsxFlowElement',\n name: 'Callout',\n attributes: [\n { type: 'mdxJsxAttribute', name: 'type', value: alert.type },\n { type: 'mdxJsxAttribute', name: 'title', value: alert.title },\n ],\n children: node.children,\n } as unknown as Blockquote;\n });\n };\n}\n\n/** The paragraph's leading text, which is where the marker lives. */\nfunction textOf(paragraph: Paragraph): string {\n const first = paragraph.children[0];\n return first !== undefined && first.type === 'text' ? first.value.trimStart() : '';\n}\n\n/** Remove the `[!NOTE]` marker, and the line break that followed it. */\nfunction stripMarker(paragraph: Paragraph, marker: string): void {\n const first = paragraph.children[0];\n if (first === undefined || first.type !== 'text') return;\n\n first.value = first.value.trimStart().slice(marker.length).replace(/^\\n/, '');\n if (first.value === '') paragraph.children.shift();\n if (paragraph.children[0]?.type === 'break') paragraph.children.shift();\n}\n\n/**\n * `[[Page]]`, `[[Page|label]]`, `[[Page#Heading]]`. fumadocs has no equivalent.\n *\n * Unresolved targets become styled plain text rather than dead links, because a link that\n * goes nowhere is worse than visibly missing text.\n */\nexport function remarkSeemoreWikilinks(options: SeemoreRemarkOptions): Transformer<Root, Root> {\n return (tree, file) => {\n const from = virtualPath(options.contentRoot, file);\n const resolver = options.getResolver();\n\n visit(tree, 'text', (node: Text, index, parent) => {\n if (parent === undefined || index === undefined) return;\n if (!node.value.includes('[[')) return;\n\n const replacement: PhrasingContent[] = [];\n let cursor = 0;\n WIKILINK.lastIndex = 0;\n\n for (let match = WIKILINK.exec(node.value); match !== null; match = WIKILINK.exec(node.value)) {\n const target = match[1] ?? '';\n if (match.index > cursor) {\n replacement.push({ type: 'text', value: node.value.slice(cursor, match.index) });\n }\n cursor = match.index + match[0].length;\n\n const resolved = resolver.resolveWikilink(target, from);\n if (resolved.warning !== undefined) options.onWarning(resolved.warning);\n\n if (resolved.href === undefined) {\n // An MDX JSX node, not raw HTML: `.md` files run through `rehypeRemoveRaw`, which\n // would silently drop an `html` node, whereas JSX nodes are passed through.\n replacement.push({\n type: 'mdxJsxTextElement',\n name: 'span',\n attributes: [\n { type: 'mdxJsxAttribute', name: 'className', value: 'seemore-broken-wikilink' },\n { type: 'mdxJsxAttribute', name: 'title', value: 'Unresolved link' },\n ],\n children: [{ type: 'text', value: resolved.label }],\n } as unknown as PhrasingContent);\n } else {\n replacement.push({\n type: 'link',\n url: resolved.href,\n children: [{ type: 'text', value: resolved.label }],\n });\n }\n }\n\n if (replacement.length === 0) return;\n if (cursor < node.value.length) replacement.push({ type: 'text', value: node.value.slice(cursor) });\n\n parent.children.splice(index, 1, ...replacement);\n return index + replacement.length;\n });\n };\n}\n\n/**\n * A referenced asset that is not on disk is a warning, not a build failure: the page is\n * visibly wrong on its own, which is the point of the distinction.\n *\n * It has to run before fumadocs' `remark-image`, which turns every image into a bundler\n * import — and an import of a file that does not exist fails the build. Turning the node\n * into JSX first takes it out of that plugin's way, leaving the broken reference visible on\n * the page exactly as the author wrote it.\n */\nexport function remarkSeemoreAssets(options: SeemoreRemarkOptions): Transformer<Root, Root> {\n return (tree, file) => {\n if (typeof file.path !== 'string' || file.path === '') return;\n const dir = dirname(file.path);\n const from = virtualPath(options.contentRoot, file);\n\n visit(tree, 'image', (node: Image, index, parent) => {\n if (parent === undefined || index === undefined) return;\n if (isExternal(node.url) || node.url.startsWith('/')) return;\n\n const target = resolve(dir, decodeURIComponent(node.url.split(/[?#]/)[0] ?? ''));\n if (existsSync(target)) return;\n\n options.onWarning(`Missing asset ${node.url} referenced by ${from}.`);\n\n parent.children.splice(index, 1, {\n type: 'mdxJsxTextElement',\n name: 'img',\n attributes: [\n { type: 'mdxJsxAttribute', name: 'src', value: node.url },\n { type: 'mdxJsxAttribute', name: 'alt', value: node.alt ?? '' },\n { type: 'mdxJsxAttribute', name: 'data-seemore-missing', value: 'true' },\n ],\n children: [],\n } as unknown as PhrasingContent);\n });\n };\n}\n\nfunction isExternal(url: string): boolean {\n return /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i.test(url);\n}\n\n/** Relative `.md`/`.mdx` links become routes, base included. */\nexport function remarkSeemoreLinks(options: SeemoreRemarkOptions): Transformer<Root, Root> {\n return (tree, file) => {\n const from = virtualPath(options.contentRoot, file);\n const resolver = options.getResolver();\n\n const rewrite = (node: { url: string }) => {\n const resolved = resolver.resolveHref(node.url, from);\n if (resolved.warning !== undefined) options.onWarning(resolved.warning);\n node.url = resolved.href;\n };\n\n visit(tree, 'link', rewrite);\n visit(tree, 'definition', rewrite);\n };\n}\n\nfunction virtualPath(contentRoot: string, file: VFile): string {\n if (typeof file.path !== 'string' || file.path === '') return '';\n return toPosix(relative(contentRoot, file.path));\n}\n","import { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\nimport type { Plugin, ViteDevServer } from 'vite';\nimport { withBase } from '../base.js';\nimport type { SeemoreContext } from '../context.js';\nimport { buildSearchIndex } from '../search/build.js';\nimport { toPosix } from '../content/slug.js';\n\nexport const VIRTUAL = {\n tree: 'virtual:seemore/tree',\n routes: 'virtual:seemore/routes',\n config: 'virtual:seemore/config',\n} as const;\n\n/**\n * Prefix for content-body imports emitted into `virtual:seemore/routes`.\n *\n * A bare absolute path would be read as *root*-relative by Vite, and the content root is\n * normally outside the Vite root. Resolving our own prefix to the real file id keeps dev and\n * build identical, and lets `@mdx-js/rollup` transform the file as it normally would.\n */\nconst PAGE_PREFIX = 'seemore-page:';\n\nconst resolvedId = (id: string) => `\\0${id}`;\n\n/**\n * Two markers, deliberately: see the comments in `src/app/styles/globals.css`.\n *\n * `@import` is only valid before the first style rule, so the theme has to go at the top —\n * and the user's own stylesheet has to go at the bottom, or it loses to the rules it is\n * meant to override and, worse, invalidates the imports it was inlined above.\n */\nconst IMPORTS_MARKER = /\\/\\* seemore:imports[\\s\\S]*?\\*\\//;\nconst USER_CSS_MARKER = /\\/\\* seemore:user-css[\\s\\S]*?\\*\\//;\n\nconst require_ = createRequire(import.meta.url);\n\nfunction styleImports(ctx: SeemoreContext): string {\n const lines: string[] = [`@import 'fumadocs-ui/css/${ctx.config.theme}.css';`];\n\n // Tailwind cannot scan class names it never sees, and fumadocs-ui ships compiled JS.\n try {\n lines.push(`@source '${dirname(require_.resolve('fumadocs-ui/package.json'))}/dist';`);\n } catch {\n // A layout without the package resolvable is already broken elsewhere; do not add noise.\n }\n\n return lines.join('\\n');\n}\n\nfunction userCss(ctx: SeemoreContext): string {\n if (ctx.config.css === undefined) return '';\n\n const css = readIfExists(ctx.config.css);\n if (css === undefined) {\n ctx.warnings.add(`The stylesheet named by \\`css\\` was not found: ${ctx.config.css}`);\n return '';\n }\n\n // Inlined rather than imported: an `@import` this far down the file is not valid CSS.\n return `/* ${ctx.config.css} */\\n${css}`;\n}\n\nexport interface SeemorePluginOptions {\n ctx: SeemoreContext;\n /** Dev serves the index from memory; build writes it to `dist/api/search.json`. */\n serveSearch?: boolean;\n}\n\nexport function seemorePlugin({ ctx, serveSearch = false }: SeemorePluginOptions): Plugin {\n let server: ViteDevServer | undefined;\n\n return {\n name: 'seemore',\n enforce: 'pre',\n\n resolveId(id) {\n // Native separators from `page.absPath` would key a second, unloadable module in\n // Vite's URL-addressed graph — canonical ids are always forward slashes.\n if (id.startsWith(PAGE_PREFIX)) return id.slice(PAGE_PREFIX.length).replace(/\\\\/g, '/');\n for (const virtualId of Object.values(VIRTUAL)) {\n if (id === virtualId) return resolvedId(virtualId);\n }\n return undefined;\n },\n\n /**\n * The theme preset, the paths Tailwind must scan, and the user's own stylesheet are\n * injected into our root stylesheet rather than imported from it.\n *\n * Tailwind v4 only processes the file that contains `@import \"tailwindcss\"`, and bare\n * specifiers in a virtual stylesheet have no directory to resolve from — injecting into\n * the real `globals.css` keeps both working.\n */\n transform(code, id) {\n const path = id.replace(/\\\\/g, '/').split('?')[0] ?? '';\n if (!path.endsWith('/src/app/styles/globals.css')) return undefined;\n const transformed = code\n .replace(IMPORTS_MARKER, () => styleImports(ctx))\n .replace(USER_CSS_MARKER, () => userCss(ctx));\n return { code: transformed, map: null };\n },\n\n async load(id) {\n if (id === resolvedId(VIRTUAL.tree)) {\n return hotStoreModule('Tree', json(await ctx.source.serializeTree()));\n }\n if (id === resolvedId(VIRTUAL.routes)) {\n return hotStoreModule('Routes', renderRoutesValue(ctx));\n }\n // Config is not a store: a change to it can alter `base`, which reconfigures Vite, so\n // the page reloads rather than patching itself.\n if (id === resolvedId(VIRTUAL.config)) return `export const config = ${json(clientConfig(ctx))};`;\n return undefined;\n },\n\n configureServer(devServer) {\n server = devServer;\n if (!serveSearch) return;\n\n // The same JSON the build emits, at the same path, so the client has one code path.\n devServer.middlewares.use(async (req, res, next) => {\n const path = (req.url ?? '').split('?')[0] ?? '';\n if (path !== withBase(ctx.config.base, '/api/search.json') && path !== '/api/search.json') return next();\n try {\n const index = await buildSearchIndex(ctx);\n res.setHeader('Content-Type', 'application/json');\n res.end(index);\n } catch (error) {\n next(error);\n }\n });\n },\n\n /** Called by the watcher after a rescan. */\n api: {\n invalidate() {\n if (server === undefined) return;\n for (const virtualId of [VIRTUAL.tree, VIRTUAL.routes]) {\n const mod = server.moduleGraph.getModuleById(resolvedId(virtualId));\n if (mod) server.moduleGraph.invalidateModule(mod);\n }\n server.ws.send({ type: 'update', updates: [] });\n },\n },\n };\n}\n\n/**\n * A self-accepting module holding one value, with subscribers that survive replacement.\n *\n * State lives on `import.meta.hot.data`, so when the module re-executes after an edit the\n * new copy still has the listeners the old one handed to React. `accept()` stops the update\n * propagating to importers, which is the difference between the sidebar re-rendering in\n * place and the page reloading.\n */\nfunction hotStoreModule(suffix: string, value: string): string {\n // `import.meta.hot.accept()` is written out in full because Vite detects self-accepting\n // modules syntactically — through an alias it sees an ordinary module and reloads the page.\n return `const state = import.meta.hot\n ? (import.meta.hot.data.seemore${suffix} ||= { listeners: new Set() })\n : { listeners: new Set() };\n\nstate.value = ${value};\n\nexport function get${suffix}() {\n return state.value;\n}\n\nexport function subscribe${suffix}(listener) {\n state.listeners.add(listener);\n return () => {\n state.listeners.delete(listener);\n };\n}\n\nif (import.meta.hot) {\n import.meta.hot.accept();\n for (const listener of state.listeners) listener();\n}\n`;\n}\n\n/**\n * `virtual:seemore/routes`: one entry per page, with the body behind a dynamic\n * import so the router, the hover prefetch and the prerender driver all read one map.\n *\n * `import.meta.glob` is deliberately not used: glob patterns that escape the Vite root fail\n * silently, which is the exact failure class seemore exists to prevent.\n */\nfunction renderRoutesValue(ctx: SeemoreContext): string {\n const entries = ctx.pages().map((page) => {\n // Backslashes are legal in a Windows path and fatal in an import specifier.\n const specifier = `${PAGE_PREFIX}${page.absPath.replace(/\\\\/g, '/')}`;\n return [\n ' {',\n ` url: ${json(page.url)},`,\n ` file: ${json(page.file)},`,\n ` absPath: ${json(page.absPath)},`,\n ` title: ${json(page.data.title)},`,\n ` description: ${json(page.data.description ?? null)},`,\n ` load: () => import(${json(specifier)}),`,\n ' },',\n ].join('\\n');\n });\n\n return `[\\n${entries.join('\\n')}\\n]`;\n}\n\n/** The serialisable slice of the config the browser needs. */\nfunction clientConfig(ctx: SeemoreContext) {\n const { config } = ctx;\n return {\n title: config.title,\n description: config.description,\n base: config.base,\n theme: config.theme,\n features: config.features,\n nav: config.nav,\n footer: config.footer,\n editLink: config.editLink,\n favicon: config.favicon === undefined ? undefined : withBase(config.base, `/${toPosix(config.favicon)}`),\n search:\n config.search.provider === 'static'\n ? { provider: 'static' as const, from: withBase(config.base, '/api/search.json') }\n : config.search,\n contentRoot: config.root,\n };\n}\n\n/** JSON that is always safe to paste into a module body. */\nfunction json(value: unknown): string {\n return JSON.stringify(value ?? null)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\nexport function readIfExists(path: string): string | undefined {\n try {\n return readFileSync(path, 'utf8');\n } catch {\n return undefined;\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { gzipSync } from 'node:zlib';\nimport { createFromSource } from 'fumadocs-core/search/server';\nimport { structure } from 'fumadocs-core/mdx-plugins';\nimport { withBase } from '../base.js';\nimport { parseFrontmatter } from '../content/frontmatter.js';\nimport type { SeemoreContext } from '../context.js';\n\n/** Above this, a static index is a real download cost worth naming. */\nexport const SIZE_WARNING_BYTES = 1_500_000;\n\n/**\n * Build the static search index.\n *\n * The index is produced node-side from the raw markdown rather than from the compiled MDX\n * modules, so dev and build share one code path and neither has to evaluate browser code.\n */\nexport async function buildSearchIndex(ctx: SeemoreContext): Promise<string> {\n const loader = await ctx.source.loader.get();\n const bodies = new Map<string, string>();\n\n for (const page of ctx.pages()) {\n try {\n // The body only: `structure` reads plain Markdown, where a frontmatter block's closing\n // `---` turns its keys into a setext heading and lands in the index as content.\n bodies.set(page.url, parseFrontmatter(readFileSync(page.absPath, 'utf8'), page.file).content);\n } catch {\n // A file deleted between scan and index is not worth failing a dev rebuild over.\n }\n }\n\n const server = createFromSource(loader, {\n buildIndex(page) {\n const body = bodies.get(page.url) ?? '';\n return {\n id: page.url,\n url: withBase(ctx.config.base, page.url),\n title: typeof page.data.title === 'string' ? page.data.title : page.url,\n description: typeof page.data.description === 'string' ? page.data.description : undefined,\n structuredData: structure(body),\n };\n },\n });\n\n const response = await server.staticGET();\n return await response.text();\n}\n\nexport interface IndexSize {\n bytes: number;\n gzipped: number;\n /** Set when the gzipped index passed {@link SIZE_WARNING_BYTES}. */\n warning?: string;\n}\n\nexport function measureIndex(json: string): IndexSize {\n const bytes = Buffer.byteLength(json);\n const gzipped = gzipSync(json).byteLength;\n\n if (gzipped <= SIZE_WARNING_BYTES) return { bytes, gzipped };\n\n return {\n bytes,\n gzipped,\n warning:\n `The static search index is ${formatBytes(gzipped)} gzipped, which every visitor downloads before ` +\n `their first search. Above ${formatBytes(SIZE_WARNING_BYTES)} consider a hosted index: set ` +\n `\\`search: { provider: 'orama-cloud', … }\\` or \\`search: { provider: 'algolia', … }\\` in seemore.config.ts.`,\n };\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} kB`;\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n}\n","import chokidar, { type FSWatcher } from 'chokidar';\nimport type { Plugin, ViteDevServer } from 'vite';\nimport type { SeemoreContext } from '../context.js';\nimport { VIRTUAL } from './plugin.js';\n\nconst CONTENT_FILE = /\\.(?:mdx?|json)$/i;\n\n/**\n * The watcher/sidebar-refresh cycle.\n *\n * The page tree, sidebar and search index are not in the module graph, so nothing invalidates\n * them on its own. chokidar watches the content root; every event rescans, and the two\n * virtual modules that depend on the corpus are reloaded through Vite's own HMR machinery so\n * the sidebar re-renders in place instead of reloading the page.\n */\nexport function seemoreWatcherPlugin(ctx: SeemoreContext): Plugin {\n let watcher: FSWatcher | undefined;\n\n return {\n name: 'seemore:watcher',\n apply: 'serve',\n\n configureServer(server) {\n watcher = chokidar.watch(ctx.contentRoot, {\n ignoreInitial: true,\n ignored: (path: string, stats?: { isFile(): boolean }) => {\n // `ignored` applies to explicitly added paths too, so the config file — which is\n // neither Markdown nor JSON — has to be let through by name.\n if (path === ctx.config.configFile) return false;\n // chokidar reports native separators, so compare against a normalised path.\n const posix = path.replace(/\\\\/g, '/');\n if (/(?:^|\\/)(?:node_modules|\\.git|dist|build|out|vendor|target|\\.seemore)(?:$|\\/)/.test(posix)) return true;\n if (/(?:^|\\/)\\.[^/]+/.test(posix)) return true;\n return stats?.isFile() === true && !CONTENT_FILE.test(posix);\n },\n });\n\n const onEvent = (event: string, path: string) => {\n void handleContentChange(server, ctx, event, path);\n };\n\n watcher.on('add', (p) => onEvent('add', p));\n watcher.on('change', (p) => onEvent('change', p));\n watcher.on('unlink', (p) => onEvent('unlink', p));\n watcher.on('addDir', (p) => onEvent('addDir', p));\n watcher.on('unlinkDir', (p) => onEvent('unlinkDir', p));\n\n // A config edit can change `base`, which reconfigures Vite itself, so the page reloads\n // rather than patching itself.\n if (ctx.config.configFile !== undefined) {\n watcher.add(ctx.config.configFile);\n watcher.on('change', (path) => {\n if (path !== ctx.config.configFile) return;\n server.environments.client.hot.send({ type: 'full-reload', path: '*' });\n server.config.logger.info(\n 'seemore config changed — reloading. Changes to `base` need a restart to take effect.',\n );\n });\n }\n\n server.httpServer?.once('close', () => void watcher?.close());\n },\n\n async closeBundle() {\n await watcher?.close();\n watcher = undefined;\n },\n };\n}\n\n/** Exported for the watcher test, which drives it without going through chokidar's timing. */\nexport async function handleContentChange(\n server: ViteDevServer,\n ctx: SeemoreContext,\n event: string,\n path: string,\n): Promise<void> {\n const scan = ctx.refresh();\n\n // Dev never exits on a content error, but it must not swallow one either: editing a file\n // back to valid has to recover without a restart, so problems are reported each time.\n for (const message of [...scan.errors, ...scan.warnings]) ctx.warnings.add(message);\n ctx.warnings.flush((line) => server.config.logger.warn(line));\n\n // Order matters: the tree must be current before anything re-renders against it.\n await reloadVirtual(server, VIRTUAL.tree);\n await reloadVirtual(server, VIRTUAL.routes);\n\n // A body edit is a plain MDX swap; the component is replaced and scroll position kept.\n if (event === 'change' && /\\.mdx?$/i.test(path)) {\n await reloadFile(server, path);\n }\n}\n\nasync function reloadVirtual(server: ViteDevServer, id: string): Promise<void> {\n await reloadById(server, `\\0${id}`);\n}\n\nasync function reloadFile(server: ViteDevServer, absolutePath: string): Promise<void> {\n // chokidar reports native separators; the module graph is addressed in forward slashes.\n await reloadById(server, absolutePath.replace(/\\\\/g, '/'));\n}\n\n/**\n * Reload a module in every environment that has it. `server.reloadModule` handles\n * invalidation and the HMR message together, which keeps us out of the business of\n * constructing update payloads by hand.\n */\nasync function reloadById(server: ViteDevServer, id: string): Promise<void> {\n const environments = Object.values(server.environments ?? {});\n\n if (environments.length === 0) {\n const legacy = server.moduleGraph.getModuleById(id);\n if (legacy) await server.reloadModule(legacy);\n return;\n }\n\n for (const environment of environments) {\n const mod = environment.moduleGraph?.getModuleById(id);\n if (mod === undefined || mod === null) continue;\n if (typeof environment.reloadModule === 'function') await environment.reloadModule(mod);\n else environment.moduleGraph.invalidateModule(mod);\n }\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { ogImagePath } from '../../shared/og.js';\nimport type { SeemoreContext } from '../context.js';\n\n/**\n * `social.cards`: one OG image per page, rendered at build time.\n *\n * `takumi-js` is an optional peer of fumadocs-ui and is not installed by default, so the\n * flag degrades to a warning rather than to an install-time cost everybody pays.\n */\nexport async function generateSocialCards(ctx: SeemoreContext, outDir: string): Promise<number> {\n // `takumi-js` is an optional peer, so it is loaded by specifier and typed structurally —\n // a hard import would make it a required dependency of every build.\n let takumi: TakumiModule;\n try {\n takumi = (await importOptional('takumi-js')) as TakumiModule;\n } catch {\n ctx.warnings.add(\n \"`social.cards` is enabled but `takumi-js` is not installed. Run `npm install takumi-js`, or remove the flag.\",\n );\n return 0;\n }\n\n let written = 0;\n for (const page of ctx.pages()) {\n const png = await renderCard(takumi, ctx.config.title, page.data.title, page.data.description);\n if (png === undefined) continue;\n\n const target = join(outDir, ogImagePath(page.url));\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, png);\n written++;\n }\n\n return written;\n}\n\ninterface TakumiModule {\n Renderer: new (options: { fonts: unknown[] }) => {\n renderAsync(node: unknown, options: { width: number; height: number; format: 'png' }): Promise<Uint8Array>;\n };\n container(props: unknown, children: unknown[]): unknown;\n text(value: string, props: unknown): unknown;\n}\n\nasync function renderCard(\n takumi: TakumiModule,\n site: string,\n title: string,\n description: unknown,\n): Promise<Uint8Array | undefined> {\n const renderer = new takumi.Renderer({ fonts: [] });\n const node = takumi.container(\n {\n style: {\n width: 1200,\n height: 630,\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n padding: 80,\n backgroundColor: '#0b0b0b',\n color: '#ffffff',\n gap: 24,\n },\n },\n [\n takumi.text(site, { style: { fontSize: 28, opacity: 0.6 } }),\n takumi.text(title, { style: { fontSize: 64, fontWeight: 700 } }),\n ...(typeof description === 'string' ? [takumi.text(description, { style: { fontSize: 30, opacity: 0.8 } })] : []),\n ],\n );\n\n return await renderer.renderAsync(node, { width: 1200, height: 630, format: 'png' });\n}\n\n/** Import by a specifier TypeScript will not try to resolve at build time. */\nasync function importOptional(specifier: string): Promise<unknown> {\n return await import(specifier);\n}\n","/**\n * Where a page's social card lives.\n *\n * Shared, because the build writes the file and the prerendered `<head>` points at it — and\n * a card nothing references is a card nobody sees.\n */\nexport function ogImagePath(url: string): string {\n const clean = url.replace(/^\\/+|\\/+$/g, '');\n // A path per route, rather than a flattened filename: `/a/b` and `/a-b` are different\n // routes and must not write to the same file.\n return clean === '' ? '/api/og/card.png' : `/api/og/${clean}/card.png`;\n}\n","import { createServer, type ViteDevServer } from 'vite';\nimport pc from 'picocolors';\nimport { loadConfig } from '../node/config/load.js';\nimport { createContext, type SeemoreContext } from '../node/context.js';\nimport { normaliseBase } from '../shared/base.js';\nimport { resolveContentRoot } from '../node/paths.js';\nimport { createViteConfig } from '../node/vite/config.js';\n\nconst DEFAULT_PORT = 4040;\n\nexport interface DevOptions {\n cwd: string;\n dir?: string;\n configPath?: string;\n base?: string;\n port?: number;\n host?: string | boolean;\n open?: boolean;\n}\n\nexport interface DevServer {\n server: ViteDevServer;\n ctx: SeemoreContext;\n url: string;\n close(): Promise<void>;\n}\n\n/**\n * The dev server. Nothing is written into the user's folder: the Vite root is\n * seemore's own `src/app`, and caches go to the OS temp directory.\n */\nexport async function runDev(options: DevOptions): Promise<DevServer> {\n const contentRoot = resolveContentRoot(options.cwd, options.dir);\n const loaded = await loadConfig({ root: options.cwd, configPath: options.configPath });\n const config = {\n ...loaded.config,\n base: options.base === undefined ? loaded.config.base : normaliseBase(options.base),\n };\n\n // Dev never exits on a content error: editing a file back to valid must recover without a\n // restart, so problems that fail the build are warnings here.\n const ctx = createContext({ config, contentRoot, includeDrafts: true });\n const scan = ctx.source.current();\n for (const message of [...scan.errors, ...scan.warnings]) ctx.warnings.add(message);\n if (scan.pages.length === 0) {\n ctx.warnings.add(`No Markdown files found under ${contentRoot}. seemore will serve an empty site until there are.`);\n }\n\n const base = createViteConfig({ ctx, mode: 'dev' });\n const server = await createServer({\n ...base,\n server: {\n ...base.server,\n port: options.port ?? DEFAULT_PORT,\n host: options.host,\n open: options.open === true ? config.base : false,\n },\n });\n\n await server.listen();\n\n const resolvedPort = server.config.server.port ?? DEFAULT_PORT;\n const url = `http://localhost:${resolvedPort}${config.base}`;\n\n ctx.warnings.flush();\n console.log(`\\n ${pc.green('seemore')} ${pc.bold(url)}`);\n console.log(` ${pc.dim(`${scan.pages.length} pages from ${contentRoot}`)}\\n`);\n\n return {\n server,\n ctx,\n url,\n close: async () => {\n await server.close();\n },\n };\n}\n"],"mappings":"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","names":["existsSync","dirname","join","resolve","pc","mkdirSync","readFileSync","writeFileSync","createRequire","tmpdir","isAbsolute","join","relative","resolve","pc","slugify","basename","CONTENT_EXT","basename","slugify","relative","dirname","resolve","z","z","z","resolve","dirname","dirname","join","writeFileSync","join","join","realpathSync","join","existsSync","dirname","resolve","dirname","resolve","existsSync","readFileSync","dirname","readFileSync","readFileSync","json","dirname","readFileSync","scan","join","realpathSync","join","mkdirSync","writeFileSync","dirname","join","join","mkdirSync","dirname","writeFileSync","resolve","scan","pc","relative","readFileSync","join","tmpdir","mkdirSync","writeFileSync","isAbsolute","createRequire","pc","scan","pc","pc","readFileSync","join","packageRoot"]}
1
+ {"version":3,"sources":["../../src/node/paths.ts","../../src/cli/index.ts","../../src/cli/build.ts","../../src/node/config/load.ts","../../src/shared/base.ts","../../src/shared/types.ts","../../src/node/config/features.ts","../../src/node/config/schema.ts","../../src/node/content/links.ts","../../src/node/content/slug.ts","../../src/node/content/source.ts","../../src/node/content/scan.ts","../../src/node/content/frontmatter.ts","../../src/node/report.ts","../../src/node/context.ts","../../src/node/prerender/emit.ts","../../src/node/prerender/deploy.ts","../../src/node/prerender/render.ts","../../src/node/vite/config.ts","../../src/node/vite/mdx.ts","../../src/node/vite/remark.ts","../../src/node/vite/plugin.ts","../../src/node/search/build.ts","../../src/node/vite/watcher.ts","../../src/node/social/cards.ts","../../src/shared/og.ts","../../src/cli/dev.ts"],"sourcesContent":["import { existsSync, realpathSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { tmpdir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * The installed seemore package directory.\n *\n * Works from the bundled CLI (`dist/cli/index.js`) and from the sources during tests, which\n * is why it walks for `package.json` rather than assuming a depth.\n */\nexport function packageRoot(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let depth = 0; depth < 10; depth++) {\n if (existsSync(join(dir, 'package.json'))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error('seemore: could not locate its own package root.');\n}\n\n/** The browser layer, which ships as source and is compiled in-process. */\nexport function appRoot(): string {\n return join(packageRoot(), 'src', 'app');\n}\n\n/**\n * Vite's caches go to the OS temp directory, keyed by content root.\n *\n * Dev writes nothing into the user's folder, and that has to include the\n * dependency-optimiser cache Vite would otherwise put in `node_modules/.vite`.\n */\nexport function cacheDir(contentRoot: string): string {\n const key = createHash('sha256').update(resolve(contentRoot)).digest('hex').slice(0, 12);\n return join(tmpdir(), 'seemore', key);\n}\n\n/**\n * `seemore [dir]`, else the folder the command runs in. Nothing is probed: which Markdown\n * becomes the site is decided by where the user stands, never by what happens to exist.\n *\n * The result is canonicalised through the filesystem. Every module id seemore derives from\n * the root — import specifiers, watcher lookups — must use the real spelling, because Vite\n * refuses to *load* a path containing a Windows 8.3 short-name segment (`RUNNER~1`) no\n * matter what the fs allow list says. Real users hit this too: `C:\\Users\\<long name>\\`\n * carries a short alias on any drive with 8.3 names enabled.\n */\nexport function resolveContentRoot(cwd: string, explicit?: string): string {\n return explicit !== undefined ? canonicalise(resolve(cwd, explicit)) : canonicalise(cwd);\n}\n\n/**\n * Resolve a path through the filesystem to its real spelling — the same treatment\n * {@link resolveContentRoot} gives the content root, needed anywhere else a path arriving\n * from outside seemore (an editor's `document.uri.fsPath`, say) has to be compared against\n * one of its own, which are already canonicalised. A symlinked ancestor (`/tmp` on macOS)\n * or a Windows 8.3 short name would otherwise make the same file compare unequal to itself.\n */\nexport function canonicalise(dir: string): string {\n try {\n return realpathSync.native(dir);\n } catch {\n // Does not exist, or not readable: keep the literal spelling rather than throw.\n return dir;\n }\n}\n","#!/usr/bin/env node\nimport { parseArgs } from 'node:util';\nimport pc from 'picocolors';\nimport { runBuild } from './build.js';\nimport { runDev } from './dev.js';\n\nconst USAGE = `\n${pc.bold('seemore')} — turn a folder of Markdown into a docs site\n\n seemore [dir] start the dev server\n seemore build [dir] build a static site into dist/\n\nOptions\n --port <number> dev server port (default 4040)\n --host [host] expose the dev server on the network\n --open / --no-open open a browser on start (default: no)\n --json print one machine-readable JSON line instead of the summary (dev only)\n --config <path> path to seemore.config.ts\n --out <dir> build output directory (default: dist)\n --base <path> subpath the site is served from, e.g. /my-repo/\n -h, --help show this message\n -v, --version show the version\n`;\n\n/**\n * `parseArgs` has no notion of an optional value, so a bare `--host` — the documented form,\n * and the one Vite uses for \"listen on every interface\" — is rewritten to `--host=` first.\n */\nfunction normaliseHostFlag(argv: string[]): string[] {\n const index = argv.indexOf('--host');\n if (index === -1) return argv;\n const next = argv[index + 1];\n if (next !== undefined && !next.startsWith('-')) return argv;\n return [...argv.slice(0, index), '--host=', ...argv.slice(index + 1)];\n}\n\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<void> {\n const { values, positionals } = parseArgs({\n args: normaliseHostFlag(argv),\n allowPositionals: true,\n options: {\n port: { type: 'string' },\n host: { type: 'string' },\n open: { type: 'boolean' },\n 'no-open': { type: 'boolean' },\n json: { type: 'boolean' },\n config: { type: 'string' },\n out: { type: 'string' },\n base: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean', short: 'v' },\n },\n });\n\n if (values.help === true) {\n console.log(USAGE);\n return;\n }\n\n if (values.version === true) {\n const { readFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { packageRoot } = await import('../node/paths.js');\n const pkg = JSON.parse(readFileSync(join(packageRoot(), 'package.json'), 'utf8')) as { version: string };\n console.log(pkg.version);\n return;\n }\n\n const [command, ...rest] = positionals;\n const isBuild = command === 'build';\n const dir = isBuild ? rest[0] : command;\n\n const shared = { cwd: process.cwd(), dir, configPath: values.config, base: values.base };\n\n if (isBuild) {\n await runBuild({ ...shared, outDir: values.out });\n return;\n }\n\n await runDev({\n ...shared,\n port: values.port === undefined ? undefined : Number(values.port),\n host: values.host === undefined ? undefined : values.host === '' ? true : values.host,\n open: values.open === true && values['no-open'] !== true,\n json: values.json === true,\n });\n}\n\nmain().catch((error: unknown) => {\n console.error(`\\n${pc.red('seemore')} ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n});\n","import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { tmpdir } from 'node:os';\nimport { isAbsolute, join, relative, resolve } from 'node:path';\nimport pc from 'picocolors';\nimport { build as viteBuild } from 'vite';\nimport { loadConfig } from '../node/config/load.js';\nimport { createContext, type SeemoreContext } from '../node/context.js';\nimport { normaliseBase } from '../shared/base.js';\nimport { resolveContentRoot } from '../node/paths.js';\nimport { applyTemplate, outputPathFor, writeHtml } from '../node/prerender/emit.js';\nimport { writeDeployArtifacts } from '../node/prerender/deploy.js';\nimport { loadPrerenderModule } from '../node/prerender/render.js';\nimport { buildSearchIndex, formatBytes, measureIndex } from '../node/search/build.js';\nimport { generateSocialCards } from '../node/social/cards.js';\nimport { createViteConfig } from '../node/vite/config.js';\n\nexport interface BuildOptions {\n cwd: string;\n dir?: string;\n configPath?: string;\n outDir?: string;\n base?: string;\n}\n\nexport async function runBuild(options: BuildOptions): Promise<{ outDir: string; routes: number }> {\n const contentRoot = resolveContentRoot(options.cwd, options.dir);\n const loaded = await loadConfig({ root: options.cwd, configPath: options.configPath });\n\n const config = { ...loaded.config, base: options.base === undefined ? loaded.config.base : normaliseBase(options.base) };\n warnAboutMissingBase(config.base, loaded.file);\n\n const ctx = createContext({ config, contentRoot });\n const outDir = resolve(options.cwd, options.outDir ?? 'dist');\n assertSafeOutDir(outDir, options.cwd, contentRoot);\n\n const scan = ctx.source.current();\n failOnErrors(ctx.errors(), contentRoot);\n if (scan.pages.length === 0) {\n throw new Error(`No Markdown files found under ${contentRoot}. Point seemore at a folder that has some, or check \\`exclude\\`.`);\n }\n for (const warning of scan.warnings) ctx.warnings.add(warning);\n\n console.log(pc.dim(`seemore ${scan.pages.length} pages from ${relative(options.cwd, contentRoot) || '.'}`));\n\n // 1. The client bundle, which also produces the HTML template every page is injected into.\n await viteBuild(createViteConfig({ ctx, mode: 'build', outDir }));\n const template = readFileSync(join(outDir, 'index.html'), 'utf8');\n\n // 2. The same module graph, evaluated in node.\n const ssrOutDir = mkdtempSync(join(tmpdir(), 'seemore-ssr-'));\n try {\n const prerender = await loadPrerenderModule(ctx, ssrOutDir);\n const urls = prerender.listRoutes();\n // When no page claims `/`, the router generates an index page there — the same component\n // the dev server renders — so the client build's empty shell never ships as the home page.\n const routes = urls.includes('/') ? urls : ['/', ...urls];\n if (routes.length > urls.length) {\n console.log(pc.dim('seemore no index page; generated one listing every page at /'));\n }\n\n for (const url of routes) {\n writeHtml(outDir, outputPathFor(url), applyTemplate(template, await prerender.render(url)));\n }\n\n // 3. The shell an unknown address falls back to, which is also Surge's `200.html`.\n const notFound = applyTemplate(template, await prerender.render('/__seemore_not_found'));\n writeHtml(outDir, '404.html', notFound);\n writeDeployArtifacts(outDir, config.base, notFound);\n\n // 4. The search index, at the same path the dev middleware serves.\n if (config.search.provider === 'static') {\n const index = await buildSearchIndex(ctx);\n mkdirSync(join(outDir, 'api'), { recursive: true });\n writeFileSync(join(outDir, 'api', 'search.json'), index, 'utf8');\n\n const size = measureIndex(index);\n console.log(pc.dim(`seemore search index ${formatBytes(size.gzipped)} gzipped`));\n if (size.warning !== undefined) ctx.warnings.add(size.warning);\n }\n\n if (config.search.provider !== 'static') await warnIfSearchSdkMissing(ctx, config.search.provider);\n\n if (config.features['social.cards']) await generateSocialCards(ctx, outDir);\n\n ctx.warnings.flush();\n console.log(pc.green(`seemore ${routes.length} pages written to ${relative(options.cwd, outDir) || outDir}`));\n\n return { outDir, routes: routes.length };\n } finally {\n rmSync(ssrOutDir, { recursive: true, force: true });\n }\n}\n\n/**\n * The build empties `outDir` before writing, and `outDir` is always outside the Vite root —\n * seemore's root is its own package — so Vite's own guard against that never fires. A typo\n * like `--out .` would delete the project, so it is refused here instead.\n */\nfunction assertSafeOutDir(outDir: string, cwd: string, contentRoot: string): void {\n const contains = (parent: string, child: string): boolean => {\n const rel = relative(parent, child);\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));\n };\n\n for (const [name, dir] of [\n ['the current directory', cwd],\n ['the content directory', contentRoot],\n ] as const) {\n if (contains(outDir, dir)) {\n throw new Error(\n `Refusing to build into ${outDir}: it is, or contains, ${name}, and the build empties its output directory first. Pass --out with a directory of its own.`,\n );\n }\n }\n}\n\n/**\n * The hosted search providers need an SDK that seemore does not depend on. Finding out in the\n * browser means an empty search box; finding out here means a line in the build log.\n */\nasync function warnIfSearchSdkMissing(ctx: SeemoreContext, provider: 'algolia' | 'orama-cloud'): Promise<void> {\n const packageName = provider === 'algolia' ? 'algoliasearch' : '@orama/core';\n try {\n createRequire(join(ctx.config.root, 'noop.js')).resolve(packageName);\n } catch {\n ctx.warnings.add(\n `\\`search.provider\\` is '${provider}', which needs ${packageName}. Run \\`npm install ${packageName}\\` or search will find nothing.`,\n );\n }\n}\n\n/** Failing conditions produce a silently wrong site; warnings produce a visibly wrong page. */\nfunction failOnErrors(errors: string[], contentRoot: string): void {\n if (errors.length === 0) return;\n throw new Error(`seemore found ${errors.length} problem(s) in ${contentRoot}:\\n\\n${errors.join('\\n\\n')}`);\n}\n\n/**\n * `base` is never inferred. Under CI, where getting it wrong ships a broken site,\n * say so — with the exact line to add.\n */\nfunction warnAboutMissingBase(base: string, configFile: string | undefined): void {\n if (base !== '/' || process.env.GITHUB_ACTIONS !== 'true') return;\n const repo = process.env.GITHUB_REPOSITORY?.split('/')[1];\n console.warn(\n pc.yellow(\n `seemore \\`base\\` is not set, and GitHub Pages serves project sites from a subpath.\\n` +\n ` Add this to ${configFile ?? 'seemore.config.ts'}:\\n\\n` +\n ` base: '/${repo ?? 'your-repo'}/',\\n\\n` +\n ` Or pass --base '/${repo ?? 'your-repo'}/'. Ignore this if you deploy to a domain root.`,\n ),\n );\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { createJiti } from 'jiti';\nimport { z } from 'zod';\nimport { normaliseBase } from '../base.js';\nimport { resolveFeatures, type FeatureFlag } from './features.js';\nimport { configSchema, THEMES, type SeemoreConfig, type ResolvedSeemoreConfig, type SearchConfig } from './schema.js';\n\nconst CONFIG_NAMES = ['seemore.config.ts', 'seemore.config.mts', 'seemore.config.js', 'seemore.config.mjs'];\n\nexport interface LoadConfigOptions {\n /** Directory to look in, and the base for relative paths inside the config. */\n root: string;\n /** `--config`; when given, a missing file is an error rather than a fallback to defaults. */\n configPath?: string;\n}\n\n/** Turn a validated config into the fully-resolved shape the rest of seemore consumes. */\nexport function resolveConfig(\n input: SeemoreConfig,\n options: { root: string; configFile?: string },\n): ResolvedSeemoreConfig {\n const parsed = parseOrThrow(input, options.configFile);\n\n const search: SearchConfig = parsed.search === 'static' ? { provider: 'static' } : (parsed.search as SearchConfig);\n\n const features = resolveFeatures(parsed.features as FeatureFlag[], {\n // Nothing to link to without an edit base, so the flag follows the option.\n 'content.action.edit': parsed.editLink !== undefined,\n });\n\n return {\n title: parsed.title,\n description: parsed.description,\n favicon: parsed.favicon,\n base: normaliseBase(parsed.base),\n theme: parsed.theme,\n css: parsed.css === undefined ? undefined : resolveFrom(options.root, parsed.css),\n features,\n nav: parsed.nav,\n footer: parsed.footer,\n editLink: parsed.editLink,\n search,\n exclude: parsed.exclude,\n root: options.root,\n configFile: options.configFile,\n };\n}\n\nexport interface LoadedConfig {\n config: ResolvedSeemoreConfig;\n /** Absolute path of the config file that was used, if any. */\n file?: string;\n}\n\n/**\n * Load `seemore.config.ts` with jiti. Not Vite's `ssrLoadModule`: the config\n * decides `base`, `base` configures Vite, and Vite would have to already exist to load it.\n */\nexport async function loadConfig(options: LoadConfigOptions): Promise<LoadedConfig> {\n const file = findConfigFile(options);\n\n if (file === undefined) {\n return { config: resolveConfig({}, { root: options.root }) };\n }\n\n const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });\n let loaded: unknown;\n try {\n loaded = await jiti.import(file, { default: true });\n } catch (error) {\n throw new Error(`Failed to load ${file}:\\n${error instanceof Error ? error.message : String(error)}`, {\n cause: error,\n });\n }\n\n if (loaded === null || typeof loaded !== 'object') {\n throw new Error(`${file} must export a config object as its default export, got ${typeof loaded}.`);\n }\n\n return {\n config: resolveConfig(loaded as SeemoreConfig, { root: dirname(file), configFile: file }),\n file,\n };\n}\n\nfunction findConfigFile({ root, configPath }: LoadConfigOptions): string | undefined {\n if (configPath !== undefined) {\n const absolute = resolveFrom(root, configPath);\n if (!existsSync(absolute)) {\n throw new Error(`Config file not found: ${absolute}`);\n }\n return absolute;\n }\n\n for (const name of CONFIG_NAMES) {\n const candidate = resolve(root, name);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction resolveFrom(root: string, path: string): string {\n return isAbsolute(path) ? path : resolve(root, path);\n}\n\nfunction parseOrThrow(input: SeemoreConfig, file: string | undefined): z.output<typeof configSchema> {\n const result = configSchema.safeParse(input);\n if (result.success) return result.data;\n\n const where = file === undefined ? 'seemore config' : file;\n const issues = result.error.issues.map((issue) => {\n const field = issue.path.length === 0 ? '(root)' : issue.path.join('.');\n return ` - ${field}: ${explain(issue)}`;\n });\n throw new Error(`Invalid ${where}:\\n${issues.join('\\n')}`);\n}\n\nfunction explain(issue: z.core.$ZodIssue): string {\n // zod's default message for a large enum truncates badly; the valid set is the useful part.\n if (issue.code === 'invalid_value' && issue.path.join('.') === 'theme') {\n return `unknown theme. Valid themes: ${THEMES.join(', ')}.`;\n }\n return issue.message;\n}\n","/**\n * Base-path handling.\n *\n * Internally a base is always normalised to leading + trailing slash (`/sub/`), because a\n * single canonical shape is what makes the \"no absolute-root URL leaks\" test possible. The\n * trailing slash is stripped again only at the point of output.\n */\n\nconst EXTERNAL = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i;\n\n/** `undefined` | `sub` | `/sub` | `/sub/` → `/sub/`. The root base is `/`. */\nexport function normaliseBase(base: string | undefined): string {\n if (base === undefined || base === '') return '/';\n if (EXTERNAL.test(base)) {\n throw new Error(\n `Invalid \\`base\\`: ${JSON.stringify(base)}. \\`base\\` is a path on the host, not a URL — use \"/${base.replace(/^.*?:\\/\\/[^/]*/, '').replace(/^\\/+/, '')}\".`,\n );\n }\n const trimmed = base.replace(/^\\/+/, '').replace(/\\/+$/, '');\n return trimmed === '' ? '/' : `/${trimmed}/`;\n}\n\n/** True for hrefs that a base must never touch: external, protocol-relative, hash, or relative. */\nexport function isExternalHref(href: string): boolean {\n return EXTERNAL.test(href) || href.startsWith('#') || !href.startsWith('/');\n}\n\n/** Prefix a root-relative path with the base. Idempotent; leaves external hrefs alone. */\nexport function withBase(base: string, href: string): string {\n const b = normaliseBase(base);\n if (b === '/' || isExternalHref(href)) return href;\n if (href === '/') return b;\n if (href === b.slice(0, -1) || href.startsWith(b)) return href;\n return b + href.replace(/^\\/+/, '');\n}\n\n/** Inverse of {@link withBase}: turn a browser pathname back into an internal route URL. */\nexport function stripBase(base: string, pathname: string): string {\n const b = normaliseBase(base);\n if (b === '/') return pathname;\n if (pathname === b || pathname === b.slice(0, -1)) return '/';\n if (!pathname.startsWith(b)) return pathname;\n return `/${pathname.slice(b.length)}`;\n}\n\n/** The form React Router wants for `basename`: leading slash, no trailing slash, `/` at root. */\nexport function toBasename(base: string): string {\n const b = normaliseBase(base);\n return b === '/' ? '/' : b.slice(0, -1);\n}\n\n/**\n * Browser pathnames are percent-encoded; route URLs are not.\n *\n * `/guía/página-uno` arrives from `location.pathname` as `/gu%C3%ADa/p%C3%A1gina-uno`, and a\n * lookup against the route map misses — so a correctly prerendered page hydrates into \"Page\n * not found\". `decodeURI`, not `decodeURIComponent`: a literal `%2F` in a filename must stay\n * encoded or it would split into two path segments.\n */\nexport function decodePath(pathname: string): string {\n try {\n return decodeURI(pathname);\n } catch {\n // Malformed escapes are the browser's problem, not ours; match on what we were given.\n return pathname;\n }\n}\n","import type { ComponentType, ReactNode } from 'react';\n\n/**\n * Types shared by the node pipeline and the browser app. This file ships as source, next to\n * `src/app`, so both halves agree on the shape of the virtual modules.\n */\n\nexport const FEATURES = [\n 'navigation.instant.prefetch',\n 'navigation.instant.preview',\n 'navigation.footer',\n 'navigation.top',\n 'navigation.path',\n 'navigation.sections',\n 'navigation.prune',\n 'toc.follow',\n 'toc.integrate',\n 'content.code.copy',\n 'content.action.edit',\n 'search.suggest',\n 'search.highlight',\n 'social.cards',\n] as const;\n\nexport type Feature = (typeof FEATURES)[number];\n/** What a user may write in `features`: a flag, or `!flag` to switch a default-on flag off. */\nexport type FeatureFlag = Feature | `!${Feature}`;\nexport type ResolvedFeatures = Record<Feature, boolean>;\n\nexport interface NavItem {\n text: string;\n link?: string;\n items?: NavItem[];\n}\n\nexport type ClientSearchConfig =\n | { provider: 'static'; from: string }\n | { provider: 'orama-cloud'; endpoint: string; apiKey: string }\n | { provider: 'algolia'; appId: string; apiKey: string; indexName: string };\n\n/** The payload of `virtual:seemore/config`. */\nexport interface ClientConfig {\n title: string;\n description?: string;\n base: string;\n theme: string;\n features: ResolvedFeatures;\n nav?: NavItem[];\n footer?: { text?: string; links?: { text: string; link: string }[] };\n editLink?: { base: string; text: string };\n favicon?: string;\n search: ClientSearchConfig;\n contentRoot: string;\n}\n\n/** One entry of `virtual:seemore/routes`. */\nexport interface RouteEntry {\n url: string;\n /** Virtual path relative to the content root — what an edit link points at. */\n file: string;\n absPath: string;\n title: string;\n description: string | null;\n load: () => Promise<PageModule>;\n}\n\nexport interface TocEntry {\n title: ReactNode;\n url: string;\n depth: number;\n}\n\nexport interface PageModule {\n default: ComponentType<{ components?: Record<string, unknown> }>;\n /** Exported by fumadocs' `rehype-toc`. */\n toc?: TocEntry[];\n}\n","import type { Feature, FeatureFlag, ResolvedFeatures } from '../../shared/types.js';\n\n/**\n * Feature flags.\n *\n * MkDocs Material's model — one flat list of dotted strings — but typed as a union, which\n * their YAML cannot do. Because seemore has default-on features where MkDocs has none, the\n * list is additive over the defaults and a `!` prefix turns a default-on feature off.\n */\n\nexport { FEATURES } from '../../shared/types.js';\nexport type { Feature, FeatureFlag, ResolvedFeatures } from '../../shared/types.js';\n\nexport const FEATURE_DEFAULTS: Record<Feature, boolean> = {\n 'navigation.instant.prefetch': true,\n 'navigation.instant.preview': false,\n 'navigation.footer': true,\n 'navigation.top': true,\n 'navigation.path': false,\n 'navigation.sections': false,\n 'navigation.prune': false,\n 'toc.follow': true,\n 'toc.integrate': false,\n 'content.code.copy': true,\n // Implicitly on when `editLink` is configured; there is nothing to link to otherwise.\n 'content.action.edit': false,\n 'search.suggest': true,\n 'search.highlight': true,\n 'social.cards': false,\n};\n\nexport function isFeatureEnabled(features: ResolvedFeatures, feature: Feature): boolean {\n return features[feature];\n}\n\n/**\n * Rules the flag set must satisfy. MkDocs reports its equivalents in prose and lets the\n * site build wrong; we fail in the config loader with the fix in the message.\n */\ntype Rule =\n | { kind: 'conflict'; a: Feature; b: Feature; why: string }\n | { kind: 'requires'; flag: Feature; needs: Feature; why: string };\n\nconst RULES: Rule[] = [\n {\n kind: 'conflict',\n a: 'toc.integrate',\n b: 'toc.follow',\n why: '`toc.integrate` merges the table of contents into the sidebar, leaving no separate TOC pane for `toc.follow` to scroll.',\n },\n {\n kind: 'requires',\n flag: 'navigation.instant.preview',\n needs: 'navigation.instant.prefetch',\n why: '`navigation.instant.preview` renders the target page in a popover, which is only possible once prefetch has loaded it.',\n },\n];\n\nexport function resolveFeatures(\n input: readonly FeatureFlag[],\n implicit: Partial<ResolvedFeatures> = {},\n): ResolvedFeatures {\n const resolved: ResolvedFeatures = { ...FEATURE_DEFAULTS, ...implicit };\n\n for (const flag of input) {\n const off = flag.startsWith('!');\n const name = (off ? flag.slice(1) : flag) as Feature;\n resolved[name] = !off;\n }\n\n const problems: string[] = [];\n for (const rule of RULES) {\n if (rule.kind === 'conflict') {\n if (!resolved[rule.a] || !resolved[rule.b]) continue;\n const fix = FEATURE_DEFAULTS[rule.b]\n ? `Add '!${rule.b}' to \\`features\\` to switch it off.`\n : `Remove '${rule.b}' from \\`features\\`.`;\n problems.push(`\\`${rule.a}\\` cannot be combined with \\`${rule.b}\\`. ${rule.why} ${fix}`);\n } else if (resolved[rule.flag] && !resolved[rule.needs]) {\n problems.push(\n `\\`${rule.flag}\\` requires \\`${rule.needs}\\`, which is switched off. ${rule.why}`,\n );\n }\n }\n\n if (problems.length > 0) {\n throw new Error(\n `Incompatible \\`features\\` in seemore config:\\n${problems.map((p) => ` - ${p}`).join('\\n')}`,\n );\n }\n\n return resolved;\n}\n","import { z } from 'zod';\nimport { FEATURES, type FeatureFlag, type ResolvedFeatures } from './features.js';\n\n/** The CSS presets fumadocs-ui ships. We do not invent a token system. */\nexport const THEMES = [\n 'neutral',\n 'black',\n 'catppuccin',\n 'dusk',\n 'ocean',\n 'purple',\n 'ruby',\n 'solar',\n 'aspen',\n 'emerald',\n 'vitepress',\n 'shadcn',\n] as const;\n\nexport type Theme = (typeof THEMES)[number];\n\nconst featureFlag = z.enum([...FEATURES, ...FEATURES.map((f) => `!${f}` as const)] as [string, ...string[]]);\n\nconst navItem: z.ZodType<NavItem> = z.lazy(() =>\n z.object({\n text: z.string(),\n link: z.string().optional(),\n items: z.array(navItem).optional(),\n }),\n);\n\nexport interface NavItem {\n text: string;\n link?: string;\n items?: NavItem[];\n}\n\nconst searchSchema = z.union([\n z.literal('static'),\n z.object({ provider: z.literal('static') }),\n z.object({\n provider: z.literal('orama-cloud'),\n endpoint: z.string(),\n apiKey: z.string(),\n }),\n z.object({\n provider: z.literal('algolia'),\n appId: z.string(),\n apiKey: z.string(),\n indexName: z.string(),\n }),\n]);\n\nexport const configSchema = z.object({\n title: z.string().default('Documentation'),\n description: z.string().optional(),\n favicon: z.string().optional(),\n /** Subpath the site is served from, e.g. `/my-repo/`. Never inferred. */\n base: z.string().optional(),\n theme: z.enum(THEMES).default('neutral'),\n /** A CSS file appended after everything else, so it wins. */\n css: z.string().optional(),\n features: z.array(featureFlag).default([]),\n nav: z.array(navItem).optional(),\n footer: z\n .object({\n text: z.string().optional(),\n links: z.array(z.object({ text: z.string(), link: z.string() })).optional(),\n })\n .optional(),\n editLink: z\n .object({\n base: z.string(),\n text: z.string().default('Edit this page'),\n })\n .optional(),\n search: searchSchema.default('static'),\n exclude: z.array(z.string()).default([]),\n});\n\n/** What a user writes in `seemore.config.ts`. */\nexport type SeemoreConfig = Omit<z.input<typeof configSchema>, 'features' | 'theme' | 'search'> & {\n features?: FeatureFlag[];\n theme?: Theme;\n search?: z.input<typeof searchSchema>;\n};\n\nexport type SearchConfig =\n | { provider: 'static' }\n | { provider: 'orama-cloud'; endpoint: string; apiKey: string }\n | { provider: 'algolia'; appId: string; apiKey: string; indexName: string };\n\n/** What the rest of seemore consumes: every optional filled in, every path absolute. */\nexport interface ResolvedSeemoreConfig {\n title: string;\n description?: string;\n favicon?: string;\n /** Always normalised to leading + trailing slash. */\n base: string;\n theme: Theme;\n /** Absolute path, resolved against the config file's directory. */\n css?: string;\n features: ResolvedFeatures;\n nav?: NavItem[];\n footer?: { text?: string; links?: { text: string; link: string }[] };\n editLink?: { base: string; text: string };\n search: SearchConfig;\n exclude: string[];\n /** Directory the config was resolved from — relative paths in it hang off this. */\n root: string;\n /** Absolute path of the config file, when there is one. */\n configFile?: string;\n}\n","import { slug as slugify } from 'github-slugger';\nimport { isExternalHref, withBase } from '../base.js';\nimport type { ContentPage } from './scan.js';\nimport { slugifySegment, toPosix } from './slug.js';\n\nconst CONTENT_EXT = /\\.mdx?$/i;\n\nexport interface ResolvedLink {\n /** The href to emit. Unchanged from the input when nothing needed resolving. */\n href: string;\n warning?: string;\n}\n\nexport interface ResolvedWikilink {\n /** `undefined` when the target does not exist — render the label as plain text. */\n href?: string;\n label: string;\n warning?: string;\n}\n\nexport interface LinkResolver {\n /** Relative `.md`/`.mdx` links → routes. Everything else passes through untouched. */\n resolveHref(href: string, fromFile: string): ResolvedLink;\n /** The inside of a `[[…]]`, i.e. `Target`, `Target|label`, `Target#Heading`, or both. */\n resolveWikilink(target: string, fromFile: string): ResolvedWikilink;\n}\n\nexport function createLinkResolver(pages: readonly ContentPage[], base: string): LinkResolver {\n /** `guide/deep-dive` (extension stripped, original casing) → page. */\n const byPath = new Map<string, ContentPage>();\n /** Lowercased basename, and its slugified form → every page that answers to it. */\n const byName = new Map<string, ContentPage[]>();\n\n const add = (map: Map<string, ContentPage[]>, key: string, page: ContentPage) => {\n const bucket = map.get(key);\n if (bucket) bucket.push(page);\n else map.set(key, [page]);\n };\n\n for (const page of pages) {\n const withoutExt = page.file.replace(CONTENT_EXT, '');\n byPath.set(withoutExt.toLowerCase(), page);\n byPath.set(page.file.toLowerCase(), page);\n // A directory index answers to its directory, so `[[guide]]` finds `guide/index.md`.\n if (page.isIndex) {\n const dir = withoutExt.split('/').slice(0, -1).join('/');\n if (dir !== '') byPath.set(dir.toLowerCase(), page);\n }\n\n const basename = withoutExt.split('/').pop() ?? '';\n add(byName, basename.toLowerCase(), page);\n const slugged = slugifySegment(basename);\n if (slugged !== basename.toLowerCase()) add(byName, slugged, page);\n }\n\n /** Shallowest path first, then alphabetically — stable regardless of scan order. */\n const pick = (candidates: ContentPage[]): ContentPage =>\n [...candidates].sort((a, b) => {\n const depth = a.file.split('/').length - b.file.split('/').length;\n return depth !== 0 ? depth : a.file.localeCompare(b.file);\n })[0]!;\n\n function lookup(target: string): { page?: ContentPage; ambiguous?: ContentPage[] } {\n const cleaned = toPosix(target).replace(/^\\/+/, '').replace(CONTENT_EXT, '');\n const key = cleaned.toLowerCase();\n\n // 1. Exact path match relative to the content root.\n const exact = byPath.get(key);\n if (exact) return { page: exact };\n\n // 2 and 3. Basename match, then slugified basename match.\n const named = byName.get(key) ?? byName.get(slugifySegment(cleaned));\n if (named === undefined || named.length === 0) return {};\n if (named.length === 1) return { page: named[0]! };\n return { page: pick(named), ambiguous: named };\n }\n\n function href(page: ContentPage, hash: string | undefined): string {\n const url = withBase(base, page.url);\n return hash === undefined ? url : `${url}#${slugify(hash)}`;\n }\n\n return {\n resolveHref(raw, fromFile) {\n if (isExternalHref(raw) && !raw.startsWith('.') && !CONTENT_EXT.test(raw.split('#')[0] ?? '')) {\n return { href: raw };\n }\n const [pathPart = '', hashPart] = splitHash(raw);\n if (!CONTENT_EXT.test(pathPart)) return { href: raw };\n\n // A leading slash means \"from the content root\", so the linking file's directory is\n // not the starting point.\n const fromDir = pathPart.startsWith('/') ? [] : toPosix(fromFile).split('/').slice(0, -1);\n const resolved = joinPosix(fromDir, pathPart);\n const page = byPath.get(resolved.toLowerCase());\n\n if (page === undefined) {\n return {\n href: raw,\n warning: `Broken link ${raw} in ${toPosix(fromFile)}: no page at ${resolved}.`,\n };\n }\n return { href: href(page, hashPart) };\n },\n\n resolveWikilink(target, fromFile) {\n const pipe = target.indexOf('|');\n const linkPart = (pipe === -1 ? target : target.slice(0, pipe)).trim();\n const label = (pipe === -1 ? target : target.slice(pipe + 1)).trim();\n const [pathPart = '', hashPart] = splitHash(linkPart);\n\n const { page, ambiguous } = lookup(pathPart);\n if (page === undefined) {\n return {\n label,\n warning: `Dead wikilink [[${target}]] in ${toPosix(fromFile)}: no page matches \"${pathPart}\".`,\n };\n }\n\n const warning =\n ambiguous === undefined\n ? undefined\n : `Ambiguous wikilink [[${target}]] in ${toPosix(fromFile)}: matches ${ambiguous\n .map((c) => c.file)\n .sort()\n .join(', ')}. Using ${page.file}.`;\n\n return { href: href(page, hashPart), label, warning };\n },\n };\n}\n\nfunction splitHash(value: string): [string, string | undefined] {\n const index = value.indexOf('#');\n if (index === -1) return [value, undefined];\n return [value.slice(0, index), value.slice(index + 1)];\n}\n\n/** Resolve `./a`, `../a`, `a` against a directory, without touching the real filesystem. */\nfunction joinPosix(fromDir: readonly string[], relative: string): string {\n const segments = [...fromDir];\n for (const part of toPosix(relative).split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') segments.pop();\n else segments.push(part);\n }\n return segments.join('/').replace(CONTENT_EXT, '');\n}\n","/**\n * Path → URL resolution.\n *\n * One slug algorithm, `github-slugger`, is used for URLs, heading anchors and the search\n * index alike — it is already a fumadocs dependency, so agreeing with it is free.\n */\nimport { slug as slugify } from 'github-slugger';\n\nconst INDEX_NAMES = new Set(['index', 'readme']);\nconst CONTENT_EXT = /\\.mdx?$/i;\n\nexport interface RouteInfo {\n /** Virtual path relative to the content root, posix separators. */\n file: string;\n /** Route URL: leading slash, never a trailing slash. The site root is `/`. */\n url: string;\n /** Slug segments; the site root is the empty array. */\n slugs: string[];\n /** Path of the emitted HTML relative to `dist/`. */\n output: string;\n /** Whether this file stands for its directory rather than for itself. */\n isIndex: boolean;\n}\n\n/** Normalise a possibly-Windows path to a posix virtual path. */\nexport function toPosix(file: string): string {\n return file.replace(/\\\\/g, '/').replace(/^\\.\\//, '').replace(/^\\/+/, '');\n}\n\n/**\n * Slugify a single path segment. Segments that slugify to nothing (`...`, emoji-only) fall\n * back to a lowercased, punctuation-stripped form so that a URL is never empty.\n */\nexport function slugifySegment(segment: string): string {\n const slugged = slugify(segment);\n if (slugged !== '') return slugged;\n const fallback = segment.toLowerCase().replace(/[^\\p{L}\\p{N}]+/gu, '-').replace(/^-+|-+$/g, '');\n return fallback === '' ? 'untitled' : fallback;\n}\n\nexport function toRoute(file: string): RouteInfo {\n const posix = toPosix(file);\n const segments = posix.split('/');\n const basename = segments.pop() ?? '';\n const stem = basename.replace(CONTENT_EXT, '');\n const isIndex = INDEX_NAMES.has(stem.toLowerCase());\n\n const slugs = segments.map(slugifySegment);\n if (!isIndex) slugs.push(slugifySegment(stem));\n\n return {\n file: posix,\n url: slugs.length === 0 ? '/' : `/${slugs.join('/')}`,\n slugs,\n output: [...slugs, 'index.html'].join('/'),\n isIndex,\n };\n}\n\nexport interface ResolvedRoutes {\n routes: RouteInfo[];\n /** Conditions that make the site silently wrong — a build error. */\n errors: string[];\n /** Conditions that are visible on the page itself — a warning. */\n warnings: string[];\n}\n\n/**\n * Resolve a whole corpus at once, because the interesting failures are corpus-level:\n * `index.md` vs `README.md` in one directory, and two different files slugifying alike.\n */\nexport function resolveRoutes(files: string[]): ResolvedRoutes {\n const sorted = [...files].map(toPosix).sort();\n const byUrl = new Map<string, RouteInfo[]>();\n const warnings: string[] = [];\n const errors: string[] = [];\n\n for (const file of sorted) {\n const route = toRoute(file);\n const bucket = byUrl.get(route.url);\n if (bucket) bucket.push(route);\n else byUrl.set(route.url, [route]);\n }\n\n const routes: RouteInfo[] = [];\n for (const [url, candidates] of [...byUrl.entries()].sort(([a], [b]) => (a < b ? -1 : 1))) {\n if (candidates.length === 1) {\n routes.push(candidates[0]!);\n continue;\n }\n\n // `index.md` beating `README.md` is a documented preference, not a collision.\n const indexes = candidates.filter((c) => c.isIndex);\n if (indexes.length === candidates.length) {\n const winner =\n indexes.find((c) => c.file.split('/').pop()?.toLowerCase().startsWith('index')) ?? indexes[0]!;\n const losers = indexes.filter((c) => c !== winner);\n warnings.push(\n `${url} has more than one index file: using ${winner.file}, ignoring ${losers\n .map((l) => l.file)\n .join(', ')}.`,\n );\n routes.push(winner);\n continue;\n }\n\n errors.push(\n `Duplicate route ${url} produced by ${candidates.length} files:\\n` +\n candidates.map((c) => ` - ${c.file}`).join('\\n') +\n `\\nRename one of them, or exclude it with \\`exclude\\` in seemore.config.ts.`,\n );\n }\n\n return { routes, errors, warnings };\n}\n","import { dynamicLoader } from 'fumadocs-core/source';\nimport type { Root } from 'fumadocs-core/page-tree';\nimport { scan, type ContentPage, type ScanOptions, type ScanResult } from './scan.js';\n\nexport interface SeemoreSource {\n /** The most recent scan. Never triggers filesystem work. */\n current(): ScanResult;\n /** Re-read the corpus and let fumadocs decide what changed. */\n refresh(): ScanResult;\n getPageTree(): Promise<Root>;\n /** Serialized for the browser — the payload of `virtual:seemore/tree`. */\n serializeTree(): Promise<unknown>;\n pages(): ContentPage[];\n loader: ReturnType<typeof dynamicLoader>;\n}\n\n/**\n * Wire the scanner to fumadocs' dynamic loader.\n *\n * `cache: 'custom'` puts us in charge of when a scan happens: the watcher calls\n * {@link SeemoreSource.refresh}, and fumadocs recomputes the page tree because the array\n * identity changed. Between refreshes `files()` hands back the same array, so reading the\n * tree is free.\n */\nexport function createSource(options: ScanOptions): SeemoreSource {\n let cached: ScanResult | undefined;\n\n const read = (): ScanResult => (cached ??= scan(options));\n\n const loader = dynamicLoader(\n {\n cache: 'custom',\n files: () => read().files,\n invalidate: () => {\n cached = undefined;\n },\n },\n { baseUrl: '/' },\n );\n\n return {\n loader,\n current: read,\n pages: () => read().pages,\n refresh() {\n loader.invalidate();\n return read();\n },\n async getPageTree() {\n const output = await loader.get();\n return output.getPageTree();\n },\n async serializeTree() {\n const output = await loader.get();\n return output.serializePageTree(output.getPageTree());\n },\n };\n}\n","import { readFileSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { globSync } from 'tinyglobby';\nimport { z } from 'zod';\nimport type { VirtualFile } from 'fumadocs-core/source';\nimport { parseFrontmatter, type FrontmatterData } from './frontmatter.js';\nimport { resolveRoutes, toPosix, type RouteInfo } from './slug.js';\n\n/** Appended to, never replaced by, `config.exclude`. */\nexport const DEFAULT_EXCLUDES = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/out/**',\n '**/vendor/**',\n '**/target/**',\n '**/.seemore/**',\n '**/.*/**',\n '**/.*',\n '**/CHANGELOG.md',\n];\n\n/** fumadocs' `meta.json` shape, validated so a typo reports a file rather than a blank folder. */\nconst metaSchema = z\n .object({\n title: z.string().optional(),\n icon: z.string().optional(),\n root: z.boolean().optional(),\n pages: z.array(z.string()).optional(),\n pagesIndex: z.string().optional(),\n defaultOpen: z.boolean().optional(),\n collapsible: z.boolean().optional(),\n description: z.string().optional(),\n })\n .loose();\n\nexport interface ContentPage extends RouteInfo {\n /** Absolute path on disk — what the generated import map imports. */\n absPath: string;\n data: FrontmatterData & { title: string };\n}\n\nexport interface ScanResult {\n /** What fumadocs' loader consumes. */\n files: VirtualFile[];\n /** What the router, prefetch map and prerender driver consume. */\n pages: ContentPage[];\n errors: string[];\n warnings: string[];\n}\n\nexport interface ScanOptions {\n contentRoot: string;\n exclude?: string[];\n /** Used as the title of a root index page that has no frontmatter title. */\n siteTitle?: string;\n /** Dev keeps drafts so they can be written; the build drops them. */\n includeDrafts?: boolean;\n}\n\nexport function scan(options: ScanOptions): ScanResult {\n const contentRoot = resolve(options.contentRoot);\n const ignore = [...DEFAULT_EXCLUDES, ...(options.exclude ?? [])];\n\n const contentFiles = globSync(['**/*.md', '**/*.mdx'], {\n cwd: contentRoot,\n ignore,\n dot: false,\n absolute: false,\n }).map(toPosix);\n\n const metaFiles = globSync(['**/meta.json'], { cwd: contentRoot, ignore, dot: false, absolute: false }).map(toPosix);\n\n const { routes, errors, warnings } = resolveRoutes(contentFiles);\n\n const pages: ContentPage[] = [];\n for (const route of routes) {\n const absPath = join(contentRoot, route.file);\n let data: FrontmatterData;\n try {\n data = parseFrontmatter(readFileSync(absPath, 'utf8'), route.file).data;\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n continue;\n }\n\n if (data.draft === true && options.includeDrafts !== true) continue;\n\n pages.push({ ...route, absPath, data: { ...data, title: titleFor(route, data, options.siteTitle) } });\n }\n\n const files: VirtualFile[] = pages.map((page) => ({\n type: 'page',\n path: page.file,\n absolutePath: page.absPath,\n // Our slugs, not fumadocs' — one algorithm decides URLs, anchors and the index.\n slugs: page.slugs,\n data: page.data,\n }));\n\n const metaDirs = new Set<string>();\n for (const file of metaFiles) {\n const absPath = join(contentRoot, file);\n try {\n const parsed = metaSchema.safeParse(JSON.parse(readFileSync(absPath, 'utf8')));\n if (!parsed.success) {\n errors.push(\n `Invalid ${file}:\\n${parsed.error.issues.map((i) => ` - ${i.path.join('.') || '(root)'}: ${i.message}`).join('\\n')}`,\n );\n continue;\n }\n metaDirs.add(dirname(file));\n files.push({ type: 'meta', path: file, absolutePath: absPath, data: parsed.data });\n } catch (error) {\n errors.push(`Invalid ${file}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n files.push(...synthesiseOrderMeta(pages, metaDirs));\n\n return { files, pages, errors, warnings };\n}\n\n/**\n * Ordering: a real `meta.json` wins; otherwise frontmatter `order` decides, then\n * title. fumadocs has no native `order`, so we express the intent in the mechanism it does\n * have — a synthetic `meta.json` whose `pages` list ends in the `...` rest marker, leaving\n * anything we did not mention in fumadocs' own alphabetical order.\n */\nfunction synthesiseOrderMeta(pages: ContentPage[], metaDirs: Set<string>): VirtualFile[] {\n const byDir = new Map<string, ContentPage[]>();\n for (const page of pages) {\n const dir = dirname(page.file);\n const bucket = byDir.get(dir);\n if (bucket) bucket.push(page);\n else byDir.set(dir, [page]);\n }\n\n const out: VirtualFile[] = [];\n for (const [dir, dirPages] of byDir) {\n if (metaDirs.has(dir)) continue;\n // Nothing to express unless something wants to move: an explicit `order`, or an index\n // page that would otherwise sort alphabetically into the middle of its own directory.\n if (!dirPages.some((p) => typeof p.data.order === 'number' || p.isIndex)) continue;\n\n const ordered = [...dirPages].sort(compareForOrder).map((p) => basename(p.file).replace(/\\.mdx?$/i, ''));\n\n out.push({\n type: 'meta',\n path: dir === '.' ? 'meta.json' : `${dir}/meta.json`,\n data: { pages: [...ordered, '...'] },\n });\n }\n return out;\n}\n\nfunction compareForOrder(a: ContentPage, b: ContentPage): number {\n // An index page stands for its directory, so it leads unless it asks not to.\n const ao = orderOf(a);\n const bo = orderOf(b);\n if (ao !== bo) return ao - bo;\n return a.data.title.localeCompare(b.data.title);\n}\n\nfunction orderOf(page: ContentPage): number {\n if (typeof page.data.order === 'number') return page.data.order;\n return page.isIndex ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;\n}\n\nfunction titleFor(route: RouteInfo, data: FrontmatterData, siteTitle: string | undefined): string {\n if (typeof data.title === 'string' && data.title !== '') return data.title;\n if (route.url === '/') return siteTitle ?? 'Home';\n return humanise(route.slugs[route.slugs.length - 1] ?? 'Untitled');\n}\n\n/** `getting-started` → `Getting Started`. Good enough to never show a raw slug in a sidebar. */\nfunction humanise(slug: string): string {\n return slug\n .split('-')\n .filter((word) => word !== '')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n","import matter from 'gray-matter';\nimport { z } from 'zod';\n\n/**\n * Frontmatter is validated, not restricted: unknown keys pass through so that a corpus\n * written for another tool still builds. Only the keys seemore acts on are typed.\n */\nexport const frontmatterSchema = z\n .object({\n title: z.string().optional(),\n description: z.string().optional(),\n icon: z.string().optional(),\n /** Sidebar ordering, second only to `meta.json`. */\n order: z.number().optional(),\n /**\n * Excluded from the build. Dev keeps drafts so they can be written, so a link to one\n * works while you write it and warns as a dead link when you build.\n */\n draft: z.boolean().optional(),\n })\n .loose();\n\nexport type FrontmatterData = z.output<typeof frontmatterSchema> & Record<string, unknown>;\n\n/** Split a source file into validated frontmatter and body. `file` is only for messages. */\nexport function parseFrontmatter(source: string, file: string): { data: FrontmatterData; content: string } {\n let parsed;\n try {\n parsed = matter(source);\n } catch (error) {\n throw new Error(\n `Invalid frontmatter in ${file}: ${error instanceof Error ? error.message.split('\\n')[0] : String(error)}`,\n { cause: error },\n );\n }\n\n return { data: validateFrontmatter(parsed.data, file), content: parsed.content };\n}\n\nexport function validateFrontmatter(data: unknown, file: string): FrontmatterData {\n const result = frontmatterSchema.safeParse(data ?? {});\n if (result.success) return result.data as FrontmatterData;\n\n const issues = result.error.issues.map((issue) => {\n const field = issue.path.length === 0 ? '(root)' : issue.path.join('.');\n return ` - ${field}: ${issue.message}`;\n });\n throw new Error(`Invalid frontmatter in ${file}:\\n${issues.join('\\n')}`);\n}\n","import pc from 'picocolors';\n\n/**\n * Warnings are collected and printed once, as a grouped summary, rather than interleaved\n * with progress output — a build that prints forty warnings between chunks is a\n * build whose warnings nobody reads.\n */\nexport interface WarningCollector {\n add(message: string): void;\n list(): string[];\n clear(): void;\n /** Print the grouped summary. Returns the number of warnings printed. */\n flush(log?: (line: string) => void): number;\n}\n\nexport function createWarningCollector(): WarningCollector {\n const seen = new Set<string>();\n\n return {\n add(message) {\n seen.add(message);\n },\n list: () => [...seen],\n clear: () => seen.clear(),\n flush(log = console.warn) {\n const messages = [...seen].sort();\n seen.clear();\n if (messages.length === 0) return 0;\n log('');\n log(pc.yellow(`${messages.length} warning${messages.length === 1 ? '' : 's'}:`));\n for (const message of messages) log(pc.yellow(` - ${message}`));\n log('');\n return messages.length;\n },\n };\n}\n","import { createLinkResolver, type LinkResolver } from './content/links.js';\nimport type { ContentPage, ScanResult } from './content/scan.js';\nimport { createSource, type SeemoreSource } from './content/source.js';\nimport type { ResolvedSeemoreConfig } from './config/schema.js';\nimport { createWarningCollector, type WarningCollector } from './report.js';\n\nexport interface SeemoreContext {\n config: ResolvedSeemoreConfig;\n /** Absolute path of the directory being documented. Usually outside the Vite root. */\n contentRoot: string;\n source: SeemoreSource;\n warnings: WarningCollector;\n pages(): ContentPage[];\n /** Rebuilt on every refresh, so remark plugins must read it late. */\n resolver(): LinkResolver;\n /** Re-read the corpus after a filesystem change. */\n refresh(): ScanResult;\n /** Slug collisions and frontmatter failures found by the most recent scan. */\n errors(): string[];\n}\n\nexport interface CreateContextOptions {\n config: ResolvedSeemoreConfig;\n contentRoot: string;\n /** Dev keeps drafts so they can be written; the build drops them. */\n includeDrafts?: boolean;\n}\n\nexport function createContext(options: CreateContextOptions): SeemoreContext {\n const { config, contentRoot } = options;\n\n const source = createSource({\n contentRoot,\n exclude: config.exclude,\n siteTitle: config.title,\n includeDrafts: options.includeDrafts,\n });\n\n let resolver = createLinkResolver(source.pages(), config.base);\n\n return {\n config,\n contentRoot,\n source,\n warnings: createWarningCollector(),\n pages: () => source.pages(),\n resolver: () => resolver,\n errors: () => source.current().errors,\n refresh() {\n const result = source.refresh();\n resolver = createLinkResolver(result.pages, config.base);\n return result;\n },\n };\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n/** Turn a route URL into the file that serves it. */\nexport function outputPathFor(url: string): string {\n const clean = url.replace(/^\\/+|\\/+$/g, '');\n return clean === '' ? 'index.html' : join(clean, 'index.html');\n}\n\nexport function writeHtml(outDir: string, relativePath: string, html: string): void {\n const target = join(outDir, relativePath);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, html, 'utf8');\n}\n\n/**\n * Inject a rendered page into the client build's `index.html`.\n *\n * The template already carries the hashed script and stylesheet Vite emitted, so the markup\n * and the assets can never drift apart.\n */\nexport function applyTemplate(template: string, { html, head }: { html: string; head: string }): string {\n // Replacer functions, not strings: a page containing `$&` or `` $` `` would otherwise\n // splice the marker — or the whole document head — into its own body.\n return template.replace('<!--seemore-head-->', () => head).replace('<!--seemore-app-->', () => html);\n}\n","import { writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/**\n * Host conventions.\n *\n * The portable output is everything else: one real `index.html` per route, plus `404.html`,\n * which every static host honours. These files are additive — small, named conventions that\n * particular hosts look for — not a list of hosts seemore supports.\n */\nexport function writeDeployArtifacts(outDir: string, base: string, shell: string): void {\n const prefix = base === '/' ? '' : base.replace(/\\/+$/, '');\n\n // Netlify and Cloudflare Pages share this format. It applies after the real files they\n // already serve, so it only catches addresses that do not exist.\n writeFileSync(join(outDir, '_redirects'), `${prefix}/* ${prefix}/index.html 200\\n`, 'utf8');\n\n // Surge looks for `200.html` as its SPA fallback.\n writeFileSync(join(outDir, '200.html'), shell, 'utf8');\n\n // GitHub Pages runs the output through Jekyll unless this file exists, and Jekyll drops\n // every file and directory whose name starts with `_`. A `docs/_internal/` folder would\n // build correctly and then 404 once deployed — the exact failure seemore exists to prevent.\n writeFileSync(join(outDir, '.nojekyll'), '', 'utf8');\n}\n","import { pathToFileURL } from 'node:url';\nimport { join } from 'node:path';\nimport { build } from 'vite';\nimport type { SeemoreContext } from '../context.js';\nimport { createViteConfig } from '../vite/config.js';\n\nexport interface RenderResult {\n html: string;\n head: string;\n}\n\nexport interface PrerenderModule {\n render(url: string): Promise<RenderResult>;\n listRoutes(): string[];\n}\n\n/**\n * Build the prerender entry for node and load it.\n *\n * This is a second Vite build rather than a reuse of the client bundle because the client\n * bundle is compiled for the browser; the driver needs the same module graph evaluated in\n * node, with the same virtual modules, so the two can never describe different sites.\n */\nexport async function loadPrerenderModule(ctx: SeemoreContext, ssrOutDir: string): Promise<PrerenderModule> {\n await build(createViteConfig({ ctx, mode: 'build', ssrOutDir }));\n\n const entry = join(ssrOutDir, 'entry.prerender.js');\n const loaded = (await import(pathToFileURL(entry).href)) as Partial<PrerenderModule>;\n\n if (typeof loaded.render !== 'function' || typeof loaded.listRoutes !== 'function') {\n throw new Error(`seemore: the prerender build at ${entry} did not export \\`render\\` and \\`listRoutes\\`.`);\n }\n\n return { render: loaded.render, listRoutes: loaded.listRoutes };\n}\n","import { realpathSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { InlineConfig, Plugin } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tailwindcss from '@tailwindcss/vite';\nimport mdx from '@mdx-js/rollup';\nimport type { SeemoreContext } from '../context.js';\nimport { appRoot, cacheDir, packageRoot } from '../paths.js';\nimport { createRehypePlugins, createRemarkPlugins } from './mdx.js';\nimport { seemorePlugin } from './plugin.js';\nimport { seemoreWatcherPlugin } from './watcher.js';\n\nexport interface ViteConfigOptions {\n ctx: SeemoreContext;\n mode: 'dev' | 'build';\n /** Absolute output directory. Ignored in dev. */\n outDir?: string;\n /** When set, build the prerender entry for node instead of the client bundle. */\n ssrOutDir?: string;\n}\n\nexport function createViteConfig({ ctx, mode, outDir, ssrOutDir }: ViteConfigOptions): InlineConfig {\n const root = appRoot();\n const isSsr = ssrOutDir !== undefined;\n\n const mdxOptions = {\n // `format` is inferred per file, so a plain `.md` never needs MDX syntax.\n remarkPlugins: createRemarkPlugins({\n contentRoot: ctx.contentRoot,\n getResolver: () => ctx.resolver(),\n onWarning: (message) => ctx.warnings.add(message),\n }),\n rehypePlugins: createRehypePlugins(),\n // MDX compiles its own JSX. Vite's builtin transform infers a file's language from its\n // extension and does not know `.md`/`.mdx`, so leaving JSX in the output would fail to\n // parse. Fast Refresh is unaffected: it is a separate transform, applied to these files\n // through the React plugin's `include` below, which is what turns a content edit into an\n // in-place component swap rather than a reload.\n jsx: false,\n };\n\n return {\n root,\n base: ctx.config.base,\n cacheDir: cacheDir(ctx.contentRoot),\n configFile: false,\n envDir: false,\n clearScreen: false,\n logLevel: mode === 'build' ? 'warn' : 'info',\n\n plugins: [\n // Order matters: MDX first, then React, so JSX from MDX is transformed and refreshed.\n { ...mdx(mdxOptions), enforce: 'pre' },\n react({ include: /\\.(?:mdx?|jsx?|tsx?)$/ }),\n // Before Tailwind: our plugin injects the theme preset into the root stylesheet, and\n // Tailwind must see the injected version.\n seemorePlugin({ ctx, serveSearch: mode === 'dev' }),\n tailwindcss(),\n ...(mode === 'dev' ? [seemoreWatcherPlugin(ctx)] : []),\n ],\n\n // Vite bundles workers with the browser export condition, but a worker has no `document`.\n // `decode-named-character-reference` — pulled in through fumadocs' search client, via\n // remark — calls `document.createElement` at module scope in its browser build, so the\n // search worker threw on load. The package ships a DOM-free `worker` entry; use it.\n worker: { plugins: () => [workerConditionPlugin()] },\n\n resolve: {\n // The app is compiled from seemore's own sources, so its dependencies must resolve\n // from seemore's directory rather than from the user's project.\n dedupe: ['react', 'react-dom', 'react-router', 'fumadocs-core', 'fumadocs-ui'],\n // In dev the module worker is served through the shared module graph and its fumadocs\n // chunk comes from the dep optimizer, where `worker.plugins` never runs — the browser\n // build of `decode-named-character-reference` is inlined into the prebundle and the\n // worker throws on load. Adding the package's own `worker` condition graph-wide flips\n // the whole dev graph (main thread included) to its DOM-free build, which behaves the\n // same; production keeps the targeted worker-bundle swap above.\n conditions: mode === 'dev' ? ['worker'] : [],\n },\n\n server: {\n fs: {\n // The content root is normally *outside* the Vite root, and files outside `allow`\n // 404 silently — the single most likely cause of \"the watcher does nothing\".\n allow: withRealPaths([root, packageRoot(), ctx.contentRoot, ctx.config.root, process.cwd()]),\n },\n watch: {\n // Only real exclusions here. Vite merges these into chokidar's ignore *list*, where a\n // leading `!` is a negated matcher that matches everything it is not — so the obvious\n // `!<contentRoot>/**` \"re-include\" would silently ignore the entire project instead.\n // Content outside the Vite root is watched by seemore's own chokidar instance.\n ignored: ['**/node_modules/**', '**/.git/**'],\n },\n },\n\n build: isSsr\n ? {\n ssr: join(root, 'entry.prerender.tsx'),\n outDir: ssrOutDir,\n emptyOutDir: true,\n copyPublicDir: false,\n minify: false,\n rollupOptions: { output: { entryFileNames: 'entry.prerender.js' } },\n }\n : {\n outDir,\n emptyOutDir: true,\n rollupOptions: { input: join(root, 'index.html') },\n // The app bundle is seemore's own, not the user's; warning them about a size they\n // cannot act on is noise.\n chunkSizeWarningLimit: 2_000,\n },\n\n // The prerender bundle is written to a scratch directory outside any `node_modules`, so\n // it has to be self-contained: an externalised `react` there resolves against the scratch\n // directory and is simply not found.\n ssr: isSsr ? { noExternal: true } : undefined,\n };\n}\n\n/**\n * Every path, plus where it actually points.\n *\n * Vite resolves a module to its real path before checking `fs.allow`, so a content root\n * reached through a symlink — `/var` on macOS, or anything under a linked directory — is\n * denied unless both spellings are listed. The failure is a silent 404, so it is worth the\n * two extra entries.\n */\nfunction withRealPaths(paths: string[]): string[] {\n const out = new Set<string>();\n for (const path of paths) {\n out.add(path);\n try {\n out.add(realpathSync.native(path));\n } catch {\n // A path that does not exist yet cannot be resolved, and does not need to be.\n }\n }\n return [...out];\n}\n\n/**\n * Point worker bundles at the DOM-free build of packages that ship two.\n *\n * Resolution goes through Vite so pnpm's layout is respected — these packages are deep\n * transitive dependencies and are not resolvable from seemore's own directory — and only the\n * final `index.dom.js` is swapped for its sibling.\n */\nfunction workerConditionPlugin(): Plugin {\n return {\n name: 'seemore:worker-conditions',\n enforce: 'pre',\n async resolveId(source, importer, options) {\n if (!WORKER_SAFE_ENTRIES.has(source)) return undefined;\n\n const resolved = await this.resolve(source, importer, options);\n if (resolved === null) return undefined;\n\n const domFree = resolved.id.replace(/index\\.dom\\.js$/, 'index.js');\n return domFree === resolved.id ? resolved : { ...resolved, id: domFree };\n },\n };\n}\n\n/**\n * Packages whose browser build touches the DOM at module scope and whose default build does\n * not. `decode-named-character-reference` reaches the worker through remark, by way of\n * fumadocs' search client.\n */\nconst WORKER_SAFE_ENTRIES = new Set(['decode-named-character-reference']);\n","import type { PluggableList } from 'unified';\nimport remarkFrontmatter from 'remark-frontmatter';\nimport {\n rehypeCode,\n rehypeToc,\n remarkAdmonition,\n remarkDirectiveAdmonition,\n remarkGfm,\n remarkHeading,\n remarkImage,\n remarkMdxMermaid,\n remarkSteps,\n} from 'fumadocs-core/mdx-plugins';\nimport {\n remarkSeemoreAlerts,\n remarkSeemoreAssets,\n remarkSeemoreLinks,\n remarkSeemoreWikilinks,\n type SeemoreRemarkOptions,\n} from './remark.js';\n\n/**\n * The remark/rehype chain. Order matters:\n *\n * - headings get their ids before `rehype-toc` reads them;\n * - our link rewriting runs after the fumadocs transforms that can create links;\n * - Shiki runs at build time in `rehype-code`, so no highlighter ships to the browser.\n *\n * `remark-structure` is deliberately absent: search indexing runs node-side over the raw\n * markdown, where it works identically in dev and build without depending on a\n * browser module having been evaluated.\n */\nexport function createRemarkPlugins(options: SeemoreRemarkOptions): PluggableList {\n return [\n // Strips the `---` block so it never renders. Its data already came from the scan.\n [remarkFrontmatter, ['yaml']],\n remarkGfm,\n remarkHeading,\n remarkAdmonition,\n remarkDirectiveAdmonition,\n // After the fumadocs admonition plugins, which handle `:::note`, and before anything that\n // rewrites link or text nodes inside the quote.\n remarkSeemoreAlerts,\n remarkSteps,\n // Before `remark-image`: a reference to a file that is not there becomes a warning and a\n // visibly broken image, rather than a failed build.\n () => remarkSeemoreAssets(options),\n [\n remarkImage,\n {\n onError: (error: Error) => {\n options.onWarning(error.message);\n },\n },\n ],\n // Rewrites ```mermaid fences to <Mermaid chart=\"…\" />. We supply the component.\n remarkMdxMermaid,\n () => remarkSeemoreWikilinks(options),\n () => remarkSeemoreLinks(options),\n ];\n}\n\nexport function createRehypePlugins(): PluggableList {\n return [\n // A fence in a language Shiki has no grammar for (` ```d2 `, anything an AI dreamt up) is\n // plain code on the page, not a dead one: `plaintext` is special-cased by Shiki and\n // never needs loading.\n [rehypeCode, { fallbackLanguage: 'plaintext' }],\n rehypeToc,\n ];\n}\n","import { existsSync } from 'node:fs';\nimport { dirname, relative, resolve } from 'node:path';\nimport { visit } from 'unist-util-visit';\nimport type { Blockquote, Image, Paragraph, PhrasingContent, Root, Text } from 'mdast';\nimport type { Transformer } from 'unified';\nimport type { VFile } from 'vfile';\nimport type { LinkResolver } from '../content/links.js';\nimport { toPosix } from '../content/slug.js';\n\nexport interface SeemoreRemarkOptions {\n contentRoot: string;\n /** Read late: the resolver is replaced on every rescan. */\n getResolver: () => LinkResolver;\n onWarning: (message: string) => void;\n}\n\nconst WIKILINK = /\\[\\[([^\\]\\n]+)\\]\\]/g;\n\n/** GitHub's alert syntax, and the fumadocs callout each kind maps onto. */\nconst ALERTS: Record<string, { type: string; title: string }> = {\n NOTE: { type: 'info', title: 'Note' },\n TIP: { type: 'idea', title: 'Tip' },\n IMPORTANT: { type: 'info', title: 'Important' },\n WARNING: { type: 'warn', title: 'Warning' },\n CAUTION: { type: 'error', title: 'Caution' },\n};\n\nconst ALERT_MARKER = /^\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]\\s*/;\n\n/**\n * GitHub alerts — `> [!NOTE]` — become fumadocs callouts.\n *\n * fumadocs ships `:::note` and directive admonitions, neither of which is what people\n * actually have in their repositories. seemore points at folders that already exist, so the\n * syntax GitHub renders is the syntax that has to work.\n */\nexport function remarkSeemoreAlerts(): Transformer<Root, Root> {\n return (tree) => {\n visit(tree, 'blockquote', (node: Blockquote, index, parent) => {\n if (parent === undefined || index === undefined) return;\n\n const first = node.children[0];\n if (first === undefined || first.type !== 'paragraph') return;\n\n const marker = ALERT_MARKER.exec(textOf(first));\n const alert = marker === null ? undefined : ALERTS[marker[1] ?? ''];\n if (marker === undefined || marker === null || alert === undefined) return;\n\n stripMarker(first, marker[0]);\n\n parent.children[index] = {\n type: 'mdxJsxFlowElement',\n name: 'Callout',\n attributes: [\n { type: 'mdxJsxAttribute', name: 'type', value: alert.type },\n { type: 'mdxJsxAttribute', name: 'title', value: alert.title },\n ],\n children: node.children,\n } as unknown as Blockquote;\n });\n };\n}\n\n/** The paragraph's leading text, which is where the marker lives. */\nfunction textOf(paragraph: Paragraph): string {\n const first = paragraph.children[0];\n return first !== undefined && first.type === 'text' ? first.value.trimStart() : '';\n}\n\n/** Remove the `[!NOTE]` marker, and the line break that followed it. */\nfunction stripMarker(paragraph: Paragraph, marker: string): void {\n const first = paragraph.children[0];\n if (first === undefined || first.type !== 'text') return;\n\n first.value = first.value.trimStart().slice(marker.length).replace(/^\\n/, '');\n if (first.value === '') paragraph.children.shift();\n if (paragraph.children[0]?.type === 'break') paragraph.children.shift();\n}\n\n/**\n * `[[Page]]`, `[[Page|label]]`, `[[Page#Heading]]`. fumadocs has no equivalent.\n *\n * Unresolved targets become styled plain text rather than dead links, because a link that\n * goes nowhere is worse than visibly missing text.\n */\nexport function remarkSeemoreWikilinks(options: SeemoreRemarkOptions): Transformer<Root, Root> {\n return (tree, file) => {\n const from = virtualPath(options.contentRoot, file);\n const resolver = options.getResolver();\n\n visit(tree, 'text', (node: Text, index, parent) => {\n if (parent === undefined || index === undefined) return;\n if (!node.value.includes('[[')) return;\n\n const replacement: PhrasingContent[] = [];\n let cursor = 0;\n WIKILINK.lastIndex = 0;\n\n for (let match = WIKILINK.exec(node.value); match !== null; match = WIKILINK.exec(node.value)) {\n const target = match[1] ?? '';\n if (match.index > cursor) {\n replacement.push({ type: 'text', value: node.value.slice(cursor, match.index) });\n }\n cursor = match.index + match[0].length;\n\n const resolved = resolver.resolveWikilink(target, from);\n if (resolved.warning !== undefined) options.onWarning(resolved.warning);\n\n if (resolved.href === undefined) {\n // An MDX JSX node, not raw HTML: `.md` files run through `rehypeRemoveRaw`, which\n // would silently drop an `html` node, whereas JSX nodes are passed through.\n replacement.push({\n type: 'mdxJsxTextElement',\n name: 'span',\n attributes: [\n { type: 'mdxJsxAttribute', name: 'className', value: 'seemore-broken-wikilink' },\n { type: 'mdxJsxAttribute', name: 'title', value: 'Unresolved link' },\n ],\n children: [{ type: 'text', value: resolved.label }],\n } as unknown as PhrasingContent);\n } else {\n replacement.push({\n type: 'link',\n url: resolved.href,\n children: [{ type: 'text', value: resolved.label }],\n });\n }\n }\n\n if (replacement.length === 0) return;\n if (cursor < node.value.length) replacement.push({ type: 'text', value: node.value.slice(cursor) });\n\n parent.children.splice(index, 1, ...replacement);\n return index + replacement.length;\n });\n };\n}\n\n/**\n * A referenced asset that is not on disk is a warning, not a build failure: the page is\n * visibly wrong on its own, which is the point of the distinction.\n *\n * It has to run before fumadocs' `remark-image`, which turns every image into a bundler\n * import — and an import of a file that does not exist fails the build. Turning the node\n * into JSX first takes it out of that plugin's way, leaving the broken reference visible on\n * the page exactly as the author wrote it.\n */\nexport function remarkSeemoreAssets(options: SeemoreRemarkOptions): Transformer<Root, Root> {\n return (tree, file) => {\n if (typeof file.path !== 'string' || file.path === '') return;\n const dir = dirname(file.path);\n const from = virtualPath(options.contentRoot, file);\n\n visit(tree, 'image', (node: Image, index, parent) => {\n if (parent === undefined || index === undefined) return;\n if (isExternal(node.url) || node.url.startsWith('/')) return;\n\n const target = resolve(dir, decodeURIComponent(node.url.split(/[?#]/)[0] ?? ''));\n if (existsSync(target)) return;\n\n options.onWarning(`Missing asset ${node.url} referenced by ${from}.`);\n\n parent.children.splice(index, 1, {\n type: 'mdxJsxTextElement',\n name: 'img',\n attributes: [\n { type: 'mdxJsxAttribute', name: 'src', value: node.url },\n { type: 'mdxJsxAttribute', name: 'alt', value: node.alt ?? '' },\n { type: 'mdxJsxAttribute', name: 'data-seemore-missing', value: 'true' },\n ],\n children: [],\n } as unknown as PhrasingContent);\n });\n };\n}\n\nfunction isExternal(url: string): boolean {\n return /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i.test(url);\n}\n\n/** Relative `.md`/`.mdx` links become routes, base included. */\nexport function remarkSeemoreLinks(options: SeemoreRemarkOptions): Transformer<Root, Root> {\n return (tree, file) => {\n const from = virtualPath(options.contentRoot, file);\n const resolver = options.getResolver();\n\n const rewrite = (node: { url: string }) => {\n const resolved = resolver.resolveHref(node.url, from);\n if (resolved.warning !== undefined) options.onWarning(resolved.warning);\n node.url = resolved.href;\n };\n\n visit(tree, 'link', rewrite);\n visit(tree, 'definition', rewrite);\n };\n}\n\nfunction virtualPath(contentRoot: string, file: VFile): string {\n if (typeof file.path !== 'string' || file.path === '') return '';\n return toPosix(relative(contentRoot, file.path));\n}\n","import { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\nimport type { Plugin, ViteDevServer } from 'vite';\nimport { withBase } from '../base.js';\nimport type { SeemoreContext } from '../context.js';\nimport { buildSearchIndex } from '../search/build.js';\nimport { toPosix } from '../content/slug.js';\nimport { canonicalise } from '../paths.js';\n\nexport const VIRTUAL = {\n tree: 'virtual:seemore/tree',\n routes: 'virtual:seemore/routes',\n config: 'virtual:seemore/config',\n} as const;\n\n/**\n * Prefix for content-body imports emitted into `virtual:seemore/routes`.\n *\n * A bare absolute path would be read as *root*-relative by Vite, and the content root is\n * normally outside the Vite root. Resolving our own prefix to the real file id keeps dev and\n * build identical, and lets `@mdx-js/rollup` transform the file as it normally would.\n */\nconst PAGE_PREFIX = 'seemore-page:';\n\nconst resolvedId = (id: string) => `\\0${id}`;\n\n/**\n * Two markers, deliberately: see the comments in `src/app/styles/globals.css`.\n *\n * `@import` is only valid before the first style rule, so the theme has to go at the top —\n * and the user's own stylesheet has to go at the bottom, or it loses to the rules it is\n * meant to override and, worse, invalidates the imports it was inlined above.\n */\nconst IMPORTS_MARKER = /\\/\\* seemore:imports[\\s\\S]*?\\*\\//;\nconst USER_CSS_MARKER = /\\/\\* seemore:user-css[\\s\\S]*?\\*\\//;\n\nconst require_ = createRequire(import.meta.url);\n\nfunction styleImports(ctx: SeemoreContext): string {\n const lines: string[] = [`@import 'fumadocs-ui/css/${ctx.config.theme}.css';`];\n\n // Tailwind cannot scan class names it never sees, and fumadocs-ui ships compiled JS.\n try {\n lines.push(`@source '${dirname(require_.resolve('fumadocs-ui/package.json'))}/dist';`);\n } catch {\n // A layout without the package resolvable is already broken elsewhere; do not add noise.\n }\n\n return lines.join('\\n');\n}\n\nfunction userCss(ctx: SeemoreContext): string {\n if (ctx.config.css === undefined) return '';\n\n const css = readIfExists(ctx.config.css);\n if (css === undefined) {\n ctx.warnings.add(`The stylesheet named by \\`css\\` was not found: ${ctx.config.css}`);\n return '';\n }\n\n // Inlined rather than imported: an `@import` this far down the file is not valid CSS.\n return `/* ${ctx.config.css} */\\n${css}`;\n}\n\nexport interface SeemorePluginOptions {\n ctx: SeemoreContext;\n /** Dev serves the index from memory; build writes it to `dist/api/search.json`. */\n serveSearch?: boolean;\n}\n\nexport function seemorePlugin({ ctx, serveSearch = false }: SeemorePluginOptions): Plugin {\n let server: ViteDevServer | undefined;\n\n return {\n name: 'seemore',\n enforce: 'pre',\n\n resolveId(id) {\n // Native separators from `page.absPath` would key a second, unloadable module in\n // Vite's URL-addressed graph — canonical ids are always forward slashes.\n if (id.startsWith(PAGE_PREFIX)) return id.slice(PAGE_PREFIX.length).replace(/\\\\/g, '/');\n for (const virtualId of Object.values(VIRTUAL)) {\n if (id === virtualId) return resolvedId(virtualId);\n }\n return undefined;\n },\n\n /**\n * The theme preset, the paths Tailwind must scan, and the user's own stylesheet are\n * injected into our root stylesheet rather than imported from it.\n *\n * Tailwind v4 only processes the file that contains `@import \"tailwindcss\"`, and bare\n * specifiers in a virtual stylesheet have no directory to resolve from — injecting into\n * the real `globals.css` keeps both working.\n */\n transform(code, id) {\n const path = id.replace(/\\\\/g, '/').split('?')[0] ?? '';\n if (!path.endsWith('/src/app/styles/globals.css')) return undefined;\n const transformed = code\n .replace(IMPORTS_MARKER, () => styleImports(ctx))\n .replace(USER_CSS_MARKER, () => userCss(ctx));\n return { code: transformed, map: null };\n },\n\n async load(id) {\n if (id === resolvedId(VIRTUAL.tree)) {\n return hotStoreModule('Tree', json(await ctx.source.serializeTree()));\n }\n if (id === resolvedId(VIRTUAL.routes)) {\n return hotStoreModule('Routes', renderRoutesValue(ctx));\n }\n // Config is not a store: a change to it can alter `base`, which reconfigures Vite, so\n // the page reloads rather than patching itself.\n if (id === resolvedId(VIRTUAL.config)) return `export const config = ${json(clientConfig(ctx))};`;\n return undefined;\n },\n\n configureServer(devServer) {\n server = devServer;\n if (!serveSearch) return;\n\n // The same JSON the build emits, at the same path, so the client has one code path.\n devServer.middlewares.use(async (req, res, next) => {\n const path = (req.url ?? '').split('?')[0] ?? '';\n if (path !== withBase(ctx.config.base, '/api/search.json') && path !== '/api/search.json') return next();\n try {\n const index = await buildSearchIndex(ctx);\n res.setHeader('Content-Type', 'application/json');\n res.end(index);\n } catch (error) {\n next(error);\n }\n });\n\n // Lets a caller that only knows an absolute file path — an editor extension, say —\n // ask the running server what URL that file resolved to, rather than reimplementing\n // `resolveRoutes`. Dev-only: the answer depends on a live corpus scan.\n devServer.middlewares.use((req, res, next) => {\n const [path = '', query = ''] = (req.url ?? '').split('?');\n if (path !== '/__seemore/route') return next();\n\n const file = new URLSearchParams(query).get('file');\n if (file === null) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Missing \"file\" query parameter.' }));\n return;\n }\n\n // `page.absPath` is built on the canonicalised content root; a caller outside\n // seemore (an editor's `document.uri.fsPath`) has no reason to have canonicalised\n // its side, so the comparison must go through the filesystem, not just `resolve`.\n const absFile = canonicalise(file);\n const page = ctx.pages().find((p) => p.absPath === absFile);\n if (page === undefined) {\n res.statusCode = 404;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: `${file} is not part of this site — excluded, or lost a duplicate slug.` }));\n return;\n }\n\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ url: withBase(ctx.config.base, page.url) }));\n });\n },\n\n /** Called by the watcher after a rescan. */\n api: {\n invalidate() {\n if (server === undefined) return;\n for (const virtualId of [VIRTUAL.tree, VIRTUAL.routes]) {\n const mod = server.moduleGraph.getModuleById(resolvedId(virtualId));\n if (mod) server.moduleGraph.invalidateModule(mod);\n }\n server.ws.send({ type: 'update', updates: [] });\n },\n },\n };\n}\n\n/**\n * A self-accepting module holding one value, with subscribers that survive replacement.\n *\n * State lives on `import.meta.hot.data`, so when the module re-executes after an edit the\n * new copy still has the listeners the old one handed to React. `accept()` stops the update\n * propagating to importers, which is the difference between the sidebar re-rendering in\n * place and the page reloading.\n */\nfunction hotStoreModule(suffix: string, value: string): string {\n // `import.meta.hot.accept()` is written out in full because Vite detects self-accepting\n // modules syntactically — through an alias it sees an ordinary module and reloads the page.\n return `const state = import.meta.hot\n ? (import.meta.hot.data.seemore${suffix} ||= { listeners: new Set() })\n : { listeners: new Set() };\n\nstate.value = ${value};\n\nexport function get${suffix}() {\n return state.value;\n}\n\nexport function subscribe${suffix}(listener) {\n state.listeners.add(listener);\n return () => {\n state.listeners.delete(listener);\n };\n}\n\nif (import.meta.hot) {\n import.meta.hot.accept();\n for (const listener of state.listeners) listener();\n}\n`;\n}\n\n/**\n * `virtual:seemore/routes`: one entry per page, with the body behind a dynamic\n * import so the router, the hover prefetch and the prerender driver all read one map.\n *\n * `import.meta.glob` is deliberately not used: glob patterns that escape the Vite root fail\n * silently, which is the exact failure class seemore exists to prevent.\n */\nfunction renderRoutesValue(ctx: SeemoreContext): string {\n const entries = ctx.pages().map((page) => {\n // Backslashes are legal in a Windows path and fatal in an import specifier.\n const specifier = `${PAGE_PREFIX}${page.absPath.replace(/\\\\/g, '/')}`;\n return [\n ' {',\n ` url: ${json(page.url)},`,\n ` file: ${json(page.file)},`,\n ` absPath: ${json(page.absPath)},`,\n ` title: ${json(page.data.title)},`,\n ` description: ${json(page.data.description ?? null)},`,\n ` load: () => import(${json(specifier)}),`,\n ' },',\n ].join('\\n');\n });\n\n return `[\\n${entries.join('\\n')}\\n]`;\n}\n\n/** The serialisable slice of the config the browser needs. */\nfunction clientConfig(ctx: SeemoreContext) {\n const { config } = ctx;\n return {\n title: config.title,\n description: config.description,\n base: config.base,\n theme: config.theme,\n features: config.features,\n nav: config.nav,\n footer: config.footer,\n editLink: config.editLink,\n favicon: config.favicon === undefined ? undefined : withBase(config.base, `/${toPosix(config.favicon)}`),\n search:\n config.search.provider === 'static'\n ? { provider: 'static' as const, from: withBase(config.base, '/api/search.json') }\n : config.search,\n contentRoot: config.root,\n };\n}\n\n/** JSON that is always safe to paste into a module body. */\nfunction json(value: unknown): string {\n return JSON.stringify(value ?? null)\n .replace(/</g, '\\\\u003c')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\nexport function readIfExists(path: string): string | undefined {\n try {\n return readFileSync(path, 'utf8');\n } catch {\n return undefined;\n }\n}\n","import { readFileSync } from 'node:fs';\nimport { gzipSync } from 'node:zlib';\nimport { createFromSource } from 'fumadocs-core/search/server';\nimport { structure } from 'fumadocs-core/mdx-plugins';\nimport { withBase } from '../base.js';\nimport { parseFrontmatter } from '../content/frontmatter.js';\nimport type { SeemoreContext } from '../context.js';\n\n/** Above this, a static index is a real download cost worth naming. */\nexport const SIZE_WARNING_BYTES = 1_500_000;\n\n/**\n * `structure()` indexes plain text, so seemore's own authoring syntax would reach search\n * results as raw markers. Wikilinks collapse to their label, or to the linked file's name\n * when there is no label, and admonition markers drop while the quoted content stays.\n */\nexport function toSearchableText(body: string): string {\n return body\n .replace(/^>\\s*\\[!\\w+\\]\\s*$/gm, '>')\n .replace(\n /\\[\\[([^\\]|#]*)(?:#[^\\]|]*)?(?:\\|([^\\]]*))?\\]\\]/g,\n (_match, target: string, label?: string) => (label || target.split('/').pop() || '').trim(),\n );\n}\n\n/**\n * Build the static search index.\n *\n * The index is produced node-side from the raw markdown rather than from the compiled MDX\n * modules, so dev and build share one code path and neither has to evaluate browser code.\n */\nexport async function buildSearchIndex(ctx: SeemoreContext): Promise<string> {\n const loader = await ctx.source.loader.get();\n const bodies = new Map<string, string>();\n\n for (const page of ctx.pages()) {\n try {\n // The body only: `structure` reads plain Markdown, where a frontmatter block's closing\n // `---` turns its keys into a setext heading and lands in the index as content.\n bodies.set(page.url, parseFrontmatter(readFileSync(page.absPath, 'utf8'), page.file).content);\n } catch {\n // A file deleted between scan and index is not worth failing a dev rebuild over.\n }\n }\n\n const server = createFromSource(loader, {\n buildIndex(page) {\n const body = bodies.get(page.url) ?? '';\n return {\n id: page.url,\n url: withBase(ctx.config.base, page.url),\n title: typeof page.data.title === 'string' ? page.data.title : page.url,\n description: typeof page.data.description === 'string' ? page.data.description : undefined,\n structuredData: structure(toSearchableText(body)),\n };\n },\n });\n\n const response = await server.staticGET();\n return await response.text();\n}\n\nexport interface IndexSize {\n bytes: number;\n gzipped: number;\n /** Set when the gzipped index passed {@link SIZE_WARNING_BYTES}. */\n warning?: string;\n}\n\nexport function measureIndex(json: string): IndexSize {\n const bytes = Buffer.byteLength(json);\n const gzipped = gzipSync(json).byteLength;\n\n if (gzipped <= SIZE_WARNING_BYTES) return { bytes, gzipped };\n\n return {\n bytes,\n gzipped,\n warning:\n `The static search index is ${formatBytes(gzipped)} gzipped, which every visitor downloads before ` +\n `their first search. Above ${formatBytes(SIZE_WARNING_BYTES)} consider a hosted index: set ` +\n `\\`search: { provider: 'orama-cloud', … }\\` or \\`search: { provider: 'algolia', … }\\` in seemore.config.ts.`,\n };\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} kB`;\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n}\n","import chokidar, { type FSWatcher } from 'chokidar';\nimport type { Plugin, ViteDevServer } from 'vite';\nimport type { SeemoreContext } from '../context.js';\nimport { VIRTUAL } from './plugin.js';\n\nconst CONTENT_FILE = /\\.(?:mdx?|json)$/i;\n\n/**\n * The watcher/sidebar-refresh cycle.\n *\n * The page tree, sidebar and search index are not in the module graph, so nothing invalidates\n * them on its own. chokidar watches the content root; every event rescans, and the two\n * virtual modules that depend on the corpus are reloaded through Vite's own HMR machinery so\n * the sidebar re-renders in place instead of reloading the page.\n */\nexport function seemoreWatcherPlugin(ctx: SeemoreContext): Plugin {\n let watcher: FSWatcher | undefined;\n\n return {\n name: 'seemore:watcher',\n apply: 'serve',\n\n configureServer(server) {\n watcher = chokidar.watch(ctx.contentRoot, {\n ignoreInitial: true,\n ignored: (path: string, stats?: { isFile(): boolean }) => {\n // `ignored` applies to explicitly added paths too, so the config file — which is\n // neither Markdown nor JSON — has to be let through by name.\n if (path === ctx.config.configFile) return false;\n // chokidar reports native separators, so compare against a normalised path.\n const posix = path.replace(/\\\\/g, '/');\n if (/(?:^|\\/)(?:node_modules|\\.git|dist|build|out|vendor|target|\\.seemore)(?:$|\\/)/.test(posix)) return true;\n if (/(?:^|\\/)\\.[^/]+/.test(posix)) return true;\n return stats?.isFile() === true && !CONTENT_FILE.test(posix);\n },\n });\n\n const onEvent = (event: string, path: string) => {\n void handleContentChange(server, ctx, event, path);\n };\n\n watcher.on('add', (p) => onEvent('add', p));\n watcher.on('change', (p) => onEvent('change', p));\n watcher.on('unlink', (p) => onEvent('unlink', p));\n watcher.on('addDir', (p) => onEvent('addDir', p));\n watcher.on('unlinkDir', (p) => onEvent('unlinkDir', p));\n\n // A config edit can change `base`, which reconfigures Vite itself, so the page reloads\n // rather than patching itself.\n if (ctx.config.configFile !== undefined) {\n watcher.add(ctx.config.configFile);\n watcher.on('change', (path) => {\n if (path !== ctx.config.configFile) return;\n server.environments.client.hot.send({ type: 'full-reload', path: '*' });\n server.config.logger.info(\n 'seemore config changed — reloading. Changes to `base` need a restart to take effect.',\n );\n });\n }\n\n server.httpServer?.once('close', () => void watcher?.close());\n },\n\n async closeBundle() {\n await watcher?.close();\n watcher = undefined;\n },\n };\n}\n\n/** Exported for the watcher test, which drives it without going through chokidar's timing. */\nexport async function handleContentChange(\n server: ViteDevServer,\n ctx: SeemoreContext,\n event: string,\n path: string,\n): Promise<void> {\n const scan = ctx.refresh();\n\n // Dev never exits on a content error, but it must not swallow one either: editing a file\n // back to valid has to recover without a restart, so problems are reported each time.\n for (const message of [...scan.errors, ...scan.warnings]) ctx.warnings.add(message);\n ctx.warnings.flush((line) => server.config.logger.warn(line));\n\n // Order matters: the tree must be current before anything re-renders against it.\n await reloadVirtual(server, VIRTUAL.tree);\n await reloadVirtual(server, VIRTUAL.routes);\n\n // A body edit is a plain MDX swap; the component is replaced and scroll position kept.\n if (event === 'change' && /\\.mdx?$/i.test(path)) {\n await reloadFile(server, path);\n }\n}\n\nasync function reloadVirtual(server: ViteDevServer, id: string): Promise<void> {\n await reloadById(server, `\\0${id}`);\n}\n\nasync function reloadFile(server: ViteDevServer, absolutePath: string): Promise<void> {\n // chokidar reports native separators; the module graph is addressed in forward slashes.\n await reloadById(server, absolutePath.replace(/\\\\/g, '/'));\n}\n\n/**\n * Reload a module in every environment that has it. `server.reloadModule` handles\n * invalidation and the HMR message together, which keeps us out of the business of\n * constructing update payloads by hand.\n */\nasync function reloadById(server: ViteDevServer, id: string): Promise<void> {\n const environments = Object.values(server.environments ?? {});\n\n if (environments.length === 0) {\n const legacy = server.moduleGraph.getModuleById(id);\n if (legacy) await server.reloadModule(legacy);\n return;\n }\n\n for (const environment of environments) {\n const mod = environment.moduleGraph?.getModuleById(id);\n if (mod === undefined || mod === null) continue;\n if (typeof environment.reloadModule === 'function') await environment.reloadModule(mod);\n else environment.moduleGraph.invalidateModule(mod);\n }\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { ogImagePath } from '../../shared/og.js';\nimport type { SeemoreContext } from '../context.js';\n\n/**\n * `social.cards`: one OG image per page, rendered at build time.\n *\n * `takumi-js` is an optional peer of fumadocs-ui and is not installed by default, so the\n * flag degrades to a warning rather than to an install-time cost everybody pays.\n */\nexport async function generateSocialCards(ctx: SeemoreContext, outDir: string): Promise<number> {\n // `takumi-js` is an optional peer, so it is loaded by specifier and typed structurally —\n // a hard import would make it a required dependency of every build.\n let takumi: TakumiModule;\n try {\n takumi = (await importOptional('takumi-js')) as TakumiModule;\n } catch {\n ctx.warnings.add(\n \"`social.cards` is enabled but `takumi-js` is not installed. Run `npm install takumi-js`, or remove the flag.\",\n );\n return 0;\n }\n\n let written = 0;\n for (const page of ctx.pages()) {\n const png = await renderCard(takumi, ctx.config.title, page.data.title, page.data.description);\n if (png === undefined) continue;\n\n const target = join(outDir, ogImagePath(page.url));\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, png);\n written++;\n }\n\n return written;\n}\n\ninterface TakumiModule {\n Renderer: new (options: { fonts: unknown[] }) => {\n renderAsync(node: unknown, options: { width: number; height: number; format: 'png' }): Promise<Uint8Array>;\n };\n container(props: unknown, children: unknown[]): unknown;\n text(value: string, props: unknown): unknown;\n}\n\nasync function renderCard(\n takumi: TakumiModule,\n site: string,\n title: string,\n description: unknown,\n): Promise<Uint8Array | undefined> {\n const renderer = new takumi.Renderer({ fonts: [] });\n const node = takumi.container(\n {\n style: {\n width: 1200,\n height: 630,\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n padding: 80,\n backgroundColor: '#0b0b0b',\n color: '#ffffff',\n gap: 24,\n },\n },\n [\n takumi.text(site, { style: { fontSize: 28, opacity: 0.6 } }),\n takumi.text(title, { style: { fontSize: 64, fontWeight: 700 } }),\n ...(typeof description === 'string' ? [takumi.text(description, { style: { fontSize: 30, opacity: 0.8 } })] : []),\n ],\n );\n\n return await renderer.renderAsync(node, { width: 1200, height: 630, format: 'png' });\n}\n\n/** Import by a specifier TypeScript will not try to resolve at build time. */\nasync function importOptional(specifier: string): Promise<unknown> {\n return await import(specifier);\n}\n","/**\n * Where a page's social card lives.\n *\n * Shared, because the build writes the file and the prerendered `<head>` points at it — and\n * a card nothing references is a card nobody sees.\n */\nexport function ogImagePath(url: string): string {\n const clean = url.replace(/^\\/+|\\/+$/g, '');\n // A path per route, rather than a flattened filename: `/a/b` and `/a-b` are different\n // routes and must not write to the same file.\n return clean === '' ? '/api/og/card.png' : `/api/og/${clean}/card.png`;\n}\n","import { createServer, type ViteDevServer } from 'vite';\nimport pc from 'picocolors';\nimport { loadConfig } from '../node/config/load.js';\nimport { createContext, type SeemoreContext } from '../node/context.js';\nimport { normaliseBase } from '../shared/base.js';\nimport { resolveContentRoot } from '../node/paths.js';\nimport { createViteConfig } from '../node/vite/config.js';\n\nconst DEFAULT_PORT = 4040;\n\nexport interface DevOptions {\n cwd: string;\n dir?: string;\n configPath?: string;\n base?: string;\n port?: number;\n host?: string | boolean;\n open?: boolean;\n /**\n * Print one JSON line on stdout at startup instead of the human summary — a stable\n * contract for a caller that spawns this as a child process, so it never has to\n * screen-scrape colored text.\n */\n json?: boolean;\n}\n\n/** The single line a `json: true` caller parses to learn where the server ended up. */\nexport interface DevReady {\n url: string;\n port: number;\n contentRoot: string;\n pageCount: number;\n}\n\nexport interface DevServer {\n server: ViteDevServer;\n ctx: SeemoreContext;\n url: string;\n close(): Promise<void>;\n}\n\n/**\n * The dev server. Nothing is written into the user's folder: the Vite root is\n * seemore's own `src/app`, and caches go to the OS temp directory.\n */\nexport async function runDev(options: DevOptions): Promise<DevServer> {\n const contentRoot = resolveContentRoot(options.cwd, options.dir);\n const loaded = await loadConfig({ root: options.cwd, configPath: options.configPath });\n const config = {\n ...loaded.config,\n base: options.base === undefined ? loaded.config.base : normaliseBase(options.base),\n };\n\n // Dev never exits on a content error: editing a file back to valid must recover without a\n // restart, so problems that fail the build are warnings here.\n const ctx = createContext({ config, contentRoot, includeDrafts: true });\n const scan = ctx.source.current();\n for (const message of [...scan.errors, ...scan.warnings]) ctx.warnings.add(message);\n if (scan.pages.length === 0) {\n ctx.warnings.add(`No Markdown files found under ${contentRoot}. seemore will serve an empty site until there are.`);\n }\n\n const base = createViteConfig({ ctx, mode: 'dev' });\n const server = await createServer({\n ...base,\n server: {\n ...base.server,\n port: options.port ?? DEFAULT_PORT,\n host: options.host,\n open: options.open === true ? config.base : false,\n },\n });\n\n await server.listen();\n\n const resolvedPort = server.config.server.port ?? DEFAULT_PORT;\n const url = `http://localhost:${resolvedPort}${config.base}`;\n\n ctx.warnings.flush();\n if (options.json === true) {\n const ready: DevReady = { url, port: resolvedPort, contentRoot, pageCount: scan.pages.length };\n console.log(JSON.stringify(ready));\n } else {\n console.log(`\\n ${pc.green('seemore')} ${pc.bold(url)}`);\n console.log(` ${pc.dim(`${scan.pages.length} pages from ${contentRoot}`)}\\n`);\n }\n\n return {\n server,\n ctx,\n url,\n close: async () => {\n await server.close();\n },\n };\n}\n"],"mappings":"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","names":["existsSync","dirname","join","resolve","pc","mkdirSync","readFileSync","writeFileSync","createRequire","tmpdir","isAbsolute","join","relative","resolve","pc","slugify","basename","CONTENT_EXT","basename","slugify","relative","dirname","resolve","z","z","z","resolve","dirname","dirname","join","writeFileSync","join","join","realpathSync","join","existsSync","dirname","resolve","dirname","resolve","existsSync","readFileSync","dirname","readFileSync","readFileSync","json","dirname","readFileSync","scan","join","realpathSync","join","mkdirSync","writeFileSync","dirname","join","join","mkdirSync","dirname","writeFileSync","resolve","scan","pc","relative","readFileSync","join","tmpdir","mkdirSync","writeFileSync","isAbsolute","createRequire","pc","scan","pc","pc","readFileSync","join","packageRoot"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seemore",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Let AI write the Markdown. Let seemore show it better — see any folder of Markdown rendered in your browser, zero config.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,5 +1,5 @@
1
1
  import { StrictMode } from 'react';
2
- import { hydrateRoot } from 'react-dom/client';
2
+ import { createRoot, hydrateRoot } from 'react-dom/client';
3
3
  import { RouterProvider, createBrowserRouter } from 'react-router';
4
4
  import { config } from 'virtual:seemore/config';
5
5
  import { decodePath, stripBase, toBasename } from '../shared/base.js';
@@ -13,12 +13,19 @@ if (container === null) throw new Error('seemore: #root is missing from the page
13
13
  const router = createBrowserRouter(createRouteObjects(), { basename: toBasename(config.base) });
14
14
 
15
15
  function mount(target: HTMLElement) {
16
- hydrateRoot(
17
- target,
16
+ const app = (
18
17
  <StrictMode>
19
18
  <RouterProvider router={router} />
20
- </StrictMode>,
19
+ </StrictMode>
21
20
  );
21
+ // The dev server serves an empty shell (rendering happens here, in the browser), so there
22
+ // is nothing to hydrate; hydrating an empty container makes React log a hydration-mismatch
23
+ // error on every load. Only a prerendered build puts element content inside #root.
24
+ if (target.children.length === 0) {
25
+ createRoot(target).render(app);
26
+ } else {
27
+ hydrateRoot(target, app);
28
+ }
22
29
  }
23
30
 
24
31
  // Hydrating against prerendered HTML needs the current page's module in hand, or React would
@@ -3,6 +3,9 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <!-- Default icon so a zero-config folder does not 404 on /favicon.ico. A favicon from
7
+ the config is injected at the marker below, after this link, and the last one wins. -->
8
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='32' y2='32' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%236D5EF5'/%3E%3Cstop offset='1' stop-color='%2317B8A6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='32' height='32' rx='7' fill='url(%23g)'/%3E%3Cpath d='M10 11h12M10 16h12M10 21h7' stroke='%23f5f5f5' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E" />
6
9
  <!--seemore-head-->
7
10
  </head>
8
11
  <body>