Documentation
Two generators produce the documentation site:
| Generator | Source | Output | Answers |
|---|---|---|---|
| TypeDoc | JSDoc in src/ |
dist/docs/ |
"what does this symbol do?" |
| HonKit | Markdown in docs/ |
dist/book/ |
"how do I work on this?" |
The split matters: anything a generator can derive from the code belongs in a doc comment, where it sits next to what it
describes and moves with it. Anything it cannot — why a layer exists, how to cut a release — belongs in docs/.
Markdown formatting and local links are checked separately:
npm run format:docs:check
npm run docs:check
The API reference
npm run build:docs
TypeDoc reads src/index.ts — the published surface, nothing else. Internals are not documented for consumers because
consumers cannot reach them.
The gate
typedoc.json sets treatWarningsAsErrors: true alongside four validations, so npm run build:docs fails on:
| Validation | Fails when |
|---|---|
notDocumented |
an exported symbol has no doc comment |
invalidLink |
a {@link Something} does not resolve |
notExported |
a documented symbol references a type that is not itself exported |
rewrittenLink |
a relative link had to be rewritten to survive |
skipErrorChecking is false, so documentation cannot be generated from a program that does not compile.
This is the point of the whole setup. Documentation that is merely encouraged rots, because nothing fails when the code moves on without it. A build that stops is a documentation defect you find at the time you introduce it.
Writing a doc comment
/**
* One sentence saying what it does.
*
* @remarks
* The reasoning a reader cannot recover from the signature — why this exists,
* what it deliberately does not do, which decision it encodes.
*
* @param name - What the caller supplies.
*
* @returns What comes back.
*
* @throws {@link MissingBindingError} when the binding is absent from the environment.
*
* @example
* ```ts
* greet('World')
* ```
*
* @author Your Name
* @version 1.0.0
* @since 1.0.0
*/
Conventions this project follows:
@sincerecords the first package version that exposed the symbol. Keep it stable after introduction. Use@versiononly where the project can maintain it accurately; release history belongs inCHANGELOG.md,docs/release-notes/, andpackage.json#version.- Every barrel carries
@moduledescribing what belongs in that layer and what may import it. Those blocks are where the architecture is explained, and they are read far more often than a separate document. - Do not restate what TypeScript already declares.
@type,@property,@public,@privateduplicate the signature, and they drift the moment it changes. - Kind tags carry no argument.
@class, not@class KVService— TypeDoc drops the tag but keeps its argument, which then renders as a stray paragraph in the summary.
The developer book
npm run build:docs:book
HonKit — the maintained successor to GitBook, whose gitbook-cli no longer installs on
any current Node. Configuration is docs/book.json, theme is docs/styles/website.css, and root is . because
book.json already lives inside docs/.
Adding a page
- Write the Markdown under the directory that matches its kind:
getting-started/— enough to get runningguides/— task-oriented, step-by-stepreference/— how things are arranged
- Add it to
docs/SUMMARY.md. HonKit builds its navigation from that file alone; a page missing from it is a page nobody will find. - Add it to the matching table in
docs/README.md.
Living versus point-in-time
getting-started/, guides/, and reference/ are living documents — if you change the behaviour they describe, update
them in the same change. release-notes/ and changes-log/ are point-in-time records. Preserve their historical
meaning, but correct broken links, factual errors, or accidentally disclosed information when necessary.
Both, plus coverage
npm run build:static
Assembles dist/: the landing page at the root, docs/ (TypeDoc), book/ (HonKit), and coverage/ (Jest HTML). Serve
it with Docker.