Read ../AGENTS.md first for shared addresses/mechanics and indexer-to-client realtime flow.
api/is the read API + WebSocket relay consumed by the client.
- Node.js
22(CI/Docker) - TypeScript
5.7.0 - Hono
4.6.0 - Drizzle ORM
0.38.0 pg8.13.0ws8.18.0
| File | Purpose |
|---|---|
src/index.ts |
Main server/routes + WebSocket upgrade (787 lines). |
src/db/client.ts |
Pool config and health check (DB_POOL_MAX, SSL, timeout). |
src/db/schema.ts |
Shared 12-table schema mirror from indexer. |
src/ws/subscriptions.ts |
PG LISTEN/NOTIFY bridge to WebSocket clients. |
src/lib/beastData.ts |
Beast metadata dictionaries for response enrichment. |
- Data REST endpoints:
/health/beasts/all/beasts/:owner/logs/beasts/stats/counts/beasts/stats/top/diplomacy/diplomacy/all/leaderboard/quest-rewards/total/adventurers/:player
- Root discovery route:
/ - WebSocket endpoint:
/ws- message types:
subscribe,unsubscribe,ping - channels:
summit,event,beast - subscribe payload:
{"type":"subscribe","channels":["summit","event","beast"]}
- message types:
Query/pagination rules agents usually need:
/beasts/all:limitdefault25, max100;offset; filtersprefix,suffix,beast_id,name,owner;sortinsummit_held_seconds|level./logs:limitdefault50, max100;offset;category,sub_category(comma-separated),player./beasts/stats/top:limitdefault25, max100;offset./diplomacy:prefixandsuffixrequired; returns HTTP400if missing.- Paginated routes return
{ data, pagination: { limit, offset, total, has_more } }.
Behavior details that affect integration:
/leaderboarddivides summed reward amounts by100000for display./beasts/stats/countsdefines alive aslast_death_timestamp < now - 86400./includes debug endpoint hints in development mode (NODE_ENV != production), but handlers are not implemented in this service file.
Indexer writes -> PostgreSQL NOTIFY (summit_update, summit_log_insert, beast_insert) -> SubscriptionHub LISTEN -> WS broadcast
- Middleware in
src/index.ts: logger, compress, CORS. - CORS is credential-enabled.
- Address normalization for owner/player queries is mandatory:
- lowercase
- 66-char
0xpadded form.
- No auth layer (public read API).
- No cache layer (responses are DB-backed).
tsconfig.json:strict: true.- Pool defaults (
src/db/client.ts):max = 15(DB_POOL_MAXoverride)connectionTimeoutMillis = 5000
- Dev:
pnpm dev(tsx watch src/index.ts) - Build:
pnpm build(tsc) - Start:
pnpm start(node dist/index.js) - Typecheck only:
pnpm exec tsc --noEmit
- Triggered by
api/**(and shared indexer/api lint gate). - Build gate:
pnpm exec tsc --noEmit->pnpm build.
Dockerfileuses multi-stage Node 22 Alpine.- Runs as non-root user.
- Healthcheck targets
:3001/health. - Graceful shutdown calls
SubscriptionHub.shutdown()onSIGINT/SIGTERM.
DATABASE_URL(required)DATABASE_SSL("true"enables SSL)DB_POOL_MAX(default15)PORT(default3001)NODE_ENV(productionhides debug entries from/response)