@vzn/vx-history-server
Website: https://vznjs.github.io/vx/ · source: https://github.com/vznjs/vx
A server for the task timings a vx scheduler asks for, that you host. It
keeps one row per task, already the numbers the scheduler uses (duration,
CPU cores, peak memory), and folds each CI run’s report into it: a
history, not a log. It speaks the vx-history protocol
(/v1) on three backends that answer alike:
- Bun, with a SQLite file.
- Cloudflare Workers, with D1. It fits the free plan: an upload is one statement, a row write per task; a query one read.
- Docker, the Bun server in an image.
vxHistory() (@vzn/vx-history)
points vx at it.
CI tokens
Section titled “CI tokens”Every request carries a CI job’s own OIDC token, checked by @vzn/vx-devtools,
under TRUST rules as @vzn/vx-cache-server’s:
a job writes its branch’s scope, a ref a rule protects only a job
matching the rule, and another repository is refused. A query names its
scopes in order, each its ref’s hash (no ref goes on the wire or into a
row plain): vxHistory() asks its branch’s rows, then the default
branch’s. AUDIENCE is the aud a
token must name, by default the origin the server is reached at.
On Bun
Section titled “On Bun”TRUST='[…]' bun packages/vx-history-server/src/bun.ts --db /var/lib/vx-history.sqlite --port 8080TIMING_DAYS (default 30) is how long a task’s row outlives its last
report; the first upload of each day sweeps.
With Docker
Section titled “With Docker”From the repo root:
docker build -f packages/vx-history-server/Dockerfile -t vx-history-server .docker run -p 8080:8080 -v vx-history:/data -e TRUST='[…]' vx-history-serverThe database is /data/vx-history.sqlite.
With vx’s other servers: compose.yaml
builds and runs all three (docker compose up -d).
On Cloudflare Workers
Section titled “On Cloudflare Workers”From this directory, with TRUST filled in wrangler.jsonc:
bun installbunx wrangler loginbunx wrangler deployThe same server as a fetch handler, over storage of your own
(src/index.ts):
createHistoryServer(options: ServerOptions)returns(req: Request) => Promise<Response>.ServerOptionsis{ store, authorize, timingDays?, now? }:authorizeis anAuthorizefrom@vzn/vx-devtools.sqliteStore(db: Db)is theStoreover a SQLiteDb({ all(sql, params), run(sql, params) }), as bun:sqlite and D1 are. AStorefoldsReports and readsTimings, each of aRepo({ issuer, id }, as the token names it, stored hashed) and a scope (a ref’s hash).WEIGHT(0.3) andRSS_DECAY(0.9) are the fold’s constants;MAX_UPLOAD_TIMINGS,MAX_QUERY_HASHESandMAX_QUERY_SCOPESits limits;errorJsonanswers a refusal.