Doc History Server
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. In the standard pnpm dev setup, zfb and the doc-history-server run concurrently via run-p.
Starting the Server
pnpm dev -- --content-dir src/content/docs --locale ja:src/content/docs-ja --port 4322Endpoints
GET /doc-history/{slug}.json
Returns the full git history for a document.
GET / doc- history/ guides/ writing- docs. jsonGET /doc-history/{locale}/{slug}.json
Returns history for a localized document.
GET / doc- history/ ja/ guides/ writing- docs. jsonGET /health
Health check endpoint.
{ "status": "ok" }Server Options
| Flag | Required | Default | Description |
|---|---|---|---|
--content-dir | Yes | -- | Content directory to scan for documents |
--locale <key>:<dir> | No | -- | Additional locale directory (repeatable) |
--port | No | 4322 | HTTP server port |
--max-entries | No | 50 | Maximum 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 / requests to this server. This means the history panel in the browser transparently fetches from the standalone server through the zfb dev server.
The root pnpm dev command runs both zfb (port 4321) and the doc-history-server (port 4322) concurrently using run-p.
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-historyCLI Options
| Flag | Required | Default | Description |
|---|---|---|---|
--content-dir | Yes | -- | Content directory to scan |
--locale <key>:<dir> | No | -- | Additional locale directory (repeatable) |
--out-dir | Yes | -- | Output directory for generated JSON files |
--max-entries | No | 50 | Maximum 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 withpnpm build(noSKIP_DOC_HISTORY— the preBuild step runsgit log --followto populate.with real dates, inlined into the SSG HTML as the visible Created/Updated/Author block)zfb/ doc- history- meta. json build-history job: full clone (
fetch-depth: 0), runs@takazudo/zudo-doc-history-server generatedeploy 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.
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. jsonArchitecture
Git Operations
History extraction uses synchronous git calls (execFileSync) for:
git log-- commit listing with--followfor rename trackinggit 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
Synchronous git --
execFileSyncis acceptable for the dev server (same-process, sequential). The CI CLI uses bounded parallelism: tasks run viaPromise.allwith a semaphore limited toMath.min(8, Math.max(2, cpus().length))concurrent workersRepo-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