zudo-doc
GitHub repository

Type to search...

to open search from anywhere

Doc History Server

Created Mar 25, 2026Updated Jul 21, 2026Takeshi Takatsudo

Standalone package for serving and generating document git history, with dual modes: REST API server for local development and CLI batch generator for CI builds.

Overview

The Doc History Server is a sub-package at packages/doc-history-server/ that handles all git history extraction for the Document History feature. It was extracted from the zfb build pipeline to decouple expensive git operations from the site build.

It operates in two modes:

  • Server mode -- runs an HTTP server during local development, serving history on demand

  • CLI mode -- batch-generates all history JSON files for production builds in CI

This separation enables a parallel CI strategy where the zfb site build and history generation run as independent jobs, reducing total build time.

Server Mode (Local Development)

The server runs on a configurable port (default 4322) and serves document history via a REST API. A project scaffolded with docHistory enabled gets this wired automatically: create-zudo-doc emits a dev script of run-p dev:zfb dev:history, so zfb and the doc-history-server run concurrently.

Starting the Server

Run it through the generated dev:history script — doc-history-server lives only in the project's node_modules/.bin, which package-manager scripts put on PATH automatically but a bare shell prompt does not:

pnpm dev:history
# or: npm run dev:history

Under the hood, that script resolves to:

doc-history-server --port 4322 --content-dir src/content/docs

When i18n is also enabled, create-zudo-doc appends a --locale <lang>:src/content/docs-<lang> flag for the secondary locale automatically. To run the server manually with other flags, see Server Options below.

Endpoints

GET /doc-history/{slug}.json

Returns the full git history for a document.

GET /doc-history/guides/writing-docs.json

GET /doc-history/{locale}/{slug}.json

Returns history for a localized document.

GET /doc-history/ja/guides/writing-docs.json

GET /health

Health check endpoint.

{ "status": "ok" }

Server Options

FlagRequiredDefaultDescription
--content-dirYes--Content directory to scan for documents
--locale <key>:<dir>No--Additional locale directory (repeatable)
--portNo4322HTTP server port
--max-entriesNo50Maximum git commits per document

Server Behavior

  • File index refreshes every 10 seconds, automatically picking up new or renamed files

  • CORS headers are included for cross-origin dev access

  • Requests for unknown slugs return 404 with { "error": "No doc found for slug: ..." }

zfb Integration

In dev mode, the doc-history zfb plugin's devMiddleware hook proxies /doc-history/* requests to this server. This means the history panel in the browser transparently fetches from the standalone server through the zfb dev server.

A docHistory-enabled project's generated dev script (run-p dev:zfb dev:history) runs both zfb (port 4321) and the doc-history-server (port 4322) concurrently.

CLI Mode (CI Builds)

The CLI generates static JSON files for all documents, intended for CI pipelines.

Usage

pnpm generate -- --content-dir src/content/docs --locale ja:src/content/docs-ja --out-dir dist/doc-history

CLI Options

FlagRequiredDefaultDescription
--content-dirYes--Content directory to scan
--locale <key>:<dir>No--Additional locale directory (repeatable)
--out-dirYes--Output directory for generated JSON files
--max-entriesNo50Maximum git commits per document

CI Pipeline Integration

The CI pipeline runs history generation as a parallel job alongside the zfb site build:

  • build-site job: full clone (fetch-depth: 0), builds the zfb site with pnpm build (no SKIP_DOC_HISTORY — the preBuild step runs git log --follow to populate .zfb/doc-history-meta.json with real dates, inlined into the SSG HTML as the visible Created/Updated/Author block)

  • build-history job: full clone (fetch-depth: 0), runs @takazudo/zudo-doc-history-server generate

  • deploy job: merges both artifacts and deploys to Cloudflare Workers

This parallelization is possible because the history generation is fully independent of the zfb build.

Tip

Both the build-history and build-site jobs require a full clone (fetch-depth: 0). build-history needs the complete commit history to extract revision data for the DocHistory island dropdown. build-site needs it so the preBuild step can populate the SSG meta block (Created/Updated/Author) with real git dates.

Note

DOC_HISTORY_SKIP_POSTBUILD (see the deployment guide) only gates the zfb plugin's inline postBuild hook running inside build-site — it has no effect on this standalone generate CLI, which is what the build-history job actually runs and always generates when invoked.

Data Format

DocHistoryEntry

A single git revision entry for a document:

interface DocHistoryEntry {
  /** Full commit hash (use .slice(0, 7) for display) */
  hash: string;
  /** ISO 8601 date string */
  date: string;
  /** Commit author name */
  author: string;
  /** First line of commit message */
  message: string;
  /** Full file content at this revision */
  content: string;
}

DocHistoryData

Complete history data for a single document:

interface DocHistoryData {
  /** Document slug (route path) */
  slug: string;
  /** Relative file path in the repository */
  filePath: string;
  /** Git revision entries, newest first */
  entries: DocHistoryEntry[];
}

Output Structure

Generated files mirror the content directory structure:

dist/doc-history/
  getting-started.json
  guides/writing-docs.json
  guides/color.json
  ja/getting-started.json
  ja/guides/writing-docs.json

Architecture

Git Operations

History extraction uses non-blocking execFile / spawn calls for:

  • git log -- commit listing with --follow for rename tracking

  • git show -- file content at each revision

The --follow flag tracks file history across renames with multiple fallback strategies, so documents that have been moved or renamed retain their complete history.

Key Design Decisions

  • One async extraction path -- both the dev server and CI CLI await getDocHistoryAsync. The CLI uses bounded parallelism with a semaphore limited to Math.min(8, Math.max(2, cpus().length)) concurrent workers; only the cached one-time repository-root probe is synchronous

  • Repo-relative paths -- API responses use relative file paths to avoid leaking absolute server paths

  • Standalone package -- decoupled from zfb to enable parallel CI builds and independent versioning

Sub-Package Location

packages/doc-history-server/
├── src/
│   ├── index.ts        # Server entry — parses args, starts HTTP server
│   ├── cli.ts          # CLI entry — parses args, batch generates JSONs
│   ├── args.ts         # Shared argument parsing with bounds checking
│   ├── server.ts       # HTTP server (REST API endpoints)
│   ├── git-history.ts  # Core git logic (log, show, follow, rename tracking)
│   ├── shared.ts       # Shared helpers (getContentDirEntries)
│   └── types.ts        # DocHistoryEntry, DocHistoryData types
├── package.json
├── tsconfig.json
└── README.md

Revision History

Takeshi TakatsudoCreated: 2026-03-25T23:13:29+09:00Updated: 2026-07-21T12:01:53+09:00

AI Assistant

Ask a question about the documentation.

Preview theme

Loading theme previews…