@lgriffin/esi.ts 9.6.0 → 9.7.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 (83) hide show
  1. package/CHANGELOG.md +417 -388
  2. package/LICENSE +26 -26
  3. package/README.md +1037 -1030
  4. package/dist/clients/AllianceClient.d.ts +2 -0
  5. package/dist/clients/AllianceClient.d.ts.map +1 -1
  6. package/dist/clients/AssetsClient.d.ts +2 -0
  7. package/dist/clients/AssetsClient.d.ts.map +1 -1
  8. package/dist/clients/BaseEsiClient.d.ts +1 -0
  9. package/dist/clients/BaseEsiClient.d.ts.map +1 -1
  10. package/dist/clients/CalendarClient.d.ts +2 -0
  11. package/dist/clients/CalendarClient.d.ts.map +1 -1
  12. package/dist/clients/CharacterClient.d.ts +8 -0
  13. package/dist/clients/CharacterClient.d.ts.map +1 -1
  14. package/dist/clients/ClonesClient.d.ts +1 -0
  15. package/dist/clients/ClonesClient.d.ts.map +1 -1
  16. package/dist/clients/ContactsClient.d.ts +6 -0
  17. package/dist/clients/ContactsClient.d.ts.map +1 -1
  18. package/dist/clients/ContractsClient.d.ts +3 -0
  19. package/dist/clients/ContractsClient.d.ts.map +1 -1
  20. package/dist/clients/CorporationsClient.d.ts +17 -0
  21. package/dist/clients/CorporationsClient.d.ts.map +1 -1
  22. package/dist/clients/FittingsClient.d.ts +1 -0
  23. package/dist/clients/FittingsClient.d.ts.map +1 -1
  24. package/dist/clients/FleetClient.d.ts +2 -0
  25. package/dist/clients/FleetClient.d.ts.map +1 -1
  26. package/dist/clients/IndustryClient.d.ts +8 -0
  27. package/dist/clients/IndustryClient.d.ts.map +1 -1
  28. package/dist/clients/KillmailsClient.d.ts +2 -0
  29. package/dist/clients/KillmailsClient.d.ts.map +1 -1
  30. package/dist/clients/LoyaltyClient.d.ts +2 -0
  31. package/dist/clients/LoyaltyClient.d.ts.map +1 -1
  32. package/dist/clients/MailClient.d.ts +5 -0
  33. package/dist/clients/MailClient.d.ts.map +1 -1
  34. package/dist/clients/MarketClient.d.ts +6 -0
  35. package/dist/clients/MarketClient.d.ts.map +1 -1
  36. package/dist/clients/PiClient.d.ts +2 -0
  37. package/dist/clients/PiClient.d.ts.map +1 -1
  38. package/dist/clients/SkillsClient.d.ts +1 -0
  39. package/dist/clients/SkillsClient.d.ts.map +1 -1
  40. package/dist/clients/WalletClient.d.ts +4 -0
  41. package/dist/clients/WalletClient.d.ts.map +1 -1
  42. package/dist/clients/WarsClient.d.ts +2 -0
  43. package/dist/clients/WarsClient.d.ts.map +1 -1
  44. package/dist/core/ApiClient.d.ts +4 -0
  45. package/dist/core/ApiClient.d.ts.map +1 -1
  46. package/dist/core/ApiClientBuilder.d.ts +3 -1
  47. package/dist/core/ApiClientBuilder.d.ts.map +1 -1
  48. package/dist/core/constants.d.ts +2 -2
  49. package/dist/core/endpoints/EndpointDefinition.d.ts +2 -2
  50. package/dist/core/endpoints/EndpointDefinition.d.ts.map +1 -1
  51. package/dist/core/endpoints/createClient.d.ts +2 -2
  52. package/dist/core/endpoints/createClient.d.ts.map +1 -1
  53. package/dist/core/logger/NoopLogger.d.ts +3 -0
  54. package/dist/core/logger/NoopLogger.d.ts.map +1 -0
  55. package/dist/core/pagination/AsyncPaginationIterator.d.ts +1 -0
  56. package/dist/core/pagination/AsyncPaginationIterator.d.ts.map +1 -1
  57. package/dist/core/rateLimiter/RateLimiter.d.ts +6 -0
  58. package/dist/core/rateLimiter/RateLimiter.d.ts.map +1 -1
  59. package/dist/core/requestPipeline/headers.d.ts.map +1 -1
  60. package/dist/core/requestPipeline/statusHandling.d.ts.map +1 -1
  61. package/dist/errors.js.map +1 -1
  62. package/dist/errors.mjs.map +1 -1
  63. package/dist/index.d.ts +4 -3
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +644 -27
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +642 -27
  68. package/dist/index.mjs.map +1 -1
  69. package/dist/schemas/common.d.ts +11 -1
  70. package/dist/schemas/common.d.ts.map +1 -1
  71. package/dist/schemas/index.js +6 -1
  72. package/dist/schemas/index.js.map +1 -1
  73. package/dist/schemas/index.mjs +6 -1
  74. package/dist/schemas/index.mjs.map +1 -1
  75. package/dist/sde/index.js.map +1 -1
  76. package/dist/sde/index.mjs.map +1 -1
  77. package/dist/sde/memory.js.map +1 -1
  78. package/dist/sde/memory.mjs.map +1 -1
  79. package/dist/testing/index.js.map +1 -1
  80. package/dist/testing/index.mjs.map +1 -1
  81. package/dist/types/generated/esi-spec.generated.d.ts +12 -12
  82. package/dist/types/generated/esi-spec.generated.d.ts.map +1 -1
  83. package/package.json +303 -289
package/CHANGELOG.md CHANGED
@@ -1,388 +1,417 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [9.1.0] - 2026-08-14
9
-
10
- ### Added
11
-
12
- - **Schema rejection tests** — 104 new tests verifying Zod schemas correctly reject invalid input shapes
13
- - **Domain property fuzz tests** — property-based fuzz testing across domain clients using fast-check
14
- - **Schema validation benchmarks** — performance benchmarks for Zod schema validation paths
15
- - **Domain response type tests** — compile-time type tests for domain client response types via tsd
16
-
17
- ### Changed
18
-
19
- - **Expanded documentation** — updated examples, architecture guide, and testing guide with broader coverage
20
- - **README refreshed** — updated feature descriptions and endpoint counts
21
-
22
- ### Fixed
23
-
24
- - **Fuzz test date handling** — switched to integer-based date arbitrary to avoid invalid `Date` values in property-based tests
25
-
26
- ## [9.0.0] - 2026-08-12
27
-
28
- ### Breaking Changes
29
-
30
- - **Default retry count changed from 0 to 3** — transient failures (502, 503, 504, timeout, rate limit) now retry automatically with exponential backoff and jitter. Set `maxRetries: 0` in `retryConfig` to restore the previous behavior
31
- - **Generated Zod schemas removed** — the `src/schemas/generated/` directory has been removed; only hand-written schemas in `src/schemas/` remain
32
-
33
- ### Added
34
-
35
- - **Sub-path exports** — targeted imports for reduced bundle size:
36
- - `@lgriffin/esi.ts/schemas` — Zod schemas for runtime validation
37
- - `@lgriffin/esi.ts/errors` — error classes and type guards
38
- - `@lgriffin/esi.ts/testing` — `TestDataFactory` for test mock data
39
- - **`isCircuitOpen()` type guard** — checks whether an error is a `CircuitOpenError`, complementing the existing `isTimeout()`, `isRetryable()`, and `isValidationError()` guards
40
- - **`generate:all` script** — runs all generators (types, endpoints, OKF) in one command
41
- - **`generate:endpoints` script** — regenerates endpoint definitions from the ESI OpenAPI spec
42
-
43
- ### Changed
44
-
45
- - **Cursor pagination routed through full pipeline** — cursor-based pagination now goes through the same middleware pipeline (rate limiter, circuit breaker, retry, caching) as offset pagination
46
- - **Pagination retry unified with `IRetryStrategy`** — pagination requests now use the injectable retry strategy instead of a separate retry path
47
-
48
- ### Fixed
49
-
50
- - **Response interceptor status fix** — response interceptors previously received a hardcoded 200 status; they now receive the actual HTTP status code from the response
51
- - **CI consolidated** — `pr-validation.yml` merged into `ci.yml`; all PR validation now runs through the main CI pipeline
52
-
53
- ## [7.4.0] - 2026-07-17
54
-
55
- ### Added
56
-
57
- - **`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
58
- - **`responseSchema` on `routeEndpoints`** — was the only endpoint file without runtime response validation; now validated with `z.looseObject({ route: z.array(z.number()) })`
59
-
60
- ### Changed
61
-
62
- - **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)
63
- - **jest-fetch-mock 3 → 4** — updated null-body status mocks (204/304) to use `new Response(null, ...)` per Fetch spec
64
- - Updated 11 minor/patch dependencies: @commitlint/cli, @microsoft/api-extractor, @redocly/cli, @types/node, @typescript-eslint/*, eslint-plugin-sonarjs, fast-check, knip, prettier, typedoc
65
-
66
- ### Fixed
67
-
68
- - CI: aligned `codeql.yml` branch targets to `[master, main, develop]`
69
- - CI: pinned `jest-coverage-comment@main` → `@v1.0.34` (supply-chain risk)
70
- - CI: added schema drift and generated types freshness checks to release pipeline
71
-
72
- ### Deprecated
73
-
74
- - `AllianceClient.getContacts()` — use `ContactsClient.getAllianceContacts()` instead
75
- - `AllianceClient.getContactLabels()` — use `ContactsClient.getAllianceContactLabels()` instead
76
-
77
- ## [7.3.0] - 2026-07-14
78
-
79
- ### Added
80
-
81
- - **`EsiResult<T>` discriminated union** and `safeMode` option for error-safe API calls
82
- - **Branded ID types** (16 types) for type-safe ESI entity references
83
- - **Expanded type-level tests** with tsd for error guards, endpoints, and domain types
84
- - **Compile-time spec-to-Zod type alignment checks**
85
- - **Schema drift detection** as a blocking CI check
86
- - **Comprehensive testing gap closure** (+1233 tests)
87
-
88
- ### Fixed
89
-
90
- - Resolved three CI jobs failing with continue-on-error
91
- - Normalized CRLF in API surface check
92
- - Fixed schemathesis report permissions and `--url` flag
93
- - Fixed API surface ordering issues
94
- - Added missing `system_id` to `MarketOrderSchema` test data
95
-
96
- ## [7.2.0] - 2026-07-08
97
-
98
- ### Added
99
-
100
- - **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.
101
- - **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`)
102
- - **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)
103
- - **Consumer type tests** with [tsd](https://github.com/tsdjs/tsd) — verifies public API type correctness (`npm run test:types`)
104
- - **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)
105
- - **Schemathesis fuzz runner** — `npm run fuzz:api` runs Schemathesis against the Prism mock (Docker, weekly CI)
106
- - Contract and fuzz test CI jobs added to `ci.yml` quality gate
107
- - Weekly spec drift detection job added to `maintenance.yml`
108
- - `jest.contract.config.cjs` and `jest.fuzz.config.cjs` test configurations
109
-
110
- ### Dependencies
111
-
112
- - Added `fast-check` (dev) — property-based testing framework
113
- - Added `@stoplight/prism-cli` (dev) — OpenAPI mock server
114
- - Added `tsd` (dev) — TypeScript type testing
115
-
116
- ## [7.1.0] - 2026-07-08
117
-
118
- ### Added
119
-
120
- - **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).
121
- - `redocly.yaml` config with tuned rulesets for ESI — structural rules as errors, CCP spec quirks as warnings
122
- - `validate:spec` npm script added to `check:all` pipeline
123
-
124
- ## [7.0.0] - 2026-07-08
125
-
126
- ### Breaking Changes
127
-
128
- - **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).
129
- - **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.
130
- - **Cache TTL metadata key** — internally changed from `x-cached-seconds` to `x-cache-age`. No consumer-facing impact (cache behavior is identical).
131
-
132
- ### Changed
133
-
134
- - Single OpenAPI spec fetch instead of dual Swagger + OpenAPI fetches
135
- - Updated all scripts, tests, and documentation to reference OpenAPI spec
136
- - Generated types now include 161 interfaces (up from 147), 126 cache TTLs, 70 scopes
137
-
138
- ## [6.1.0] - 2026-07-07
139
-
140
- ### Added
141
-
142
- - **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
143
- - **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)
144
- - **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)
145
- - Live output captured for all example scripts in `examples/output/`
146
- - 3 new TDD test files and 1 new BDD feature file (81 TDD files, 40 BDD features total)
147
- - 2 new fleet validation unit tests
148
-
149
- ### Fixed
150
-
151
- - **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)
152
- - **Fleet rename test names** — test mock names shortened to respect ESI's 10-character limit (`'New Squad Name'` → `'New Squad'`)
153
-
154
- ### Changed
155
-
156
- - README rewritten with "Why ESI.ts vs. OpenAPI-generated clients" comparison, full endpoint coverage table, and updated architecture/testing references
157
- - `guides/ARCHITECTURE.md`, `guides/TESTING.md`, and `TESTING.md` updated to current test counts (121 suites, 3,224 tests)
158
- - Autopilot example waypoint changed from Jita to Rens
159
-
160
- ### Schemas
161
-
162
- - Multiple Zod schema fixes discovered during live endpoint validation: added missing enum values, corrected optional fields, and adjusted types to match actual ESI responses
163
-
164
- ## [6.0.0] - 2026-07-03
165
-
166
- ### Added
167
-
168
- - **Runtime response validation** via [Zod](https://zod.dev/) schemas — every ESI endpoint response is validated at runtime, catching shape mismatches before they propagate to consumer code
169
- - Zod schemas for all 31 domain modules (133 interfaces) in `src/schemas/`, exported under the `schemas` namespace
170
- - `EsiValidationError` class (extends `EsiError`) thrown when response data doesn't match the expected schema
171
- - `isValidationError()` type guard for catching validation errors
172
- - `validateResponse` option on `EsiClientConfig` — on by default, can be disabled globally
173
- - `responseSchema` field on `EndpointDefinition` — wires schemas into the request pipeline via `createClient()`
174
- - New developer guide: `guides/RUNTIME-VALIDATION.md`
175
- - Response Validation Pipeline diagram in `guides/ARCHITECTURE.md`
176
- - Comprehensive TDD tests for schema parsing, validation integration, and common schemas (94 new tests)
177
- - BDD feature and step definitions for 9 runtime validation scenarios
178
-
179
- ### Changed
180
-
181
- - All TypeScript types in `src/types/` are now derived from Zod schemas via `z.infer<>` — schemas are the single source of truth
182
- - Schemas use `.passthrough()` mode so extra fields from ESI are preserved, not rejected
183
- - Test mock data across 25 test files updated to be spec-accurate (required by runtime validation)
184
- - Path-parameter IDs (e.g., `character_id`, `alliance_id`) are now optional in schemas, matching ESI which omits them from response bodies
185
-
186
- ### Dependencies
187
-
188
- - Added `zod` as a production dependency
189
-
190
- ## [5.3.0] - 2026-06-30
191
-
192
- ### Added
193
-
194
- - **Accept-Language configuration** — `language` option on `EsiClientConfig` injects the `Accept-Language` header for localized ESI responses (en, de, fr, ja, ru, zh, ko, es); changeable at runtime via `ApiClient.setLanguage()`
195
- - **ESI scope metadata** — generated `esi-scopes.generated.ts` with `EsiScope` union type (63 scopes) and `esiEndpointScopes` record mapping 119 authenticated endpoints to their required OAuth scopes
196
- - Exported `EsiScope` type and `esiEndpointScopes` map from package root
197
- - **Streaming pagination** — `stream*` methods on domain clients yield `PageResult<T>` one page at a time via `AsyncGenerator`, enabling backpressure and early termination for large paginated datasets
198
- - Streaming methods added to `MarketClient` (6), `ContractsClient` (3), `WalletClient` (3), `AssetsClient` (2), `KillmailsClient` (2)
199
- - `buildEndpointPath()` utility extracted from `createClient.ts` and exported from package root
200
- - `streamEndpoint()` protected method on `BaseEsiClient` for building custom streaming domain clients
201
- - Streaming pagination example (`npm run example:streaming`)
202
-
203
- ## [5.2.0] - 2026-06-29
204
-
205
- ### Added
206
-
207
- - **Spec-driven type generation** from ESI swagger spec (`npm run generate:types`) — 147 TypeScript interfaces + cache TTL map for 119 endpoints
208
- - **Spec-aware cache bypass** — GET requests within ESI-specified `x-cached-seconds` TTL return cached data with zero HTTP calls, layered on top of ETag caching
209
- - **`batch()` and `batchPost()` methods** on `EsiClient` — bounded concurrency for multi-ID fetches, auto-chunking for POST endpoints
210
- - **`EsiSpec` namespace export** with generated response types alongside hand-written types
211
- - **Type drift detection** in `npm run validate:esi` — compares hand-written types against generated spec types
212
- - CI step to verify generated types are up to date
213
- - **Retry with exponential backoff** — configurable retry for transient 5xx, timeout, and rate limit errors with jitter; respects circuit breaker state; GET-only by default with `retryMutations` opt-in
214
- - **`TimeoutError`** subclass of `EsiError` — typed timeout errors with `timeoutMs` property; per-request timeout override via `handleRequest()`
215
- - **Enhanced response metadata** via `withMetadata()` — rate limit info (`RateLimitMeta`), response timing (`responseTimeMs`), and cache hit type (`cacheHitType`: `'spec-ttl'` | `'etag-304'` | `'stale-on-error'`)
216
- - `RetryConfig` interface and `retryConfig` option on `EsiClientConfig`
217
- - `CircuitOpenError` passthrough in request handler (previously wrapped as generic Error)
218
- - **Per-group rate limiting** — 36 ESI rate limit groups extracted from the OpenAPI meta spec at build time; each group gets its own token bucket instead of a single global counter, preventing a burst of market requests from starving unrelated endpoints
219
- - **Optional per-user bucketing** — `userKeyExtractor` config option creates separate bucket sets per user key, supporting multi-character EVE applications
220
- - **Group-aware rate limit status** — `getGroupStatus(group)` and `getAllGroupStatuses()` methods for fine-grained rate limit monitoring; `isBlocked(group?)` accepts an optional group name
221
- - Generated `esi-rate-limit-groups.generated.ts` with 146 endpoint-to-group mappings
222
- - Exported `RateLimitGroupStatus` and `RateLimitGroupSpec` types
223
-
224
- ## [5.1.0] - 2026-06-26
225
-
226
- ### Added
227
-
228
- - **`noUncheckedIndexedAccess`** compiler flag — array/record indexing now returns `T | undefined`, catching unguarded index access at compile time
229
- - **`noImplicitReturns`** compiler flag — all function code paths must explicitly return a value
230
- - **`noImplicitOverride`** compiler flag — `override` keyword required when overriding base class methods
231
- - **`tsconfig.test.json`** — separate TypeScript config for tests, relaxing `noUncheckedIndexedAccess` for test utility patterns
232
-
233
- ### Changed
234
-
235
- - `RateLimiter` token cost lookup inlined (removed unnecessary `Record` indirection)
236
- - Jest configs (`jest.unit.config.cjs`, `jest.integration.config.cjs`) now use `tsconfig.test.json`
237
-
238
- ### Fixed
239
-
240
- - Unguarded indexed access in `ApiRequestHandler`, `CircuitBreaker`, `RateLimiter`, and `headersUtil`
241
-
242
- ## [5.0.0] - 2026-06-26
243
-
244
- ### Breaking Changes
245
-
246
- - **Removed `SovereigntyClient.getSovereigntyMap()`** — sunset ESI endpoint; use `getSovereigntySystems()` instead
247
- - **Removed `SovereigntyClient.getSovereigntyStructures()`** — sunset ESI endpoint; use `getSovereigntySystems()` instead
248
-
249
- ### Added
250
-
251
- - **Dependabot** — automated weekly dependency update PRs with grouped ESLint and testing ecosystems
252
- - **CodeQL Analysis** — GitHub-native security scanning workflow
253
- - **Commitlint** — conventional commit message validation via husky hook
254
- - **Version consistency script** — `npm run validate:versions` checks `package.json` matches `constants.ts`
255
- - **`npm run check:all`** — comprehensive validation including ESI endpoint and version checks
256
- - Coverage and npm download badges in README
257
- - `.editorconfig`, `.nvmrc`, `CONTRIBUTING.md`, `SECURITY.md`
258
- - ClientRegistry test coverage for all 35 client types
259
-
260
- ### Fixed
261
-
262
- - **POST body format** for asset and contact endpoints — request body was incorrectly structured
263
- - **POST body format** for `/universe/ids` and `/universe/names` — same issue
264
- - **Circuit breaker** now treats HTTP 420/429 rate-limit responses as failures
265
- - **configManager** uses `require.resolve` instead of `process.cwd()` fallback for reliable path resolution
266
- - **User-Agent version** — ESI requests were sending `esi.ts/3.4.0` instead of current version
267
- - **Compatibility date** — updated from `2025-12-16` to `2026-05-19` (Equinox)
268
- - TypeScript badge in README updated from 5.0+ to 6.0+
269
-
270
- ### Removed
271
-
272
- - `src/TODO` — fully completed roadmap
273
- - `jest.improved.config.cjs` — dead config matching zero test files
274
- - `docs/` — generated TypeDoc output removed from git tracking (CI builds as artifact)
275
- - Unused `getHeaders` test helper
276
-
277
- ### Changed
278
-
279
- - `package.json`: added `keywords`, `homepage`, `bugs` URLs, `files` includes README/LICENSE/CHANGELOG
280
- - Moved `docs/architecture.md` to `guides/ARCHITECTURE.md`
281
- - Updated `guides/TESTING.md` and `guides/DOCUMENTATION.md` to current state
282
- - Test coverage raised from 75% to 91%+
283
-
284
- ### Dependencies
285
-
286
- - `@typescript-eslint/eslint-plugin`: 7.18.0 → 8.x
287
- - `@typescript-eslint/parser`: 7.18.0 → 8.x
288
- - `@types/node`: 18.x → 26.x
289
- - `@commitlint/cli`: 19.x → 21.x
290
- - `eslint-config-prettier`: 9.x → 10.x
291
- - `lint-staged`: 16.x → 17.x
292
- - `jest-junit`: 16.x → 17.x
293
- - GitHub Actions: checkout v4→v7, setup-node v4→v6, upload-artifact v4→v7, codeql-action v3→v4, gh-pages v3→v4, action-gh-release v1→v3
294
-
295
- ## [4.1.1] - 2026-06-08
296
-
297
- ### Changed
298
-
299
- - **TypeScript 5.9 → 6.0** — upgraded to TypeScript 6.0.3, the last version before the Go-based TS7 compiler
300
- - `tsconfig.json`: added explicit `moduleResolution: "bundler"` (TS6 changed the default from `node` to `bundler`)
301
- - `tsconfig.json`: added explicit `rootDir: "./src"` (TS6 requires this when emitting)
302
- - `tsconfig.json`: removed `esModuleInterop: true` (always-on in TS6)
303
-
304
- ## [4.1.0] - 2026-06-08
305
-
306
- ### Added
307
-
308
- - **Equinox ESI compliance** — new endpoints and types for the [Equinox expansion](https://developers.eveonline.com/blog/equinox-on-esi-structures-sovereignty-and-access-lists) (compatibility date 2026-05-19)
309
- - **`SovereigntyClient.getSovereigntySystems()`** — combined sovereignty systems route with separate ADM indices (`military_index`, `industry_index`, `strategic_index`), occupancy data, and anchored structures in a single response
310
- - **`SkyhooksClient`** — new domain client with `getSovereigntyHubs()`, `getOrbitalSkyhooks()`, and `getRaidableSkyhooks()` endpoints for Upwell sovereignty structures
311
- - **`MercenaryClient`** — new domain client with `getMercenaryDens()` and `getMercenaryTacticalOperations()` endpoints for mercenary content
312
- - **`AccessListsClient`** — new domain client with `getAccessList(id)` for reading access list (ACL) contents including character, corporation, and alliance entries
313
- - `TestDataFactory` methods for all new Equinox types: `createSovereigntySystem()`, `createSovereigntyHub()`, `createOrbitalSkyhook()`, `createRaidableSkyhook()`, `createMercenaryDen()`, `createMercenaryTacticalOperation()`, `createAccessListEntry()`
314
- - TDD and BDD test coverage for all new endpoints
315
-
316
- ### Changed
317
-
318
- - `SovereigntyClient.getSovereigntyMap()` and `getSovereigntyStructures()` marked as deprecated — use `getSovereigntySystems()` instead
319
- - Domain client count increased from 32 to 35
320
-
321
- ### Dependencies
322
-
323
- - `ts-jest`: 29.4.9 → 29.4.11
324
- - `eslint-plugin-prettier`: 5.5.5 → 5.5.6
325
-
326
- ## [4.0.0] - 2026-05-15
327
-
328
- ### Breaking Changes
329
-
330
- - **Removed `RateLimiter.getInstance()` singleton** - Create instances with `new RateLimiter()` instead
331
- - **Removed global cache/circuit breaker functions** - `initializeETagCache()`, `getETagCache()`, `resetETagCache()`, `initializeCircuitBreaker()`, `getCircuitBreaker()`, `resetCircuitBreaker()` are no longer exported from `ApiRequestHandler`
332
- - Each `EsiClient` and `ApiClientBuilder` now creates its own `RateLimiter`, `ETagCacheManager`, and `CircuitBreaker` instances
333
-
334
- ### Added
335
-
336
- - **`BaseEsiClient` base class** — eliminates ~650 lines of repeated constructor/field/`withMetadata()` boilerplate across all 33 domain clients
337
- - **`RequestDeduplicator`** — coalesces concurrent identical GET requests into a single in-flight fetch, sharing the result across all callers (enabled by default; disable with `enableRequestDeduplication: false`)
338
- - **`EsiDiagnostics` API** — `client.diagnostics` accessor for cache/circuit-breaker stats, moved out of the main `EsiClient` API surface
339
- - **`fetchPages()` async generator** — memory-efficient page-by-page iteration over paginated ESI responses
340
- - **Request timeouts** — `config.timeout` now wired to `AbortController` (default 30s); previously the field existed but was never connected to `fetch()` calls
341
- - **`EsiError` retry helpers** — `isTimeout()`, `retryable` getter, and `isRetryable()` guard for smarter consumer retry logic
342
- - **`RateLimiterConfig`** — `minDelayMs` and `decelerationThreshold` exposed via `EsiClientConfig` for consumer-tunable rate limiting
343
- - TypeScript declaration files (`.d.ts`) now emitted with builds
344
- - `exports` field in `package.json` for modern Node.js module resolution
345
- - `engines` field specifying Node.js >= 18.0.0
346
- - `publishConfig` with public access for scoped package
347
- - `RateLimiter`, `ETagCacheManager`, and `CircuitBreaker` classes exported from main index
348
- - `ApiClientBuilder.setRateLimiter()`, `.setCache()`, `.setCircuitBreaker()` builder methods
349
- - `validateBaseUrl()` for SSRF protection — validates ESI host allowlist and HTTPS
350
- - `unsafeAllowCustomHost` config option to bypass base URL validation
351
- - URL sanitization in `EsiError` — sensitive query params (`token`, `access_token`, `api_key`) are redacted
352
- - Path parameters encoded with `encodeURIComponent()` for defense-in-depth
353
- - URL assertions in all client unit tests — every test now verifies the correct endpoint URL
354
- - Endpoint definition contract tests — 1800+ tests validating path templates, params, methods
355
- - Test coverage for `RequestDeduplicator`, `EsiDiagnostics`, `AsyncPaginationIterator`, and extended `EsiError` tests
356
- - `CHANGELOG.md` following Keep a Changelog format
357
- - Changelog validation step in release workflow
358
-
359
- ### Fixed
360
-
361
- - `.d.ts` files not generated during build (`declaration: true` added to `tsconfig.json`)
362
- - Release pipeline CNAME placeholder removed from GitHub Pages deployment
363
- - `ContractsClient.ts` test file renamed to `.test.ts` so Jest actually runs it
364
-
365
- ### Changed
366
-
367
- - `RateLimiter` constructor is now public
368
- - Cache, rate limiter, and circuit breaker are instance-based per client (no global shared state)
369
- - `ApiClientBuilder.build()` auto-creates a `RateLimiter` if none was explicitly set
370
- - `api-responses.ts` (1366 lines) split into 29 domain-specific type files with barrel re-export for backward compatibility
371
- - `RateLimiter` uses `logWarn` instead of `console.warn` for consistent observability
372
- - Reduced allocations and deduplicated fetch/sleep logic across core modules
373
-
374
- ## [3.4.0] - 2026-04-29
375
-
376
- ### Added
377
-
378
- - ESI response header best practices documentation
379
- - Dogma test coverage (10 TDD + 9 BDD tests)
380
- - Gated authenticated integration tests (32 tests across 14 endpoint groups)
381
- - EVE SSO token creator for local integration testing
382
- - Search endpoint `categories` query parameter
383
-
384
- ### Fixed
385
-
386
- - 3 industry endpoint paths (`corporation` -> `corporations`) for mining routes
387
- - Pagination middleware bypass: pages 2+ now route through request pipeline
388
- - Consolidated duplicate alliance contact endpoints
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [9.7.0] - 2026-09-09
9
+
10
+ First release since 9.6.0. Versions 9.6.1 and 9.6.2 were bumped in
11
+ `package.json` but never published, so upgrading from 9.6.0 picks up
12
+ everything below.
13
+
14
+ ### Added
15
+
16
+ - **`fetchAllPages` concurrent pagination** — fetch every page of a paginated endpoint in parallel with configurable concurrency (default 8). Adds `fetchAllEndpoint()` on `BaseEsiClient` and 73 `fetchAll*` convenience methods across all 19 domain clients, mirroring the existing `stream*` methods ([#180](https://github.com/lgriffin/ESI.ts/issues/180))
17
+ - **Typed response headers on `EsiResponseMeta`** — `etag`, `pages`, `expires`, `errorLimitRemain` and `errorLimitReset` are now typed fields, so consumers get autocomplete and type safety instead of raw string header lookups ([#179](https://github.com/lgriffin/ESI.ts/issues/179))
18
+ - **Per-endpoint rate limit overrides** — `endpointOverrides` in `RateLimiterConfig` lets you set endpoint-specific limits that take precedence over the generated group specs, for tightening sensitive endpoints such as market history ([#181](https://github.com/lgriffin/ESI.ts/issues/181))
19
+ - **`FetchLike` injection and `createNoopLogger()`** — `ApiClient` accepts an injectable `fetch` via `setFetch()` / `getFetch()` so tests can substitute in-memory doubles, and `createNoopLogger()` gives silent test output. Ships with an `InMemoryFetch` test helper ([#213](https://github.com/lgriffin/ESI.ts/issues/213), [#214](https://github.com/lgriffin/ESI.ts/issues/214))
20
+ - **`npm run help`** — a grouped, intent-organised command reference replacing the flat ~100-entry script listing, with keyword search (`npm run help wallet`)
21
+
22
+ ### Changed
23
+
24
+ - **Actionable auth error messages** — `NO_AUTH_TOKEN`, 401 and 403 errors now name the likely cause (missing `ESI_ACCESS_TOKEN`, expired token, missing OAuth scopes) and the specific fix (env var, `setAccessToken`, `onTokenRefresh` callback, or scope configuration)
25
+ - **`npm audit` moved off the PR merge path** — the merge path now runs a diff-aware `Dependency Audit` job that compares base against head and fails only on advisories a PR _introduces_. Pre-existing advisories are the nightly audit's responsibility, so a third-party disclosure no longer turns unrelated PRs red ([#248](https://github.com/lgriffin/ESI.ts/pull/248))
26
+ - **Audit acceptance allowlist** — reviewed known risks are recorded in `scripts/audit-exceptions.json` with a reason and a mandatory expiry date, honoured by the PR gate, the nightly audit and the release gate. An entry past its expiry is a hard failure
27
+ - **Schemathesis moved off the PR path** to a nightly run ([#234](https://github.com/lgriffin/ESI.ts/pull/234))
28
+ - **Types regenerated from the ESI spec** — upstream renamed `AllianceDetail` to `AlliancesDetail`
29
+ - Dependency updates: zod, eslint, jest, knip, lint-staged, `@redocly/cli`, `@types/node`
30
+
31
+ ### Fixed
32
+
33
+ - **`USER_AGENT` reported a stale version** — `src/core/constants.ts` had drifted to `9.2.0` while `package.json` was on `9.6.1`, so requests identified themselves to CCP as `esi.ts/9.2.0`. `package.json`, `constants.ts` and `.release-please-manifest.json` are now aligned
34
+ - **Nightly audit report corruption** — `nightly-audit.yml` merged stderr into its JSON report, so a single warning line would have made every `jq` query silently report zero vulnerabilities
35
+ - Zod v4 deprecation: `z.ZodTypeAny` replaced with `z.ZodType`
36
+
37
+ ## [9.1.0] - 2026-08-14
38
+
39
+ ### Added
40
+
41
+ - **Schema rejection tests** — 104 new tests verifying Zod schemas correctly reject invalid input shapes
42
+ - **Domain property fuzz tests** — property-based fuzz testing across domain clients using fast-check
43
+ - **Schema validation benchmarks** — performance benchmarks for Zod schema validation paths
44
+ - **Domain response type tests** — compile-time type tests for domain client response types via tsd
45
+
46
+ ### Changed
47
+
48
+ - **Expanded documentation** — updated examples, architecture guide, and testing guide with broader coverage
49
+ - **README refreshed** — updated feature descriptions and endpoint counts
50
+
51
+ ### Fixed
52
+
53
+ - **Fuzz test date handling** — switched to integer-based date arbitrary to avoid invalid `Date` values in property-based tests
54
+
55
+ ## [9.0.0] - 2026-08-12
56
+
57
+ ### Breaking Changes
58
+
59
+ - **Default retry count changed from 0 to 3** — transient failures (502, 503, 504, timeout, rate limit) now retry automatically with exponential backoff and jitter. Set `maxRetries: 0` in `retryConfig` to restore the previous behavior
60
+ - **Generated Zod schemas removed** — the `src/schemas/generated/` directory has been removed; only hand-written schemas in `src/schemas/` remain
61
+
62
+ ### Added
63
+
64
+ - **Sub-path exports** — targeted imports for reduced bundle size:
65
+ - `@lgriffin/esi.ts/schemas` — Zod schemas for runtime validation
66
+ - `@lgriffin/esi.ts/errors` — error classes and type guards
67
+ - `@lgriffin/esi.ts/testing` — `TestDataFactory` for test mock data
68
+ - **`isCircuitOpen()` type guard** — checks whether an error is a `CircuitOpenError`, complementing the existing `isTimeout()`, `isRetryable()`, and `isValidationError()` guards
69
+ - **`generate:all` script** — runs all generators (types, endpoints, OKF) in one command
70
+ - **`generate:endpoints` script** — regenerates endpoint definitions from the ESI OpenAPI spec
71
+
72
+ ### Changed
73
+
74
+ - **Cursor pagination routed through full pipeline** — cursor-based pagination now goes through the same middleware pipeline (rate limiter, circuit breaker, retry, caching) as offset pagination
75
+ - **Pagination retry unified with `IRetryStrategy`** — pagination requests now use the injectable retry strategy instead of a separate retry path
76
+
77
+ ### Fixed
78
+
79
+ - **Response interceptor status fix** — response interceptors previously received a hardcoded 200 status; they now receive the actual HTTP status code from the response
80
+ - **CI consolidated** — `pr-validation.yml` merged into `ci.yml`; all PR validation now runs through the main CI pipeline
81
+
82
+ ## [7.4.0] - 2026-07-17
83
+
84
+ ### Added
85
+
86
+ - **`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
87
+ - **`responseSchema` on `routeEndpoints`** — was the only endpoint file without runtime response validation; now validated with `z.looseObject({ route: z.array(z.number()) })`
88
+
89
+ ### Changed
90
+
91
+ - **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)
92
+ - **jest-fetch-mock 3 → 4** — updated null-body status mocks (204/304) to use `new Response(null, ...)` per Fetch spec
93
+ - Updated 11 minor/patch dependencies: @commitlint/cli, @microsoft/api-extractor, @redocly/cli, @types/node, @typescript-eslint/*, eslint-plugin-sonarjs, fast-check, knip, prettier, typedoc
94
+
95
+ ### Fixed
96
+
97
+ - CI: aligned `codeql.yml` branch targets to `[master, main, develop]`
98
+ - CI: pinned `jest-coverage-comment@main` → `@v1.0.34` (supply-chain risk)
99
+ - CI: added schema drift and generated types freshness checks to release pipeline
100
+
101
+ ### Deprecated
102
+
103
+ - `AllianceClient.getContacts()` — use `ContactsClient.getAllianceContacts()` instead
104
+ - `AllianceClient.getContactLabels()` — use `ContactsClient.getAllianceContactLabels()` instead
105
+
106
+ ## [7.3.0] - 2026-07-14
107
+
108
+ ### Added
109
+
110
+ - **`EsiResult<T>` discriminated union** and `safeMode` option for error-safe API calls
111
+ - **Branded ID types** (16 types) for type-safe ESI entity references
112
+ - **Expanded type-level tests** with tsd for error guards, endpoints, and domain types
113
+ - **Compile-time spec-to-Zod type alignment checks**
114
+ - **Schema drift detection** as a blocking CI check
115
+ - **Comprehensive testing gap closure** (+1233 tests)
116
+
117
+ ### Fixed
118
+
119
+ - Resolved three CI jobs failing with continue-on-error
120
+ - Normalized CRLF in API surface check
121
+ - Fixed schemathesis report permissions and `--url` flag
122
+ - Fixed API surface ordering issues
123
+ - Added missing `system_id` to `MarketOrderSchema` test data
124
+
125
+ ## [7.2.0] - 2026-07-08
126
+
127
+ ### Added
128
+
129
+ - **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.
130
+ - **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`)
131
+ - **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)
132
+ - **Consumer type tests** with [tsd](https://github.com/tsdjs/tsd) — verifies public API type correctness (`npm run test:types`)
133
+ - **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)
134
+ - **Schemathesis fuzz runner** — `npm run fuzz:api` runs Schemathesis against the Prism mock (Docker, weekly CI)
135
+ - Contract and fuzz test CI jobs added to `ci.yml` quality gate
136
+ - Weekly spec drift detection job added to `maintenance.yml`
137
+ - `jest.contract.config.cjs` and `jest.fuzz.config.cjs` test configurations
138
+
139
+ ### Dependencies
140
+
141
+ - Added `fast-check` (dev) — property-based testing framework
142
+ - Added `@stoplight/prism-cli` (dev) — OpenAPI mock server
143
+ - Added `tsd` (dev) — TypeScript type testing
144
+
145
+ ## [7.1.0] - 2026-07-08
146
+
147
+ ### Added
148
+
149
+ - **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).
150
+ - `redocly.yaml` config with tuned rulesets for ESI — structural rules as errors, CCP spec quirks as warnings
151
+ - `validate:spec` npm script added to `check:all` pipeline
152
+
153
+ ## [7.0.0] - 2026-07-08
154
+
155
+ ### Breaking Changes
156
+
157
+ - **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).
158
+ - **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.
159
+ - **Cache TTL metadata key** — internally changed from `x-cached-seconds` to `x-cache-age`. No consumer-facing impact (cache behavior is identical).
160
+
161
+ ### Changed
162
+
163
+ - Single OpenAPI spec fetch instead of dual Swagger + OpenAPI fetches
164
+ - Updated all scripts, tests, and documentation to reference OpenAPI spec
165
+ - Generated types now include 161 interfaces (up from 147), 126 cache TTLs, 70 scopes
166
+
167
+ ## [6.1.0] - 2026-07-07
168
+
169
+ ### Added
170
+
171
+ - **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
172
+ - **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)
173
+ - **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)
174
+ - Live output captured for all example scripts in `examples/output/`
175
+ - 3 new TDD test files and 1 new BDD feature file (81 TDD files, 40 BDD features total)
176
+ - 2 new fleet validation unit tests
177
+
178
+ ### Fixed
179
+
180
+ - **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)
181
+ - **Fleet rename test names** — test mock names shortened to respect ESI's 10-character limit (`'New Squad Name'` → `'New Squad'`)
182
+
183
+ ### Changed
184
+
185
+ - README rewritten with "Why ESI.ts vs. OpenAPI-generated clients" comparison, full endpoint coverage table, and updated architecture/testing references
186
+ - `guides/ARCHITECTURE.md`, `guides/TESTING.md`, and `TESTING.md` updated to current test counts (121 suites, 3,224 tests)
187
+ - Autopilot example waypoint changed from Jita to Rens
188
+
189
+ ### Schemas
190
+
191
+ - Multiple Zod schema fixes discovered during live endpoint validation: added missing enum values, corrected optional fields, and adjusted types to match actual ESI responses
192
+
193
+ ## [6.0.0] - 2026-07-03
194
+
195
+ ### Added
196
+
197
+ - **Runtime response validation** via [Zod](https://zod.dev/) schemas — every ESI endpoint response is validated at runtime, catching shape mismatches before they propagate to consumer code
198
+ - Zod schemas for all 31 domain modules (133 interfaces) in `src/schemas/`, exported under the `schemas` namespace
199
+ - `EsiValidationError` class (extends `EsiError`) thrown when response data doesn't match the expected schema
200
+ - `isValidationError()` type guard for catching validation errors
201
+ - `validateResponse` option on `EsiClientConfig` — on by default, can be disabled globally
202
+ - `responseSchema` field on `EndpointDefinition` — wires schemas into the request pipeline via `createClient()`
203
+ - New developer guide: `guides/RUNTIME-VALIDATION.md`
204
+ - Response Validation Pipeline diagram in `guides/ARCHITECTURE.md`
205
+ - Comprehensive TDD tests for schema parsing, validation integration, and common schemas (94 new tests)
206
+ - BDD feature and step definitions for 9 runtime validation scenarios
207
+
208
+ ### Changed
209
+
210
+ - All TypeScript types in `src/types/` are now derived from Zod schemas via `z.infer<>` — schemas are the single source of truth
211
+ - Schemas use `.passthrough()` mode so extra fields from ESI are preserved, not rejected
212
+ - Test mock data across 25 test files updated to be spec-accurate (required by runtime validation)
213
+ - Path-parameter IDs (e.g., `character_id`, `alliance_id`) are now optional in schemas, matching ESI which omits them from response bodies
214
+
215
+ ### Dependencies
216
+
217
+ - Added `zod` as a production dependency
218
+
219
+ ## [5.3.0] - 2026-06-30
220
+
221
+ ### Added
222
+
223
+ - **Accept-Language configuration** — `language` option on `EsiClientConfig` injects the `Accept-Language` header for localized ESI responses (en, de, fr, ja, ru, zh, ko, es); changeable at runtime via `ApiClient.setLanguage()`
224
+ - **ESI scope metadata** — generated `esi-scopes.generated.ts` with `EsiScope` union type (63 scopes) and `esiEndpointScopes` record mapping 119 authenticated endpoints to their required OAuth scopes
225
+ - Exported `EsiScope` type and `esiEndpointScopes` map from package root
226
+ - **Streaming pagination** — `stream*` methods on domain clients yield `PageResult<T>` one page at a time via `AsyncGenerator`, enabling backpressure and early termination for large paginated datasets
227
+ - Streaming methods added to `MarketClient` (6), `ContractsClient` (3), `WalletClient` (3), `AssetsClient` (2), `KillmailsClient` (2)
228
+ - `buildEndpointPath()` utility extracted from `createClient.ts` and exported from package root
229
+ - `streamEndpoint()` protected method on `BaseEsiClient` for building custom streaming domain clients
230
+ - Streaming pagination example (`npm run example:streaming`)
231
+
232
+ ## [5.2.0] - 2026-06-29
233
+
234
+ ### Added
235
+
236
+ - **Spec-driven type generation** from ESI swagger spec (`npm run generate:types`) — 147 TypeScript interfaces + cache TTL map for 119 endpoints
237
+ - **Spec-aware cache bypass** — GET requests within ESI-specified `x-cached-seconds` TTL return cached data with zero HTTP calls, layered on top of ETag caching
238
+ - **`batch()` and `batchPost()` methods** on `EsiClient` — bounded concurrency for multi-ID fetches, auto-chunking for POST endpoints
239
+ - **`EsiSpec` namespace export** with generated response types alongside hand-written types
240
+ - **Type drift detection** in `npm run validate:esi` — compares hand-written types against generated spec types
241
+ - CI step to verify generated types are up to date
242
+ - **Retry with exponential backoff** — configurable retry for transient 5xx, timeout, and rate limit errors with jitter; respects circuit breaker state; GET-only by default with `retryMutations` opt-in
243
+ - **`TimeoutError`** subclass of `EsiError` — typed timeout errors with `timeoutMs` property; per-request timeout override via `handleRequest()`
244
+ - **Enhanced response metadata** via `withMetadata()` — rate limit info (`RateLimitMeta`), response timing (`responseTimeMs`), and cache hit type (`cacheHitType`: `'spec-ttl'` | `'etag-304'` | `'stale-on-error'`)
245
+ - `RetryConfig` interface and `retryConfig` option on `EsiClientConfig`
246
+ - `CircuitOpenError` passthrough in request handler (previously wrapped as generic Error)
247
+ - **Per-group rate limiting** — 36 ESI rate limit groups extracted from the OpenAPI meta spec at build time; each group gets its own token bucket instead of a single global counter, preventing a burst of market requests from starving unrelated endpoints
248
+ - **Optional per-user bucketing** — `userKeyExtractor` config option creates separate bucket sets per user key, supporting multi-character EVE applications
249
+ - **Group-aware rate limit status** — `getGroupStatus(group)` and `getAllGroupStatuses()` methods for fine-grained rate limit monitoring; `isBlocked(group?)` accepts an optional group name
250
+ - Generated `esi-rate-limit-groups.generated.ts` with 146 endpoint-to-group mappings
251
+ - Exported `RateLimitGroupStatus` and `RateLimitGroupSpec` types
252
+
253
+ ## [5.1.0] - 2026-06-26
254
+
255
+ ### Added
256
+
257
+ - **`noUncheckedIndexedAccess`** compiler flag — array/record indexing now returns `T | undefined`, catching unguarded index access at compile time
258
+ - **`noImplicitReturns`** compiler flag — all function code paths must explicitly return a value
259
+ - **`noImplicitOverride`** compiler flag — `override` keyword required when overriding base class methods
260
+ - **`tsconfig.test.json`** — separate TypeScript config for tests, relaxing `noUncheckedIndexedAccess` for test utility patterns
261
+
262
+ ### Changed
263
+
264
+ - `RateLimiter` token cost lookup inlined (removed unnecessary `Record` indirection)
265
+ - Jest configs (`jest.unit.config.cjs`, `jest.integration.config.cjs`) now use `tsconfig.test.json`
266
+
267
+ ### Fixed
268
+
269
+ - Unguarded indexed access in `ApiRequestHandler`, `CircuitBreaker`, `RateLimiter`, and `headersUtil`
270
+
271
+ ## [5.0.0] - 2026-06-26
272
+
273
+ ### Breaking Changes
274
+
275
+ - **Removed `SovereigntyClient.getSovereigntyMap()`** — sunset ESI endpoint; use `getSovereigntySystems()` instead
276
+ - **Removed `SovereigntyClient.getSovereigntyStructures()`** — sunset ESI endpoint; use `getSovereigntySystems()` instead
277
+
278
+ ### Added
279
+
280
+ - **Dependabot** — automated weekly dependency update PRs with grouped ESLint and testing ecosystems
281
+ - **CodeQL Analysis** — GitHub-native security scanning workflow
282
+ - **Commitlint** — conventional commit message validation via husky hook
283
+ - **Version consistency script** — `npm run validate:versions` checks `package.json` matches `constants.ts`
284
+ - **`npm run check:all`** — comprehensive validation including ESI endpoint and version checks
285
+ - Coverage and npm download badges in README
286
+ - `.editorconfig`, `.nvmrc`, `CONTRIBUTING.md`, `SECURITY.md`
287
+ - ClientRegistry test coverage for all 35 client types
288
+
289
+ ### Fixed
290
+
291
+ - **POST body format** for asset and contact endpoints — request body was incorrectly structured
292
+ - **POST body format** for `/universe/ids` and `/universe/names` — same issue
293
+ - **Circuit breaker** now treats HTTP 420/429 rate-limit responses as failures
294
+ - **configManager** uses `require.resolve` instead of `process.cwd()` fallback for reliable path resolution
295
+ - **User-Agent version** — ESI requests were sending `esi.ts/3.4.0` instead of current version
296
+ - **Compatibility date** — updated from `2025-12-16` to `2026-05-19` (Equinox)
297
+ - TypeScript badge in README updated from 5.0+ to 6.0+
298
+
299
+ ### Removed
300
+
301
+ - `src/TODO` — fully completed roadmap
302
+ - `jest.improved.config.cjs` — dead config matching zero test files
303
+ - `docs/` — generated TypeDoc output removed from git tracking (CI builds as artifact)
304
+ - Unused `getHeaders` test helper
305
+
306
+ ### Changed
307
+
308
+ - `package.json`: added `keywords`, `homepage`, `bugs` URLs, `files` includes README/LICENSE/CHANGELOG
309
+ - Moved `docs/architecture.md` to `guides/ARCHITECTURE.md`
310
+ - Updated `guides/TESTING.md` and `guides/DOCUMENTATION.md` to current state
311
+ - Test coverage raised from 75% to 91%+
312
+
313
+ ### Dependencies
314
+
315
+ - `@typescript-eslint/eslint-plugin`: 7.18.0 → 8.x
316
+ - `@typescript-eslint/parser`: 7.18.0 → 8.x
317
+ - `@types/node`: 18.x → 26.x
318
+ - `@commitlint/cli`: 19.x → 21.x
319
+ - `eslint-config-prettier`: 9.x → 10.x
320
+ - `lint-staged`: 16.x → 17.x
321
+ - `jest-junit`: 16.x → 17.x
322
+ - GitHub Actions: checkout v4→v7, setup-node v4→v6, upload-artifact v4→v7, codeql-action v3→v4, gh-pages v3→v4, action-gh-release v1→v3
323
+
324
+ ## [4.1.1] - 2026-06-08
325
+
326
+ ### Changed
327
+
328
+ - **TypeScript 5.9 → 6.0** — upgraded to TypeScript 6.0.3, the last version before the Go-based TS7 compiler
329
+ - `tsconfig.json`: added explicit `moduleResolution: "bundler"` (TS6 changed the default from `node` to `bundler`)
330
+ - `tsconfig.json`: added explicit `rootDir: "./src"` (TS6 requires this when emitting)
331
+ - `tsconfig.json`: removed `esModuleInterop: true` (always-on in TS6)
332
+
333
+ ## [4.1.0] - 2026-06-08
334
+
335
+ ### Added
336
+
337
+ - **Equinox ESI compliance** — new endpoints and types for the [Equinox expansion](https://developers.eveonline.com/blog/equinox-on-esi-structures-sovereignty-and-access-lists) (compatibility date 2026-05-19)
338
+ - **`SovereigntyClient.getSovereigntySystems()`** — combined sovereignty systems route with separate ADM indices (`military_index`, `industry_index`, `strategic_index`), occupancy data, and anchored structures in a single response
339
+ - **`SkyhooksClient`** — new domain client with `getSovereigntyHubs()`, `getOrbitalSkyhooks()`, and `getRaidableSkyhooks()` endpoints for Upwell sovereignty structures
340
+ - **`MercenaryClient`** — new domain client with `getMercenaryDens()` and `getMercenaryTacticalOperations()` endpoints for mercenary content
341
+ - **`AccessListsClient`** — new domain client with `getAccessList(id)` for reading access list (ACL) contents including character, corporation, and alliance entries
342
+ - `TestDataFactory` methods for all new Equinox types: `createSovereigntySystem()`, `createSovereigntyHub()`, `createOrbitalSkyhook()`, `createRaidableSkyhook()`, `createMercenaryDen()`, `createMercenaryTacticalOperation()`, `createAccessListEntry()`
343
+ - TDD and BDD test coverage for all new endpoints
344
+
345
+ ### Changed
346
+
347
+ - `SovereigntyClient.getSovereigntyMap()` and `getSovereigntyStructures()` marked as deprecated — use `getSovereigntySystems()` instead
348
+ - Domain client count increased from 32 to 35
349
+
350
+ ### Dependencies
351
+
352
+ - `ts-jest`: 29.4.9 → 29.4.11
353
+ - `eslint-plugin-prettier`: 5.5.5 → 5.5.6
354
+
355
+ ## [4.0.0] - 2026-05-15
356
+
357
+ ### Breaking Changes
358
+
359
+ - **Removed `RateLimiter.getInstance()` singleton** - Create instances with `new RateLimiter()` instead
360
+ - **Removed global cache/circuit breaker functions** - `initializeETagCache()`, `getETagCache()`, `resetETagCache()`, `initializeCircuitBreaker()`, `getCircuitBreaker()`, `resetCircuitBreaker()` are no longer exported from `ApiRequestHandler`
361
+ - Each `EsiClient` and `ApiClientBuilder` now creates its own `RateLimiter`, `ETagCacheManager`, and `CircuitBreaker` instances
362
+
363
+ ### Added
364
+
365
+ - **`BaseEsiClient` base class** — eliminates ~650 lines of repeated constructor/field/`withMetadata()` boilerplate across all 33 domain clients
366
+ - **`RequestDeduplicator`** — coalesces concurrent identical GET requests into a single in-flight fetch, sharing the result across all callers (enabled by default; disable with `enableRequestDeduplication: false`)
367
+ - **`EsiDiagnostics` API** — `client.diagnostics` accessor for cache/circuit-breaker stats, moved out of the main `EsiClient` API surface
368
+ - **`fetchPages()` async generator** — memory-efficient page-by-page iteration over paginated ESI responses
369
+ - **Request timeouts** — `config.timeout` now wired to `AbortController` (default 30s); previously the field existed but was never connected to `fetch()` calls
370
+ - **`EsiError` retry helpers** — `isTimeout()`, `retryable` getter, and `isRetryable()` guard for smarter consumer retry logic
371
+ - **`RateLimiterConfig`** — `minDelayMs` and `decelerationThreshold` exposed via `EsiClientConfig` for consumer-tunable rate limiting
372
+ - TypeScript declaration files (`.d.ts`) now emitted with builds
373
+ - `exports` field in `package.json` for modern Node.js module resolution
374
+ - `engines` field specifying Node.js >= 18.0.0
375
+ - `publishConfig` with public access for scoped package
376
+ - `RateLimiter`, `ETagCacheManager`, and `CircuitBreaker` classes exported from main index
377
+ - `ApiClientBuilder.setRateLimiter()`, `.setCache()`, `.setCircuitBreaker()` builder methods
378
+ - `validateBaseUrl()` for SSRF protection — validates ESI host allowlist and HTTPS
379
+ - `unsafeAllowCustomHost` config option to bypass base URL validation
380
+ - URL sanitization in `EsiError` — sensitive query params (`token`, `access_token`, `api_key`) are redacted
381
+ - Path parameters encoded with `encodeURIComponent()` for defense-in-depth
382
+ - URL assertions in all client unit tests — every test now verifies the correct endpoint URL
383
+ - Endpoint definition contract tests — 1800+ tests validating path templates, params, methods
384
+ - Test coverage for `RequestDeduplicator`, `EsiDiagnostics`, `AsyncPaginationIterator`, and extended `EsiError` tests
385
+ - `CHANGELOG.md` following Keep a Changelog format
386
+ - Changelog validation step in release workflow
387
+
388
+ ### Fixed
389
+
390
+ - `.d.ts` files not generated during build (`declaration: true` added to `tsconfig.json`)
391
+ - Release pipeline CNAME placeholder removed from GitHub Pages deployment
392
+ - `ContractsClient.ts` test file renamed to `.test.ts` so Jest actually runs it
393
+
394
+ ### Changed
395
+
396
+ - `RateLimiter` constructor is now public
397
+ - Cache, rate limiter, and circuit breaker are instance-based per client (no global shared state)
398
+ - `ApiClientBuilder.build()` auto-creates a `RateLimiter` if none was explicitly set
399
+ - `api-responses.ts` (1366 lines) split into 29 domain-specific type files with barrel re-export for backward compatibility
400
+ - `RateLimiter` uses `logWarn` instead of `console.warn` for consistent observability
401
+ - Reduced allocations and deduplicated fetch/sleep logic across core modules
402
+
403
+ ## [3.4.0] - 2026-04-29
404
+
405
+ ### Added
406
+
407
+ - ESI response header best practices documentation
408
+ - Dogma test coverage (10 TDD + 9 BDD tests)
409
+ - Gated authenticated integration tests (32 tests across 14 endpoint groups)
410
+ - EVE SSO token creator for local integration testing
411
+ - Search endpoint `categories` query parameter
412
+
413
+ ### Fixed
414
+
415
+ - 3 industry endpoint paths (`corporation` -> `corporations`) for mining routes
416
+ - Pagination middleware bypass: pages 2+ now route through request pipeline
417
+ - Consolidated duplicate alliance contact endpoints