commit 512443c84e5ccd144230a3144052bd93d09f5afe
parent e65c4ad68a33cf3935bd8f8915a1c9b53826aa5d
Author: mtmn <miro@haravara.org>
Date: Sat, 11 Apr 2026 11:44:31 +0200
chore: add favicon
Diffstat:
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