From 5b11997e743690cd1aafe51cc2f0f0621455cbc4 Mon Sep 17 00:00:00 2001 From: Grug Date: Fri, 23 Oct 2026 15:03:23 +0800 Subject: [PATCH] Stage npm releases from a release workflow, add CI, bump reallysimpledocs to 1.0.14 (#215) * Stage npm releases from a release workflow, add CI checks, bump reallysimpledocs to 1.0.14 * Announce releases on Discord only after the site deploys --------- Co-authored-by: grugbraindev <178141691+grugbraindev@users.noreply.github.com> --- .github/workflows/ci.yml | 38 ++++ .github/workflows/deploy-site.yml | 33 --- .github/workflows/discord-release.yml | 72 ------- .github/workflows/release.yml | 277 ++++++++++++++++++++++++++ CONTRIBUTING.md | 38 ++-- package.json | 2 + scripts/check.js | 65 ++++++ site/package-lock.json | 208 +------------------ site/package.json | 2 +- 9 files changed, 414 insertions(+), 321 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/deploy-site.yml delete mode 100644 .github/workflows/discord-release.yml create mode 100644 .github/workflows/release.yml create mode 100644 scripts/check.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..96758c5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - uses: actions/setup-node@v7 + with: + node-version: 24 + cache: npm + cache-dependency-path: | + package-lock.json + site/package-lock.json + + - run: npm ci + + # Package: build, check every export exists and the JS parses, list the tarball. + - run: npm run check + + # Docs site: build it and check llms.txt links to the .md exports. + - run: npm run check:site diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml deleted file mode 100644 index 71e373c..0000000 --- a/.github/workflows/deploy-site.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Deploy site on release - -# Cloudflare Workers Builds deploys the site from the `release` branch. -# Publishing a GitHub release moves `release` to the released tag. - -on: - release: - types: [published] - workflow_dispatch: - inputs: - tag: - description: Tag to deploy (for example 1.1.0) - required: true - type: string - -permissions: - contents: write - -jobs: - move-release-branch: - runs-on: ubuntu-latest - if: github.event_name == 'workflow_dispatch' || github.event.release.prerelease == false - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Point release branch at tag - env: - TAG: ${{ inputs.tag || github.event.release.tag_name }} - run: | - SHA=$(git rev-parse "refs/tags/$TAG^{commit}") - git push --force origin "$SHA:refs/heads/release" diff --git a/.github/workflows/discord-release.yml b/.github/workflows/discord-release.yml deleted file mode 100644 index 27c85a9..0000000 --- a/.github/workflows/discord-release.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Announce release on Discord - -on: - release: - types: [published] - workflow_dispatch: - inputs: - tag: - description: Release tag to announce - required: true - type: string - -permissions: - contents: read - -jobs: - announce: - runs-on: ubuntu-latest - - steps: - - name: Send Discord announcement - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - RELEASE_TAG_INPUT: ${{ inputs.tag }} - REPO: ${{ github.repository }} - GH_TOKEN: ${{ github.token }} - run: | - test -n "$DISCORD_WEBHOOK_URL" - - if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then - test -n "$RELEASE_TAG_INPUT" - curl --fail-with-body \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GH_TOKEN" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "$GITHUB_API_URL/repos/$REPO/releases/tags/$RELEASE_TAG_INPUT" \ - > release.json - else - jq '.release' "$GITHUB_EVENT_PATH" > release.json - fi - - if [ "$(jq -r '.prerelease' release.json)" = "true" ]; then - echo "Skipping prerelease." - exit 0 - fi - - jq -n \ - --arg repo "$REPO" \ - --arg name "$(jq -r '.name // ""' release.json)" \ - --arg tag "$(jq -r '.tag_name' release.json)" \ - --arg url "$(jq -r '.html_url' release.json)" \ - --arg body "$(jq -r '.body // ""' release.json)" \ - '($body | if length > 1500 then .[:1500] + "...\n\n[Read more](" + $url + ")" else . end) as $description | - { - username: "Basecoat Releases", - allowed_mentions: { parse: [] }, - embeds: [{ - title: ($repo + " " + $tag), - url: $url, - description: ((if $name != "" then "**" + $name + "**\n\n" else "" end) + $description), - color: 5793266 - }] - }' > payload.json - - curl --fail-with-body \ - --retry 3 \ - --retry-all-errors \ - --retry-delay 2 \ - -H "Content-Type: application/json" \ - -X POST \ - -d @payload.json \ - "$DISCORD_WEBHOOK_URL" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..455f59e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,277 @@ +name: Release + +# Publishing a GitHub release (not a prerelease): +# 1. publish: checks the tag is on main and matches package.json, runs the checks, +# then stages the version on npm with `npm stage publish`, using trusted publishing +# (OIDC, no token). A maintainer then approves it on npmjs.com (Staged Packages tab) +# or with `npm stage approve `, with 2FA. Until then the version is not +# installable. +# 2. deploy-site: waits until the version is live on npm (polls every 30 seconds for +# up to about 5h50m), then points the `release` branch at the tag. Cloudflare +# Workers Builds deploys basecoatui.com from `release`, so the docs never describe +# a version npm does not serve. If you approve later than that, re-run the failed +# jobs once approved (deploy-site, then announce). +# 3. announce: posts the release to Discord (DISCORD_WEBHOOK_URL secret), only after +# deploy-site succeeded: the version is on npm and `release` has moved. +# +# Running this workflow manually never publishes to npm. Pick a mode: +# deploy move `release` to the tag (redeploy or roll back the site), +# only if that version is already on npm. No Discord post. +# announce post the tag's GitHub release to Discord again. No deploy. +# deploy and announce both, announcing only if the deploy succeeded. +# +# Prereleases are ignored by every job. +# +# npm trusted publisher settings (allow `npm stage publish` only): repository +# hunvreus/basecoat, workflow release.yml, no environment. Renaming this file breaks +# publishing. + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: Release tag (for example 1.1.0). Never publishes to npm. + required: true + type: string + mode: + description: "deploy: move the site to this tag (version must be on npm). announce: post the release to Discord again. deploy and announce: both." + required: true + type: choice + default: deploy + options: + - deploy + - announce + - deploy and announce + +permissions: {} + +concurrency: + group: release + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.release.prerelease == false + permissions: + contents: read + id-token: write + env: + TAG: ${{ github.event.release.tag_name }} + steps: + - uses: actions/checkout@v7 + with: + ref: refs/tags/${{ github.event.release.tag_name }} + persist-credentials: false + fetch-depth: 0 + + - name: Check the tag is on main + run: | + git fetch --no-tags origin main + if ! git merge-base --is-ancestor HEAD FETCH_HEAD; then + echo "::error::Tag $TAG is not on main. Release from a commit on main." + exit 1 + fi + + - uses: actions/setup-node@v7 + with: + node-version: 24 + registry-url: https://registry.npmjs.org + # No dependency cache in a publishing job (cache poisoning). + package-manager-cache: false + + - name: Ensure npm supports staged publishing (>= 11.15.0) + run: | + if ! node -e 'const [a,b]=process.argv[1].split(".").map(Number);process.exit(a>11||(a===11&&b>=15)?0:1)' "$(npm --version)"; then + npm install -g npm@^11.15.0 + fi + npm --version + + - name: Check package.json version matches the tag + id: version + run: | + NAME=$(node -p 'require("./package.json").name') + VERSION=$(node -p 'require("./package.json").version') + if [ "$VERSION" != "${TAG#v}" ]; then + echo "::error::package.json version is $VERSION but the release tag is $TAG. Bump package.json and tag that commit." + exit 1 + fi + echo "name=$NAME" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Check whether this version is already on npm + id: npm + env: + NAME: ${{ steps.version.outputs.name }} + VERSION: ${{ steps.version.outputs.version }} + run: | + STATUS=$(curl -sS -o /dev/null -w '%{http_code}' "https://registry.npmjs.org/$NAME/$VERSION") + case "$STATUS" in + 200) + echo "::notice::$NAME@$VERSION is already on npm. Skipping publish." + echo "published=true" >> "$GITHUB_OUTPUT" ;; + 404) + echo "published=false" >> "$GITHUB_OUTPUT" ;; + *) + echo "::error::Unexpected HTTP $STATUS from the npm registry." + exit 1 ;; + esac + + - name: Install dependencies + if: steps.npm.outputs.published == 'false' + run: npm ci + + # Builds dist/ and templates/, checks every export exists, and lists the tarball. + # `npm stage publish` builds again through the prepack script. + - name: Run checks + if: steps.npm.outputs.published == 'false' + run: npm run check + + # Short-lived OIDC tokens cannot run `npm stage list`, so an already-staged version + # is detected from the registry's conflict error instead: staged and published + # versions share one version index, so re-staging the same version is refused. + - name: Stage on npm + if: steps.npm.outputs.published == 'false' + run: | + set +e + npm stage publish --provenance 2>&1 | tee "$RUNNER_TEMP/stage.log" + STATUS=${PIPESTATUS[0]} + set -e + if [ "$STATUS" -eq 0 ]; then + echo "::notice::Staged. Approve it on npmjs.com (Staged Packages tab) or with npm stage approve, using 2FA. The site deploys once it is live." + elif grep -Eqi 'E409|EPUBLISHCONFLICT|previously published|already (been )?(staged|published|exists)|cannot (publish|stage) over' "$RUNNER_TEMP/stage.log"; then + echo "::notice::This version is already staged or published on npm. Skipping." + else + exit "$STATUS" + fi + + deploy-site: + runs-on: ubuntu-latest + needs: publish + if: >- + always() && + (needs.publish.result == 'success' || needs.publish.result == 'skipped') && + ((github.event_name == 'release' && github.event.release.prerelease == false) || + (github.event_name == 'workflow_dispatch' && inputs.mode != 'announce')) + # GitHub-hosted jobs stop at 6 hours. The wait below gives up before that. + timeout-minutes: 355 + permissions: + contents: write + env: + TAG: ${{ inputs.tag || github.event.release.tag_name }} + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Check the tag is on main + id: tag + run: | + SHA=$(git rev-parse --verify "refs/tags/$TAG^{commit}") + if ! git merge-base --is-ancestor "$SHA" origin/main; then + echo "::error::Tag $TAG is not on main. Only tags on main can go live." + exit 1 + fi + { + echo "sha=$SHA" + echo "name=$(git show "$SHA:package.json" | jq -r .name)" + echo "version=$(git show "$SHA:package.json" | jq -r .version)" + } >> "$GITHUB_OUTPUT" + + - name: Wait until the version is live on npm + env: + NAME: ${{ steps.tag.outputs.name }} + VERSION: ${{ steps.tag.outputs.version }} + # Manual runs do not wait: the version must already be on npm. + MAX_WAIT: ${{ github.event_name == 'release' && '21000' || '0' }} + run: | + while :; do + STATUS=$(curl -sS -o /dev/null -w '%{http_code}' "https://registry.npmjs.org/$NAME/$VERSION" || echo 000) + if [ "$STATUS" = "200" ]; then + echo "$NAME@$VERSION is live on npm." + exit 0 + fi + if [ "$SECONDS" -ge "$MAX_WAIT" ]; then + if [ "$MAX_WAIT" = "0" ]; then + echo "::error::$NAME@$VERSION is not on npm (HTTP $STATUS). A manual run only deploys versions that are already published." + else + echo "::error::$NAME@$VERSION is still not live on npm after $((MAX_WAIT / 60)) minutes. Approve the staged package on npmjs.com (Staged Packages tab), then re-run this deploy-site job (Re-run failed jobs). If you rejected it, nothing needs to happen: the site was not deployed." + fi + exit 1 + fi + echo "Waiting for $NAME@$VERSION on npm (HTTP $STATUS). Approve the staged package on npmjs.com. Checking again in 30 seconds." + sleep 30 + done + + - name: Point release branch at tag + env: + SHA: ${{ steps.tag.outputs.sha }} + run: git push --force origin "$SHA:refs/heads/release" + + # Same message as the old discord-release.yml. + announce: + runs-on: ubuntu-latest + needs: deploy-site + if: >- + always() && + ((needs.deploy-site.result == 'success' && + ((github.event_name == 'release' && github.event.release.prerelease == false) || + (github.event_name == 'workflow_dispatch' && inputs.mode == 'deploy and announce'))) || + (github.event_name == 'workflow_dispatch' && inputs.mode == 'announce')) + permissions: + contents: read + steps: + - name: Send Discord announcement + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + RELEASE_TAG_INPUT: ${{ inputs.tag }} + REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} + run: | + test -n "$DISCORD_WEBHOOK_URL" + + if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then + test -n "$RELEASE_TAG_INPUT" + curl --fail-with-body \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GH_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "$GITHUB_API_URL/repos/$REPO/releases/tags/$RELEASE_TAG_INPUT" \ + > release.json + else + jq '.release' "$GITHUB_EVENT_PATH" > release.json + fi + + if [ "$(jq -r '.prerelease' release.json)" = "true" ]; then + echo "Skipping prerelease." + exit 0 + fi + + jq -n \ + --arg repo "$REPO" \ + --arg name "$(jq -r '.name // ""' release.json)" \ + --arg tag "$(jq -r '.tag_name' release.json)" \ + --arg url "$(jq -r '.html_url' release.json)" \ + --arg body "$(jq -r '.body // ""' release.json)" \ + '($body | if length > 1500 then .[:1500] + "...\n\n[Read more](" + $url + ")" else . end) as $description | + { + username: "Basecoat Releases", + allowed_mentions: { parse: [] }, + embeds: [{ + title: ($repo + " " + $tag), + url: $url, + description: ((if $name != "" then "**" + $name + "**\n\n" else "" end) + $description), + color: 5793266 + }] + }' > payload.json + + curl --fail-with-body \ + --retry 3 \ + --retry-all-errors \ + --retry-delay 2 \ + -H "Content-Type: application/json" \ + -X POST \ + -d @payload.json \ + "$DISCORD_WEBHOOK_URL" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f7b215..781ecd9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,13 +2,14 @@ - Support development by sponsoring the author: https://github.com/sponsors/hunvreus - Submit pull requests (PRs) against the `main` branch. -- For branches, we have: - - `main` is our production and default branch. This is what we deploy to https://basecoatui.com and publish to https://www.npmjs.com/package/basecoat-css. +- Branches: + - `main` is the default branch. All work lands here, and https://main-basecoat.hunvreus.workers.dev previews it. + - `release` is what https://basecoatui.com deploys. Only the release workflow moves it (see below). - New features are worked in `feature/name-of-the-feature` branches. - Issues are addressed in `issue/123-main-issue` branches. - When ready, open a PR against `main`. - Keep changes focused: one feature or fix per PR. -- Test locally before submitting. +- Test locally before submitting: `npm run check` (package) and `npm run check:site` (docs site). CI runs both on every PR. - Follow existing code style. ## Cloudflare Workers deploys @@ -24,19 +25,32 @@ Workers Builds settings: - Build command: `npm run docs:build` - Deploy command: `npx wrangler deploy` - Non-production branch deploy command: `npx wrangler versions upload` -- Production branch: `main` +- Production branch: `release` - Enable builds for non-production branches for branch preview URLs. -Thanks for helping! - -## Releases and the docs site +## Releasing The site at basecoatui.com deploys from the `release` branch, not `main`, so the docs always match the version on npm. Nobody commits to `release` directly. -To release: +To cut a release: -1. Bump the version in `package.json`, commit, tag (for example `1.1.0`) and push. -2. Run `npm publish`. -3. Publish a GitHub release for the tag, for example `gh release create 1.1.0 --generate-notes`. +1. Bump the version on `main`: `npm version 1.1.0 --no-git-tag-version`, then commit (for example "Prepare 1.1.0 release") and push. +2. Tag that commit with the same version, with no `v` prefix, and push: `git tag 1.1.0 && git push origin 1.1.0`. +3. Publish a GitHub release for the tag: `gh release create 1.1.0 --generate-notes --latest --verify-tag`. +4. Approve the staged version on npmjs.com, in the package's Staged Packages tab, or with `npm stage approve `. Both ask for 2FA. -Publishing the release runs `.github/workflows/deploy-site.yml`, which points `release` at the tag. Cloudflare then builds and deploys the site. To redeploy or roll back, run that workflow manually with the tag you want live. +Publishing the release runs `.github/workflows/release.yml`: + +- **publish** checks that the tag is on `main` and matches the version in `package.json`, runs `npm run check`, and stages the version on npm with `npm stage publish`, using trusted publishing. A staged version is not installable until a maintainer approves it. If the version is already staged or published, this step is skipped. +- **deploy-site** waits until the version is live on npm, then points `release` at the tag, and Cloudflare builds and deploys the site. It checks every 30 seconds for up to about 5h50m. If you approve later than that, the job fails with a message: after approving, use Re-run failed jobs on that run, which re-runs deploy-site and then announce. If staging fails or you reject the version, the site is not deployed. +- **announce** posts the release notes to Discord, only after deploy-site succeeded. By then the version is installable from npm and `release` has moved, so Cloudflare is building the new site (that takes a few minutes). + +Do not run `npm publish` by hand. Versions reach npm only through this workflow and your approval. The workflow needs no npm token and adds a provenance statement linking each version to the commit it was built from. Prereleases are not staged, deployed or announced. + +You can also run the Release workflow manually from the Actions tab, with a tag and a mode. A manual run never publishes to npm. + +- `deploy` (default) redeploys or rolls back the site: it moves `release` to the tag, only if that version is already on npm. It doesn't post to Discord. +- `announce` posts the tag's GitHub release to Discord again, for example after a failed post. It doesn't deploy. +- `deploy and announce` does both, and announces only if the deploy succeeded. + +Thanks for helping! diff --git a/package.json b/package.json index f5fd70d..037c1bc 100644 --- a/package.json +++ b/package.json @@ -123,6 +123,8 @@ "scripts": { "build": "node ./scripts/build.js", "prepack": "node ./scripts/build.js", + "check": "npm run build && node ./scripts/check.js && npm pack --dry-run --ignore-scripts", + "check:site": "npm run docs:build && node ./scripts/check.js site", "docs:build": "npm run build && npm --prefix site clean-install --progress=false && npm --prefix site run build", "docs:dev": "npm --prefix site run dev", "docs:preview": "npm run docs:build && npm --prefix site run preview", diff --git a/scripts/check.js b/scripts/check.js new file mode 100644 index 0000000..9a487c7 --- /dev/null +++ b/scripts/check.js @@ -0,0 +1,65 @@ +// Cheap sanity checks. Run after a build. +// node scripts/check.js package: every export target exists, JS parses +// node scripts/check.js site docs site: site/dist built, llms.txt links to .md exports +import fs from 'fs'; +import path from 'path'; +import { execFileSync } from 'child_process'; +import { fileURLToPath } from 'url'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const errors = []; + +function checkPackage() { + const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); + + for (const [key, target] of Object.entries(pkg.exports)) { + const file = path.join(root, target); + if (target.includes('*')) { + const dir = path.dirname(file.slice(0, file.indexOf('*')) + 'x'); + if (!fs.existsSync(dir) || fs.readdirSync(dir).length === 0) { + errors.push(`export "${key}": no files in ${path.relative(root, dir)}`); + } + } else if (!fs.existsSync(file) || fs.statSync(file).size === 0) { + errors.push(`export "${key}": ${target} is missing or empty`); + } + } + + const jsDir = path.join(root, 'dist', 'js'); + for (const name of fs.existsSync(jsDir) ? fs.readdirSync(jsDir) : []) { + if (!name.endsWith('.js')) continue; + try { + execFileSync(process.execPath, ['--check', path.join(jsDir, name)], { stdio: 'pipe' }); + } catch (error) { + const message = error.stderr.toString().split('\n').find((line) => /Error/.test(line)); + errors.push(`dist/js/${name} does not parse: ${message || 'syntax error'}`); + } + } +} + +function checkSite() { + const dist = path.join(root, 'site', 'dist'); + for (const file of ['index.html', 'llms.txt', 'llms-full.txt']) { + if (!fs.existsSync(path.join(dist, file))) errors.push(`site/dist/${file} is missing`); + } + const llms = path.join(dist, 'llms.txt'); + if (!fs.existsSync(llms)) return; + const links = [...fs.readFileSync(llms, 'utf8').matchAll(/^- \[[^\]]*\]\(([^)]+)\)/gm)].map((m) => m[1]); + if (links.length === 0) errors.push('site/dist/llms.txt has no links'); + for (const link of links) { + if (!link.endsWith('.md')) errors.push(`site/dist/llms.txt links to ${link}, not a .md export`); + } +} + +const target = process.argv[2] || 'package'; +if (target === 'package') checkPackage(); +else if (target === 'site') checkSite(); +else { + console.error(`Unknown target "${target}". Use "package" or "site".`); + process.exit(2); +} + +if (errors.length) { + console.error(`${target} check failed:\n- ${errors.join('\n- ')}`); + process.exit(1); +} +console.log(`${target} check passed.`); diff --git a/site/package-lock.json b/site/package-lock.json index b577476..f469c7b 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -10,7 +10,7 @@ "htmx.org": "^2.0.10", "lucide-static": "^1.17.0", "nunjucks": "^3.2.4", - "reallysimpledocs": "^1.0.12" + "reallysimpledocs": "^1.0.14" }, "devDependencies": { "astro": "^6.4.6", @@ -19,7 +19,7 @@ }, "..": { "name": "basecoat-css", - "version": "1.0.1", + "version": "1.0.2", "license": "MIT", "devDependencies": { "@tailwindcss/cli": "^4.1.17", @@ -812,7 +812,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -835,7 +834,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -858,7 +856,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -875,7 +872,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -892,7 +888,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -909,7 +904,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -926,7 +920,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -943,7 +936,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -960,7 +952,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -977,7 +968,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -994,7 +984,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1011,7 +1000,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1028,7 +1016,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1051,7 +1038,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1074,7 +1060,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1097,7 +1082,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1120,7 +1104,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1143,7 +1126,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1166,7 +1148,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1189,7 +1170,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1212,7 +1192,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { @@ -1232,7 +1211,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1252,7 +1230,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1272,7 +1249,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -2439,20 +2415,6 @@ "resolved": "..", "link": true }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/blake3-wasm": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", @@ -2466,20 +2428,6 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -2530,32 +2478,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -3160,20 +3082,6 @@ } } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/flattie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", @@ -3239,20 +3147,6 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3575,20 +3469,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-decimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", @@ -3614,31 +3494,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-hexadecimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", @@ -3682,17 +3537,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -5502,38 +5346,10 @@ "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", "license": "MIT" }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/reallysimpledocs": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/reallysimpledocs/-/reallysimpledocs-1.0.12.tgz", - "integrity": "sha512-nZIvrHdDcr2TImpT3TlhjLb3420xikeyXUqOuuvfosuEPgbfTYvnfg9MpgLvOciQLCjsuSGdpQzNrdW5MTVurQ==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/reallysimpledocs/-/reallysimpledocs-1.0.14.tgz", + "integrity": "sha512-TRiCxZZ3j6+AacD3HzeYr1+6soUdJN3ZkNtrdYON2OtiqlLc5qb0GHV1c4k+49l9z4/20FQ0qGH2r0YXoWwOQg==", "license": "MIT", "dependencies": { "@astrojs/markdown-remark": "^7.2.0", @@ -6231,20 +6047,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", diff --git a/site/package.json b/site/package.json index ca7fb1b..a8ec25e 100644 --- a/site/package.json +++ b/site/package.json @@ -15,7 +15,7 @@ "htmx.org": "^2.0.10", "lucide-static": "^1.17.0", "nunjucks": "^3.2.4", - "reallysimpledocs": "^1.0.12" + "reallysimpledocs": "^1.0.14" }, "devDependencies": { "astro": "^6.4.6",