Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/gentle-hoops-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@btravstack/entity": patch
---

Point the package README at the new documentation site,
<https://btravstack.github.io/entity/>, instead of the Markdown files in the
repository. No code change.
30 changes: 30 additions & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: "Setup Node.js and pnpm"
description: "Setup Node.js and pnpm, install dependencies"

# CI and Release call btravstack/config's reusable workflows, which do their own
# setup. This composite exists for Deploy Documentation, which runs its own
# steps in this repo and needs the same toolchain.

runs:
using: "composite"
steps:
- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: pnpm

- name: Setup Turbo Cache
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-

- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile
62 changes: 62 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Deploy Documentation

# Publish the VitePress site once CI is green on main. Chaining off CI rather
# than pushing directly means the site is never built from a commit that does
# not compile, and the `github-pages` environment's branch policy sees `main`
# (a `workflow_run` event runs against the default branch).
on:
workflow_run:
workflows: ["CI"]
types:
- completed
branches:
- main
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
# A Pages deploy replaces the whole site, so only one may be in flight.
group: pages
cancel-in-progress: false

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
build:
# A `workflow_run` fires on ANY CI conclusion (failure, cancelled); deploy
# only after a successful one. `workflow_dispatch` is unconditional.
if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Setup
uses: ./.github/actions/setup

# The docs build runs TypeDoc (straight from packages/entity/src into
# docs/api/entity) and then VitePress — see docs/package.json.
- name: Build documentation
run: pnpm --filter ./docs exec turbo build

- name: Upload artifact
uses: actions/upload-pages-artifact@v5
with:
path: docs/.vitepress/dist

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
name: Deploy
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ coverage/
# Turbo
.turbo/

# VitePress
docs/.vitepress/cache/
docs/.vitepress/dist/
# The package's API reference, generated by TypeDoc at build time
# (the hand-written docs/api/index.md overview is kept)
docs/api/entity/

# Logs
*.log

Expand Down
31 changes: 28 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,43 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
fallible operation returns an `unthrown` `Result<T, InvalidEntity>` instead of
throwing.

pnpm + turbo monorepo with a single package, `packages/entity`. Root scripts
delegate to turbo; package scripts are where the real commands live.
pnpm + turbo monorepo with two workspaces: the package, `packages/entity`, and
the documentation site, `docs`. Root scripts delegate to turbo; workspace
scripts are where the real commands live.

## Commands

Scripts are in `package.json`; the root ones delegate to turbo. Two things
Scripts are in `package.json`; the root ones delegate to turbo. Three things
that are not derivable from there:

- **The gate CI runs, in order**: `format --check`, `lint`, `typecheck`,
`test`, `knip`, `build`. `typecheck` is three passes — the main `tsc`, the
`.test-d.ts` pass, and the consumer declaration-emit pass.
- **A single test file runs from inside `packages/entity`**, not the root.
- **The docs site runs from inside `docs`**: `pnpm --filter ./docs dev`.
`pnpm build` at the root builds it too, since it is a workspace.

## The documentation site

`docs/` is a VitePress site deployed to <https://btravstack.github.io/entity/>
by `.github/workflows/deploy-docs.yml` once CI is green on `main`. It is
organised by the four [Diátaxis](https://diataxis.fr/) modes — `tutorial/`,
`how-to/`, `reference/`, `explanation/` — with one shared sidebar across all
four so any page reaches any other. `docs/.vitepress/theme/custom.css` sets a
single `--accent` token; the shared `@btravstack/theme` derives every other
shade from it.

Its build is `typedoc && vitepress build`. TypeDoc reads
`packages/entity/src/index.ts` straight through and writes `docs/api/entity/`,
which is git-ignored and regenerated every build — `docs/api/index.md` is the
one hand-written page under `api/`.

TypeDoc runs from **`docs/`** rather than from `packages/entity/` (where the
other btravstack repos put it), with its own TypeScript from the named
`typedoc` catalog. That is forced, not stylistic: the default catalog's
`typescript: 7.0.2` is the native port and ships no JS compiler API, so TypeDoc
cannot run against it. Measured — the reason is inline in
`pnpm-workspace.yaml`.

## Architecture

Expand Down
30 changes: 27 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,35 @@ pnpm lint # oxlint
pnpm typecheck # tsc (incl. type-level tests)
pnpm test # vitest
pnpm knip # dead code / unused deps
pnpm build # tsdown dual CJS/ESM + d.ts
pnpm build # tsdown dual CJS/ESM + d.ts, and the docs site
```

Run `pnpm format` (no `--check`) to auto-fix formatting.

### The documentation site

`docs/` is a workspace of its own — a [VitePress](https://vitepress.dev) site
organised by the four [Diátaxis](https://diataxis.fr/) modes (Tutorial, How-to,
Reference, Explanation), deployed to
<https://btravstack.github.io/entity/> by `.github/workflows/deploy-docs.yml`
once CI is green on `main`.

```sh
pnpm --filter ./docs dev # local preview with hot reload
pnpm --filter ./docs build # what CI and the deploy build
```

The build is `typedoc && vitepress build`. TypeDoc reads
`packages/entity/src/index.ts` and writes `docs/api/entity/` (git-ignored,
regenerated every build); `docs/api/index.md` is the one hand-written page
there.

TypeDoc runs from **`docs/`**, not from `packages/entity/` as it does in the
other btravstack repos, and with its own TypeScript. That is forced, not
stylistic: the catalog's `typescript: 7.0.2` is the native port, which ships no
JS compiler API for TypeDoc to drive. The named `typedoc` catalog in
`pnpm-workspace.yaml` pins 6.0.3 for that one job, with the reason inline.

### Type-level tests

Behaviour that only shows up at the type level — the construction seal, the
Expand Down Expand Up @@ -69,8 +93,8 @@ types, while the plain `tsc` pass is `noEmit` from the shared base.

## Design rules (binding)

`docs/reference.md` documents the public behaviour and `docs/explanation.md`
the rationale behind it; many of those rules were measured against a specific
`docs/reference/` documents the public behaviour and `docs/explanation/` the
rationale behind it; many of those rules were measured against a specific
compiler/library version, not assumed. Where a
source comment records a measurement (a TS diagnostic code, a specific
library's output), treat it as a regression guard, not decoration — verify
Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
[![TypeScript](https://img.shields.io/badge/TypeScript-7.0-blue?logo=typescript)](https://www.typescriptlang.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

[**Reference**](./docs/reference.md) · [**Explanation**](./docs/explanation.md) · [**How-to guides**](./docs/how-to)
[**Documentation**](https://btravstack.github.io/entity/) · [**Getting started**](https://btravstack.github.io/entity/tutorial/getting-started) · [**Reference**](https://btravstack.github.io/entity/reference/declaration) · [**Why entity?**](https://btravstack.github.io/entity/explanation/why-entity)

</div>

Expand Down Expand Up @@ -67,7 +67,8 @@ pnpm add @btravstack/entity zod unthrown @unthrown/standard-schema
```

`zod`, `unthrown` and `@unthrown/standard-schema` are **peer dependencies** —
install all four. ([Why](./docs/explanation.md#peer-dependencies).)
install all four.
([Why](https://btravstack.github.io/entity/explanation/peer-dependencies).)

## A worked example

Expand Down Expand Up @@ -146,13 +147,14 @@ existing one.

## Documentation

- **[Reference](./docs/reference.md)** — every member, option and type, with signatures.
- **[Explanation](./docs/explanation.md)** — why it is built this way: sealed construction, deep immutability, no I/O, why entities are not subclassable.
- **How-to guides**
- [Expose an HTTP contract](./docs/how-to/http-contract.md)
- [Persist and rehydrate](./docs/how-to/persist-and-rehydrate.md)
- [Model an aggregate](./docs/how-to/model-an-aggregate.md)
- [Test domain logic](./docs/how-to/test-domain-logic.md)
**[btravstack.github.io/entity](https://btravstack.github.io/entity/)** — built
with VitePress from [`docs/`](./docs), and organised by the four
[Diátaxis](https://diataxis.fr/) modes:

- **[Tutorial](https://btravstack.github.io/entity/tutorial/getting-started)** — from nothing to a working entity, one step at a time.
- **How-to guides** — [expose an HTTP contract](https://btravstack.github.io/entity/how-to/http-contract) · [persist and rehydrate](https://btravstack.github.io/entity/how-to/persist-and-rehydrate) · [model an aggregate](https://btravstack.github.io/entity/how-to/model-an-aggregate) · [test domain logic](https://btravstack.github.io/entity/how-to/test-domain-logic)
- **[Reference](https://btravstack.github.io/entity/reference/declaration)** — every member, option and type, with signatures. Plus the [generated API reference](https://btravstack.github.io/entity/api/).
- **[Explanation](https://btravstack.github.io/entity/explanation/why-entity)** — why it is built this way: sealed construction, deep immutability, no I/O, why entities are not subclassable.

## Development

Expand Down
Loading
Loading