Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3487d48
feat(sources): recognise component-prefixed release tags
TitusKirch Sep 14, 2026
a48d1a8
Merge remote-tracking branch 'origin/main' into HEAD
TitusKirch Sep 14, 2026
790a546
build: restructure the repository into a Turborepo monorepo
TitusKirch Sep 15, 2026
e5ea1ae
docs(adr): record hosting the provider layers in a Turborepo monorepo
TitusKirch Sep 15, 2026
3b2a342
docs(claude): record that a root-only commit never releases the layer
TitusKirch Sep 15, 2026
cc4311a
fix(image): cover the whole viewport from the zoom dialog's first frame
TitusKirch Sep 15, 2026
39ee6e4
fix(toc): mark the heading a table-of-contents click jumped to
TitusKirch Sep 15, 2026
e1af601
fix(changelog): animate the height of the selected-kinds row
TitusKirch Sep 15, 2026
04bc8c0
feat(header): reveal the new theme as a circle from the toggle
TitusKirch Sep 15, 2026
cb93d59
feat(sources): recognise component-prefixed release tags
TitusKirch Sep 15, 2026
ae6a567
fix(www): retain every released minor documentation line
TitusKirch Sep 15, 2026
a707406
fix(changelog): assign contributors through the git graph
TitusKirch Sep 15, 2026
247e91e
fix(ci): leave release commits to the release deploy
TitusKirch Sep 15, 2026
ee936b6
Merge remote-tracking branch 'origin/main' into dev
TitusKirch Sep 15, 2026
52a92ee
fix(sources): split a release tag at its last @ instead of by one pat…
TitusKirch Sep 15, 2026
c8aa11a
chore(release): count only what shipped after 0.5.0 toward the layer
TitusKirch Sep 15, 2026
d2ce31f
fix(types): accept releases on a source in app.config
TitusKirch Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:
# and the path list must agree. The command answers `cacheable=false` for a
# private or authenticated source, and the body then caches nothing.
with:
remote-source-cache-command: node ./bin/duxt-cache-key.mjs --root www --github >> "$GITHUB_OUTPUT"
remote-source-cache-command: node ./packages/duxt/bin/duxt-cache-key.mjs --root apps/www --github >> "$GITHUB_OUTPUT"
39 changes: 25 additions & 14 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ on:
# the hostname — none of which is a commit.
workflow_dispatch:

# ON EVERY PUSH TO MAIN, THEN AGAIN FOR A PUBLISHED RELEASE. `www/` reads
# ON EVERY ORDINARY PUSH TO MAIN, AND FOR A PUBLISHED RELEASE. `apps/www/` reads
# `docs/` off the CHECKOUT — `origin.ref` in its `app.config.ts` names the
# repository for the edit links and downloads nothing — so a documentation fix
# does not wait for a release. The second build is deliberately redundant: it
# runs only after release-please has created the tag, which makes `latest`
# deterministic rather than dependent on two workflows' scheduling.
# does not wait for a release. A release-please merge is the exception: its push
# arrives before the tag and stands down for the release event that follows.
# Otherwise both builds may publish in either order, and the tag-blind push can
# overwrite the release build that resolved `latest` correctly.
#
# The consequence, stated rather than hidden: the version badge comes from
# `package.json`, which release-please bumps, so between a promotion and its
Expand All @@ -53,6 +54,16 @@ jobs:
build:
name: Build www
runs-on: ubuntu-latest
# A release-please merge fires this workflow before its tag exists. The
# published-release event fires it again once the tag is available, so only
# that second run may build and publish the release commit. Both subject
# forms are already recognised by the prerelease workflow beside this one.
if: >-
${{
github.event_name != 'push'
|| !startsWith(github.event.head_commit.message, 'chore(main): release')
&& !startsWith(github.event.head_commit.message, 'chore: release')
}}
# DISPOSABLE WORK, BUT ONLY WHEN A COMMIT ASKED FOR IT. A newer push to
# main makes this build's artefact stale before it exists, so the runner
# drops it rather than finishing it and queueing an upload nobody wants —
Expand Down Expand Up @@ -100,7 +111,7 @@ jobs:
run: pnpm install --frozen-lockfile

# THE DOWNLOAD CACHE, NOT THE PARSE CACHE. Content clones every remote
# source into `www/.data/content` and keys the directory by repository AND
# source into `apps/www/.data/content` and keys the directory by repository AND
# ref, so what a run downloads is a function of the RESOLVED source list —
# which is exactly what this command prints, `latest` already replaced by
# the tag it means. `contents.sqlite` lives in the same directory and is
Expand All @@ -118,7 +129,7 @@ jobs:
# `remote-source-cache-command`, which `ci.yml` passes this same command.
- name: Resolve the remote-source cache key
id: sources
run: node ./bin/duxt-cache-key.mjs --root www --github >> "$GITHUB_OUTPUT"
run: node ./packages/duxt/bin/duxt-cache-key.mjs --root apps/www --github >> "$GITHUB_OUTPUT"

# NO `restore-keys`, deliberately. An exact key means a hit never re-saves,
# which is right for the tags this site pins — they cannot move, so one
Expand Down Expand Up @@ -174,7 +185,7 @@ jobs:
env:
SOURCE_SHA: ${{ steps.source.outputs.sha }}
run: |
node ./bin/duxt-og-cache.mjs --root www --run "$SOURCE_SHA" --github \
node ./packages/duxt/bin/duxt-og-cache.mjs --root apps/www --run "$SOURCE_SHA" --github \
>> "$GITHUB_OUTPUT"

- name: Restore the rendered OG images
Expand Down Expand Up @@ -222,7 +233,7 @@ jobs:
BUILD_MS: ${{ steps.build.outputs.ms }}
run: |
report() {
node ./bin/duxt-og-cache.mjs --root www --report \
node ./packages/duxt/bin/duxt-og-cache.mjs --root apps/www --report \
--since "$SINCE" --log build.log --build-ms "$BUILD_MS" "$@"
}
report >> "$GITHUB_STEP_SUMMARY"
Expand All @@ -243,7 +254,7 @@ jobs:

# The build/publication boundary, made literal. `.output` is the whole of
# what wrangler uploads: the module Worker and the prerendered assets
# beside it, exactly as `www/wrangler.jsonc` names them.
# beside it, exactly as `apps/www/wrangler.jsonc` names them.
#
# This round trip is the price of being able to cancel a build without
# risking an upload, and it is paid on every deploy. `retention-days: 1`
Expand All @@ -252,7 +263,7 @@ jobs:
- uses: actions/upload-artifact@v7
with:
name: www-output
path: www/.output
path: apps/www/.output
retention-days: 1
# Nitro emits dotfiles into `.output/public` — `_headers`' neighbours,
# and whatever a module drops under `.well-known`. The action skips
Expand Down Expand Up @@ -286,7 +297,7 @@ jobs:
group: deploy-www-publish
cancel-in-progress: false
steps:
# wrangler, `www/wrangler.jsonc` and the workspace it resolves from. The
# wrangler, `apps/www/wrangler.jsonc` and the workspace it resolves from. The
# site itself is not rebuilt here; it arrives as the artefact below, so
# this checkout follows the build's ref rather than the trigger's.
- uses: actions/checkout@v6
Expand All @@ -306,14 +317,14 @@ jobs:
- uses: actions/download-artifact@v8
with:
name: www-output
path: www/.output
path: apps/www/.output

# The Cloudflare deploy token from the kirchDev-ci Bitwarden project. It
# needs `Workers Scripts: Edit` AND `D1: Edit`; the D1 half is newer than
# the token, so verify it is there before blaming the build.
#
# No `Workers Routes: Edit`: the route is tofu's, not wrangler's — see the
# header of `www/wrangler.jsonc`.
# header of `apps/www/wrangler.jsonc`.
- name: Fetch secrets from Bitwarden
uses: bitwarden/sm-action@1238aae8fc64b212641190a9227c8a734ab1a793 # v3.0.1
with:
Expand All @@ -337,4 +348,4 @@ jobs:
DEPLOY_COMMITTED_AT: ${{ needs.build.outputs.committed-at }}
DEPLOY_TRIGGER: ${{ github.event_name }}
DEPLOY_WORKER: duxt-www
run: node scripts/deploy-summary.ts >> "$GITHUB_STEP_SUMMARY"
run: node apps/www/scripts/deploy-summary.ts >> "$GITHUB_STEP_SUMMARY"
20 changes: 10 additions & 10 deletions .github/workflows/prerender-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# no body for "build one repository's site eighteen times and compare the
# prerender phase", and there is unlikely ever to be a second caller for one.
#
# WHAT IT IS FOR. `prerender.concurrency: 8` in `www/nuxt.config.ts` is the
# WHAT IT IS FOR. `prerender.concurrency: 8` in `apps/www/nuxt.config.ts` is the
# answer to a build that produced 335 `createImage timeout` lines — 335 pages
# that shipped with no OG image, silently, because a missing OG image fails
# nothing. Eight brought that to 140 and the number was never revisited. Issue
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:
# number: Nitro's own timing starts after the content is parsed.
- name: Resolve the remote-source cache key
id: sources
run: node ./bin/duxt-cache-key.mjs --root www --github >> "$GITHUB_OUTPUT"
run: node ./packages/duxt/bin/duxt-cache-key.mjs --root apps/www --github >> "$GITHUB_OUTPUT"

- name: Restore the downloaded sources
if: steps.sources.outputs.cacheable == 'true'
Expand Down Expand Up @@ -158,8 +158,8 @@ jobs:

for run in $(seq 1 "$REPETITIONS"); do
for state in cold warm; do
rm -rf www/.output
if [ "$state" = cold ]; then rm -rf www/.cache/og-image; fi
rm -rf apps/www/.output
if [ "$state" = cold ]; then rm -rf apps/www/.cache/og-image; fi

started=$(date +%s%3N)
# `/usr/bin/time` for #44's "resource use where available": `%M`
Expand All @@ -172,10 +172,10 @@ jobs:
| tee build.log; then ok=true; else ok=false; fi
elapsed=$(($(date +%s%3N) - started))

node ./bin/duxt-og-cache.mjs --root www --report --github \
node ./packages/duxt/bin/duxt-og-cache.mjs --root apps/www --report --github \
--since "$started" --log build.log > og.txt

node scripts/prerender-bench.ts --measure \
node apps/www/scripts/prerender-bench.ts --measure \
--concurrency "$SETTING" --state "$state" --run "$run" \
--log build.log --og og.txt --build-ms "$elapsed" --ok "$ok" \
--max-rss-kb "$(tail -n 1 rss.txt)" --cores "$(nproc)" \
Expand All @@ -194,7 +194,7 @@ jobs:
env:
SETTING: ${{ matrix.concurrency }}
run: |
node scripts/prerender-bench.ts --verdict \
node apps/www/scripts/prerender-bench.ts --verdict \
--results "runs-$SETTING.jsonl" --baseline "$SETTING" \
>> "$GITHUB_STEP_SUMMARY"

Expand Down Expand Up @@ -251,7 +251,7 @@ jobs:
find runs -name '*.jsonl' -exec cat {} + >> all.jsonl

decide() {
node scripts/prerender-bench.ts --verdict --results all.jsonl \
node apps/www/scripts/prerender-bench.ts --verdict --results all.jsonl \
--baseline "$BASELINE" --threshold "$THRESHOLD" \
--repetitions "$REPETITIONS" "$@"
}
Expand All @@ -267,12 +267,12 @@ jobs:
retention-days: 90

# A benchmark that found a better setting has found a CODE CHANGE, and
# changing `www/nuxt.config.ts` from a workflow would land an unreviewed
# changing `apps/www/nuxt.config.ts` from a workflow would land an unreviewed
# commit off the back of a measurement. So it says so and stops.
- name: Say what the measurement asks for
if: steps.verdict.outputs.adopt == 'true'
env:
CHOSEN: ${{ steps.verdict.outputs.chosen }}
run: |
echo "::notice::Measured: prerender.concurrency should become" \
"$CHOSEN. Change www/nuxt.config.ts in a pull request."
"$CHOSEN. Change apps/www/nuxt.config.ts in a pull request."
Loading
Loading