corpus

Log | Files | Refs | README | LICENSE

commit 512443c84e5ccd144230a3144052bd93d09f5afe
parent e65c4ad68a33cf3935bd8f8915a1c9b53826aa5d
Author: mtmn <miro@haravara.org>
Date:   Sat, 11 Apr 2026 11:44:31 +0200

chore: add favicon

Diffstat:
Aassets/favicon.ico | 0
Aassets/favicon.png | 0
Mflake.nix | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/Main.purs | 22++++++++++++++++------
4 files changed, 93 insertions(+), 25 deletions(-)

diff --git a/assets/favicon.ico b/assets/favicon.ico Binary files differ. diff --git a/assets/favicon.png b/assets/favicon.png Binary files differ. diff --git a/flake.nix b/flake.nix @@ -13,36 +13,56 @@ flake-utils.lib.eachDefaultSystem ( system: let pkgs = nixpkgs.legacyPackages.${system}; - in { - packages.default = pkgs.buildNpmPackage { + lib = pkgs.lib; + + scorpus = pkgs.buildNpmPackage { pname = "scorpus"; version = "1.0.0"; - src = pkgs.lib.cleanSource ./.; + src = self; npmDepsHash = "sha256-L+9L3RY5CNLudmQL7EZwZO8x0kQ2MKCqSsn37ZIIKWE="; - nativeBuildInputs = with pkgs; [ purescript spago esbuild makeWrapper ]; + nativeBuildInputs = with pkgs; [ + purescript + spago + esbuild + makeWrapper + python3 + pkg-config + nodejs + # Native addon build dependencies + gnumake + stdenv.cc + # DuckDB build dependencies + duckdb + # Remove duplicates + ] ++ lib.optionals stdenv.isLinux [ + # Linux-specific build tools + glibc + # Other system dependencies that might be needed + ]; - # npm install will try to download purescript/spago binaries by default. - # We want to use the ones from nixpkgs. - PURESCRIPT_DOWNLOAD_BINARY = "0"; - SPAGO_DOWNLOAD_BINARY = "0"; - - # We need to run spago build and then esbuild. - # buildNpmPackage's buildPhase runs 'npm run build' by default. - # We can override it if we want. buildPhase = '' - export HOME=$TMPDIR - # Since we are using pkgs.spago, we might need to tell it where to find packages. - # But it will still try to download them if they are not there. - # For now, let's see what happens. + export HOME="$TMPDIR" + # Node-gyp settings + export npm_config_nodedir="${pkgs.nodejs}" + export npm_config_python="${pkgs.python3}/bin/python" + # C/C++ compiler settings + export CC="${pkgs.stdenv.cc}/bin/cc" + export CXX="${pkgs.stdenv.cc}/bin/c++" + export LINK="${pkgs.stdenv.cc}/bin/cc" + # Library paths + export CFLAGS="-I${pkgs.duckdb}/include" + export LDFLAGS="-L${pkgs.duckdb}/lib" + # Enable multi-core building + export npm_config_jobs="$NIX_BUILD_CORES" + npm run build ''; installPhase = '' mkdir -p $out/lib/scorpus - cp server.js client.js package.json $out/lib/scorpus/ - cp -r node_modules $out/lib/scorpus/ + cp -r server.js client.js package.json node_modules assets $out/lib/scorpus/ mkdir -p $out/bin makeWrapper ${pkgs.nodejs}/bin/node $out/bin/scorpus-server \ @@ -50,9 +70,47 @@ --add-flags "$out/lib/scorpus/server.js" ''; }; + in { + packages.default = scorpus; + + packages.container = pkgs.dockerTools.buildLayeredImage { + name = "scorpus"; + tag = "latest"; + contents = [pkgs.nodejs pkgs.cacert]; + config = { + Cmd = ["${scorpus}/bin/scorpus-server"]; + WorkingDir = "/app"; + ExposedPorts = { + "8321/tcp" = {}; + }; + User = "1000:1000"; + Env = [ + "PORT=8321" + "DATABASE_FILE=/app/data/scorpus.db" + "NODE_ENV=production" + ]; + }; + extraCommands = '' + mkdir -p app/data + chown -R 1000:1000 app + chmod 700 app/data + ''; + }; devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ nodejs esbuild purs-tidy ]; + buildInputs = with pkgs; [ + nodejs + purescript + awscli2 + duckdb + spago + esbuild + # Native addon build dependencies + gnumake + stdenv.cc + python3 + pkg-config + ]; }; } ); diff --git a/src/Main.purs b/src/Main.purs @@ -161,6 +161,8 @@ indexHtml = <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>scorpus</title> + <link rel="icon" type="image/x-icon" href="/favicon.ico"> + <link rel="icon" type="image/png" href="/favicon.png"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Intel+One+Mono:wght@300;400;500;700&display=swap" rel="stylesheet"> @@ -373,7 +375,8 @@ handleRequest db req res = do "/proxy" -> serveProxy db url res "/cover" -> serveCover url res "/client.js" -> serveClientJs res - "/favicon.ico" -> serveFavicon res + "/favicon.ico" -> serveAsset "image/x-icon" "assets/favicon.ico" res + "/favicon.png" -> serveAsset "image/png" "assets/favicon.png" res _ -> do Log.warn $ "Path not found: " <> path serveNotFound res @@ -588,12 +591,19 @@ serveProxy db url res = do void $ writeString w UTF8 responseBody end w -serveFavicon :: Response -> Effect Unit -serveFavicon res = do - setHeader "Content-Type" "image/x-icon" (toOutgoingMessage res) +serveAsset :: String -> String -> Response -> Effect Unit +serveAsset contentType path res = do + setHeader "Content-Type" contentType (toOutgoingMessage res) setHeader "Access-Control-Allow-Origin" "*" (toOutgoingMessage res) - setStatusCode 200 res - end (toWriteable (toOutgoingMessage res)) + launchAff_ do + result <- try $ FSA.readFile path + liftEffect $ case result of + Right buf -> do + setStatusCode 200 res + let w = toWriteable (toOutgoingMessage res) + writeBuffer w (unsafeCoerce buf) + end w + Left _ -> serveNotFound res serveNotFound :: Response -> Effect Unit serveNotFound res = do