{"version":3,"file":"content-layer-ClVrTnzu.mjs","names":["parseYaml","coreConvert","pathResolve","fsWatch"],"sources":["../src/frontmatter.ts","../src/convert.ts","../src/utils/read-time.ts","../src/entry.ts","../src/plugins/index.ts","../src/utils/glob.ts","../src/utils/slug.ts","../src/validation/load-content-config.ts","../src/store.ts","../src/content-layer.ts"],"sourcesContent":["/**\n * Frontmatter extraction and validation.\n *\n * Uses gray-matter to parse YAML frontmatter from markdown,\n * and optionally validates against a Zod schema.\n */\n\nimport matter from \"gray-matter\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { ZodSchema } from \"zod\";\nimport { validateSchema } from \"./validation/schema-validator\";\n\nexport type FrontmatterResult = {\n  frontmatter: Record<string, any>;\n  content: string;\n};\n\n/** Extract frontmatter from raw markdown using gray-matter. */\nexport function extractFrontmatter(raw: string): FrontmatterResult {\n  const { data, content } = matter(raw, { engines: { yaml: parseYaml } });\n  return { frontmatter: data, content };\n}\n\n/**\n * Validate frontmatter against a Zod schema. Returns parsed data or errors.\n *\n * @deprecated Use `validateSchema()` from `@pagesmith/core` for richer\n * validation results including field paths and severity levels.\n */\nexport function validateFrontmatter<T>(\n  frontmatter: Record<string, any>,\n  schema: ZodSchema<T>,\n): { success: true; data: T } | { success: false; errors: string[] } {\n  const { issues, validatedData } = validateSchema(frontmatter, schema);\n\n  if (issues.length === 0) {\n    return { success: true, data: validatedData as T };\n  }\n\n  const errors = issues.map((issue) =>\n    issue.field ? `${issue.field}: ${issue.message}` : issue.message,\n  );\n  return { success: false, errors };\n}\n","import { dirname } from \"path\";\nimport { extractFrontmatter } from \"./frontmatter\";\nimport { processMarkdown } from \"./markdown\";\nimport type { Heading } from \"./schemas/heading\";\nimport type { MarkdownConfig } from \"./schemas/markdown-config\";\n\nexport type ConvertOptions = {\n  markdown?: MarkdownConfig;\n  /**\n   * Absolute or project-relative source path for the markdown being converted.\n   * Provide this when the markdown references local images so Pagesmith can\n   * resolve refs from the markdown file and fill intrinsic dimensions.\n   */\n  sourcePath?: string;\n  /**\n   * Allowed root directory for relative local image refs. Defaults to the\n   * markdown file's own directory when `sourcePath` is provided. Set this when\n   * you want `convert()` to allow refs that move outside the file directory but\n   * still stay inside a broader content root, matching `entry.render()`.\n   */\n  assetRoot?: string;\n};\n\nexport type ConvertResult = {\n  html: string;\n  headings: Heading[];\n  /** @deprecated Use `headings` for consistency with `processMarkdown()` and `entry.render()`. */\n  toc: Heading[];\n  frontmatter: Record<string, unknown>;\n};\n\nexport async function convert(input: string, options: ConvertOptions = {}): Promise<ConvertResult> {\n  const preExtracted = options.sourcePath\n    ? {\n        ...extractFrontmatter(input),\n        fileData: {\n          pagesmithFilePath: options.sourcePath,\n          pagesmithAssetRoot: options.assetRoot ?? dirname(options.sourcePath),\n        },\n      }\n    : undefined;\n\n  const result = await processMarkdown(input, options.markdown || {}, preExtracted);\n  return {\n    html: result.html,\n    headings: result.headings,\n    toc: result.headings,\n    frontmatter: result.frontmatter,\n  };\n}\n","/**\n * Read time estimation.\n *\n * Computes estimated reading time from markdown source (~200 words per minute).\n */\n\n/** Compute read time in minutes from raw markdown. */\nexport function computeReadTime(rawMarkdown: string): number {\n  const plainText = rawMarkdown\n    .replace(/```[\\s\\S]*?```/g, \" \")\n    .replace(/^( {4}|\\t).+$/gm, \" \")\n    .replace(/^---[\\s\\S]*?---/m, \" \")\n    .replace(/<[^>]+>/g, \" \")\n    .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n    .replace(/[#*_~`>]/g, \" \")\n    .replace(/\\s+/g, \" \")\n    .trim();\n  const wordCount = plainText.split(\" \").filter(Boolean).length;\n  return Math.max(1, Math.ceil(wordCount / 200));\n}\n","/**\n * ContentEntry — represents a single content entry in a collection.\n *\n * Supports lazy rendering: data is available immediately after loading,\n * but HTML rendering is deferred until render() is called.\n */\n\nimport { dirname } from \"path\";\nimport type { Heading } from \"./schemas/heading\";\nimport type { MarkdownConfig } from \"./schemas/markdown-config\";\nimport { processMarkdown } from \"./markdown\";\nimport { computeReadTime } from \"./utils/read-time\";\n\nexport type RenderedContent = {\n  /** Processed HTML */\n  html: string;\n  /** Extracted headings for TOC */\n  headings: Heading[];\n  /** Estimated read time in minutes */\n  readTime: number;\n};\n\nexport class ContentEntry<T = Record<string, any>> {\n  /** URL-friendly identifier */\n  readonly slug: string;\n  /** Collection this entry belongs to */\n  readonly collection: string;\n  /** Absolute path to source file */\n  readonly filePath: string;\n  /** Validated data (frontmatter or parsed data) */\n  readonly data: T;\n  /** Raw body content (markdown only) */\n  readonly rawContent?: string;\n\n  /** Cached render result */\n  private _rendered?: RenderedContent;\n  /** Markdown config for rendering */\n  private _markdownConfig: MarkdownConfig;\n  /** Allowed root for resolving relative local assets referenced by this entry. */\n  private _assetRoot?: string;\n\n  constructor(\n    slug: string,\n    collection: string,\n    filePath: string,\n    data: T,\n    rawContent: string | undefined,\n    markdownConfig: MarkdownConfig,\n    assetRoot?: string,\n  ) {\n    this.slug = slug;\n    this.collection = collection;\n    this.filePath = filePath;\n    this.data = data;\n    this.rawContent = rawContent;\n    this._markdownConfig = markdownConfig;\n    this._assetRoot = assetRoot;\n  }\n\n  /** Render the entry content to HTML. Cached after first call. */\n  async render(options?: { force?: boolean }): Promise<RenderedContent> {\n    if (this._rendered && !options?.force) {\n      return this._rendered;\n    }\n\n    if (!this.rawContent) {\n      // Non-markdown entries have no renderable content\n      this._rendered = { html: \"\", headings: [], readTime: 0 };\n      return this._rendered;\n    }\n\n    const result = await processMarkdown(this.rawContent, this._markdownConfig, {\n      content: this.rawContent,\n      frontmatter: this.data as Record<string, unknown>,\n      fileData: {\n        pagesmithFilePath: this.filePath,\n        pagesmithAssetRoot: this._assetRoot ?? dirname(this.filePath),\n      },\n    });\n    const readTime = computeReadTime(this.rawContent);\n\n    this._rendered = {\n      html: result.html,\n      headings: result.headings,\n      readTime,\n    };\n\n    return this._rendered;\n  }\n\n  /** Clear cached render result. */\n  clearRenderCache(): void {\n    this._rendered = undefined;\n  }\n}\n","/**\n * Plugin registration and execution.\n */\n\nimport type { ContentPlugin } from \"../schemas/content-config\";\n\n/** Collect all remark plugins from content plugins. */\nexport function collectRemarkPlugins(plugins: ContentPlugin[]): any[] {\n  return plugins.filter((p) => p.remarkPlugin).map((p) => p.remarkPlugin!);\n}\n\n/** Collect all rehype plugins from content plugins. */\nexport function collectRehypePlugins(plugins: ContentPlugin[]): any[] {\n  return plugins.filter((p) => p.rehypePlugin).map((p) => p.rehypePlugin!);\n}\n\n/** Run all plugin validators against an entry. */\nexport function runPluginValidators(\n  plugins: ContentPlugin[],\n  entry: { data: Record<string, any>; content?: string },\n): string[] {\n  const issues: string[] = [];\n  for (const plugin of plugins) {\n    if (plugin.validate) {\n      try {\n        issues.push(...plugin.validate(entry));\n      } catch (err) {\n        issues.push(\n          `[${plugin.name}] Validator threw: ${err instanceof Error ? err.message : String(err)}`,\n        );\n      }\n    }\n  }\n  return issues;\n}\n\nexport type { ContentPlugin } from \"../schemas/content-config\";\n","/**\n * File discovery via glob patterns.\n */\n\nimport fg from \"fast-glob\";\nimport { resolve } from \"path\";\n\nexport interface DiscoverOptions {\n  /** Directory to search in (absolute path) */\n  directory: string;\n  /** Glob patterns to include */\n  include: string[];\n  /** Glob patterns to exclude */\n  exclude?: string[];\n}\n\n/** Discover files matching glob patterns in a directory. */\nexport async function discoverFiles(options: DiscoverOptions): Promise<string[]> {\n  const { directory, include, exclude = [] } = options;\n\n  const files = await fg(include, {\n    cwd: directory,\n    absolute: true,\n    ignore: [\"**/node_modules/**\", \"**/dist/**\", \"**/dev/**\", ...exclude],\n  });\n\n  return files.map((p) => resolve(p));\n}\n","/**\n * Path-to-slug conversion.\n *\n * Generalized from packages/core/src/content/collector.ts.\n */\n\nimport { extname, relative } from \"path\";\n\n/**\n * Convert a content file path to a URL-friendly slug.\n *\n * Examples:\n *   content/posts/hello-world/README.md  ->  'hello-world'\n *   content/posts/hello-world/index.md   ->  'hello-world'\n *   content/posts/hello-world.md         ->  'hello-world'\n *   content/authors/john.json            ->  'john'\n *   content/posts/nested/deep/post.md    ->  'nested/deep/post'\n */\nexport function toSlug(filePath: string, directory: string): string {\n  const ext = extname(filePath);\n  let slug = relative(directory, filePath).replace(/\\\\/g, \"/\");\n\n  // Remove file extension\n  if (ext) {\n    slug = slug.slice(0, -ext.length);\n  }\n\n  // Strip README / index suffixes\n  if (slug === \"README\" || slug === \"index\") return \"/\";\n  if (slug.endsWith(\"/README\")) slug = slug.slice(0, -7);\n  if (slug.endsWith(\"/index\")) slug = slug.slice(0, -6);\n\n  return slug;\n}\n","/**\n * Auto-discover and load a project's `content.config.ts` (or `.mts/.mjs/.js`)\n * so the content validator can apply each collection's Zod schema to the\n * markdown files it owns.\n *\n * Why this exists:\n *  - `content.config.*` is the canonical place where Pagesmith users declare\n *    their typed collections (`defineCollections({ ... })`).\n *  - Each collection carries `directory + include + schema`. By replaying\n *    those globs we know exactly which schema to apply to each markdown file.\n *  - Node 24 strips TypeScript types from dynamic imports automatically, so a\n *    pure `.mjs` CLI binary can load a `.ts` config without an extra build\n *    step or runtime loader.\n */\n\nimport { existsSync } from \"fs\";\nimport { dirname, isAbsolute, resolve } from \"path\";\nimport { pathToFileURL } from \"url\";\nimport fg from \"fast-glob\";\nimport type { ZodType } from \"zod\";\n\nconst DEFAULT_CONFIG_BASENAMES = [\n  \"content.config.ts\",\n  \"content.config.mts\",\n  \"content.config.mjs\",\n  \"content.config.js\",\n];\n\nexport type DiscoveredContentConfig = {\n  /** Absolute path of the resolved config module. */\n  filePath: string;\n  /** Project root the config lives under (used to resolve `directory` paths). */\n  projectRoot: string;\n};\n\n/**\n * Walk the candidate directories looking for the first `content.config.*`\n * file. Returns `null` when none is found (auto-load is opt-out).\n */\nexport function discoverContentConfig(\n  searchDirs: readonly string[],\n  basenames: readonly string[] = DEFAULT_CONFIG_BASENAMES,\n): DiscoveredContentConfig | null {\n  for (const dir of searchDirs) {\n    const projectRoot = resolve(dir);\n    for (const name of basenames) {\n      const candidate = resolve(projectRoot, name);\n      if (existsSync(candidate)) {\n        return { filePath: candidate, projectRoot };\n      }\n    }\n  }\n  return null;\n}\n\n/**\n * Minimal shape we need from a collection definition. Mirrors the public\n * `CollectionDef` from `defineCollection` so we stay schema-agnostic and do\n * not import the full type graph here.\n */\nexport type LoadedCollection = {\n  /** Loader identifier — `'markdown'` is the only kind that participates in markdown validation. */\n  loader: string | { kind?: string };\n  /** Directory relative to the project root. */\n  directory: string;\n  /** Include glob patterns relative to `directory`. */\n  include?: string[];\n  /** Exclude glob patterns relative to `directory`. */\n  exclude?: string[];\n  /** Optional Zod schema applied to each entry in this collection. */\n  schema?: ZodType;\n};\n\nexport type LoadedCollections = Record<string, LoadedCollection>;\n\n/** Pull the `collections` map from a loaded module. */\nfunction pickCollections(mod: Record<string, unknown>): LoadedCollections | null {\n  const candidates = [mod.default, mod.collections, mod.config];\n  for (const candidate of candidates) {\n    if (candidate && typeof candidate === \"object\") {\n      const obj = candidate as Record<string, unknown>;\n      // Heuristic: must look like a map of collections, not the wrapped\n      // `{ root, collections }` returned by `defineConfig`.\n      if (\"collections\" in obj && typeof obj.collections === \"object\") {\n        return obj.collections as LoadedCollections;\n      }\n      // Treat plain objects whose values look like collection defs as the map.\n      const values = Object.values(obj);\n      if (\n        values.length > 0 &&\n        values.every(\n          (value) => value && typeof value === \"object\" && \"directory\" in (value as object),\n        )\n      ) {\n        return obj as LoadedCollections;\n      }\n    }\n  }\n  return null;\n}\n\n/**\n * Dynamically import the discovered config and extract the collections map.\n *\n * Node 24's automatic TypeScript type-stripping handles `.ts` files\n * transparently. Files that import other relative TS modules also resolve\n * because Node uses the file:// URL of the importer.\n */\nexport async function loadContentCollections(\n  configPath: string,\n): Promise<LoadedCollections | null> {\n  const url = pathToFileURL(isAbsolute(configPath) ? configPath : resolve(configPath)).href;\n  const mod = (await import(/* @vite-ignore */ /* webpackIgnore: true */ url)) as Record<\n    string,\n    unknown\n  >;\n  return pickCollections(mod);\n}\n\nexport type FileSchemaEntry = {\n  collectionName: string;\n  schema?: ZodType;\n  loaderKind: string;\n};\n\n/**\n * Walk every collection's `directory + include` patterns and build a lookup\n * from absolute file path to the collection (and its schema) that owns it.\n *\n * Earlier collections in declaration order win when a file matches more than\n * one collection — this lets users put a more-specific collection first to\n * intentionally override the broader one.\n */\nexport async function buildFileSchemaMap(\n  collections: LoadedCollections,\n  projectRoot: string,\n): Promise<Map<string, FileSchemaEntry>> {\n  const map = new Map<string, FileSchemaEntry>();\n  for (const [collectionName, definition] of Object.entries(collections)) {\n    const loaderKind =\n      typeof definition.loader === \"string\"\n        ? definition.loader\n        : (definition.loader?.kind ?? \"data\");\n    if (loaderKind !== \"markdown\") continue;\n\n    const baseDir = resolve(projectRoot, definition.directory);\n    if (!existsSync(baseDir)) continue;\n\n    const include = definition.include ?? [\"**/*.md\", \"**/*.mdx\"];\n    const exclude = definition.exclude ?? [];\n    const matched = await fg(include, {\n      cwd: baseDir,\n      absolute: true,\n      ignore: exclude,\n      onlyFiles: true,\n      dot: false,\n    });\n\n    for (const filePath of matched) {\n      if (map.has(filePath)) continue;\n      map.set(filePath, {\n        collectionName,\n        schema: definition.schema,\n        loaderKind,\n      });\n    }\n  }\n  return map;\n}\n\n/**\n * High-level helper: discover, load, and build the per-file schema lookup\n * in one call. Returns `null` when no config is found (the validator falls\n * back to schema-less structural validation).\n */\nexport async function loadContentSchemaMap(searchDirs: readonly string[]): Promise<{\n  configPath: string;\n  projectRoot: string;\n  collections: LoadedCollections;\n  schemaByFile: Map<string, FileSchemaEntry>;\n} | null> {\n  const discovered = discoverContentConfig(searchDirs);\n  if (!discovered) return null;\n  const collections = await loadContentCollections(discovered.filePath);\n  if (!collections) return null;\n  const schemaByFile = await buildFileSchemaMap(collections, dirname(discovered.filePath));\n  return {\n    configPath: discovered.filePath,\n    projectRoot: dirname(discovered.filePath),\n    collections,\n    schemaByFile,\n  };\n}\n","/**\n * ContentStore — in-memory cache for loaded collections.\n *\n * Handles file discovery, loading, validation, and caching.\n * Not exported directly — used internally by ContentLayer.\n */\n\nimport { resolve } from \"path\";\nimport type { MarkdownConfig } from \"./schemas/markdown-config\";\nimport type { ZodType } from \"zod\";\nimport { ContentEntry } from \"./entry\";\nimport { defaultIncludePatterns, resolveLoader } from \"./loaders\";\nimport type { Loader } from \"./loaders/types\";\nimport { collectRehypePlugins, collectRemarkPlugins, runPluginValidators } from \"./plugins\";\nimport type { CollectionDef, RawEntry } from \"./schemas/collection\";\nimport type { ContentLayerConfig } from \"./schemas/content-config\";\nimport { defaultConcurrency, mapWithConcurrency } from \"./utils/concurrency\";\nimport { discoverFiles } from \"./utils/glob\";\nimport { toSlug } from \"./utils/slug\";\nimport { validateSchema, type ValidationIssue } from \"./validation\";\nimport { builtinMarkdownValidators, runValidators } from \"./validation/runner\";\nimport type { ContentValidator } from \"./validation/types\";\n\n// Collection loading is IO-bound (filesystem reads + parsing), so allow twice\n// the CPU parallelism in flight to keep the disk busy while some workers await.\nconst MAX_CONCURRENCY = defaultConcurrency() * 2;\n\ntype CacheEntry = {\n  entry: ContentEntry;\n  issues: ValidationIssue[];\n};\n\nexport class ContentStore {\n  private cache = new Map<string, Map<string, CacheEntry>>();\n  private loaded = new Set<string>();\n  private loading = new Map<string, Promise<ContentEntry[]>>();\n  private config: ContentLayerConfig;\n  private rootDir: string;\n  private markdownConfig: MarkdownConfig;\n\n  constructor(config: ContentLayerConfig) {\n    this.config = config;\n    this.rootDir = config.root ? resolve(config.root) : process.cwd();\n    this.markdownConfig = this.createMarkdownConfig();\n  }\n\n  /** Load a collection (if not already loaded) and return entries. */\n  async loadCollection<S extends ZodType>(\n    name: string,\n    def: CollectionDef<S>,\n  ): Promise<ContentEntry[]> {\n    if (this.loaded.has(name)) {\n      const cached = this.cache.get(name);\n      return cached ? Array.from(cached.values()).map((c) => c.entry) : [];\n    }\n\n    const existing = this.loading.get(name);\n    if (existing) return existing;\n\n    const promise = this._doLoadCollection(name, def);\n    this.loading.set(name, promise);\n    try {\n      return await promise;\n    } finally {\n      this.loading.delete(name);\n    }\n  }\n\n  private async _doLoadCollection<S extends ZodType>(\n    name: string,\n    def: CollectionDef<S>,\n  ): Promise<ContentEntry[]> {\n    const loader = resolveLoader(def.loader);\n    const directory = resolve(this.rootDir, def.directory);\n    const include = def.include ?? defaultIncludePatterns(loader);\n\n    const files = await discoverFiles({\n      directory,\n      include,\n      exclude: def.exclude,\n    });\n\n    const entries = new Map<string, CacheEntry>();\n    const strict = this.config.strict ?? false;\n    const results = await mapWithConcurrency(\n      files,\n      async (filePath) => {\n        try {\n          return await this.loadEntry(name, filePath, directory, loader, def);\n        } catch (err) {\n          const message = err instanceof Error ? err.message : String(err);\n          const loadError = new Error(`[${name}] Failed to load ${filePath}: ${message}`, {\n            cause: err,\n          });\n\n          if (strict) {\n            throw loadError;\n          }\n\n          console.warn(`[pagesmith] ${loadError.message}`);\n          const slug = def.slugify ? def.slugify(filePath, directory) : toSlug(filePath, directory);\n          return {\n            entry: new ContentEntry(\n              slug,\n              name,\n              filePath,\n              {},\n              undefined,\n              this.markdownConfig,\n              directory,\n            ),\n            issues: [\n              { message: loadError.message, severity: \"error\" as const, source: \"schema\" as const },\n            ],\n          };\n        }\n      },\n      MAX_CONCURRENCY,\n    );\n\n    for (const result of results) {\n      if (result) {\n        entries.set(result.entry.slug, result);\n      }\n    }\n\n    this.cache.set(name, entries);\n    this.loaded.add(name);\n\n    return Array.from(entries.values()).map((c) => c.entry);\n  }\n\n  /** Load a single entry from a file. */\n  private async loadEntry(\n    collectionName: string,\n    filePath: string,\n    directory: string,\n    loader: Loader,\n    def: CollectionDef<any>,\n  ): Promise<CacheEntry | null> {\n    const loaded = await loader.load(filePath);\n    const slug = def.slugify ? def.slugify(filePath, directory) : toSlug(filePath, directory);\n\n    let raw: RawEntry = {\n      data: loaded.data,\n      content: loaded.content,\n      filePath,\n      slug,\n    };\n\n    // Apply transform\n    if (def.transform) {\n      raw = await def.transform(raw);\n    }\n\n    // Apply computed fields (clone data to avoid mutating loader output)\n    if (def.computed) {\n      raw = { ...raw, data: { ...raw.data } };\n      for (const [key, fn] of Object.entries(def.computed) as Array<\n        [string, (entry: RawEntry) => any]\n      >) {\n        raw.data[key] = await fn(raw);\n      }\n    }\n\n    // Apply filter\n    if (def.filter && !def.filter(raw)) {\n      return null;\n    }\n\n    // Validate schema once to collect issues and transformed data.\n    const { issues, validatedData } = validateSchema(raw.data, def.schema);\n\n    // Custom validation\n    if (def.validate) {\n      const customError = def.validate(raw);\n      if (customError) {\n        issues.push({ message: customError, severity: \"error\", source: \"custom\" });\n      }\n    }\n\n    // Run content validators on markdown entries\n    const isMarkdownEntry = raw.content !== undefined;\n    if (isMarkdownEntry) {\n      const validators = this.resolveValidators(def);\n      if (validators.length > 0) {\n        const contentIssues = await runValidators(\n          {\n            filePath,\n            slug,\n            collection: collectionName,\n            rawContent: raw.content,\n            data: raw.data,\n            getEntry: (col, s) => {\n              const cached = this.cache.get(col)?.get(s);\n              if (!cached) return undefined;\n              return { slug: cached.entry.slug, data: cached.entry.data };\n            },\n          },\n          validators,\n        );\n        issues.push(...contentIssues);\n      }\n    }\n\n    if (this.config.plugins?.length) {\n      const pluginIssues = runPluginValidators(this.config.plugins, {\n        data: raw.data,\n        content: raw.content,\n      });\n      for (const message of pluginIssues) {\n        issues.push({ message, severity: \"error\", source: \"plugin\" });\n      }\n    }\n\n    const entry = new ContentEntry(\n      slug,\n      collectionName,\n      filePath,\n      validatedData,\n      raw.content,\n      this.markdownConfig,\n      directory,\n    );\n\n    return { entry, issues };\n  }\n\n  /** Get a single entry by slug. */\n  getEntry(collection: string, slug: string): ContentEntry | undefined {\n    return this.cache.get(collection)?.get(slug)?.entry;\n  }\n\n  isCollectionLoaded(collection: string): boolean {\n    return this.loaded.has(collection);\n  }\n\n  /** Get validation issues for a collection. */\n  getIssues(collection: string): Map<string, ValidationIssue[]> {\n    const result = new Map<string, ValidationIssue[]>();\n    const entries = this.cache.get(collection);\n    if (!entries) return result;\n    for (const [slug, cached] of entries) {\n      if (cached.issues.length > 0) {\n        result.set(slug, cached.issues);\n      }\n    }\n    return result;\n  }\n\n  /** Invalidate a single entry and reload it without reloading the entire collection. */\n  async invalidate(collection: string, slug: string): Promise<void> {\n    const def = this.config.collections[collection];\n    if (!def) return;\n\n    const collectionCache = this.cache.get(collection);\n    if (!collectionCache) return;\n\n    const existing = collectionCache.get(slug);\n    if (!existing) return;\n\n    const loader = resolveLoader(def.loader);\n    const directory = resolve(this.rootDir, def.directory);\n\n    try {\n      const result = await this.loadEntry(\n        collection,\n        existing.entry.filePath,\n        directory,\n        loader,\n        def,\n      );\n      if (result) {\n        collectionCache.set(slug, result);\n      } else {\n        // Entry was filtered out after reload\n        collectionCache.delete(slug);\n      }\n    } catch {\n      // File may have been deleted; remove from cache\n      collectionCache.delete(slug);\n    }\n  }\n\n  /** Invalidate an entire collection. */\n  async invalidateCollection(collection: string): Promise<void> {\n    this.cache.delete(collection);\n    this.loaded.delete(collection);\n  }\n\n  /** Invalidate all collections. */\n  invalidateAll(): void {\n    this.cache.clear();\n    this.loaded.clear();\n  }\n\n  /** Get cache statistics for debugging and monitoring. */\n  getCacheStats(): { collections: number; entries: Record<string, number>; totalEntries: number } {\n    const entries: Record<string, number> = {};\n    let totalEntries = 0;\n    for (const [name, cache] of this.cache) {\n      entries[name] = cache.size;\n      totalEntries += cache.size;\n    }\n    return { collections: this.loaded.size, entries, totalEntries };\n  }\n\n  /** Invalidate entries matching a predicate without reloading the entire collection. */\n  async invalidateWhere(\n    collection: string,\n    predicate: (entry: ContentEntry) => boolean,\n  ): Promise<number> {\n    const collectionCache = this.cache.get(collection);\n    if (!collectionCache) return 0;\n\n    const def = this.config.collections[collection];\n    if (!def) return 0;\n\n    const loader = resolveLoader(def.loader);\n    const directory = resolve(this.rootDir, def.directory);\n    let count = 0;\n\n    for (const [slug, cached] of collectionCache) {\n      if (!predicate(cached.entry)) continue;\n      count++;\n      try {\n        const result = await this.loadEntry(\n          collection,\n          cached.entry.filePath,\n          directory,\n          loader,\n          def,\n        );\n        if (result) {\n          collectionCache.set(slug, result);\n        } else {\n          collectionCache.delete(slug);\n        }\n      } catch {\n        collectionCache.delete(slug);\n      }\n    }\n\n    return count;\n  }\n\n  /** Resolve the list of content validators for a collection. */\n  private resolveValidators(def: CollectionDef<any>): ContentValidator[] {\n    const builtin = def.disableBuiltinValidators ? [] : builtinMarkdownValidators;\n    const custom = def.validators ?? [];\n    return [...builtin, ...custom];\n  }\n\n  private createMarkdownConfig(): MarkdownConfig {\n    const base = this.config.markdown ?? {};\n    const remarkPlugins = [...(base.remarkPlugins ?? [])];\n    const rehypePlugins = [...(base.rehypePlugins ?? [])];\n    const plugins = this.config.plugins ?? [];\n\n    if (plugins.length > 0) {\n      remarkPlugins.push(...collectRemarkPlugins(plugins));\n      rehypePlugins.push(...collectRehypePlugins(plugins));\n    }\n\n    return {\n      ...base,\n      ...(remarkPlugins.length > 0 ? { remarkPlugins } : {}),\n      ...(rehypePlugins.length > 0 ? { rehypePlugins } : {}),\n    };\n  }\n}\n","/**\n * ContentLayer — the main API for working with content collections.\n *\n * Created via createContentLayer(config). Provides methods to:\n * - Load and query collections (getCollection, getEntry)\n * - Convert markdown directly (convert)\n * - Invalidate cache (invalidate, invalidateCollection, invalidateAll)\n * - Validate all entries (validate)\n */\n\nimport { watch as fsWatch, type FSWatcher } from \"fs\";\nimport { resolve as pathResolve } from \"path\";\n\nimport { convert as coreConvert } from \"./convert\";\nimport type { ConvertResult } from \"./convert\";\nimport type { MarkdownConfig } from \"./schemas/markdown-config\";\nimport type { ContentEntry } from \"./entry\";\nimport type { CollectionDef, InferCollectionData } from \"./schemas/collection\";\nimport type { ContentLayerConfig } from \"./schemas/content-config\";\nimport { ContentStore } from \"./store\";\nimport type { ValidationResult } from \"./validation\";\n\nexport type WatchEvent = {\n  collection: string;\n  event: string;\n  filename: string | null;\n};\n\nexport type WatchHandle = {\n  close(): void;\n};\n\nexport type WatchCallback = (event: WatchEvent) => void;\n\n/** Typed content layer that preserves collection schema types. */\nexport type TypedContentLayer<T extends Record<string, CollectionDef>> = ContentLayer & {\n  getCollection<K extends keyof T & string>(\n    name: K,\n  ): Promise<ContentEntry<InferCollectionData<T[K]>>[]>;\n  getEntry<K extends keyof T & string>(\n    collection: K,\n    slug: string,\n  ): Promise<ContentEntry<InferCollectionData<T[K]>> | undefined>;\n};\n\nexport interface ContentLayer {\n  /** Get all entries in a collection. */\n  getCollection(name: string): Promise<ContentEntry[]>;\n\n  /** Get a single entry by collection name and slug. */\n  getEntry(collection: string, slug: string): Promise<ContentEntry | undefined>;\n\n  /** Convert raw markdown to HTML (no collection, no validation). */\n  convert(markdown: string, options?: LayerConvertOptions): Promise<ConvertResult>;\n\n  /** Invalidate a single entry's cache. */\n  invalidate(collection: string, slug: string): Promise<void>;\n\n  /** Invalidate an entire collection's cache. */\n  invalidateCollection(collection: string): Promise<void>;\n\n  /** Invalidate all cached data. */\n  invalidateAll(): void;\n\n  /** Validate all entries in a collection (or all collections). */\n  validate(collection?: string): Promise<ValidationResult[]>;\n\n  /** Get the names of all configured collections. */\n  getCollectionNames(): string[];\n\n  /** Get the definition of a collection. */\n  getCollectionDef(name: string): CollectionDef | undefined;\n\n  /** Get all collection definitions. */\n  getCollections(): Record<string, CollectionDef>;\n\n  /** Invalidate entries in a collection that match a predicate. Returns count of invalidated entries. */\n  invalidateWhere(collection: string, predicate: (entry: ContentEntry) => boolean): Promise<number>;\n\n  /** Watch collection directories for changes. Returns a handle to stop watching. */\n  watch(callback: WatchCallback): WatchHandle;\n\n  /** Get cache statistics for debugging and monitoring. */\n  getCacheStats(): { collections: number; entries: Record<string, number>; totalEntries: number };\n}\n\nexport type LayerConvertOptions = {\n  markdown?: MarkdownConfig;\n  /**\n   * Absolute or project-relative source path for the markdown being converted.\n   * Provide this when the markdown references local images so `convert()` can\n   * resolve refs from the markdown file and fill intrinsic dimensions.\n   */\n  sourcePath?: string;\n  /**\n   * Allowed root directory for relative local image refs. Defaults to the\n   * markdown file's own directory when `sourcePath` is provided. Set this when\n   * you want `layer.convert()` to allow refs that move outside the file\n   * directory but still stay inside a broader content root, matching\n   * `entry.render()`.\n   */\n  assetRoot?: string;\n};\n\nclass ContentLayerImpl implements ContentLayer {\n  private store: ContentStore;\n  private config: ContentLayerConfig;\n\n  constructor(config: ContentLayerConfig) {\n    this.config = config;\n    this.store = new ContentStore(config);\n  }\n\n  async getCollection(name: string): Promise<ContentEntry[]> {\n    const def = this.config.collections[name];\n    if (!def) {\n      throw new Error(\n        `Collection \"${name}\" not found. Available: ${Object.keys(this.config.collections).join(\n          \", \",\n        )}`,\n      );\n    }\n    return this.store.loadCollection(name, def);\n  }\n\n  async getEntry(collection: string, slug: string): Promise<ContentEntry | undefined> {\n    const cached = this.store.getEntry(collection, slug);\n    if (cached) return cached;\n\n    // If the collection was already loaded and this slug wasn't found, short-circuit.\n    if (this.store.isCollectionLoaded(collection)) return undefined;\n\n    // The first getEntry call loads the full collection and then serves from cache.\n    // Single-entry loading would skip collection-level transforms and validation context.\n    await this.getCollection(collection);\n    return this.store.getEntry(collection, slug);\n  }\n\n  async convert(markdown: string, options?: LayerConvertOptions): Promise<ConvertResult> {\n    return coreConvert(markdown, {\n      markdown: options?.markdown ?? this.config.markdown,\n      sourcePath: options?.sourcePath,\n      assetRoot: options?.assetRoot,\n    });\n  }\n\n  async invalidate(collection: string, slug: string): Promise<void> {\n    await this.store.invalidate(collection, slug);\n  }\n\n  async invalidateCollection(collection: string): Promise<void> {\n    await this.store.invalidateCollection(collection);\n  }\n\n  invalidateAll(): void {\n    this.store.invalidateAll();\n  }\n\n  async invalidateWhere(\n    collection: string,\n    predicate: (entry: ContentEntry) => boolean,\n  ): Promise<number> {\n    return this.store.invalidateWhere(collection, predicate);\n  }\n\n  async validate(collection?: string): Promise<ValidationResult[]> {\n    const names = collection ? [collection] : Object.keys(this.config.collections);\n    const results: ValidationResult[] = [];\n\n    for (const name of names) {\n      // Ensure loaded\n      await this.getCollection(name);\n\n      const issues = this.store.getIssues(name);\n      const entries = Array.from(issues.entries()).map(([slug, entryIssues]) => {\n        const entry = this.store.getEntry(name, slug);\n        return {\n          slug,\n          filePath: entry?.filePath ?? \"\",\n          issues: entryIssues,\n        };\n      });\n\n      let errors = 0;\n      let warnings = 0;\n      for (const entry of entries) {\n        for (const issue of entry.issues) {\n          if (issue.severity === \"error\") errors++;\n          else warnings++;\n        }\n      }\n\n      results.push({ collection: name, entries, errors, warnings });\n    }\n\n    return results;\n  }\n\n  getCollectionNames(): string[] {\n    return Object.keys(this.config.collections);\n  }\n\n  getCollectionDef(name: string): CollectionDef | undefined {\n    return this.config.collections[name];\n  }\n\n  getCollections(): Record<string, CollectionDef> {\n    return { ...this.config.collections };\n  }\n\n  watch(callback: WatchCallback): WatchHandle {\n    const watchers: FSWatcher[] = [];\n    const root = this.config.root ?? process.cwd();\n    const timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n    for (const [name, def] of Object.entries(this.config.collections)) {\n      const dir = pathResolve(root, def.directory);\n      try {\n        const watcher = fsWatch(dir, { recursive: true }, (event, filename) => {\n          // Debounce: coalesce rapid changes per collection within 100ms\n          const existing = timers.get(name);\n          if (existing) clearTimeout(existing);\n          timers.set(\n            name,\n            setTimeout(() => {\n              timers.delete(name);\n              void this.store.invalidateCollection(name);\n              callback({ collection: name, event, filename });\n            }, 100),\n          );\n        });\n        watcher.on(\"error\", (err) => {\n          console.warn(`Content watcher error for \"${name}\":`, err.message);\n        });\n        watchers.push(watcher);\n      } catch {\n        // Directory may not exist yet — skip silently\n      }\n    }\n\n    return {\n      close() {\n        for (const w of watchers) w.close();\n        for (const t of timers.values()) clearTimeout(t);\n        timers.clear();\n      },\n    };\n  }\n\n  getCacheStats() {\n    return this.store.getCacheStats();\n  }\n}\n\n/** Create a new content layer from a configuration. */\nexport function createContentLayer<T extends Record<string, CollectionDef>>(\n  config: ContentLayerConfig & { collections: T },\n): TypedContentLayer<T>;\nexport function createContentLayer(config: ContentLayerConfig): ContentLayer;\nexport function createContentLayer(config: ContentLayerConfig): ContentLayer {\n  return new ContentLayerImpl(config);\n}\n"],"mappings":"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"}