@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.
Files changed (143) hide show
  1. package/CHANGELOG.md +110 -1
  2. package/README.md +245 -159
  3. package/dist/clients/AllianceClient.d.ts +2 -0
  4. package/dist/clients/AllianceClient.d.ts.map +1 -1
  5. package/dist/clients/AllianceClient.js +2 -0
  6. package/dist/clients/BaseEsiClient.d.ts +4 -2
  7. package/dist/clients/BaseEsiClient.d.ts.map +1 -1
  8. package/dist/clients/BaseEsiClient.js +9 -0
  9. package/dist/clients/ContactsClient.d.ts +6 -4
  10. package/dist/clients/ContactsClient.d.ts.map +1 -1
  11. package/dist/clients/ContactsClient.js +9 -7
  12. package/dist/clients/FleetClient.d.ts +2 -2
  13. package/dist/clients/FleetClient.d.ts.map +1 -1
  14. package/dist/clients/FleetClient.js +8 -2
  15. package/dist/clients/SovereigntyClient.d.ts +1 -1
  16. package/dist/clients/SovereigntyClient.d.ts.map +1 -1
  17. package/dist/clients/UiClient.d.ts +11 -9
  18. package/dist/clients/UiClient.d.ts.map +1 -1
  19. package/dist/clients/UiClient.js +15 -13
  20. package/dist/core/constants.d.ts +2 -2
  21. package/dist/core/constants.js +1 -1
  22. package/dist/core/endpoints/EndpointDefinition.d.ts +12 -4
  23. package/dist/core/endpoints/EndpointDefinition.d.ts.map +1 -1
  24. package/dist/core/endpoints/allianceEndpoints.d.ts +17 -14
  25. package/dist/core/endpoints/allianceEndpoints.d.ts.map +1 -1
  26. package/dist/core/endpoints/allianceEndpoints.js +3 -0
  27. package/dist/core/endpoints/assetEndpoints.d.ts +16 -0
  28. package/dist/core/endpoints/assetEndpoints.d.ts.map +1 -1
  29. package/dist/core/endpoints/assetEndpoints.js +1 -0
  30. package/dist/core/endpoints/characterEndpoints.d.ts +8 -0
  31. package/dist/core/endpoints/characterEndpoints.d.ts.map +1 -1
  32. package/dist/core/endpoints/characterEndpoints.js +1 -0
  33. package/dist/core/endpoints/cloneEndpoints.d.ts +17 -15
  34. package/dist/core/endpoints/cloneEndpoints.d.ts.map +1 -1
  35. package/dist/core/endpoints/cloneEndpoints.js +2 -0
  36. package/dist/core/endpoints/contactEndpoints.d.ts +11 -3
  37. package/dist/core/endpoints/contactEndpoints.d.ts.map +1 -1
  38. package/dist/core/endpoints/contactEndpoints.js +5 -3
  39. package/dist/core/endpoints/corporationEndpoints.d.ts +27 -0
  40. package/dist/core/endpoints/corporationEndpoints.d.ts.map +1 -1
  41. package/dist/core/endpoints/corporationEndpoints.js +7 -0
  42. package/dist/core/endpoints/createClient.d.ts +5 -1
  43. package/dist/core/endpoints/createClient.d.ts.map +1 -1
  44. package/dist/core/endpoints/createClient.js +74 -55
  45. package/dist/core/endpoints/dogmaEndpoints.d.ts +41 -38
  46. package/dist/core/endpoints/dogmaEndpoints.d.ts.map +1 -1
  47. package/dist/core/endpoints/dogmaEndpoints.js +3 -0
  48. package/dist/core/endpoints/esi-cache-ttls.generated.d.ts.map +1 -1
  49. package/dist/core/endpoints/esi-cache-ttls.generated.js +14 -7
  50. package/dist/core/endpoints/esi-scopes.generated.d.ts +1 -1
  51. package/dist/core/endpoints/esi-scopes.generated.d.ts.map +1 -1
  52. package/dist/core/endpoints/esi-scopes.generated.js +11 -3
  53. package/dist/core/endpoints/factionEndpoints.d.ts +2 -2
  54. package/dist/core/endpoints/fittingEndpoints.d.ts +1 -1
  55. package/dist/core/endpoints/freelanceJobsEndpoints.d.ts +8 -8
  56. package/dist/core/endpoints/mailEndpoints.d.ts +15 -0
  57. package/dist/core/endpoints/mailEndpoints.d.ts.map +1 -1
  58. package/dist/core/endpoints/mailEndpoints.js +2 -0
  59. package/dist/core/endpoints/marketEndpoints.d.ts +20 -0
  60. package/dist/core/endpoints/marketEndpoints.d.ts.map +1 -1
  61. package/dist/core/endpoints/marketEndpoints.js +4 -0
  62. package/dist/core/endpoints/metaEndpoints.d.ts +2 -0
  63. package/dist/core/endpoints/metaEndpoints.d.ts.map +1 -1
  64. package/dist/core/endpoints/metaEndpoints.js +2 -0
  65. package/dist/core/endpoints/piEndpoints.d.ts +4 -0
  66. package/dist/core/endpoints/piEndpoints.d.ts.map +1 -1
  67. package/dist/core/endpoints/piEndpoints.js +2 -0
  68. package/dist/core/endpoints/routeEndpoints.d.ts +4 -0
  69. package/dist/core/endpoints/routeEndpoints.d.ts.map +1 -1
  70. package/dist/core/endpoints/routeEndpoints.js +2 -0
  71. package/dist/core/endpoints/searchEndpoints.d.ts +13 -0
  72. package/dist/core/endpoints/searchEndpoints.d.ts.map +1 -1
  73. package/dist/core/endpoints/searchEndpoints.js +2 -0
  74. package/dist/core/endpoints/skillEndpoints.d.ts +10 -0
  75. package/dist/core/endpoints/skillEndpoints.d.ts.map +1 -1
  76. package/dist/core/endpoints/skillEndpoints.js +1 -0
  77. package/dist/core/endpoints/sovereigntyEndpoints.d.ts +30 -16
  78. package/dist/core/endpoints/sovereigntyEndpoints.d.ts.map +1 -1
  79. package/dist/core/endpoints/sovereigntyEndpoints.js +1 -1
  80. package/dist/core/endpoints/uiEndpoints.d.ts +14 -4
  81. package/dist/core/endpoints/uiEndpoints.d.ts.map +1 -1
  82. package/dist/core/endpoints/uiEndpoints.js +8 -4
  83. package/dist/core/endpoints/universeEndpoints.d.ts +9 -1
  84. package/dist/core/endpoints/universeEndpoints.d.ts.map +1 -1
  85. package/dist/core/endpoints/universeEndpoints.js +8 -0
  86. package/dist/core/endpoints/walletEndpoints.d.ts +5 -0
  87. package/dist/core/endpoints/walletEndpoints.d.ts.map +1 -1
  88. package/dist/core/endpoints/walletEndpoints.js +3 -0
  89. package/dist/core/endpoints/warEndpoints.d.ts +1 -0
  90. package/dist/core/endpoints/warEndpoints.d.ts.map +1 -1
  91. package/dist/core/endpoints/warEndpoints.js +1 -0
  92. package/dist/core/util/testHelpers.js +2 -2
  93. package/dist/index.d.ts +1 -1
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/schemas/assets.d.ts +1 -0
  96. package/dist/schemas/assets.d.ts.map +1 -1
  97. package/dist/schemas/assets.js +1 -1
  98. package/dist/schemas/character.d.ts +8 -0
  99. package/dist/schemas/character.d.ts.map +1 -1
  100. package/dist/schemas/character.js +9 -1
  101. package/dist/schemas/corporation.d.ts +18 -0
  102. package/dist/schemas/corporation.d.ts.map +1 -1
  103. package/dist/schemas/corporation.js +15 -1
  104. package/dist/schemas/faction-warfare.d.ts +2 -2
  105. package/dist/schemas/faction-warfare.js +2 -2
  106. package/dist/schemas/fittings.d.ts +1 -1
  107. package/dist/schemas/fittings.js +1 -1
  108. package/dist/schemas/freelance-jobs.d.ts +8 -8
  109. package/dist/schemas/freelance-jobs.js +5 -5
  110. package/dist/schemas/mail.d.ts +14 -0
  111. package/dist/schemas/mail.d.ts.map +1 -1
  112. package/dist/schemas/mail.js +10 -1
  113. package/dist/schemas/market.d.ts +13 -0
  114. package/dist/schemas/market.d.ts.map +1 -1
  115. package/dist/schemas/market.js +14 -1
  116. package/dist/schemas/skills.d.ts +10 -0
  117. package/dist/schemas/skills.d.ts.map +1 -1
  118. package/dist/schemas/skills.js +11 -1
  119. package/dist/schemas/sovereignty.d.ts +28 -14
  120. package/dist/schemas/sovereignty.d.ts.map +1 -1
  121. package/dist/schemas/sovereignty.js +35 -8
  122. package/dist/schemas/universe.d.ts +1 -1
  123. package/dist/schemas/universe.js +1 -1
  124. package/dist/testing/TestDataFactory.d.ts +1 -0
  125. package/dist/testing/TestDataFactory.d.ts.map +1 -1
  126. package/dist/testing/TestDataFactory.js +19 -10
  127. package/dist/types/api-responses.d.ts +1 -0
  128. package/dist/types/api-responses.d.ts.map +1 -1
  129. package/dist/types/api-responses.js +1 -0
  130. package/dist/types/branded.d.ts +23 -0
  131. package/dist/types/branded.d.ts.map +1 -0
  132. package/dist/types/branded.js +6 -0
  133. package/dist/types/common.d.ts +10 -0
  134. package/dist/types/common.d.ts.map +1 -1
  135. package/dist/types/generated/esi-spec.generated.d.ts +655 -430
  136. package/dist/types/generated/esi-spec.generated.d.ts.map +1 -1
  137. package/dist/types/generated/esi-spec.generated.js +3 -3
  138. package/dist/types/generated/spec-alignment.check.d.ts +13 -0
  139. package/dist/types/generated/spec-alignment.check.d.ts.map +1 -0
  140. package/dist/types/generated/spec-alignment.check.js +14 -0
  141. package/dist/types/market.d.ts +2 -1
  142. package/dist/types/market.d.ts.map +1 -1
  143. 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
- ## [Unreleased]
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
  [![Coverage](https://img.shields.io/badge/coverage-65%25%2B-brightgreen)](https://github.com/lgriffin/ESI.ts)
9
9
  [![npm downloads](https://img.shields.io/npm/dm/%40lgriffin/esi.ts)](https://www.npmjs.com/package/@lgriffin/esi.ts)
10
10
 
11
- A type-safe TypeScript client for the [EVE Online ESI API](https://esi.evetech.net/).
12
-
13
- - Typed responses for all endpoints with **runtime validation** via Zod schemas
14
- - Spec-driven type generation from ESI swagger spec (147 interfaces)
15
- - ETag caching with Cache-Control TTL, stale-on-error, and write invalidation
16
- - Spec-aware cache TTLs — zero-request cache hits within ESI-specified windows
17
- - Batch requests with bounded concurrency and auto-chunking
18
- - Automatic offset-based pagination, cursor-based pagination, and streaming pagination support
19
- - Rate limiting with header-driven backoff
20
- - Automatic token refresh with 401 retry and concurrent coalescing
21
- - 35 domain clients covering the full ESI surface
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 | `getCharacterCalendar(id)` |
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()`, `getDogmaEffects()` |
221
- | Factions | `client.factions` | Some | `getFactionWarStats()` |
222
- | Fittings | `client.fittings` | Yes | `getFittings(id)`, `createFitting(id, body)` |
223
- | Fleets | `client.fleets` | Yes | `getFleet(id)`, `getFleetMembers(id)` |
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 | `setWaypoint(id)` |
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-cached-seconds` from the ESI swagger spec (119 of 195 endpoints). Within the TTL window, repeated GET requests return cached data with **zero HTTP calls** — not even a conditional GET.
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
- Runnable examples are in the `examples/` directory.
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 (esi-wallet.read_character_wallet.v1)
663
- npm run example:skills # Trained skills, queue, attributes (esi-skills.read_skills.v1, esi-skills.read_skillqueue.v1)
664
- npm run example:assets # Asset inventory with bulk name lookup (esi-assets.read_assets.v1)
665
- npm run example:killmails # Recent killmails + full details (esi-killmails.read_killmails.v1)
666
- npm run example:fleet # Fleet info, members, wing/squad structure (esi-fleets.read_fleet.v1)
667
- npm run example:mail # Inbox headers, labels, mailing lists (esi-mail.read_mail.v1)
668
- npm run example:location # Current system, online status, ship (esi-location.read_location.v1)
669
- npm run example:fittings # Saved fittings + clone state + implants (esi-fittings.read_fittings.v1, esi-clones.read_clones.v1)
670
- npm run example:contacts # Contact list with standings + labels (esi-characters.read_contacts.v1)
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 + improved + BDD tests
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 swagger spec
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 swagger spec
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 swagger spec:
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 `https://esi.evetech.net/latest/swagger.json` and reports:
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