diff --git a/.assetsignore b/.assetsignore new file mode 100644 index 0000000..fe213fd --- /dev/null +++ b/.assetsignore @@ -0,0 +1,18 @@ +# Files that must not be served as part of the docs site. +# +# `mint export` copies repo files into the export and adds its own +# local-serving helpers, so without this they end up published: +# serve.js, Start Docs.* Mintlify's double-click-to-serve helpers +# justfile, scripts/ copied out of this repo by the exporter +# LICENSE, README.md repo files, not site content +# +# This file is committed at the repo root and copied into dist/ by +# `just export`, because dist/ is regenerated on every build. +serve.js +Start Docs.bat +Start Docs.command +justfile +scripts +LICENSE +README.md +.assetsignore diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 67f139b..2aab5f4 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -43,6 +43,16 @@ jobs: key: cache-lychee-${{ github.sha }} restore-keys: cache-lychee- + # External links only (--scheme): internal links and anchors are covered by + # `npm run check` above, and extensionless Mintlify paths are not files. + # `--base .` is rejected by current lychee (base must be a URL or absolute + # path); --root-dir resolves root-relative links instead. + # dash.cloudflare.com bot-blocks CI with 403 — excluded rather than accepting + # 403 globally, which would mask genuinely forbidden links. + # localhost/loopback URLs are documentation examples, not live links. + # Generous timeout/retries: lychee exits non-zero on a timeout as well as a + # broken link, so a slow third-party host would otherwise block every PR. + # docs.[a-z]+.privacykey.org: no docs domain has DNS yet; drop this exclusion once they resolve - name: Run lychee uses: lycheeverse/lychee-action@v2 with: @@ -50,9 +60,18 @@ jobs: --cache --max-cache-age 1d --no-progress - --base . + --timeout 30 + --max-retries 5 + --retry-wait-time 3 + --scheme https + --scheme http + --root-dir ${{ github.workspace }} --exclude-path images --exclude-path .github + --exclude-loopback + --exclude 'localhost' + --exclude 'dash\.cloudflare\.com' + --exclude 'docs\.[a-z]+\.privacykey\.org' --accept 200,206,429 './**/*.mdx' './**/*.md' diff --git a/.gitignore b/.gitignore index e5b72bc..d9fca57 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,7 @@ Thumbs.db # Logs *.log npm-debug.log* + +# Mintlify export output (built by `just export`) +export.zip +dist/ diff --git a/README.md b/README.md index 78ab4a3..2ed7c23 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ Source for the [privacycommand](https://github.com/privacykey/privacycommand) documentation site, built with [Mintlify](https://mintlify.com). -Published at `docs.privacycommand.privacykey.org`. +Production is a Cloudflare Worker serving the static export as assets +([`wrangler.jsonc`](wrangler.jsonc)). `just deploy` builds and publishes it. +**Hostname:** `docs.privacycommand.privacykey.org` *(DNS not configured yet)* ## Local preview diff --git a/justfile b/justfile index fd5b06a..a7a122c 100644 --- a/justfile +++ b/justfile @@ -16,11 +16,9 @@ run: # Build the Mintlify static export into dist/ [group("deploy")] export: - npx --yes mint@latest export - rm -rf dist - unzip -q export.zip -d dist + npm run build # Deploy the docs site to Cloudflare [group("deploy")] deploy: export - npx --yes wrangler@latest deploy --assets dist --name docs-privacycommand --compatibility-date 2026-05-01 + npx --yes wrangler@latest deploy diff --git a/package.json b/package.json index 538465d..ccc1b02 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "dev": "npx --yes mint dev", + "build": "npx --yes mint@latest export && rm -rf dist && mkdir -p dist && (unzip -q -o export.zip -d dist || python3 -m zipfile -e export.zip dist) && cp .assetsignore dist/.assetsignore", "check": "node scripts/check-docs.mjs", "linkcheck": "lychee --base . './**/*.mdx' './**/*.md'" }, diff --git a/wrangler.jsonc b/wrangler.jsonc new file mode 100644 index 0000000..a571542 --- /dev/null +++ b/wrangler.jsonc @@ -0,0 +1,22 @@ +{ + // Static-assets-only Worker: no `main` entry point, so there is no Worker + // script — Cloudflare just serves the exported files. Asset requests are + // unmetered. + // + // `dist/` is the unpacked `mint export` output and is NOT in git. It is + // built by `npm run build`. Workers Builds has NO default build command, so + // a connected repo must set its build command to `npm run build` in the + // Cloudflare dashboard, or the deploy fails with "directory does not exist". + // `just export` and `just deploy` call the same script. + // + // The Mintlify export carries no 404.html, so not_found_handling is left at + // its default rather than pointing at a page that does not exist. + "name": "docs-privacycommand", + "compatibility_date": "2026-05-01", + "observability": { + "enabled": true + }, + "assets": { + "directory": "./dist" + } +}