Skip to content

Provider Ping

Source catalog · Knowledge graph

Facts

FactValue
Statusdormant
Hosting platformvps
Repositoryhttps://github.com/meta4m/provider-ping
Tech stacklanguage: typescript, framework: nextjs, ui: react, styling: tailwindcss, ui_kit: shadcn-ui, animation: framer-motion, data_fetching: tanstack-query, validation: zod, crypto: libsodium, auth: jose, charts: recharts, package_manager: pnpm, containerization: docker
Tagsllm, monitoring, self-hosted, uptime, status-dashboard, encryption
Last audited2026-09-15
Upstream dependenciesNone declared
Downstream dependenciesNone declared

Secrets manifest

Key names and metadata only. Encrypted records are available in this project’s vault below.

No secrets declared in this project’s manifest.

Overview

Project Overview: Provider Ping

1. Executive Summary

  • Mission: Single-admin, self-hosted dashboard for monitoring LLM/inference provider uptime and surface area — scheduled pings against provider health endpoints with green/red status, latency sparklines, 24-hour uptime %, live model lists, and balance/credits, all with no external services (no Postgres, no Redis, no cloud account).
  • Target Audience: Solo operators self-hosting on a single VPS or home server who run workloads across multiple LLM providers and want one pane of glass for provider health, latency, and quota surface.
  • Primary Maintainer: The operator (meta4m) — solo developer; v1 was built end-to-end by the MiniMax M3 model inside FreeBuff per the README preface, with issues routed to iullah@gmail.com.

2. Current Status & Roadmap

  • Lifecycle State: dormant — v1.0.0 “initial public release” plus SECURITY.md landed 2026-07-05 (3 commits total, 2026-07-04 → 2026-07-05) with no activity in the ~10 weeks since the audit.
  • Ongoing work: none visible. docs/HANDOFF.md (same date) records unresolved issues — an app “stuck at login” investigation, pre-existing tsc errors in auto-ping-control.tsx, no /api/health endpoint, no regression test for the secrets race — and the README defers chat-test streaming, >24 h history graphs, webhooks, auto-derived kinds, and multi-user to a v2 that has not started.

3. Core Capabilities

  • 15+ prebuilt providers seeded in data/seed.json (OpenAI, Groq, Mistral, Together, OpenRouter, DeepSeek, Cohere, xAI, Fireworks, Perplexity, Anthropic, Google Gemini, Replicate, Ollama, vLLM) plus a custom OpenAI-compat slot; host auto-detected from the Base URL.
  • Scheduled + manual pings: 60 s dashboard auto-ping, a Ping all sweep, and a server-side cron scheduler booted by instrumentation.ts (pause/config endpoints under /api/ping-scheduler/*); every ping appended to data/pings/<id>.jsonl.
  • Status UI (components/dashboard/): animated status dots with last HTTP status and latency, 30-ping sparklines, 24 h uptime %, model-kind pills, provider cards/rows.
  • Models + balance surfaces: live per-provider model lists (Gemini supportedMethods, Ollama parameter sizes, OpenRouter context windows) and balance/credits for OpenAI, OpenRouter, Together, Replicate.
  • Encrypted at rest: provider API keys sealed with libsodium XChaCha20-Poly1305 (secretbox) over providers.json with a per-install salt; list views expose only an 8-hex BLAKE2b fingerprint, and the full key leaves the server only via the authenticated reveal-key endpoint.
  • Single-admin auth: first-run /setup flow, scrypt-hashed password (OWASP 2024 params) in data/secrets.json (chmod 600), jose JWT in an HttpOnly cookie; Edge middleware does a presence-only cookie check with real verification on Node.
  • Docker-friendly: multi-stage non-root image (uid 1001) with a /login healthcheck and a compose file persisting to the pp-data volume.

4. Key References

  • Repository: meta4m/provider-ping
  • Production URL: none evidenced — the product is deliberately self-hosted (VPS/home server via pnpm start or Docker); no deployed instance is referenced anywhere in the repo.
  • Architecture Docs: architecture.md · Deployment Guide: deployment.md

Architecture

Architecture & System Design: Provider Ping

1. System Topology

graph TD
Admin[Admin browser] --> MW["middleware.ts<br/>Edge: cookie presence check"]
MW --> Pages["Next.js App Router<br/>/setup · /login · dashboard"]
Pages --> API["API routes: auth, providers CRUD,<br/>ping / models / balance / reveal-key, ping-scheduler"]
API --> Sched["lib/server-scheduler.ts<br/>cron sweep booted by instrumentation.ts"]
API --> Reg["lib/providers/registry.ts<br/>Anthropic · Gemini · Replicate · Ollama · OpenAICompat"]
Sched --> Reg
Reg --> Up["15+ external provider APIs<br/>incl. local Ollama / vLLM"]
API --> Store["lib/storage.ts<br/>encrypted providers.json + pings/*.jsonl"]
Store --> Sec["lib/secrets-store.ts<br/>data/secrets.json"]

2. Core Components & Subsystems

  • App Router UI (app/, components/): dashboard page with provider cards/rows, status dots, sparklines; /setup and /login flows; TanStack Query polling wrapper; Framer Motion animations; shadcn/ui + Tailwind v4.
  • API layer (app/api/): auth/{login,logout,setup}, providers CRUD (/api/providers, /api/providers/[id]), per-provider ping/models/balance/reveal-key, providers/ping-all, ping-scheduler/{status,pause,config}, and a feature-flag-gated /api/chat placeholder that 404s in v1.
  • Provider registry (lib/providers/): bespoke classes for the four non-OpenAI shapes (Anthropic, Gemini, Replicate, Ollama) and an OpenAICompatProvider fallback for everything else; lib/provider-detect.ts auto-detects the host and derives default model kinds from the Base URL.
  • Storage layer (lib/storage.ts): encrypted providers.json (XChaCha20-Poly1305, key derived from APP_SECRET via scrypt + per-install salt), an in-memory ping ring buffer on globalThis (1500 pings ≈ 25 h), and JSONL append per ping for >24 h trends.
  • Auth & secrets (lib/auth.ts vs lib/auth.server.ts, lib/secrets-store.ts, instrumentation.ts): scrypt password verifier + jose JWT session cookie; boot hook loads secrets.json into an in-memory cache so nothing reads process.env.APP_SECRET after first boot.
  • Server scheduler (lib/server-scheduler.ts): HMR-safe singleton on globalThis, paused/setIntervalSeconds controls, bounded-concurrency sweeps (PING_CONCURRENCY).

3. Data Flow & Storage Contracts

  • No database — DATA_DIR (default ./data in dev, /app/data in Docker) is the entire state: providers.json (encrypted provider records + salt, gitignored), secrets.json (APP_SECRET + scrypt adminHash, chmod 600, gitignored), pings/<id>.jsonl (append-only ping log, gitignored), and seed.json (bootstrap list, committed).
  • Secrets deliberately stay out of env: APP_SECRET is read from process.env exactly once at first boot as an optional override, then persisted to secrets.json; ADMIN_PASSWORD is only read by the offline scripts/admin-set-password.mjs pre-hash helper — the app never reads either at runtime.
  • Provider API keys: entered via the dashboard, stored encrypted at rest, decrypted only server-side for outbound pings; list endpoints expose only the BLAKE2b fingerprint, with plaintext retrieval solely through the authenticated reveal-key route.
  • Ping history: 24 h uptime is derived from the in-memory ring buffer (rebuilt on restart from the next sweep); the on-disk JSONL holds the full history for the planned v2 time-series UI.

4. Architectural Decision Records (ADRs)

ADR-01: Zero-dependency file storage over any database
  • Context: Single-admin, self-hosted, “no external services” is a stated product requirement.
  • Decision: All state lives in DATA_DIR JSON files; encryption at rest replaces a secrets manager.
  • Consequences: One process / one admin by design; backup = copy the directory; no horizontal scaling or multi-instance safety.
ADR-02: APP_SECRET lives in secrets.json, not process.env
  • Context: A Next.js worker-pool race meant cold workers didn’t see process.env.APP_SECRET, causing 500s and an Edge-lockout loop (documented in docs/HANDOFF.md).
  • Decision: instrumentation.ts loads secrets.json into an in-memory cache at boot; the Edge middleware is presence-only and JWT verification happens on Node.
  • Consequences: The cold-worker race is closed; rotating APP_SECRET effectively resets the install because ciphertexts are bound to secret + salt.
ADR-03: Edge/Node code split via the .server.ts convention
  • Context: middleware.ts runs on the Edge runtime and must never transitively import node:fs/node:crypto.
  • Decision: lib/auth.ts (jose-only, Edge-safe) vs lib/auth.server.ts (Node-only session/password helpers); accidental Edge import fails the build rather than crashing at runtime.
  • Consequences: Runtime isolation is enforced by the bundler; auth verification stays on Node where the secrets cache lives, at the cost of a presence-only Edge gate.
ADR-04: Registry pattern with an OpenAI-compat fallback
  • Context: 15+ target providers, most OpenAI-compatible, four with bespoke API shapes.
  • Decision: registry.ts special-cases Anthropic/Gemini/Replicate/Ollama; everything else routes through OpenAICompatProvider.
  • Consequences: New OpenAI-shaped providers need only a seed entry; non-standard providers each require a dedicated class.

Deployment

Deployment & Operational Runbook: Provider Ping

1. Hosting & Environments

EnvironmentPlatformURL / EndpointAuto-Deploy Branch
Self-hosted productionSingle VPS / home server — Node process or Docker Composenone evidenced in the repo (no deployed instance referenced)none — no CI/CD workflows exist
Local devNext.js dev serverhttp://localhost:3000 (auto-redirects to /setup on first run)N/A

The repo contains no .github/ workflows and no Vercel/Cloudflare configuration; deployment is entirely manual, by design.

2. Prerequisites & Toolchain

  • Node.js ≥ 22, pnpm ≥ 9 (corepack enable pins the version), Git.
  • Docker ≥ 24 with Compose v2 for the container route (image is node:22-alpine, installs curl for the healthcheck).

3. Local Development Setup

Terminal window
git clone https://github.com/meta4m/provider-ping.git
cd provider-ping
corepack enable
pnpm install
pnpm dev # → http://localhost:3000, redirects to /setup

First run auto-generates a 32-byte APP_SECRET into data/secrets.json (chmod 600) and asks for the admin password. Note: the README’s cp .env.example .env step references a .env.example that is absent from the repo — every env var is optional with defaults, so this is cosmetic (for Docker, touch .env satisfies the compose env_file).

4. Environment & Secrets Provisioning

Refer to spec.yml — the secrets manifest is empty. No secrets required.

  • APP_SECRET and the admin password are self-managed: the first boot generates APP_SECRET (a process.env.APP_SECRET override is honored once, then persisted), the password is set via /setup, and provider API keys are entered in the UI and stored encrypted at rest.
  • Nothing to retrieve from the 2Brain vault for this project.
  • Optional runtime knobs (all defaulted in lib/env.ts): DATA_DIR, PORT, LOG_LEVEL, AUTO_REFRESH_SECONDS, PING_CONCURRENCY, PING_TIMEOUT_MS, PING_DEFAULT_INTERVAL_SECONDS, SERVER_SCHEDULER_ENABLED, ENABLE_CHAT_TEST.

5. Deployment Commands

Terminal window
# Option A — Node process (pair with pm2 / systemd / runit per README)
pnpm install --frozen-lockfile
pnpm build
pnpm start
# Option B — Docker (non-root uid 1001, /login healthcheck, pp-data volume)
touch .env # compose env_file requires the file; all vars optional
docker compose up -d --build

6. Verification & Health Checks

  • Container healthcheck: curl -fsS http://localhost:3000/login every 30 s (both the Dockerfile HEALTHCHECK and docker-compose.yml).
  • Known gap (flagged in docs/HANDOFF.md): there is no /api/health endpoint — process liveness is the only automated signal.
  • Smoke test: log in → add a provider → Ping all → check status dot, sparkline, and the Models pill; pnpm lint for code health (HANDOFF records pre-existing tsc errors in auto-ping-control.tsx).

7. Incident Response & Rollback

  • Rollback: redeploy the previous revision — git checkout <good-sha> && pnpm build && pnpm start — or docker compose down and re-run the prior image.
  • Locked out / corrupted auth: rm data/secrets.json → next boot re-offers /setup; rm data/providers.json data/secrets.json wipes everything and re-seeds from data/seed.json.
  • Pre-hash a known admin password (backup/restore path): node scripts/admin-set-password.mjs (reads ADMIN_PASSWORD from env) prints a scrypt verifier to paste into data/secrets.json under adminHash with chmod 600.
  • Suspected key exposure: rotate at the upstream provider and re-enter the key in the UI; on-disk ciphertexts are bound to the install salt + APP_SECRET, so rotating the secret effectively resets the store.
  • Stuck at login (known open issue in docs/HANDOFF.md): restart the dev server first; the Edge/Node secrets race was redesigned around it, but no regression test exists yet.

Project vault

Cloudflare Access authorization and your passphrase are required to retrieve and decrypt stored values.

Client-Side Encrypted Secret Vault

Zero-knowledge architecture. Secrets are encrypted client-side using Web Crypto AES-256-GCM before leaving this browser tab. Edge databases store only ciphertext, IV, and salt.

Encrypted Records for provider-ping (0)

Encrypted records have not been loaded.

Add / Rotate Encrypted Secret