API service that connects your GitHub account to a single set of endpoints: aggregated dependency data from all your repos, a browsable file tree (VFS) across those repos, and repo metadata (READMEs, languages, stars, deployments, npm package info). Use it for dashboards, portfolios, or tooling that needs repo and package data in one place.
bun run dev– watch mode forsrc/index.tsbun start– run the serverbun test– test suitebun lint– Biome lintbun format– Biome formatterbun x tsc --noEmit– type-check
GET /– HTML links (browser) or JSON linksGET /health– health probeGET /docs– OpenAPI docs
GET /package.json?version=max|min|minmaxPOST /package.json/refresh?version=max|min|minmax– refreshes cache, then redirects toGET /package.json?...
GET /files– nested object tree of repo directories + GitHub file linksGET /files?format=terminal– terminal-friendlyFileSystemItemtree:- root:
~ - children:
github,projects - same file tree, just wrapped in a typed terminal-friendly shape
- root:
POST /files/refresh– refreshes files cache, then redirects toGET /filesGET /files/*– traverse directories/files in the VFS; files return GitHub links by defaultGET /files/*?content=true– fetch exact file contents on demand for that one file path
GET /repos- query:
type,q,include,fields,sort,limit,offset - Default include: when
includeis omitted, responses include full enrichment:readme,languages,deployments,npm,deployment-links. Useinclude=readme(etc.) to request only specific fields. - Search:
qfilters repos by substring match (case-insensitive) inname,full_name,description,topics, and README body. - List responses are cached server-side by query (5 min); responses also send
Cache-ControlandETagfor client/HTTP caching.
- query:
GET /repos/:owner/:repo– whenincludeis omitted, uses the same full default set as the list.GET /repos/:owner/:repo/readmeGET /repos/:owner/:repo/languagesGET /repos/:owner/:repo/deploymentsGET /repos/:owner/:repo/npmGET /repos/:owner/:repo/deployment-links
- Deployments are resolved with fallback:
- GitHub deployments
- If none, external matches (Vercel/Netlify/Render) by exact repo URL match
- npm package lookup is exact and uses only root
package.jsonname.
PORT(default3000)NODE_ENV(defaultdevelopment)API_KEYS(comma-separated accepted API keys)API_KEY_REQUIRED(defaulttruein production,falseotherwise)API_KEY_ALLOW_X_HEADER(defaulttrue; allowsx-api-keyfallback)TRUST_PROXY_HEADERS(defaultfalse; trustx-forwarded-forfamily only behind trusted ingress)RATE_LIMIT_ENABLED(defaulttruein production,falseotherwise)RATE_LIMIT_MAX(default120)RATE_LIMIT_WINDOW_MS(default60000)RATE_LIMIT_HEADERS(defaulttrue)USERNAMEGITHUB_TOKENNETLIFY_TOKEN,VERCEL_TOKEN,RENDER_TOKEN(optional fallback sources)CORS_ORIGIN(default*; comma-separated allowlist supported)CORS_METHODS(defaultGET,POST,PUT,PATCH,DELETE,OPTIONS)CORS_HEADERS(defaultContent-Type,Authorization,Accept)CORS_EXPOSE_HEADERS(optional)CORS_ALLOW_CREDENTIALS(defaultfalse)CORS_MAX_AGE(default86400)USE_LOCAL_DATA(optional) – if true,/filesreads the file tree snapshot fromdata.json(e.g. prebuilt or cached)SAVE_FILE(optional) – if true, the generated/filestree snapshot is persisted todata.jsonREPOS_ALLOW_PRIVATE(optional, defaultfalse) – if false,GET /repos?type=privateandtype=allreturn 403, and aggregated/package.jsonuses public repos only; set totrueto allow listing private reposDATA_JSON_PATHdefaults to<repo>/data.json
@elysiajs/openapifor/docs@elysiajs/staticfor static assets@elysiajs/corsfor CORS/preflight handling@elysiajs/bearerforAuthorization: BearerAPI-key extractionelysia-rate-limitfor request throttling on API routes- Cache is intentionally custom (
src/cache.ts) because we need TTL + development persistence intodata.json.cache.
- Protected API prefixes:
/package.json,/files,/repos - Public routes:
/,/health,/docs, static assets - Send API key using:
Authorization: Bearer <key>(primary)x-api-key: <key>(optional fallback, controlled by env)
- If
API_KEY_REQUIRED=trueandAPI_KEYSis empty, the server fails fast at startup. OPTIONSpreflight requests bypass API-key auth so browser CORS preflight is never blocked.- Rate limit key is
pathname + client IPand only applies to protected API prefixes. - Browser note: API keys in React/browser clients are visible to users, so treat them as client identifiers, not secrets.
- Backend note: API keys are appropriate for server-to-server clients because secrets remain on the server side.
- Memory cache is always primary (process-local), with TTLs from
src/env.ts. - HTTP responses for core JSON endpoints include
Cache-Control+ETagand support conditional requests (If-None-Match->304). - In development (
NODE_ENV=development), generic cache is also persisted todata.json.cachefor inspection. - On restart/redeploy, memory cache is cleared; development cache can be rehydrated from
data.json.cache. - Current cache keys:
packageData-*(/package.json) – 1 weekfiles(/files) – 1 weekrepos-list:*(GET /reposby query params) – 5 mindeployment-platforms(external deployment matching) – 1 hour
data.jsonnamespaces:cache: generic cache entries (development persistence).vfs: files tree snapshot used by/files.
- Files service behavior:
USE_LOCAL_DATA=true: read VFS snapshot fromdata.json.vfs.SAVE_FILE=true: write fetched VFS snapshot todata.json.vfs.
bun installbun run dev- Open http://localhost:3000
- Check docs at http://localhost:3000/docs
- Quick API checks:
curl -H "Accept: application/json" http://localhost:3000/filescurl -H "Accept: application/json" "http://localhost:3000/files?format=terminal"curl -H "Accept: application/json" http://localhost:3000/repos(full list with default enrichment)curl -H "Accept: application/json" "http://localhost:3000/repos?q=nebula"(search)