{ inputs = { ihp.url = "github:digitallyinduced/ihp/v1.5"; nixpkgs.follows = "ihp/nixpkgs"; nixpkgs-nixos.follows = "ihp/nixpkgs-nixos"; flake-parts.follows = "ihp/flake-parts"; devenv.follows = "ihp/devenv"; systems.follows = "ihp/systems"; devenv-root = { url = "file+file:///dev/null"; flake = false; }; }; outputs = inputs@{ self, nixpkgs, nixpkgs-nixos, ihp, flake-parts, systems, ... }: flake-parts.lib.mkFlake { inherit inputs; } { systems = import systems; imports = [ ihp.flakeModules.default ]; perSystem = { pkgs, config, lib, ... }: { ihp = { appName = "inter-hub"; enable = true; projectPath = ./.; packages = with pkgs; [ tailwindcss ]; haskellPackages = p: with p; [ # Haskell dependencies go here p.ihp base wai text # ihp-mail # Email support: https://ihp.digitallyinduced.com/Guide/mail.html # ihp-datasync # Real-time DataSync # ihp-job-dashboard # Job dashboard UI # ihp-typed-sql # Type-safe SQL queries # ihp-pglistener # PostgreSQL LISTEN/NOTIFY # Phase 5: Anthropic API calls http-conduit aeson string-conversions # Phase 9: External API, crypto, SDK generation cryptohash-sha256 base16-bytestring random-bytestring yaml network-uri ]; devHaskellPackages = p: with p; [ cabal-install hlint hspec ihp-hspec ]; # Hoogle documentation server — disabled to save ~400 MB on constrained host withHoogle = false; # Disable relation type machinery for faster compilation # relationSupport = false; # Skip tests/haddock for specific packages to speed up builds # dontCheckPackages = [ "my-package" ]; # doJailbreakPackages = [ "my-package" ]; # dontHaddockPackages = [ "my-package" ]; # Production build tuning # optimizationLevel = "2"; # Default: "1", use "2" for more optimized production binaries # rtsFlags = "-A96m -N"; # GHC runtime flags for compiled binaries # Mount additional directories under /static/ in production builds # static.extraDirs = { # # Frontend = self.packages.${system}.frontend; # }; # static.makeBundling = true; # Set false if not using Makefile for CSS/JS bundling }; # OCI container image for Kubernetes deployment (Railiance01). # Build: nix build .#docker # Push: skopeo copy docker-archive:result docker://92.205.130.254:32166/coulomb/inter-hub:SHA # Uses IHP's built-in unoptimized image; binary is /bin/RunProdServer. packages.docker = config.packages.unoptimized-docker-image; # Custom configuration that will start with `devenv up` devenv.shells.default = { # Start Mailhog on local development to catch outgoing emails # services.mailhog.enable = true; # PostgreSQL extensions # services.postgres.extensions = extensions: [ extensions.postgis ]; # GHC 9.10.3 crash fix: Generated.ActualTypes uses `module M` re-export # syntax for 61 sub-modules; the resulting ActualTypes.hi exceeds GHC's # ~274 MB binary-deserialization limit (crash at position 287686318). # # pkgs is built from `import nixpkgs { overlays = devenv.shells.default.overlays; }`. # IHP adds ihp.overlays.default to this list, which sets # pkgs.ghc = haskellPackages.override { overrides = ihpOverrides }. # We extend pkgs.ghc with a mkDerivation override (lib.mkAfter ensures # we run after IHP's overlay, so prev.ghc is already IHP's package set). # For inter-hub-models: rewrite ActualTypes.hs export list from (module N) # syntax to explicit T(..) re-exports — keeps hub functional for qualified # references (Generated.ActualTypes.T) while producing compact .hi. # Generated.Types stubbed; inter-hub-lib replaces its import with direct # entity imports (sourceRoot is per-package, originals intact there). overlays = lib.mkAfter [ (final: prev: { ghc = prev.ghc.extend (hfinal: hprev: { mkDerivation = args: let drv = hprev.mkDerivation args; in if (args.pname or "") == "inter-hub-models" then drv.overrideAttrs (old: { # GHC 9.10.3 crash: `module M` re-export syntax in Generated.ActualTypes # embeds 61 full sub-interfaces into ActualTypes.hi (~287 MB), exceeding # GHC's 274 MB binary read limit. # # Fix: rewrite the hub's export list from `module M` syntax to explicit # T(..) re-exports. Explicit re-exports store only name references in # the .hi file (compact); `module M` embeds the full sub-interface. # Hub stays functional (consumers still qualify via Generated.ActualTypes), # but .hi stays small. configureFlags = (old.configureFlags or []) ++ [ "--ghc-option=-O0" "--ghc-option=-fomit-interface-pragmas" "--disable-split-sections" "--ghc-option=-j1" # GHC 9.10.3 bug: libHSghc-9.10.3-5702.a is truncated (last AR # entry Expr.o claims 517544 bytes but only 82258 remain). # GHC's internal static linker (readAr via Data.Binary.Get) panics # after all 477 modules compile when it flushes deferred symbol # loads from IHP's TH splices that transitively need the ghc pkg. # Fix: delegate TH evaluation to ghc-iserv-dyn, which uses dlopen # on libHSghc.so (intact) instead of readAr on the truncated .a. # ghc-iserv-dyn is not in ghc-with-packages/bin/, so use -pgmi # with the absolute path in the unwrapped GHC store path. "--ghc-option=-fexternal-interpreter" "--ghc-option=-pgmi" "--ghc-option=${hprev.ghc}/lib/ghc-9.10.3/bin/ghc-iserv-dyn" ]; postUnpack = (old.postUnpack or "") + '' _actual="$sourceRoot/build/Generated/ActualTypes.hs" # Rewrite hub export list: (module N, ...) → explicit names. # IHP pattern: data Foo' params = Foo {...} (primed type, unprimed ctor) # type Foo = Foo' arg1 arg2 (concrete alias, kind *) # ADTs: export T(..) to include type + ctor + fields. # type aliases: export T (no (..) — not an ADT). # type instance lines start with lowercase 'i', so don't match [A-Z]. _types=$( { awk '/^data [A-Z]|^newtype [A-Z]/{print $2"(..)"} /^type [A-Z]/{print $2}' \ "$sourceRoot/build/Generated/Enums.hs" find "$sourceRoot/build/Generated/ActualTypes" -name "*.hs" | \ sort | while IFS= read -r _m; do awk '/^data [A-Z]|^newtype [A-Z]/{print $2"(..)"} /^type [A-Z]/{print $2}' "$_m" done } | sort -u ) _exports=$(echo "$_types" | \ awk 'NR==1{printf " %s", $0; next} {printf "\n , %s", $0} END{printf "\n"}') _imports=$(awk '/^import Generated\./{print}' "$_actual") { printf 'module Generated.ActualTypes\n ( %s ) where\n' "$_exports" printf '%s\n' "$_imports" } > "$_actual.new" && mv "$_actual.new" "$_actual" ''; }) else drv; }); }) ]; # Resource limits for constrained host (2 CPU, ~3.8 GiB RAM). # -A32m: smaller minor heap (reduces GC pressure). # -M2g: hard heap ceiling (prevents OOM on large compiles). # Note: -N1 is intentionally omitted — it requires -threaded and # would break build-generated-code and similar tools. # GHC parallel module compilation is capped via -j1 in .ghci. env.GHCRTS = "-A32m -M2g"; # Custom processes that don't appear in https://devenv.sh/reference/options/ processes = { tailwind.exec = "tailwindcss -c tailwind/tailwind.config.js -i ./tailwind/app.css -o static/app.css --watch=always"; }; }; }; # Adding the new NixOS configuration for "production" # See https://ihp.digitallyinduced.com/Guide/deployment.html#deploying-with-deploytonixos for more info # Used to deploy the IHP application flake.nixosConfigurations."production" = import ./Config/nix/hosts/production/host.nix { inherit inputs; }; }; # The following configuration speeds up build times by using the devenv, cachix and digitallyinduced binary caches # You can add your own cachix cache here to speed up builds. For that uncomment the following lines and replace `CHANGE-ME` with your cachix cache name nixConfig = { extra-substituters = [ "https://devenv.cachix.org" "https://cachix.cachix.org" "https://digitallyinduced.cachix.org" # "https://CHANGE-ME.cachix.org" ]; extra-trusted-public-keys = [ "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=" "cachix.cachix.org-1:eWNHQldwUO7G2VkjpnjDbWwy4KQ/HNxht7H4SSoMckM=" "digitallyinduced.cachix.org-1:y+wQvrnxQ+PdEsCt91rmvv39qRCYzEgGQaldK26hCKE=" # "CHANGE-ME.cachix.org-1:CHANGE-ME-PUBLIC-KEY" ]; }; }