From 781572c561eacf42373ce26a764f495deaf43cff Mon Sep 17 00:00:00 2001 From: Hunter Haugen Date: Wed, 1 Apr 2026 21:57:09 -0700 Subject: [PATCH] add flow for ebooks --- flake.nix | 3 +- hosts/liminal/configuration.nix | 2 + hosts/ruil/configuration.nix | 1 + hosts/ruil/modules/flow.nix | 52 ++++++++++++++++++++++ pkgs/flow/package.nix | 78 +++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 hosts/ruil/modules/flow.nix create mode 100644 pkgs/flow/package.nix diff --git a/flake.nix b/flake.nix index 977dc28..0b63334 100644 --- a/flake.nix +++ b/flake.nix @@ -102,6 +102,7 @@ overlay-local = final: prev: { codex = prev.callPackage ./pkgs/codex/package.nix { }; + flow = prev.callPackage ./pkgs/flow/package.nix { }; opencode = prev.callPackage ./pkgs/opencode/package.nix { }; pi-coding-agent = prev.callPackage ./pkgs/pi-coding-agent/package.nix { }; beads = @@ -179,7 +180,7 @@ inherit openclaw-flake; }; modules = [ - ({ ... }: { nixpkgs.overlays = [ overlay-unstable overlay-etherpad-fixes openclaw-flake.overlays.default ]; }) + ({ ... }: { nixpkgs.overlays = [ overlay-unstable overlay-etherpad-fixes overlay-local openclaw-flake.overlays.default ]; }) home-manager.nixosModules.home-manager ./hosts/ruil/configuration.nix sops-nix.nixosModules.sops diff --git a/hosts/liminal/configuration.nix b/hosts/liminal/configuration.nix index 8dd16cb..843436a 100644 --- a/hosts/liminal/configuration.nix +++ b/hosts/liminal/configuration.nix @@ -293,6 +293,7 @@ cmake just dtach + sox # claude voice ]; }; users.users.hunner = { @@ -408,6 +409,7 @@ dtach whois plus42 + sox # claude voice ]; }; systemd.user.services = { diff --git a/hosts/ruil/configuration.nix b/hosts/ruil/configuration.nix index b4f77cc..f421b74 100644 --- a/hosts/ruil/configuration.nix +++ b/hosts/ruil/configuration.nix @@ -5,6 +5,7 @@ ./hardware-configuration.nix ./modules/vaultwarden.nix ./modules/etherpad-lite.nix + ./modules/flow.nix ./modules/forgejo.nix (modulesPath + "/virtualisation/digital-ocean-config.nix") ]; diff --git a/hosts/ruil/modules/flow.nix b/hosts/ruil/modules/flow.nix new file mode 100644 index 0000000..ae23ceb --- /dev/null +++ b/hosts/ruil/modules/flow.nix @@ -0,0 +1,52 @@ +{ pkgs, ... }: + +let + domain = "epub.hunner.dev"; + booksDir = "/var/lib/flow/books"; + port = 3010; +in +{ + systemd.tmpfiles.rules = [ + "d /var/lib/flow 0755 root root - -" + "d ${booksDir} 0755 root root - -" + ]; + + systemd.services.flow = { + description = "Flow EPUB reader"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + DynamicUser = true; + Environment = [ + "PORT=${toString port}" + "NEXT_TELEMETRY_DISABLED=1" + "NEXT_PUBLIC_DROPBOX_CLIENT_ID=" + "DROPBOX_CLIENT_SECRET=" + ]; + ExecStart = "${pkgs.flow}/bin/flow"; + Restart = "on-failure"; + RestartSec = "5s"; + WorkingDirectory = "${pkgs.flow}/share/flow/apps/reader"; + }; + }; + + # Flow on epub.hunner.dev (Cloudflare proxy/tunnel -> nginx -> localhost:3010). + services.nginx.virtualHosts.${domain} = { + enableACME = true; + forceSSL = true; + locations."^~ /books/" = { + alias = "${booksDir}/"; + extraConfig = '' + autoindex on; + add_header Access-Control-Allow-Origin "*" always; + ''; + }; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + proxyWebsockets = true; + recommendedProxySettings = true; + }; + }; +} diff --git a/pkgs/flow/package.nix b/pkgs/flow/package.nix new file mode 100644 index 0000000..7a64bc3 --- /dev/null +++ b/pkgs/flow/package.nix @@ -0,0 +1,78 @@ +{ + lib, + stdenv, + fetchFromGitHub, + makeWrapper, + nodejs_20, + pnpm_10, +}: +stdenv.mkDerivation (finalAttrs: { + pname = "flow"; + version = "unstable-2026-03-28"; + + src = fetchFromGitHub { + owner = "pacexy"; + repo = "flow"; + rev = "36f3cc7c4581f62ff6d72b75641c674020bb1e9f"; + hash = "sha256-Bro3DrYNtBvPKCOJBZMb7EBRrAnsC/3QIdKnLvo6FJA="; + }; + + pnpmDeps = pnpm_10.fetchDeps { + inherit (finalAttrs) pname version src; + fetcherVersion = 3; + pnpm = pnpm_10; + hash = "sha256-+m5PTXjmSQcH98T3MmrBRds8JBCHiq0qmRP3JjISUAc="; + }; + + nativeBuildInputs = [ + makeWrapper + nodejs_20 + pnpm_10.configHook + ]; + + env = { + DOCKER = "1"; + NEXT_TELEMETRY_DISABLED = "1"; + }; + + postPatch = '' + # Upstream currently imports `@flow/reader/locales`, but the tsconfig path + # aliases only cover `apps/reader/src/*`, which breaks clean production + # builds from source. + sed -i '/"@flow\/reader\/\*"/a\ "@flow/reader/locales": ["apps/reader/locales/index.ts"],' tsconfig.json + ''; + + buildPhase = '' + runHook preBuild + + pnpm --offline --filter reader build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin $out/share/flow + + cp -R apps/reader/.next/standalone/. $out/share/flow/ + mkdir -p $out/share/flow/apps/reader/.next + cp -R apps/reader/.next/static $out/share/flow/apps/reader/.next/static + cp -R apps/reader/public $out/share/flow/apps/reader/public + + makeWrapper ${lib.getExe nodejs_20} $out/bin/flow \ + --add-flags $out/share/flow/apps/reader/server.js + + runHook postInstall + ''; + + meta = { + description = "Browser-based ePub reader"; + homepage = "https://github.com/pacexy/flow"; + license = lib.licenses.agpl3Only; + mainProgram = "flow"; + platforms = nodejs_20.meta.platforms; + }; + + dontCheckForBrokenSymlinks = true; +})