diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..76439bd --- /dev/null +++ b/.envrc @@ -0,0 +1,22 @@ +# Automatically load the Nix development shell when entering this directory +# Requires direnv: https://direnv.net/ +# +# To enable: +# 1. Install direnv +# 2. Run: direnv allow +# +# This will automatically install all required dependencies for the project. +if ! has nix_direnv_version || ! nix_direnv_version 3.1.0; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.0/direnvrc" "sha256-yMJ2OVMzrFaDPn7q8nCBZFRYpL/f0RcHzhmw/i6btJM=" +fi +use_flake + +# Reclaim stale Nix store paths in the background, at most once per week. +# nix-direnv pins the current dev shell, so only older versions are freed. +if has nix-collect-garbage; then + _gc_stamp="$PWD/.direnv/nix-gc-stamp" + if [ ! -f "$_gc_stamp" ] || [ -n "$(find "$_gc_stamp" -mtime +7 2>/dev/null)" ]; then + touch "$_gc_stamp" + (nix-collect-garbage --delete-older-than 7d >/dev/null 2>&1 &) + fi +fi diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ca60fb6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +# +# cooldown.default-days holds back any newly published version until it is at +# least N days old. This buys time for a compromised release (supply-chain +# attack) to be noticed and yanked before we pull it in. Security updates +# bypass the cooldown. It only gates Dependabot-driven updates, not a manual +# `bun update`. +# +# Nix has no Dependabot ecosystem, so flake.lock is bumped by the monthly +# update-flake.yml workflow instead. + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: "bun" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + groups: + bun: + patterns: + - "*" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 4fa2c1d..3f359f1 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -10,9 +10,12 @@ jobs: steps: - uses: actions/checkout@v4 + # Keep in step with the bun in flake.nix (via nixpkgs) and with + # `packageManager` in package.json, so a local `nix develop` shell and CI + # agree on the version that writes bun.lock. - uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.4 + bun-version: 1.3.13 - run: bun install --frozen-lockfile - run: bun run check diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml new file mode 100644 index 0000000..c25e702 --- /dev/null +++ b/.github/workflows/update-flake.yml @@ -0,0 +1,32 @@ +name: Update Flake + +permissions: + contents: write + pull-requests: write + +on: + workflow_dispatch: # Allow manual triggering + schedule: + - cron: '0 12 1 * *' # Run monthly on the 1st at noon UTC + +jobs: + update-flake: + name: Update flake.lock + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@1d87d45818068401a10cf16bdc5f00b24994a83f # main + with: + determinate: false + + - name: Update flake.lock + uses: DeterminateSystems/update-flake-lock@f21d5f4a9e57815a4941a2e7c3860f4664cb3a96 # main + with: + pr-title: "Update flake.lock" + pr-labels: | + dependencies + automated diff --git a/.gitignore b/.gitignore index 82fd71b..a20575a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,11 @@ dist/ .astro/ tsconfig.tsbuildinfo +# Nix / direnv +.direnv/ +result +result-* + # Mac shit .DS_Store diff --git a/CLAUDE.md b/CLAUDE.md index 5a09f0e..18e21ca 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,8 +41,14 @@ just fix # Auto-fix code formatting/lint issues - **Styling**: Tailwind CSS - **Build**: Vite - **Code Quality**: Biome for linting/formatting -- **Package Manager**: bun v1.3.4 +- **Package Manager**: bun v1.3.13 - **Task Runner**: just +- **Toolchain**: pinned in `flake.nix`; `nix develop` (or direnv, via `.envrc`) provides bun, node, and just + +The bun version lives in three places that must agree: `flake.nix` (via +nixpkgs), `packageManager` in `package.json`, and `bun-version` in +`.github/workflows/pr.yml`. When the monthly `update-flake.yml` PR moves +nixpkgs, move the other two to match. ### Key Components diff --git a/README.md b/README.md index b15b74a..5ec9b05 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,17 @@ Join the [Discord](https://discord.moq.dev) for updates and discussion. ## Setup -Install the dependencies with `bun`: +The toolchain (`bun`, `node`, `just`) is pinned in `flake.nix`: + +```bash +nix develop -c just dev +``` + +With [direnv](https://direnv.net/) installed, `direnv allow` loads that shell +automatically on every `cd` into the repo. + +Don't have Nix? Install `bun` and `just` yourself, matching the `bun` version in +`packageManager`. Either way, the dependencies come from `bun`: ```bash bun i diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bf64e52 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1787964612, + "narHash": "sha256-0N9nghg3nwzX6b6qc77EzjR9cu/Z+UR66FlfsCqiURs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e8be7818e19ada32105a8af937a6a473b38167ca", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d5df627 --- /dev/null +++ b/flake.nix @@ -0,0 +1,50 @@ +{ + description = "moq.dev - the blog, moq.pub, and moq.watch"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + nixpkgs, + flake-utils, + ... + }: + flake-utils.lib.eachSystem + [ + "x86_64-linux" + "aarch64-linux" + "aarch64-darwin" + ] + ( + system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + # Everything in the justfile runs through bun: astro, vite, biome, + # tsc, and wrangler are all `bun run` or `bunx`. + # + # This is the version `packageManager` and pr.yml pin to. A bare + # `bun i` on a newer bun rewrites bun.lock, which is noise in a + # diff, so the three pins are kept in step. `nix flake update` + # moving bun is the signal to move the other two. + bun + + # Astro and Vite target node, and parts of their toolchains shell + # out to it rather than to bun. + nodejs_24 + + # The task runner every recipe in the justfile is written for. + just + ]; + }; + + formatter = pkgs.nixfmt-tree; + } + ); +} diff --git a/package.json b/package.json index 6665138..6cfc7b3 100644 --- a/package.json +++ b/package.json @@ -38,5 +38,5 @@ "vite-plugin-static-copy": "^2.3.2", "wrangler": "^4.100.0" }, - "packageManager": "bun@1.3.4" + "packageManager": "bun@1.3.13" }