Compare commits

..

5 Commits

Author SHA1 Message Date
Fredrik Johansson
e146126f86 Api endpoint added /api/latency-targets
All checks were successful
Docker / build-and-push (push) Successful in 1m48s
2026-07-26 18:48:39 +02:00
Fredrik Johansson
3adf06e4e1 Add favicon
All checks were successful
Docker / build-and-push (push) Successful in 1m44s
Pulse-line mark in the status-yellow accent, on both the status page and /admin. Wires up static file serving and fixes the Dockerfile to actually ship the public/ dir into the runtime image.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-19 19:50:36 +02:00
Fredrik Johansson
957be073ab Add .dockerignore to shrink the build context sent to the daemon
All checks were successful
Docker / build-and-push (push) Successful in 1m59s
node_modules/.git/dist were being sent on every build with no
.dockerignore at all — same class of fix as goonk's recent deploy-speed
pass. Verified by building with the new file in place (adventure and
new spot-checked with a full container run + health check; the rest
share the same multi-stage Dockerfile pattern).
2026-07-16 18:48:35 +02:00
Fredrik Johansson
4174b8d59c docker issue
All checks were successful
Docker / build-and-push (push) Successful in 1m52s
2026-07-12 23:23:53 +02:00
Fredrik Johansson
0711a7f7ad Add pull_policy: always, matching wisp/keep's convention
All checks were successful
Docker / build-and-push (push) Successful in 1m51s
Missed when the admin-panel work copied wisp's docker-compose.yml
pattern. Without it, `docker compose up -d` won't re-pull a new
:latest image if a container with the old one is already running —
the host's bulk deploy script (docker compose up -d per project, no
explicit pull step) would silently leave this project stale on every
redeploy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 20:46:32 +02:00
9 changed files with 49 additions and 2 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
node_modules
**/node_modules
dist
**/dist
.git
.env
.env.example
*.log
data

View File

@@ -16,6 +16,7 @@ RUN apk add --no-cache python3 make g++
COPY package*.json ./
RUN npm install --omit=dev && apk del python3 make g++
COPY --from=build /app/dist ./dist
COPY --from=build /app/public ./public
# DATA_DIR (SQLite DB) is a mutable runtime volume — not baked into the
# image, so redeploys don't clobber host overrides / manual targets.

View File

@@ -92,6 +92,26 @@ GET /api/status
`status` is `"up"` for any response (including 4xx — the server is reachable), `"down"` for connection errors and 5xx, `"unknown"` before the first check completes.
```
GET /api/latency-targets
```
```json
{
"refreshedAt": "2026-07-26T18:00:00Z",
"targets": [
{
"key": "wisp.dev.example.com",
"name": "Wisp",
"url": "https://wisp.dev.example.com/",
"source": "npm"
}
]
}
```
`/api/latency-targets` exposes the current computed check list after include-pattern filtering plus admin overrides/manual targets, making it suitable as a source of truth for downstream probe consumers.
### Admin API
All routes below `/api/admin` (except `/auth/check`) require an `X-Admin-Password` header matching `ADMIN_PASSWORD`. Returns `503` for every route if `ADMIN_PASSWORD` is unset.

View File

@@ -2,6 +2,9 @@ services:
app:
image: ${IMAGE}
restart: unless-stopped
pull_policy: always
env_file:
- .env
ports:
- "${PORT:-3035}:3035"
environment:

4
public/favicon.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<rect width="32" height="32" rx="7" fill="#080808"/>
<path d="M6 18 L11 18 L13.5 11 L18 23 L20.5 18 L26 18" fill="none" stroke="#e8c400" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 275 B

View File

@@ -5,6 +5,7 @@ export function renderAdminPage(): string {
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>admin / status</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
:root {

View File

@@ -60,7 +60,7 @@ async function refreshNpmHosts(): Promise<void> {
}
}
function currentTargets(): CheckTarget[] {
export function currentTargets(): CheckTarget[] {
return computeTargets(rawHosts, getAllOverrides(), listManualTargets());
}

View File

@@ -1,17 +1,25 @@
import express from 'express';
import { config } from './config.js';
import { startChecker, getStore } from './checker.js';
import { startChecker, getStore, currentTargets } from './checker.js';
import { renderPage } from './page.js';
import { renderAdminPage } from './adminPage.js';
import { router as adminRouter } from './admin.js';
const app = express();
app.use(express.json());
app.use(express.static('public'));
app.get('/api/status', (_req, res) => {
res.json(getStore());
});
app.get('/api/latency-targets', (_req, res) => {
res.json({
refreshedAt: new Date().toISOString(),
targets: currentTargets(),
});
});
app.use('/api/admin', adminRouter);
app.get('/admin', (_req, res) => {

View File

@@ -34,6 +34,7 @@ export function renderPage(store: StatusStore): string {
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="60">
<title>status / goonk</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
:root {