Every ESI operation, typed
Domain clients cover every operation in the ESI OpenAPI specification, and spec:coverage fails the build if one goes missing. Types, cache TTLs, rate-limit groups and scopes are generated from the spec.
Using the client
A TypeScript client built as an engineered product rather than a generated wrapper. Caching, rate limiting, retry and pagination follow the rules ESI actually enforces.

npm install @lgriffin/esi.tsimport { EsiClient } from '@lgriffin/esi.ts';
const client = new EsiClient({ userAgent: 'my-app/1.0 (you@example.com)' });
try {
const status = await client.status.getStatus();
console.log(`${status.players} pilots online`);
} finally {
client.shutdown();
}For many characters over one runtime, @lgriffin/esi.ts/client gives a public view in which an authenticated call does not compile, and a view per identity:
import { createEsi, identityFromToken } from '@lgriffin/esi.ts/client';
const esi = createEsi({ userAgent: 'my-app/1.0 (you@example.com)' });
const status = await esi.public.status.get();
// An access token from your SSO flow. An EsiTokenManager's
// tokens.identity(characterId) gives a refreshing identity instead.
const characterId = 2114794365;
const wallet = await esi
.as(identityFromToken(process.env.ESI_ACCESS_TOKEN ?? ''))
.character(characterId)
.wallet.get();Construction, configuration, authentication, pagination, errors, logging and the SDE, plus the engineering charter, architecture and quality gates the project runs to.
Every runnable program in examples/, type-checked in CI; the ones that need no token run against live ESI every night.
The TypeDoc reference generated from the TSDoc in src/: every client, method, option, error and response type.
Every EARS requirement the client is held to, with the scenarios that prove it and its verdict from the release's run: searchable by domain, pattern and charter id.