summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgithub/README.md26
-rw-r--r--cgithub/package.json2
-rw-r--r--cgithub/pnpm-lock.yaml29
-rw-r--r--cgithub/src/index.ts25
-rw-r--r--hostnix/elmo/Makefile2
-rw-r--r--hostnix/elmo/cgithub.nix27
-rw-r--r--hostnix/elmo/packages/cgithub/default.nix46
7 files changed, 152 insertions, 5 deletions
diff --git a/cgithub/README.md b/cgithub/README.md
index 45c94cf..135e5ce 100644
--- a/cgithub/README.md
+++ b/cgithub/README.md
@@ -1,10 +1,30 @@
cgithub is a lightweight GitHub alternative frontend. It has no bloated
-JavaScript and doesn't require API keys. It runs on Cloudflare Workers; to use
-it, deploy your own instance then replace `github.com` in your URL with your
-domain.
+JavaScript and doesn't require API keys. It can run on Cloudflare Workers or
+as a local Node server; to use it, run your own instance then replace
+`github.com` in your URL with your domain.
![Screenshot of cgithub repository page.](docs/screenshot.png)
+## Development
+
+Run the Cloudflare version locally with:
+
+```sh
+pnpm run dev
+```
+
+Run the Node server locally with:
+
+```sh
+pnpm run dev:local
+```
+
+To deploy the Worker to Cloudflare:
+
+```sh
+pnpm run deploy
+```
+
## Features
Implemented:
diff --git a/cgithub/package.json b/cgithub/package.json
index f711cf8..5bb194c 100644
--- a/cgithub/package.json
+++ b/cgithub/package.json
@@ -6,10 +6,12 @@
"type": "module",
"scripts": {
"dev": "node scripts/build.ts && wrangler dev",
+ "dev:local": "node scripts/build.ts && node src/index.ts",
"deploy": "node scripts/build.ts && wrangler deploy",
"test": "node --test --test-concurrency=4 src/app.test.ts src/scraper.test.ts"
},
"dependencies": {
+ "@hono/node-server": "^1.19.17",
"css-select": "^6.0.0",
"domhandler": "^5.0.3",
"domutils": "^3.2.2",
diff --git a/cgithub/pnpm-lock.yaml b/cgithub/pnpm-lock.yaml
index 6f4ff25..c5947cb 100644
--- a/cgithub/pnpm-lock.yaml
+++ b/cgithub/pnpm-lock.yaml
@@ -8,6 +8,9 @@ importers:
.:
dependencies:
+ '@hono/node-server':
+ specifier: ^1.19.17
+ version: 1.19.17(hono@4.11.5)
css-select:
specifier: ^6.0.0
version: 6.0.0
@@ -248,6 +251,12 @@ packages:
cpu: [x64]
os: [win32]
+ '@hono/node-server@1.19.17':
+ resolution: {integrity: sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==}
+ engines: {node: '>=18.14.1'}
+ peerDependencies:
+ hono: ^4
+
'@img/colour@1.1.0':
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
engines: {node: '>=18'}
@@ -278,89 +287,105 @@ packages:
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-arm@1.2.4':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-ppc64@1.2.4':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-riscv64@1.2.4':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.2.4':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-x64@1.2.4':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@img/sharp-linux-arm64@0.34.5':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-arm@0.34.5':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-ppc64@0.34.5':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-riscv64@0.34.5':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-s390x@0.34.5':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-x64@0.34.5':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.34.5':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@img/sharp-linuxmusl-x64@0.34.5':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@img/sharp-wasm32@0.34.5':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
@@ -679,6 +704,10 @@ snapshots:
'@esbuild/win32-x64@0.28.1':
optional: true
+ '@hono/node-server@1.19.17(hono@4.11.5)':
+ dependencies:
+ hono: 4.11.5
+
'@img/colour@1.1.0': {}
'@img/sharp-darwin-arm64@0.34.5':
diff --git a/cgithub/src/index.ts b/cgithub/src/index.ts
new file mode 100644
index 0000000..79f09d9
--- /dev/null
+++ b/cgithub/src/index.ts
@@ -0,0 +1,25 @@
+import { createAdaptorServer, serve } from "@hono/node-server";
+import { serveStatic } from "@hono/node-server/serve-static";
+import { Eta } from "eta";
+import { Hono } from "hono";
+import path from "node:path";
+import { createApp } from "./app.ts";
+
+const root = path.join(import.meta.dirname, "..");
+const eta = new Eta({ views: path.join(root, "views") });
+
+const app = new Hono();
+app.use("/static/*", serveStatic({ root: path.join(root, "public") }));
+app.route("/", createApp(eta));
+
+if (process.env.LISTEN_FDS === "1") {
+ const server = createAdaptorServer(app);
+ server.listen({ fd: 3 }, () => {
+ console.log("Server running via systemd socket activation");
+ });
+} else {
+ const port = parseInt(process.env.PORT || "3000", 10);
+ serve({ fetch: app.fetch, port }, (info) => {
+ console.log(`Server running on http://localhost:${info.port}`);
+ });
+}
diff --git a/hostnix/elmo/Makefile b/hostnix/elmo/Makefile
index 825a23e..dfe8025 100644
--- a/hostnix/elmo/Makefile
+++ b/hostnix/elmo/Makefile
@@ -1,5 +1,7 @@
push:
rsync -r --rsync-path='sudo rsync' --exclude Makefile . elmo:/etc/nixos/
+ rsync -r --delete --chown=joe:users --rsync-path='sudo rsync' \
+ --exclude node_modules --exclude .wrangler ../../cgithub/ elmo:/etc/nixos/cgithub/
switch: push
ssh elmo sudo nixos-rebuild switch
diff --git a/hostnix/elmo/cgithub.nix b/hostnix/elmo/cgithub.nix
index ec7c162..45ca323 100644
--- a/hostnix/elmo/cgithub.nix
+++ b/hostnix/elmo/cgithub.nix
@@ -1,11 +1,34 @@
-{ ... }:
+{ pkgs, ... }:
+let
+ # The Makefile copies cgithub/ next to this flake before rebuilding.
+ cgithub = pkgs.callPackage ./packages/cgithub { src = ./cgithub; };
+in
{
+ systemd.sockets.cgithub = {
+ wantedBy = [ "sockets.target" ];
+ socketConfig = {
+ ListenStream = "/run/cgithub/socket";
+ SocketGroup = "nginx";
+ SocketMode = "0660";
+ };
+ };
+
+ systemd.services.cgithub = {
+ requires = [ "cgithub.socket" ];
+ after = [ "cgithub.socket" ];
+ serviceConfig = {
+ Type = "exec";
+ DynamicUser = true;
+ ExecStart = "${cgithub}/bin/cgithub-server";
+ };
+ };
+
services.nginx.virtualHosts."fluffy-kitten.elmo.mou.fo" = {
useACMEHost = "elmo.mou.fo";
forceSSL = true;
locations."/" = {
- return = "301 https://cgithub.jmou.workers.dev$request_uri";
+ proxyPass = "http://unix:/run/cgithub/socket";
};
};
}
diff --git a/hostnix/elmo/packages/cgithub/default.nix b/hostnix/elmo/packages/cgithub/default.nix
new file mode 100644
index 0000000..12e6086
--- /dev/null
+++ b/hostnix/elmo/packages/cgithub/default.nix
@@ -0,0 +1,46 @@
+{
+ bash,
+ fetchPnpmDeps,
+ nodejs_22,
+ pnpm_11,
+ pnpmConfigHook,
+ stdenv,
+ src,
+}:
+
+let
+ pnpm = pnpm_11;
+in
+stdenv.mkDerivation (finalAttrs: {
+ pname = "cgithub";
+ version = "1.0.0";
+ inherit src;
+
+ nativeBuildInputs = [
+ nodejs_22
+ pnpmConfigHook
+ pnpm
+ ];
+
+ pnpmDeps = fetchPnpmDeps {
+ inherit (finalAttrs) pname version src;
+ inherit pnpm;
+ fetcherVersion = 4;
+ hash = "sha256-XxkTo+JeFyPEVgIJYm4/VaIAijaj4Sc0EzCCjZsu62Q=";
+ };
+
+ buildPhase = ''
+ node scripts/build.ts
+ '';
+
+ installPhase = ''
+ mkdir -p "$out/bin"
+ cp -a . "$out/"
+
+ cat > "$out/bin/cgithub-server" <<EOF
+ #!${bash}/bin/bash
+ exec ${nodejs_22}/bin/node "$out/src/index.ts" "\$@"
+ EOF
+ chmod +x "$out/bin/cgithub-server"
+ '';
+})