@lgriffin/esi.ts 6.0.0 → 7.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -1
- package/README.md +245 -159
- package/dist/clients/AllianceClient.d.ts +2 -0
- package/dist/clients/AllianceClient.d.ts.map +1 -1
- package/dist/clients/AllianceClient.js +2 -0
- package/dist/clients/BaseEsiClient.d.ts +4 -2
- package/dist/clients/BaseEsiClient.d.ts.map +1 -1
- package/dist/clients/BaseEsiClient.js +9 -0
- package/dist/clients/ContactsClient.d.ts +6 -4
- package/dist/clients/ContactsClient.d.ts.map +1 -1
- package/dist/clients/ContactsClient.js +9 -7
- package/dist/clients/FleetClient.d.ts +2 -2
- package/dist/clients/FleetClient.d.ts.map +1 -1
- package/dist/clients/FleetClient.js +8 -2
- package/dist/clients/SovereigntyClient.d.ts +1 -1
- package/dist/clients/SovereigntyClient.d.ts.map +1 -1
- package/dist/clients/UiClient.d.ts +11 -9
- package/dist/clients/UiClient.d.ts.map +1 -1
- package/dist/clients/UiClient.js +15 -13
- package/dist/core/constants.d.ts +2 -2
- package/dist/core/constants.js +1 -1
- package/dist/core/endpoints/EndpointDefinition.d.ts +12 -4
- package/dist/core/endpoints/EndpointDefinition.d.ts.map +1 -1
- package/dist/core/endpoints/allianceEndpoints.d.ts +17 -14
- package/dist/core/endpoints/allianceEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/allianceEndpoints.js +3 -0
- package/dist/core/endpoints/assetEndpoints.d.ts +16 -0
- package/dist/core/endpoints/assetEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/assetEndpoints.js +1 -0
- package/dist/core/endpoints/characterEndpoints.d.ts +8 -0
- package/dist/core/endpoints/characterEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/characterEndpoints.js +1 -0
- package/dist/core/endpoints/cloneEndpoints.d.ts +17 -15
- package/dist/core/endpoints/cloneEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/cloneEndpoints.js +2 -0
- package/dist/core/endpoints/contactEndpoints.d.ts +11 -3
- package/dist/core/endpoints/contactEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/contactEndpoints.js +5 -3
- package/dist/core/endpoints/corporationEndpoints.d.ts +27 -0
- package/dist/core/endpoints/corporationEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/corporationEndpoints.js +7 -0
- package/dist/core/endpoints/createClient.d.ts +5 -1
- package/dist/core/endpoints/createClient.d.ts.map +1 -1
- package/dist/core/endpoints/createClient.js +74 -55
- package/dist/core/endpoints/dogmaEndpoints.d.ts +41 -38
- package/dist/core/endpoints/dogmaEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/dogmaEndpoints.js +3 -0
- package/dist/core/endpoints/esi-cache-ttls.generated.d.ts.map +1 -1
- package/dist/core/endpoints/esi-cache-ttls.generated.js +14 -7
- package/dist/core/endpoints/esi-scopes.generated.d.ts +1 -1
- package/dist/core/endpoints/esi-scopes.generated.d.ts.map +1 -1
- package/dist/core/endpoints/esi-scopes.generated.js +11 -3
- package/dist/core/endpoints/factionEndpoints.d.ts +2 -2
- package/dist/core/endpoints/fittingEndpoints.d.ts +1 -1
- package/dist/core/endpoints/freelanceJobsEndpoints.d.ts +8 -8
- package/dist/core/endpoints/mailEndpoints.d.ts +15 -0
- package/dist/core/endpoints/mailEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/mailEndpoints.js +2 -0
- package/dist/core/endpoints/marketEndpoints.d.ts +20 -0
- package/dist/core/endpoints/marketEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/marketEndpoints.js +4 -0
- package/dist/core/endpoints/metaEndpoints.d.ts +2 -0
- package/dist/core/endpoints/metaEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/metaEndpoints.js +2 -0
- package/dist/core/endpoints/piEndpoints.d.ts +4 -0
- package/dist/core/endpoints/piEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/piEndpoints.js +2 -0
- package/dist/core/endpoints/routeEndpoints.d.ts +4 -0
- package/dist/core/endpoints/routeEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/routeEndpoints.js +2 -0
- package/dist/core/endpoints/searchEndpoints.d.ts +13 -0
- package/dist/core/endpoints/searchEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/searchEndpoints.js +2 -0
- package/dist/core/endpoints/skillEndpoints.d.ts +10 -0
- package/dist/core/endpoints/skillEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/skillEndpoints.js +1 -0
- package/dist/core/endpoints/sovereigntyEndpoints.d.ts +30 -16
- package/dist/core/endpoints/sovereigntyEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/sovereigntyEndpoints.js +1 -1
- package/dist/core/endpoints/uiEndpoints.d.ts +14 -4
- package/dist/core/endpoints/uiEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/uiEndpoints.js +8 -4
- package/dist/core/endpoints/universeEndpoints.d.ts +9 -1
- package/dist/core/endpoints/universeEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/universeEndpoints.js +8 -0
- package/dist/core/endpoints/walletEndpoints.d.ts +5 -0
- package/dist/core/endpoints/walletEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/walletEndpoints.js +3 -0
- package/dist/core/endpoints/warEndpoints.d.ts +1 -0
- package/dist/core/endpoints/warEndpoints.d.ts.map +1 -1
- package/dist/core/endpoints/warEndpoints.js +1 -0
- package/dist/core/util/testHelpers.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/schemas/assets.d.ts +1 -0
- package/dist/schemas/assets.d.ts.map +1 -1
- package/dist/schemas/assets.js +1 -1
- package/dist/schemas/character.d.ts +8 -0
- package/dist/schemas/character.d.ts.map +1 -1
- package/dist/schemas/character.js +9 -1
- package/dist/schemas/corporation.d.ts +18 -0
- package/dist/schemas/corporation.d.ts.map +1 -1
- package/dist/schemas/corporation.js +15 -1
- package/dist/schemas/faction-warfare.d.ts +2 -2
- package/dist/schemas/faction-warfare.js +2 -2
- package/dist/schemas/fittings.d.ts +1 -1
- package/dist/schemas/fittings.js +1 -1
- package/dist/schemas/freelance-jobs.d.ts +8 -8
- package/dist/schemas/freelance-jobs.js +5 -5
- package/dist/schemas/mail.d.ts +14 -0
- package/dist/schemas/mail.d.ts.map +1 -1
- package/dist/schemas/mail.js +10 -1
- package/dist/schemas/market.d.ts +13 -0
- package/dist/schemas/market.d.ts.map +1 -1
- package/dist/schemas/market.js +14 -1
- package/dist/schemas/skills.d.ts +10 -0
- package/dist/schemas/skills.d.ts.map +1 -1
- package/dist/schemas/skills.js +11 -1
- package/dist/schemas/sovereignty.d.ts +28 -14
- package/dist/schemas/sovereignty.d.ts.map +1 -1
- package/dist/schemas/sovereignty.js +35 -8
- package/dist/schemas/universe.d.ts +1 -1
- package/dist/schemas/universe.js +1 -1
- package/dist/testing/TestDataFactory.d.ts +1 -0
- package/dist/testing/TestDataFactory.d.ts.map +1 -1
- package/dist/testing/TestDataFactory.js +19 -10
- package/dist/types/api-responses.d.ts +1 -0
- package/dist/types/api-responses.d.ts.map +1 -1
- package/dist/types/api-responses.js +1 -0
- package/dist/types/branded.d.ts +23 -0
- package/dist/types/branded.d.ts.map +1 -0
- package/dist/types/branded.js +6 -0
- package/dist/types/common.d.ts +10 -0
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/generated/esi-spec.generated.d.ts +655 -430
- package/dist/types/generated/esi-spec.generated.d.ts.map +1 -1
- package/dist/types/generated/esi-spec.generated.js +3 -3
- package/dist/types/generated/spec-alignment.check.d.ts +13 -0
- package/dist/types/generated/spec-alignment.check.d.ts.map +1 -0
- package/dist/types/generated/spec-alignment.check.js +14 -0
- package/dist/types/market.d.ts +2 -1
- package/dist/types/market.d.ts.map +1 -1
- package/package.json +52 -12
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,116 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [7.4.0] - 2026-07-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`withSafeMode()` on all domain clients** — mirrors existing `withMetadata()`, surfaces the `EsiResult<T>` discriminated union (`{ ok: true, data, meta } | { ok: false, error }`) without needing to call `createClient()` directly
|
|
13
|
+
- **`responseSchema` on `routeEndpoints`** — was the only endpoint file without runtime response validation; now validated with `z.looseObject({ route: z.array(z.number()) })`
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **ESLint 8 → 10 flat config migration** — replaced `.eslintrc.cjs` with `eslint.config.mjs`, switched to unified `typescript-eslint` package, dropped `eslint-plugin-prettier` (redundant with lint-staged)
|
|
18
|
+
- **jest-fetch-mock 3 → 4** — updated null-body status mocks (204/304) to use `new Response(null, ...)` per Fetch spec
|
|
19
|
+
- Updated 11 minor/patch dependencies: @commitlint/cli, @microsoft/api-extractor, @redocly/cli, @types/node, @typescript-eslint/*, eslint-plugin-sonarjs, fast-check, knip, prettier, typedoc
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- CI: aligned `codeql.yml` branch targets to `[master, main, develop]`
|
|
24
|
+
- CI: pinned `jest-coverage-comment@main` → `@v1.0.34` (supply-chain risk)
|
|
25
|
+
- CI: added schema drift and generated types freshness checks to release pipeline
|
|
26
|
+
|
|
27
|
+
### Deprecated
|
|
28
|
+
|
|
29
|
+
- `AllianceClient.getContacts()` — use `ContactsClient.getAllianceContacts()` instead
|
|
30
|
+
- `AllianceClient.getContactLabels()` — use `ContactsClient.getAllianceContactLabels()` instead
|
|
31
|
+
|
|
32
|
+
## [7.3.0] - 2026-07-14
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **`EsiResult<T>` discriminated union** and `safeMode` option for error-safe API calls
|
|
37
|
+
- **Branded ID types** (16 types) for type-safe ESI entity references
|
|
38
|
+
- **Expanded type-level tests** with tsd for error guards, endpoints, and domain types
|
|
39
|
+
- **Compile-time spec-to-Zod type alignment checks**
|
|
40
|
+
- **Schema drift detection** as a blocking CI check
|
|
41
|
+
- **Comprehensive testing gap closure** (+1233 tests)
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- Resolved three CI jobs failing with continue-on-error
|
|
46
|
+
- Normalized CRLF in API surface check
|
|
47
|
+
- Fixed schemathesis report permissions and `--url` flag
|
|
48
|
+
- Fixed API surface ordering issues
|
|
49
|
+
- Added missing `system_id` to `MarketOrderSchema` test data
|
|
50
|
+
|
|
51
|
+
## [7.2.0] - 2026-07-08
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- **Contract testing infrastructure** — deep validation of all endpoint definitions against the live ESI OpenAPI spec (`npm run contract:live`). Checks path parameter alignment, required query params, request body consistency, auth requirements, response schema coverage, HTTP methods, pagination metadata, and deprecation sync. 8 contract validation categories with known-exception tracking.
|
|
56
|
+
- **Property-based fuzz testing** with [fast-check](https://github.com/dubzzz/fast-check) — 601 tests fuzzing `validatePathParam()`, `validateQueryParam()`, `buildEndpointPath()`, and all Zod schemas with random/adversarial inputs (`npm run fuzz`)
|
|
57
|
+
- **OpenAPI spec snapshot & diff** — `npm run contract:snapshot` saves a baseline; `npm run contract:diff` detects breaking changes via [oasdiff](https://github.com/Tufin/oasdiff) (Docker)
|
|
58
|
+
- **Consumer type tests** with [tsd](https://github.com/tsdjs/tsd) — verifies public API type correctness (`npm run test:types`)
|
|
59
|
+
- **Prism mock server** — `npm run mock:esi` starts a spec-conformant ESI mock on port 4010 via [@stoplight/prism-cli](https://stoplight.io/open-source/prism)
|
|
60
|
+
- **Schemathesis fuzz runner** — `npm run fuzz:api` runs Schemathesis against the Prism mock (Docker, weekly CI)
|
|
61
|
+
- Contract and fuzz test CI jobs added to `ci.yml` quality gate
|
|
62
|
+
- Weekly spec drift detection job added to `maintenance.yml`
|
|
63
|
+
- `jest.contract.config.cjs` and `jest.fuzz.config.cjs` test configurations
|
|
64
|
+
|
|
65
|
+
### Dependencies
|
|
66
|
+
|
|
67
|
+
- Added `fast-check` (dev) — property-based testing framework
|
|
68
|
+
- Added `@stoplight/prism-cli` (dev) — OpenAPI mock server
|
|
69
|
+
- Added `tsd` (dev) — TypeScript type testing
|
|
70
|
+
|
|
71
|
+
## [7.1.0] - 2026-07-08
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- **Redocly CLI integration** — lints the live ESI OpenAPI spec for structural validity and best-practice compliance (`npm run validate:spec`). Catches spec breakage from CCP before it breaks generated types, cache TTLs, or scopes. Baseline: 0 errors, 328 warnings (all known CCP spec issues).
|
|
76
|
+
- `redocly.yaml` config with tuned rulesets for ESI — structural rules as errors, CCP spec quirks as warnings
|
|
77
|
+
- `validate:spec` npm script added to `check:all` pipeline
|
|
78
|
+
|
|
79
|
+
## [7.0.0] - 2026-07-08
|
|
80
|
+
|
|
81
|
+
### Breaking Changes
|
|
82
|
+
|
|
83
|
+
- **Swagger 2.0 → OpenAPI 3.1 migration** — all generated types, cache TTLs, scopes, and rate limit groups are now sourced from the ESI OpenAPI 3.1 spec (`/meta/openapi.json`) instead of the deprecated Swagger 2.0 spec (`/latest/swagger.json`). See [esi-issues#1490](https://github.com/esi/esi-issues/issues/1490).
|
|
84
|
+
- **Generated interface names changed** — `EsiSpec` namespace types now use OpenAPI schema names (e.g., `AllianceDetail` instead of `GetAlliancesAllianceIdOk`). These are generated types; hand-written consumer types are unchanged.
|
|
85
|
+
- **Cache TTL metadata key** — internally changed from `x-cached-seconds` to `x-cache-age`. No consumer-facing impact (cache behavior is identical).
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
|
|
89
|
+
- Single OpenAPI spec fetch instead of dual Swagger + OpenAPI fetches
|
|
90
|
+
- Updated all scripts, tests, and documentation to reference OpenAPI spec
|
|
91
|
+
- Generated types now include 161 interfaces (up from 147), 126 cache TTLs, 70 scopes
|
|
92
|
+
|
|
93
|
+
## [6.1.0] - 2026-07-07
|
|
94
|
+
|
|
95
|
+
### Added
|
|
96
|
+
|
|
97
|
+
- **Fleet wing/squad name validation** — `renameFleetWing()` and `renameFleetSquad()` now reject names exceeding ESI's 10-character limit before sending the request, with a clear error message
|
|
98
|
+
- **43 runnable example scripts** covering all 210 ESI endpoints against live Tranquility (10 new example files: character-details, corporation-details, calendar-search, loyalty-pi, faction-details, industry-mining, market-orders, universe-encyclopedia, corp-contracts-wallet, dogma-meta-sov)
|
|
99
|
+
- **3 write-operation example scripts** — `write-operations.ts` (contacts, fittings, mail, UI lifecycle), `universe-post-helpers.ts` (name resolution, affiliation), `freelance-jobs.ts` (cursor-paginated queries)
|
|
100
|
+
- Live output captured for all example scripts in `examples/output/`
|
|
101
|
+
- 3 new TDD test files and 1 new BDD feature file (81 TDD files, 40 BDD features total)
|
|
102
|
+
- 2 new fleet validation unit tests
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
|
|
106
|
+
- **Fleet test babel parse errors** — replaced TypeScript cast syntax `(result as any[]).forEach(...)` with direct index access in fleet tests (pre-existing bug unmasked by stricter transpilation)
|
|
107
|
+
- **Fleet rename test names** — test mock names shortened to respect ESI's 10-character limit (`'New Squad Name'` → `'New Squad'`)
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
|
|
111
|
+
- README rewritten with "Why ESI.ts vs. OpenAPI-generated clients" comparison, full endpoint coverage table, and updated architecture/testing references
|
|
112
|
+
- `guides/ARCHITECTURE.md`, `guides/TESTING.md`, and `TESTING.md` updated to current test counts (121 suites, 3,224 tests)
|
|
113
|
+
- Autopilot example waypoint changed from Jita to Rens
|
|
114
|
+
|
|
115
|
+
### Schemas
|
|
116
|
+
|
|
117
|
+
- Multiple Zod schema fixes discovered during live endpoint validation: added missing enum values, corrected optional fields, and adjusted types to match actual ESI responses
|
|
9
118
|
|
|
10
119
|
## [6.0.0] - 2026-07-03
|
|
11
120
|
|
package/README.md
CHANGED
|
@@ -8,17 +8,46 @@
|
|
|
8
8
|
[](https://github.com/lgriffin/ESI.ts)
|
|
9
9
|
[](https://www.npmjs.com/package/@lgriffin/esi.ts)
|
|
10
10
|
|
|
11
|
-
A
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
A production-grade TypeScript client for the [EVE Online ESI API](https://esi.evetech.net/), built on the **OpenAPI 3.1 spec**, with runtime validation, intelligent caching, and full endpoint coverage.
|
|
12
|
+
|
|
13
|
+
**v7.0.0** — Fully migrated from the deprecated Swagger 2.0 spec to OpenAPI 3.1 (`/meta/openapi.json`). All generated types, cache TTLs, scopes, and rate limit groups are now sourced from a single OpenAPI fetch. See [esi-issues#1490](https://github.com/esi/esi-issues/issues/1490) for the deprecation notice.
|
|
14
|
+
|
|
15
|
+
**208 endpoint definitions — 194 from the public ESI OpenAPI spec, plus 14 for newer EVE features (Equinox sovereignty, orbital skyhooks, mercenary dens, access lists, freelance jobs). All 206 exercisable endpoints validated against live Tranquility on 2026-07-08.**
|
|
16
|
+
|
|
17
|
+
## Why ESI.ts vs. OpenAPI-Generated Clients?
|
|
18
|
+
|
|
19
|
+
Tools like `openapi-typescript` or `openapi-generator` can produce a typed client from the ESI OpenAPI spec in minutes. They're a reasonable starting point — but they stop at type generation. ESI.ts is a purpose-built SDK that handles the problems you hit _after_ the types compile.
|
|
20
|
+
|
|
21
|
+
### What generators give you
|
|
22
|
+
|
|
23
|
+
- TypeScript interfaces from the OpenAPI spec
|
|
24
|
+
- Basic request/response typing
|
|
25
|
+
- A thin HTTP wrapper
|
|
26
|
+
|
|
27
|
+
### What ESI.ts gives you on top of that
|
|
28
|
+
|
|
29
|
+
| Capability | openapi-typescript | ESI.ts |
|
|
30
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| **Runtime response validation** | None — types are erased at compile time. If CCP changes a field, you get silent data corruption. | Every GET response is validated at runtime via [Zod](https://zod.dev/) schemas — all 173 GET endpoints have schemas. Schema mismatches throw `EsiValidationError` immediately. |
|
|
32
|
+
| **Intelligent caching** | None — you build your own. | Three-tier: spec-aware TTL (zero HTTP calls within ESI's `x-cached-seconds` window), ETag conditional GETs, stale-on-error fallback on 5xx. Write operations auto-invalidate related GET caches. |
|
|
33
|
+
| **Rate limiting** | None — you build your own. | 36 per-group token buckets extracted from the ESI spec at build time. Market requests can't starve wallet requests. Optional per-user bucketing for multi-character apps. |
|
|
34
|
+
| **Pagination** | Manual — you write the page loop. | Automatic offset pagination, cursor-based pagination (Equinox-era endpoints), and streaming `AsyncGenerator` pagination for memory-efficient processing of large datasets. |
|
|
35
|
+
| **Retry & resilience** | None. | Exponential backoff with jitter, circuit breaker (closed/open/half-open), automatic 401 token refresh with concurrent coalescing. |
|
|
36
|
+
| **Wire format correctness** | Generates from spec, but ESI's spec has inconsistencies (query params documented as body, missing required fields). | Every endpoint tested against live ESI. Wire format bugs (query params vs. body, field naming) are caught and fixed — see the contacts and UI endpoint fixes in v6.1.0. |
|
|
37
|
+
| **Batch operations** | None. | `batch()` with bounded concurrency for GET fan-out, `batchPost()` with auto-chunking for large POST payloads. |
|
|
38
|
+
| **Domain knowledge** | None — generic HTTP client. | 35 domain clients with typed methods, JSDoc documentation, and input validation (e.g., fleet wing/squad names are capped at 10 characters before hitting the API). |
|
|
39
|
+
| **Testing** | Whatever you write. | 121+ test suites, 3,800+ tests across 9 tiers including property-based fuzzing (fast-check), deep contract tests against live OpenAPI spec, and consumer type tests (tsd). 43 runnable example scripts. |
|
|
40
|
+
|
|
41
|
+
### The real problem with generated clients
|
|
42
|
+
|
|
43
|
+
The ESI OpenAPI spec is not a perfect source of truth. During live endpoint validation against the OpenAPI 3.1 spec, we discovered:
|
|
44
|
+
|
|
45
|
+
- `addContacts`, `editContacts`, and 4 UI endpoints document parameters as request body when ESI actually expects query parameters
|
|
46
|
+
- `deleteCharacterContacts` expects comma-separated contact IDs as a query param, not a JSON body
|
|
47
|
+
- Fleet wing/squad names have a 10-character limit not documented in the spec
|
|
48
|
+
- The `updateMailMetadata` endpoint uses the field name `read`, not `is_read`
|
|
49
|
+
|
|
50
|
+
A generated client faithfully reproduces these spec bugs. ESI.ts fixes them.
|
|
22
51
|
|
|
23
52
|
## Installation
|
|
24
53
|
|
|
@@ -44,7 +73,7 @@ Verify everything works:
|
|
|
44
73
|
|
|
45
74
|
```bash
|
|
46
75
|
npm run example:status # quick smoke test — checks ESI is reachable
|
|
47
|
-
npm test # run the full test suite
|
|
76
|
+
npm test # run the full test suite (121 suites, 3,224 tests)
|
|
48
77
|
```
|
|
49
78
|
|
|
50
79
|
## Quick Start
|
|
@@ -207,43 +236,74 @@ Key behaviors:
|
|
|
207
236
|
|
|
208
237
|
All clients are accessed as properties on the `EsiClient` instance. Authenticated endpoints require an access token.
|
|
209
238
|
|
|
210
|
-
| Client | Property | Auth | Examples
|
|
211
|
-
| -------------- | ---------------------- | ---- |
|
|
212
|
-
| Alliance | `client.alliance` | Some | `getAlliances()`, `getAllianceById(id)`
|
|
213
|
-
| Assets | `client.assets` | Yes | `getCharacterAssets(id)`
|
|
214
|
-
| Calendar | `client.calendar` | Yes | `
|
|
215
|
-
| Characters | `client.characters` | Some | `getCharacterPublicInfo(id)`, `getCharacterPortrait(id)`
|
|
216
|
-
| Clones | `client.clones` | Yes | `getCharacterClones(id)`
|
|
217
|
-
| Contacts | `client.contacts` | Yes | `getCharacterContacts(id)`
|
|
218
|
-
| Contracts | `client.contracts` | Yes | `getCharacterContracts(id)`
|
|
219
|
-
| Corporations | `client.corporations` | Some | `getCorporationInfo(id)`, `getCorporationMembers(id)`
|
|
220
|
-
| Dogma | `client.dogma` | No | `getDogmaAttributes()`, `
|
|
221
|
-
| Factions | `client.factions` | Some | `getFactionWarStats()`
|
|
222
|
-
| Fittings | `client.fittings` | Yes | `getFittings(id)`, `createFitting(id, body)`
|
|
223
|
-
| Fleets | `client.fleets` | Yes | `
|
|
224
|
-
| Incursions | `client.incursions` | No | `getIncursions()`
|
|
225
|
-
| Industry | `client.industry` | Some | `getCharacterIndustryJobs(id)`
|
|
226
|
-
| Insurance | `client.insurance` | No | `getInsurancePrices()`
|
|
227
|
-
| Killmails | `client.killmails` | Some | `getKillmail(id, hash)`
|
|
228
|
-
| Location | `client.location` | Yes | `getCharacterLocation(id)`
|
|
229
|
-
| Loyalty | `client.loyalty` | Yes | `getCharacterLoyaltyPoints(id)`
|
|
230
|
-
| Mail | `client.mail` | Yes | `getCharacterMail(id)`
|
|
231
|
-
| Market | `client.market` | Some | `getMarketPrices()`, `getMarketOrders(regionId)`
|
|
232
|
-
| PI | `client.pi` | Yes | `getCharacterPlanets(id)`
|
|
233
|
-
| Route | `client.route` | No | `getRoute(origin, destination)`
|
|
234
|
-
| Search | `client.search` | Some | `search(characterId, query)`
|
|
235
|
-
| Skills | `client.skills` | Yes | `getCharacterSkills(id)`
|
|
236
|
-
| Sovereignty | `client.sovereignty` | No | `getSovereigntySystems()`, `getSovereigntyMap()`
|
|
237
|
-
| Skyhooks | `client.skyhooks` | No | `getSovereigntyHubs()`, `getRaidableSkyhooks()`
|
|
238
|
-
| Mercenary | `client.mercenary` | No | `getMercenaryDens()`, `getMercenaryTacticalOperations()`
|
|
239
|
-
| Access Lists | `client.accessLists` | Yes | `getAccessList(id)`
|
|
240
|
-
| Status | `client.status` | No | `getStatus()`
|
|
241
|
-
| UI | `client.ui` | Yes | `
|
|
242
|
-
| Universe | `client.universe` | Some | `getSystemById(id)`, `getTypeById(id)`
|
|
243
|
-
| Wallet | `client.wallet` | Yes | `getCharacterWallet(id)`
|
|
244
|
-
| Wars | `client.wars` | No | `getWars()`, `getWarById(id)`
|
|
245
|
-
| Freelance Jobs | `client.freelanceJobs` | Some | `getFreelanceJobs()`, `getFreelanceJobById(id)`
|
|
246
|
-
| Meta | `client.meta` | No | `getOpenApiJson()`, `getOpenApiYaml()`
|
|
239
|
+
| Client | Property | Auth | Examples |
|
|
240
|
+
| -------------- | ---------------------- | ---- | -------------------------------------------------------------------------------- |
|
|
241
|
+
| Alliance | `client.alliance` | Some | `getAlliances()`, `getAllianceById(id)` |
|
|
242
|
+
| Assets | `client.assets` | Yes | `getCharacterAssets(id)` |
|
|
243
|
+
| Calendar | `client.calendar` | Yes | `getCalendarEvents(id)` |
|
|
244
|
+
| Characters | `client.characters` | Some | `getCharacterPublicInfo(id)`, `getCharacterPortrait(id)` |
|
|
245
|
+
| Clones | `client.clones` | Yes | `getCharacterClones(id)` |
|
|
246
|
+
| Contacts | `client.contacts` | Yes | `getCharacterContacts(id)`, `postCharacterContacts(id, standing, contactIds)` |
|
|
247
|
+
| Contracts | `client.contracts` | Yes | `getCharacterContracts(id)` |
|
|
248
|
+
| Corporations | `client.corporations` | Some | `getCorporationInfo(id)`, `getCorporationMembers(id)` |
|
|
249
|
+
| Dogma | `client.dogma` | No | `getDogmaAttributes()`, `getDynamicItemInfo(typeId, itemId)` |
|
|
250
|
+
| Factions | `client.factions` | Some | `getFactionWarStats()` |
|
|
251
|
+
| Fittings | `client.fittings` | Yes | `getFittings(id)`, `createFitting(id, body)` |
|
|
252
|
+
| Fleets | `client.fleets` | Yes | `getFleetInformation(id)`, `getFleetMembers(id)` |
|
|
253
|
+
| Incursions | `client.incursions` | No | `getIncursions()` |
|
|
254
|
+
| Industry | `client.industry` | Some | `getCharacterIndustryJobs(id)` |
|
|
255
|
+
| Insurance | `client.insurance` | No | `getInsurancePrices()` |
|
|
256
|
+
| Killmails | `client.killmails` | Some | `getKillmail(id, hash)` |
|
|
257
|
+
| Location | `client.location` | Yes | `getCharacterLocation(id)` |
|
|
258
|
+
| Loyalty | `client.loyalty` | Yes | `getCharacterLoyaltyPoints(id)` |
|
|
259
|
+
| Mail | `client.mail` | Yes | `getCharacterMail(id)`, `sendMail(id, body)` |
|
|
260
|
+
| Market | `client.market` | Some | `getMarketPrices()`, `getMarketOrders(regionId)` |
|
|
261
|
+
| PI | `client.pi` | Yes | `getCharacterPlanets(id)` |
|
|
262
|
+
| Route | `client.route` | No | `getRoute(origin, destination)` |
|
|
263
|
+
| Search | `client.search` | Some | `search(characterId, query)` |
|
|
264
|
+
| Skills | `client.skills` | Yes | `getCharacterSkills(id)` |
|
|
265
|
+
| Sovereignty | `client.sovereignty` | No | `getSovereigntySystems()`, `getSovereigntyMap()` |
|
|
266
|
+
| Skyhooks | `client.skyhooks` | No | `getSovereigntyHubs()`, `getRaidableSkyhooks()` |
|
|
267
|
+
| Mercenary | `client.mercenary` | No | `getMercenaryDens()`, `getMercenaryTacticalOperations()` |
|
|
268
|
+
| Access Lists | `client.accessLists` | Yes | `getAccessList(id)` |
|
|
269
|
+
| Status | `client.status` | No | `getStatus()` |
|
|
270
|
+
| UI | `client.ui` | Yes | `setAutopilotWaypoint(destId, addToBeginning, clear)`, `openNewMailWindow(body)` |
|
|
271
|
+
| Universe | `client.universe` | Some | `getSystemById(id)`, `getTypeById(id)` |
|
|
272
|
+
| Wallet | `client.wallet` | Yes | `getCharacterWallet(id)` |
|
|
273
|
+
| Wars | `client.wars` | No | `getWars()`, `getWarById(id)` |
|
|
274
|
+
| Freelance Jobs | `client.freelanceJobs` | Some | `getFreelanceJobs()`, `getFreelanceJobById(id)` |
|
|
275
|
+
| Meta | `client.meta` | No | `getOpenApiJson()`, `getOpenApiYaml()` |
|
|
276
|
+
|
|
277
|
+
## Runtime Response Validation
|
|
278
|
+
|
|
279
|
+
ESI.ts validates API responses at runtime using [Zod](https://zod.dev/) schemas. All GET endpoints have schemas — these are the endpoints that return data your application consumes, where a silent shape change from CCP would cause bugs. POST/PUT/DELETE mutations typically return `204 No Content` (no body to validate) or simple confirmation values, so schemas are omitted where there is nothing meaningful to validate.
|
|
280
|
+
|
|
281
|
+
Validation is **on by default**. Extra fields from ESI are preserved via `z.looseObject()` passthrough mode, so new fields added by CCP won't break your application — they flow through to your code untouched.
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
import {
|
|
285
|
+
EsiClient,
|
|
286
|
+
EsiValidationError,
|
|
287
|
+
isValidationError,
|
|
288
|
+
schemas,
|
|
289
|
+
} from '@lgriffin/esi.ts';
|
|
290
|
+
|
|
291
|
+
const client = new EsiClient();
|
|
292
|
+
|
|
293
|
+
// Validation happens automatically on every request
|
|
294
|
+
const character = await client.characters.getCharacterPublicInfo(12345);
|
|
295
|
+
|
|
296
|
+
// Disable validation globally if needed
|
|
297
|
+
const rawClient = new EsiClient({ validateResponse: false });
|
|
298
|
+
|
|
299
|
+
// Use schemas directly for your own validation
|
|
300
|
+
const result = schemas.CharacterInfoSchema.safeParse(someData);
|
|
301
|
+
if (result.success) {
|
|
302
|
+
console.log(result.data.name);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
See [guides/RUNTIME-VALIDATION.md](guides/RUNTIME-VALIDATION.md) for the full guide on schemas, error handling, and extending schemas.
|
|
247
307
|
|
|
248
308
|
## Caching
|
|
249
309
|
|
|
@@ -271,7 +331,7 @@ const uncachedClient = new EsiClient({ enableETagCache: false });
|
|
|
271
331
|
|
|
272
332
|
### Spec-Aware Cache TTLs
|
|
273
333
|
|
|
274
|
-
The library reads `x-
|
|
334
|
+
The library reads `x-cache-age` from the ESI OpenAPI spec (126 of 195 endpoints). Within the TTL window, repeated GET requests return cached data with **zero HTTP calls** — not even a conditional GET.
|
|
275
335
|
|
|
276
336
|
This layers on top of ETag caching in three tiers:
|
|
277
337
|
|
|
@@ -323,82 +383,6 @@ const allNames = await client.batchPost(
|
|
|
323
383
|
);
|
|
324
384
|
```
|
|
325
385
|
|
|
326
|
-
## Runtime Response Validation
|
|
327
|
-
|
|
328
|
-
ESI.ts validates every API response at runtime using [Zod](https://zod.dev/) schemas. If CCP changes the ESI API and the response no longer matches the expected shape, you get an immediate `EsiValidationError` instead of silent data corruption.
|
|
329
|
-
|
|
330
|
-
Validation is **on by default**. Extra fields from ESI are preserved (passthrough mode), so new fields added by CCP won't break your application.
|
|
331
|
-
|
|
332
|
-
```typescript
|
|
333
|
-
import {
|
|
334
|
-
EsiClient,
|
|
335
|
-
EsiValidationError,
|
|
336
|
-
isValidationError,
|
|
337
|
-
schemas,
|
|
338
|
-
} from '@lgriffin/esi.ts';
|
|
339
|
-
|
|
340
|
-
const client = new EsiClient();
|
|
341
|
-
|
|
342
|
-
// Validation happens automatically on every request
|
|
343
|
-
const character = await client.characters.getCharacterPublicInfo(12345);
|
|
344
|
-
|
|
345
|
-
// Disable validation globally if needed
|
|
346
|
-
const rawClient = new EsiClient({ validateResponse: false });
|
|
347
|
-
|
|
348
|
-
// Use schemas directly for your own validation
|
|
349
|
-
const result = schemas.CharacterInfoSchema.safeParse(someData);
|
|
350
|
-
if (result.success) {
|
|
351
|
-
console.log(result.data.name);
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
See [guides/RUNTIME-VALIDATION.md](guides/RUNTIME-VALIDATION.md) for the full guide on schemas, error handling, and extending schemas.
|
|
356
|
-
|
|
357
|
-
## Generated Types
|
|
358
|
-
|
|
359
|
-
The library includes TypeScript interfaces generated directly from the ESI swagger spec, available as the `EsiSpec` namespace. These are guaranteed to match the live spec and complement the hand-written types:
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
import { EsiSpec } from '@lgriffin/esi.ts';
|
|
363
|
-
|
|
364
|
-
// Generated type — exact spec field names and optionality
|
|
365
|
-
const order: EsiSpec.GetMarketsRegionIdOrders200Ok = {
|
|
366
|
-
order_id: 123,
|
|
367
|
-
type_id: 34,
|
|
368
|
-
price: 5.5,
|
|
369
|
-
volume_remain: 1000,
|
|
370
|
-
volume_total: 5000,
|
|
371
|
-
is_buy_order: false,
|
|
372
|
-
// ...
|
|
373
|
-
};
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
To regenerate types from the latest ESI spec:
|
|
377
|
-
|
|
378
|
-
```bash
|
|
379
|
-
npm run generate:types # fetches spec, generates 147 interfaces + cache TTL map + rate limit groups + scope map
|
|
380
|
-
npm run validate:esi # reports type drift between hand-written and generated types
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
## ESI Scopes
|
|
384
|
-
|
|
385
|
-
The library includes a generated scope-to-endpoint mapping extracted from the ESI swagger spec. Use it to check which OAuth scopes an endpoint requires before making a request:
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
import { esiEndpointScopes, EsiScope } from '@lgriffin/esi.ts';
|
|
389
|
-
|
|
390
|
-
// Look up scopes for a specific endpoint
|
|
391
|
-
const walletScopes = esiEndpointScopes['GET:characters/{character_id}/wallet'];
|
|
392
|
-
// → ['esi-wallet.read_character_wallet.v1']
|
|
393
|
-
|
|
394
|
-
// Check if an endpoint requires auth
|
|
395
|
-
const isPublic = !esiEndpointScopes['GET:universe/types/{type_id}'];
|
|
396
|
-
// → true (public endpoint, no scopes needed)
|
|
397
|
-
|
|
398
|
-
// Type-safe scope values
|
|
399
|
-
const scope: EsiScope = 'esi-assets.read_assets.v1';
|
|
400
|
-
```
|
|
401
|
-
|
|
402
386
|
## Streaming Pagination
|
|
403
387
|
|
|
404
388
|
For large paginated endpoints (market orders, contracts, assets), streaming yields one page at a time via `AsyncGenerator` instead of eagerly fetching all pages into memory:
|
|
@@ -495,6 +479,51 @@ Key points:
|
|
|
495
479
|
- **Duplicates across pages** are expected when records are modified between requests
|
|
496
480
|
- Existing offset-based routes (`getMarketOrders`, etc.) are unchanged
|
|
497
481
|
|
|
482
|
+
## Generated Types
|
|
483
|
+
|
|
484
|
+
The library includes TypeScript interfaces generated directly from the ESI OpenAPI 3.1 spec, available as the `EsiSpec` namespace. These are guaranteed to match the live spec and complement the hand-written types:
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
import { EsiSpec } from '@lgriffin/esi.ts';
|
|
488
|
+
|
|
489
|
+
// Generated type — uses OpenAPI schema names (v7.0.0+)
|
|
490
|
+
const order: EsiSpec.MarketsRegionIdOrdersGet = {
|
|
491
|
+
order_id: 123,
|
|
492
|
+
type_id: 34,
|
|
493
|
+
price: 5.5,
|
|
494
|
+
volume_remain: 1000,
|
|
495
|
+
volume_total: 5000,
|
|
496
|
+
is_buy_order: false,
|
|
497
|
+
// ...
|
|
498
|
+
};
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
To regenerate types from the latest ESI spec:
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
npm run generate:types # fetches OpenAPI spec, generates 161 interfaces + cache TTL map + rate limit groups + scope map
|
|
505
|
+
npm run validate:esi # reports type drift between hand-written and generated types
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## ESI Scopes
|
|
509
|
+
|
|
510
|
+
The library includes a generated scope-to-endpoint mapping extracted from the ESI OpenAPI spec. Use it to check which OAuth scopes an endpoint requires before making a request:
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
import { esiEndpointScopes, EsiScope } from '@lgriffin/esi.ts';
|
|
514
|
+
|
|
515
|
+
// Look up scopes for a specific endpoint
|
|
516
|
+
const walletScopes = esiEndpointScopes['GET:characters/{character_id}/wallet'];
|
|
517
|
+
// → ['esi-wallet.read_character_wallet.v1']
|
|
518
|
+
|
|
519
|
+
// Check if an endpoint requires auth
|
|
520
|
+
const isPublic = !esiEndpointScopes['GET:universe/types/{type_id}'];
|
|
521
|
+
// → true (public endpoint, no scopes needed)
|
|
522
|
+
|
|
523
|
+
// Type-safe scope values
|
|
524
|
+
const scope: EsiScope = 'esi-assets.read_assets.v1';
|
|
525
|
+
```
|
|
526
|
+
|
|
498
527
|
## Error Handling
|
|
499
528
|
|
|
500
529
|
API errors throw `EsiError` with `statusCode`, `message`, and `url` properties:
|
|
@@ -628,9 +657,29 @@ const marketClient = EsiApiFactory.createMarketClient({
|
|
|
628
657
|
const prices = await marketClient.getMarketPrices();
|
|
629
658
|
```
|
|
630
659
|
|
|
660
|
+
## Endpoint Coverage
|
|
661
|
+
|
|
662
|
+
All 208 endpoint definitions have been validated against live Tranquility using the **OpenAPI 3.1 spec** — 194 from the public ESI spec plus 14 for newer EVE features. 206 endpoints are exercisable (2 mercenary den endpoints await CCP deployment). Full output is captured in [`openapi.output.md`](openapi.output.md).
|
|
663
|
+
|
|
664
|
+
| Category | Endpoints | Method |
|
|
665
|
+
| --------------------------- | --------- | -------------------------------------------------- |
|
|
666
|
+
| Public GETs | 78 | 43 runnable example scripts with captured output |
|
|
667
|
+
| Authenticated GETs | 72 | Example scripts + live testing with EVE SSO tokens |
|
|
668
|
+
| Contacts (POST/PUT/DELETE) | 3 | Live create/edit/delete lifecycle |
|
|
669
|
+
| Fittings (POST/DELETE) | 2 | Live create/delete lifecycle |
|
|
670
|
+
| Mail (POST/PUT/DELETE) | 5 | Live send/label/metadata/delete lifecycle |
|
|
671
|
+
| UI (POST) | 5 | Live testing with EVE client running |
|
|
672
|
+
| Calendar (PUT) | 1 | Live RSVP to event |
|
|
673
|
+
| Fleet (GET/POST/PUT/DELETE) | 14 | Live fleet with fleet commander + squad members |
|
|
674
|
+
| Assets POST | 3 | Live asset location/name queries |
|
|
675
|
+
| CSPA (POST) | 1 | Live charge cost calculation |
|
|
676
|
+
| Dogma dynamic (GET) | 1 | Live mutaplasmid (Abyssal) item query |
|
|
677
|
+
| Universe POST helpers | 3 | Live name resolution and affiliation |
|
|
678
|
+
| Freelance Jobs (GET) | 4 | Live queries (graceful 404 for no active jobs) |
|
|
679
|
+
|
|
631
680
|
## Examples
|
|
632
681
|
|
|
633
|
-
|
|
682
|
+
43 runnable examples are in the `examples/` directory.
|
|
634
683
|
|
|
635
684
|
### Public Endpoints (no auth needed)
|
|
636
685
|
|
|
@@ -651,23 +700,39 @@ npm run example:rate-limiting # Rate limiter & pagination demonstration
|
|
|
651
700
|
npm run example:cursor-pagination # Freelance Jobs with cursor pagination
|
|
652
701
|
npm run example:streaming # Streaming pagination for large datasets
|
|
653
702
|
npm run example:token-refresh # Automatic token refresh on 401
|
|
703
|
+
npm run example:universe-encyclopedia # Ancestries, bloodlines, races, celestials
|
|
704
|
+
npm run example:dogma-meta-sov # Dogma effects, sovereignty, meta endpoint
|
|
705
|
+
npm run example:faction-details # Faction warfare leaderboards and stats
|
|
654
706
|
```
|
|
655
707
|
|
|
656
708
|
### Authenticated Endpoints (require ESI_ACCESS_TOKEN)
|
|
657
709
|
|
|
658
|
-
These examples require an EVE SSO token with the listed scopes. Set `ESI_ACCESS_TOKEN` in your environment or `.env` file.
|
|
659
|
-
|
|
660
710
|
```bash
|
|
661
711
|
npm run example # Full character profile assembly
|
|
662
|
-
npm run example:wallet # Wallet balance, journal, transactions
|
|
663
|
-
npm run example:skills # Trained skills, queue, attributes
|
|
664
|
-
npm run example:assets # Asset inventory with bulk name lookup
|
|
665
|
-
npm run example:killmails # Recent killmails + full details
|
|
666
|
-
npm run example:fleet # Fleet info, members, wing/squad structure
|
|
667
|
-
npm run example:mail # Inbox headers, labels, mailing lists
|
|
668
|
-
npm run example:location # Current system, online status, ship
|
|
669
|
-
npm run example:fittings # Saved fittings + clone state + implants
|
|
670
|
-
npm run example:contacts # Contact list with standings + labels
|
|
712
|
+
npm run example:wallet # Wallet balance, journal, transactions
|
|
713
|
+
npm run example:skills # Trained skills, queue, attributes
|
|
714
|
+
npm run example:assets # Asset inventory with bulk name lookup
|
|
715
|
+
npm run example:killmails # Recent killmails + full details
|
|
716
|
+
npm run example:fleet # Fleet info, members, wing/squad structure
|
|
717
|
+
npm run example:mail # Inbox headers, labels, mailing lists
|
|
718
|
+
npm run example:location # Current system, online status, ship
|
|
719
|
+
npm run example:fittings # Saved fittings + clone state + implants
|
|
720
|
+
npm run example:contacts # Contact list with standings + labels
|
|
721
|
+
npm run example:character-details # Blueprints, roles, standings, medals
|
|
722
|
+
npm run example:corporation-details # Corp members, divisions, structures
|
|
723
|
+
npm run example:calendar-search # Calendar events + character search
|
|
724
|
+
npm run example:loyalty-pi # Loyalty points + planetary interaction
|
|
725
|
+
npm run example:industry-mining # Industry jobs + mining ledger
|
|
726
|
+
npm run example:market-orders # Character/corp market orders
|
|
727
|
+
npm run example:corp-contracts-wallet # Corp contracts, contacts, wallets
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### Write Operations (require specific scopes + caution)
|
|
731
|
+
|
|
732
|
+
```bash
|
|
733
|
+
npm run example:write-ops # Contacts, fittings, mail, UI lifecycle tests
|
|
734
|
+
npm run example:universe-posts # Name resolution + character affiliation (public)
|
|
735
|
+
npm run example:freelance-jobs # Freelance job queries
|
|
671
736
|
```
|
|
672
737
|
|
|
673
738
|
### Parallel Requests
|
|
@@ -711,6 +776,35 @@ try {
|
|
|
711
776
|
}
|
|
712
777
|
```
|
|
713
778
|
|
|
779
|
+
## Testing
|
|
780
|
+
|
|
781
|
+
ESI.ts has a comprehensive multi-tier testing strategy:
|
|
782
|
+
|
|
783
|
+
| Tier | Tests | Purpose |
|
|
784
|
+
| -------------------------- | ---------------- | ------------------------------------------------------------------ |
|
|
785
|
+
| **TDD unit tests** | 81 files | Every client method, endpoint path, query param, and body format |
|
|
786
|
+
| **BDD scenario tests** | 40 feature files | Behavioral specifications in Gherkin (Given/When/Then) |
|
|
787
|
+
| **Mocked integration** | Full suite | Cross-layer request flow with jest-fetch-mock |
|
|
788
|
+
| **Live smoke tests** | 43 examples | Every endpoint against live Tranquility |
|
|
789
|
+
| **ESI spec contract** | 15 tests | Endpoint definitions validated against live OpenAPI spec |
|
|
790
|
+
| **Deep contract tests** | 8 categories | Path params, query params, body, auth, schemas, pagination vs spec |
|
|
791
|
+
| **Property-based fuzzing** | 601 tests | fast-check fuzzing of validation, URL construction, Zod schemas |
|
|
792
|
+
| **Type-level tests** | tsd | Consumer API type correctness via tsd |
|
|
793
|
+
| **Gated auth tests** | 33 tests | Authenticated endpoints with real tokens |
|
|
794
|
+
|
|
795
|
+
```bash
|
|
796
|
+
npm test # Unit + BDD tests (121 suites, 3,224 tests)
|
|
797
|
+
npm run coverage # Tests with coverage report (thresholds enforced)
|
|
798
|
+
npm run bdd # BDD scenario tests only
|
|
799
|
+
npm run contract # Contract tests (skipped without ESI_LIVE_TESTS=true)
|
|
800
|
+
npm run fuzz # Property-based fuzz tests (601 tests)
|
|
801
|
+
npm run test:types # tsd consumer type tests
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
Coverage thresholds are enforced in CI: branches 50%, functions 50%, lines 65%, statements 65%.
|
|
805
|
+
|
|
806
|
+
See [guides/TESTING.md](guides/TESTING.md) for the full testing guide, and [guides/ARCHITECTURE.md](guides/ARCHITECTURE.md) for architecture diagrams.
|
|
807
|
+
|
|
714
808
|
## Development
|
|
715
809
|
|
|
716
810
|
### Prerequisites
|
|
@@ -731,6 +825,7 @@ The project uses a comprehensive suite of static analysis and code quality tools
|
|
|
731
825
|
| [eslint-plugin-sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs) | Cognitive complexity and code smell detection | Integrated into `npm run lint` |
|
|
732
826
|
| [husky](https://typicode.github.io/husky/) | Git pre-commit hooks | Automatic on commit |
|
|
733
827
|
| [lint-staged](https://github.com/lint-staged/lint-staged) | Run linters on staged files only | Automatic on commit |
|
|
828
|
+
| [Redocly CLI](https://redocly.com/docs/cli/) | OpenAPI spec validation and linting | `npm run validate:spec` |
|
|
734
829
|
|
|
735
830
|
### Available Scripts
|
|
736
831
|
|
|
@@ -743,16 +838,21 @@ npm run format # Format code with Prettier
|
|
|
743
838
|
npm run format:check # Check formatting without modifying
|
|
744
839
|
|
|
745
840
|
# Testing
|
|
746
|
-
npm test # Unit tests
|
|
747
|
-
npm run test:all # Unit +
|
|
841
|
+
npm test # Unit tests (121 suites, 3,224 tests)
|
|
842
|
+
npm run test:all # Unit + BDD + integration + fuzz + type tests
|
|
748
843
|
npm run coverage # Tests with coverage report (thresholds enforced)
|
|
749
844
|
npm run bdd # BDD scenario tests
|
|
845
|
+
npm run contract:live # Deep contract tests against live ESI spec
|
|
846
|
+
npm run fuzz # Property-based fuzz tests (fast-check)
|
|
847
|
+
npm run test:types # Consumer type tests (tsd)
|
|
848
|
+
npm run mock:esi # Start Prism mock ESI server on port 4010
|
|
750
849
|
|
|
751
850
|
# Static Analysis
|
|
752
851
|
npm run knip # Detect dead code and unused exports
|
|
753
|
-
npm run validate:esi # Validate endpoints against live ESI
|
|
852
|
+
npm run validate:esi # Validate endpoints against live ESI OpenAPI spec
|
|
853
|
+
npm run validate:spec # Lint ESI OpenAPI spec with Redocly (structural + best practices)
|
|
754
854
|
npm run validate # Run all checks: lint, format, build, coverage, knip
|
|
755
|
-
npm run generate:types # Regenerate TypeScript interfaces from ESI
|
|
855
|
+
npm run generate:types # Regenerate TypeScript interfaces from ESI OpenAPI spec
|
|
756
856
|
|
|
757
857
|
# Documentation
|
|
758
858
|
npm run docs # Generate TypeDoc API documentation
|
|
@@ -761,13 +861,13 @@ npm run docs:serve # Serve docs locally on port 8080
|
|
|
761
861
|
|
|
762
862
|
### ESI Endpoint Validation
|
|
763
863
|
|
|
764
|
-
To verify that the codebase endpoint definitions match the live ESI
|
|
864
|
+
To verify that the codebase endpoint definitions match the live ESI OpenAPI spec:
|
|
765
865
|
|
|
766
866
|
```bash
|
|
767
867
|
npm run validate:esi
|
|
768
868
|
```
|
|
769
869
|
|
|
770
|
-
This fetches
|
|
870
|
+
This fetches the ESI OpenAPI spec and reports:
|
|
771
871
|
|
|
772
872
|
- Endpoints in the codebase that are no longer in the ESI spec
|
|
773
873
|
- Endpoints in the ESI spec that the codebase doesn't cover
|
|
@@ -784,7 +884,7 @@ Every pull request runs the full validation suite:
|
|
|
784
884
|
- ESLint (with security and sonarjs plugins)
|
|
785
885
|
- Prettier formatting check
|
|
786
886
|
- TypeScript compilation
|
|
787
|
-
- Generated types staleness check (regenerates from live ESI spec and verifies no diff)
|
|
887
|
+
- Generated types staleness check (regenerates from live ESI OpenAPI spec and verifies no diff)
|
|
788
888
|
- Unit tests across Node.js 18, 20, and 22
|
|
789
889
|
- BDD scenario tests
|
|
790
890
|
- Coverage threshold enforcement (branches: 50%, functions: 50%, lines: 65%, statements: 65%)
|
|
@@ -793,20 +893,6 @@ Every pull request runs the full validation suite:
|
|
|
793
893
|
|
|
794
894
|
See [.github/workflows/README.md](.github/workflows/README.md) for full workflow details.
|
|
795
895
|
|
|
796
|
-
## Testing
|
|
797
|
-
|
|
798
|
-
```bash
|
|
799
|
-
npm test # Unit + BDD tests (108 suites, 2836 tests)
|
|
800
|
-
npm run coverage # Tests with coverage report (thresholds enforced)
|
|
801
|
-
npm run bdd # BDD scenario tests only
|
|
802
|
-
```
|
|
803
|
-
|
|
804
|
-
To verify against the live ESI API:
|
|
805
|
-
|
|
806
|
-
```bash
|
|
807
|
-
npm run example:status # Confirms ESI connectivity and server status
|
|
808
|
-
```
|
|
809
|
-
|
|
810
896
|
## Contributing
|
|
811
897
|
|
|
812
898
|
1. Fork the repository
|