{ description = "SolidHaus — Local-first household inventory app"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; flake-parts.url = "github:hercules-ci/flake-parts"; sd-card.url = "git+ssh://git@git.toph.so/toph/sd-card"; }; outputs = inputs @ { flake-parts, nixpkgs, sd-card, ... }: flake-parts.lib.mkFlake {inherit inputs;} { systems = ["x86_64-linux" "aarch64-linux"]; perSystem = { config, pkgs, system, ... }: let nodejs = pkgs.nodejs_22; buildNpmPackage = pkgs.buildNpmPackage.override { nodejs = nodejs; }; in { packages = { # Build the SvelteKit app solidhaus = buildNpmPackage { pname = "solidhaus"; version = "0.0.1"; src = ./.; npmDepsHash = "sha256-d7k2YpmFt/Ba0j0SrhgoHQdhYjxHO46BliOzyecZgbY="; buildPhase = '' npm run build ''; installPhase = '' mkdir -p $out cp -r build/* $out/ ''; meta = { description = "Local-first household inventory app with barcode scanning"; homepage = "https://git.toph.so/toph/solidhaus"; }; }; # OCI image with nginx serving the built app solidhaus-image = pkgs.dockerTools.buildLayeredImage { name = "registry.toph.so/solidhaus"; tag = "latest"; contents = with pkgs; [ fakeNss nginx ]; config = { Cmd = [ "${pkgs.nginx}/bin/nginx" "-c" "/etc/nginx/nginx.conf" "-g" "daemon off;" ]; ExposedPorts = { "80/tcp" = {}; }; WorkingDir = "/usr/share/nginx/html"; }; extraCommands = '' # Create directory structure mkdir -p var/log/nginx mkdir -p var/cache/nginx mkdir -p tmp mkdir -p etc/nginx # Copy built app mkdir -p usr/share/nginx/html cp -r ${config.packages.solidhaus}/* usr/share/nginx/html/ # Create nginx config cat > etc/nginx/nginx.conf <<'EOF' user nobody nobody; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /tmp/nginx.pid; events { worker_connections 1024; } http { include ${pkgs.nginx}/conf/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; sendfile on; keepalive_timeout 65; # Gzip compression gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss; server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # SPA fallback location / { try_files $uri $uri/ /index.html; } # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Cache static assets location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; } } } EOF ''; }; # nix run .#dev — start SvelteKit dev server with annotation proxy dev = sd-card.lib.${system}.mkDevApp { inherit pkgs; devCmd = "${nodejs}/bin/npm run dev"; devPort = 5173; # Vite default port }; default = config.packages.solidhaus; }; apps = { # Push image to registry push-solidhaus-image = { type = "app"; program = pkgs.lib.getExe (pkgs.writeShellApplication { name = "push-solidhaus-image"; runtimeInputs = [pkgs.skopeo]; text = '' image=$(nix build --no-link --print-out-paths .#solidhaus-image) skopeo copy \ --insecure-policy \ "docker-archive:$image" \ "docker://registry.toph.so/solidhaus:latest" ''; }); }; }; devShells.default = pkgs.mkShell { packages = sd-card.packages.${system}.tools # tea, jq, nodejs, playwright ++ (with pkgs; [ nodejs nodePackages.npm ]); }; }; }; }