2 min read

@document0/core

The core package handles everything related to reading your content from disk, building data structures for your UI, serving search and LLM endpoints, and processing OpenAPI specs.

DocsSource

The main entry point. Scans a directory for .md and .mdx files and produces typed PageData objects. All results are cached on the instance — subsequent calls return instantly.

import { DocsSource } from "@document0/core";

const source = new DocsSource({
  rootDir: "./content/docs", // required: absolute or relative path
  baseUrl: "/docs",          // default: "/docs"
  extensions: [".md", ".mdx"], // default
});

Methods

getPages()

Returns all pages as a flat array of PageData. Cached after first call.

const pages = await source.getPages();
// PageData[]

getPageTree()

Returns a nested TreeNode[] for sidebar rendering. Respects _meta.json ordering. Cached after first call.

const tree = await source.getPageTree();
// TreeNode[]

getPage(slug)

O(1) lookup of a single page by its slug string (e.g. "guides/installation").

const page = await source.getPage("installation");
// PageData | undefined

getPageByUrl(url)

O(1) lookup of a single page by its full URL (e.g. "/docs/guides/installation").

const page = await source.getPageByUrl("/docs/installation");
// PageData | undefined

invalidate()

Clears all cached data (pages, tree, search index, lookup maps). Call this when content files change to force a reload.

source.invalidate();

Content watching (dev)

Next.js: use @document0/next-dev (withDocument0 + one content-stamp import) so the dev bundler invalidates your DocsSource module when content/ changes (Fumadocs-style). See the Next.js guide.

Other runtimes: watchDocsSource from @document0/core/watch (Node-only; separate entry so chokidar is not pulled into unrelated graphs).

PageData

interface PageData {
  slug: string;           // e.g. "guides/installation"
  slugs: string[];        // e.g. ["guides", "installation"]
  url: string;            // e.g. "/docs/guides/installation"
  filePath: string;       // absolute path to the .mdx file
  content: string;        // raw markdown body (frontmatter stripped)
  frontmatter: {
    title: string;
    description?: string;
    icon?: string;
    full?: boolean;
    [key: string]: unknown;
  };
}

Page tree

TreeNode

type TreeNode = PageNode | FolderNode | SeparatorNode;

interface PageNode {
  type: "page";
  name: string;
  url: string;
  slug: string;
  icon?: string;
}

interface FolderNode {
  type: "folder";
  name: string;
  icon?: string;
  defaultOpen?: boolean;
  index?: PageNode;       // index.mdx inside this folder
  children: TreeNode[];
}

interface SeparatorNode {
  type: "separator";
  name: string;           // label, or empty string for an unlabelled divider
}

_meta.json

Place a _meta.json file in any content directory to control ordering and labels.

{
  "title": "Guides",
  "pages": [
    "index",
    "--- Getting Started",
    "installation",
    "---",
    "advanced"
  ],
  "defaultOpen": true,
  "icon": "📖"
}
  • Strings starting with "--- " become labelled separators
  • "---" alone becomes an unlabelled divider
  • Pages not listed are appended alphabetically

getBreadcrumbs

Returns the breadcrumb trail from the root to the current page.

import { getBreadcrumbs } from "@document0/core";

const crumbs = getBreadcrumbs(tree, "/docs/guides/installation");
// BreadcrumbItem[]
interface BreadcrumbItem {
  name: string;
  url?: string;  // undefined for the current (last) item
}

getPageNeighbours

Returns the previous and next pages in document order.

import { getPageNeighbours } from "@document0/core";

const { previous, next } = getPageNeighbours(tree, "/docs/installation");
// { previous: PageNode | null, next: PageNode | null }

isActiveOrAncestor

Returns true if a tree node is the active page or an ancestor of it, useful for expanding folders in a sidebar.

import { isActiveOrAncestor } from "@document0/core";

const open = isActiveOrAncestor(folderNode, currentUrl);

createSearchRoute

Creates an API route handler backed by Orama with full-text search, fuzzy matching, and relevance ranking. The search index is cached per DocsSource instance and cleared on invalidate().

import { createSearchRoute } from "@document0/core/search";

// app/internal/search/route.ts
export const { GET } = createSearchRoute(source);

The returned GET handler accepts a ?q= query parameter and responds with SearchResult[].

interface SearchResult {
  title: string;
  description?: string;
  url: string;
  score: number;
}

llms.txt

Generate llms.txt files so LLMs and AI tools can ingest your documentation.

createLlmsTxtRoute

Serves a concise index of all pages as llms.txt.

import { createLlmsTxtRoute } from "@document0/core/llms";

// app/llms.txt/route.ts
export const { GET } = createLlmsTxtRoute(source, {
  title: "My Docs",
  description: "Documentation for my project",
  baseUrl: "https://docs.example.com",
});

createLlmsFullTxtRoute

Serves the complete content of every page concatenated into a single text file.

import { createLlmsFullTxtRoute } from "@document0/core/llms";

// app/llms-full.txt/route.ts
export const { GET } = createLlmsFullTxtRoute(source, {
  title: "My Docs",
  description: "Documentation for my project",
  baseUrl: "https://docs.example.com",
});

createMdxPageRoute

Serves raw markdown content for a single page by slug.

import { createMdxPageRoute } from "@document0/core/llms";

// app/api/page/[...slug]/route.ts
export const { GET } = createMdxPageRoute(source);

OpenAPI

createOpenAPISource

Parses an OpenAPI 3.x spec and generates OpenAPIPageData for each operation.

import { createOpenAPISource } from "@document0/core/openapi";

const operations = createOpenAPISource(specObject, { baseUrl: "/docs/api" });

buildOpenAPITree

Builds a TreeNode[] from OpenAPI operations, grouped by tag.

import { buildOpenAPITree } from "@document0/core/openapi";

const tree = buildOpenAPITree(operations);

buildOpenAPISearchIndex

Returns SearchResult[] from OpenAPI operations for use with search.

import { buildOpenAPISearchIndex } from "@document0/core/openapi";

const results = buildOpenAPISearchIndex(operations);