@lgriffin/esi.ts 10.2.0 → 11.0.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 (431) hide show
  1. package/CHANGELOG.md +414 -32
  2. package/LICENSE +667 -19
  3. package/NOTICE +19 -0
  4. package/README.md +149 -902
  5. package/dist/EsiClient.d.mts +5 -36
  6. package/dist/EsiClient.d.ts +5 -36
  7. package/dist/EsiClient.d.ts.map +1 -1
  8. package/dist/EsiClientBuilder.d.mts +128 -1
  9. package/dist/EsiClientBuilder.d.ts +128 -1
  10. package/dist/EsiClientBuilder.d.ts.map +1 -1
  11. package/dist/adapters/PipelineTransport.d.ts +16 -0
  12. package/dist/adapters/PipelineTransport.d.ts.map +1 -0
  13. package/dist/auth/EsiTokenManager.d.mts +62 -21
  14. package/dist/auth/EsiTokenManager.d.ts +62 -21
  15. package/dist/auth/EsiTokenManager.d.ts.map +1 -1
  16. package/dist/auth/EveSsoClient.d.mts +9 -9
  17. package/dist/auth/EveSsoClient.d.ts +9 -9
  18. package/dist/auth/EveSsoClient.d.ts.map +1 -1
  19. package/dist/auth/errors.d.mts +2 -2
  20. package/dist/auth/errors.d.ts +2 -2
  21. package/dist/auth/errors.d.ts.map +1 -1
  22. package/dist/auth/jwt.d.mts +7 -7
  23. package/dist/auth/jwt.d.ts +7 -7
  24. package/dist/auth/jwt.d.ts.map +1 -1
  25. package/dist/auth/storage/FileTokenStorage.d.mts +1 -1
  26. package/dist/auth/storage/FileTokenStorage.d.ts +1 -1
  27. package/dist/auth/storage/FileTokenStorage.d.ts.map +1 -1
  28. package/dist/{chunk-BBSHKVPI.js → chunk-CM63VGGF.js} +1 -1
  29. package/dist/chunk-CM63VGGF.js.map +1 -0
  30. package/dist/chunk-DFRTIZK4.js +275 -0
  31. package/dist/chunk-DFRTIZK4.js.map +1 -0
  32. package/dist/{chunk-VZS32UQ3.mjs → chunk-HXS7ZVEL.mjs} +129 -28
  33. package/dist/chunk-HXS7ZVEL.mjs.map +1 -0
  34. package/dist/chunk-JNFQXEWZ.mjs +275 -0
  35. package/dist/chunk-JNFQXEWZ.mjs.map +1 -0
  36. package/dist/chunk-KIY3XA5Q.mjs +2980 -0
  37. package/dist/chunk-KIY3XA5Q.mjs.map +1 -0
  38. package/dist/{chunk-R7D7M2LQ.mjs → chunk-MGOE2YNH.mjs} +1 -1
  39. package/dist/chunk-MGOE2YNH.mjs.map +1 -0
  40. package/dist/{chunk-SAQBXXTM.js → chunk-MRKZ55XI.js} +130 -29
  41. package/dist/chunk-MRKZ55XI.js.map +1 -0
  42. package/dist/chunk-NKFIHGC6.js +2980 -0
  43. package/dist/chunk-NKFIHGC6.js.map +1 -0
  44. package/dist/{chunk-MSJHIJXA.js → chunk-S73PKM2Y.js} +20 -5
  45. package/dist/chunk-S73PKM2Y.js.map +1 -0
  46. package/dist/{chunk-3ZI5A37L.mjs → chunk-YUHGSPQ7.mjs} +19 -4
  47. package/dist/chunk-YUHGSPQ7.mjs.map +1 -0
  48. package/dist/client/identity.d.mts +20 -0
  49. package/dist/client/identity.d.ts +20 -0
  50. package/dist/client/identity.d.ts.map +1 -0
  51. package/dist/client/index.d.mts +11 -0
  52. package/dist/client/index.d.ts +11 -0
  53. package/dist/client/index.d.ts.map +1 -0
  54. package/dist/client/index.js +6607 -0
  55. package/dist/client/index.js.map +1 -0
  56. package/dist/client/index.mjs +6607 -0
  57. package/dist/client/index.mjs.map +1 -0
  58. package/dist/client/runtime.d.mts +67 -0
  59. package/dist/client/runtime.d.ts +67 -0
  60. package/dist/client/runtime.d.ts.map +1 -0
  61. package/dist/clients/BaseEsiClient.d.ts.map +1 -1
  62. package/dist/clients/ClientRegistry.d.mts +45 -0
  63. package/dist/clients/ClientRegistry.d.ts +45 -0
  64. package/dist/clients/ClientRegistry.d.ts.map +1 -0
  65. package/dist/clients/CorporationsClient.d.mts +3 -3
  66. package/dist/clients/CorporationsClient.d.ts +3 -3
  67. package/dist/clients/CorporationsClient.d.ts.map +1 -1
  68. package/dist/clients/MailClient.d.mts +2 -2
  69. package/dist/clients/MailClient.d.ts +2 -2
  70. package/dist/clients/MailClient.d.ts.map +1 -1
  71. package/dist/clients/MetaClient.d.mts +3 -2
  72. package/dist/clients/MetaClient.d.ts +3 -2
  73. package/dist/clients/MetaClient.d.ts.map +1 -1
  74. package/dist/clients/MilitaryCampaignsClient.d.mts +14 -7
  75. package/dist/clients/MilitaryCampaignsClient.d.ts +14 -7
  76. package/dist/clients/MilitaryCampaignsClient.d.ts.map +1 -1
  77. package/dist/clients/RouteClient.d.mts +4 -4
  78. package/dist/clients/RouteClient.d.ts +4 -4
  79. package/dist/clients/RouteClient.d.ts.map +1 -1
  80. package/dist/clients/SkillsClient.d.mts +1 -1
  81. package/dist/clients/SkillsClient.d.ts +1 -1
  82. package/dist/clients/SkillsClient.d.ts.map +1 -1
  83. package/dist/clients/SkyhooksClient.d.mts +4 -3
  84. package/dist/clients/SkyhooksClient.d.ts +4 -3
  85. package/dist/clients/SkyhooksClient.d.ts.map +1 -1
  86. package/dist/core/ApiClient.d.mts +11 -0
  87. package/dist/core/ApiClient.d.ts +11 -0
  88. package/dist/core/ApiClient.d.ts.map +1 -1
  89. package/dist/core/ApiClientBuilder.d.ts.map +1 -1
  90. package/dist/core/ApiRequestHandler.d.ts +2 -1
  91. package/dist/core/ApiRequestHandler.d.ts.map +1 -1
  92. package/dist/core/BatchRequestHandler.d.mts +13 -2
  93. package/dist/core/BatchRequestHandler.d.ts +13 -2
  94. package/dist/core/BatchRequestHandler.d.ts.map +1 -1
  95. package/dist/core/EsiClientConfig.d.mts +60 -0
  96. package/dist/core/EsiClientConfig.d.ts +60 -0
  97. package/dist/core/EsiClientConfig.d.ts.map +1 -0
  98. package/dist/core/RetryStrategy.d.mts +3 -3
  99. package/dist/core/RetryStrategy.d.ts +3 -3
  100. package/dist/core/RetryStrategy.d.ts.map +1 -1
  101. package/dist/core/cache/ETagCacheManager.d.mts +9 -4
  102. package/dist/core/cache/ETagCacheManager.d.ts +9 -4
  103. package/dist/core/cache/ETagCacheManager.d.ts.map +1 -1
  104. package/dist/core/cache/cacheKey.d.ts +31 -6
  105. package/dist/core/cache/cacheKey.d.ts.map +1 -1
  106. package/dist/core/circuitBreaker/CircuitBreaker.d.mts +8 -12
  107. package/dist/core/circuitBreaker/CircuitBreaker.d.ts +8 -12
  108. package/dist/core/circuitBreaker/CircuitBreaker.d.ts.map +1 -1
  109. package/dist/core/clock.d.ts +8 -0
  110. package/dist/core/clock.d.ts.map +1 -0
  111. package/dist/core/configureApiClient.d.mts +1 -1
  112. package/dist/core/configureApiClient.d.ts +1 -1
  113. package/dist/core/configureApiClient.d.ts.map +1 -1
  114. package/dist/core/constants.d.ts +3 -3
  115. package/dist/core/constants.d.ts.map +1 -1
  116. package/dist/core/endpoints/EndpointDefinition.d.mts +17 -0
  117. package/dist/core/endpoints/EndpointDefinition.d.ts +17 -0
  118. package/dist/core/endpoints/EndpointDefinition.d.ts.map +1 -1
  119. package/dist/core/endpoints/assetEndpoints.d.mts +12 -0
  120. package/dist/core/endpoints/assetEndpoints.d.ts +12 -0
  121. package/dist/core/endpoints/assetEndpoints.d.ts.map +1 -1
  122. package/dist/core/endpoints/characterEndpoints.d.mts +10 -0
  123. package/dist/core/endpoints/characterEndpoints.d.ts +10 -0
  124. package/dist/core/endpoints/characterEndpoints.d.ts.map +1 -1
  125. package/dist/core/endpoints/contactEndpoints.d.mts +1 -0
  126. package/dist/core/endpoints/contactEndpoints.d.ts +1 -0
  127. package/dist/core/endpoints/contactEndpoints.d.ts.map +1 -1
  128. package/dist/core/endpoints/contractEndpoints.d.mts +2 -0
  129. package/dist/core/endpoints/contractEndpoints.d.ts +2 -0
  130. package/dist/core/endpoints/contractEndpoints.d.ts.map +1 -1
  131. package/dist/core/endpoints/corporationEndpoints.d.mts +16 -3
  132. package/dist/core/endpoints/corporationEndpoints.d.ts +16 -3
  133. package/dist/core/endpoints/corporationEndpoints.d.ts.map +1 -1
  134. package/dist/core/endpoints/createClient.d.mts +2 -2
  135. package/dist/core/endpoints/createClient.d.ts +2 -2
  136. package/dist/core/endpoints/createClient.d.ts.map +1 -1
  137. package/dist/core/endpoints/esi-cache-ttls.generated.d.ts.map +1 -1
  138. package/dist/core/endpoints/esi-rate-limit-groups.generated.d.ts.map +1 -1
  139. package/dist/core/endpoints/esi-scopes.generated.d.ts.map +1 -1
  140. package/dist/core/endpoints/fittingEndpoints.d.mts +3 -0
  141. package/dist/core/endpoints/fittingEndpoints.d.ts +3 -0
  142. package/dist/core/endpoints/fittingEndpoints.d.ts.map +1 -1
  143. package/dist/core/endpoints/fleetEndpoints.d.mts +6 -0
  144. package/dist/core/endpoints/fleetEndpoints.d.ts +6 -0
  145. package/dist/core/endpoints/fleetEndpoints.d.ts.map +1 -1
  146. package/dist/core/endpoints/industryEndpoints.d.mts +2 -2
  147. package/dist/core/endpoints/industryEndpoints.d.ts +2 -2
  148. package/dist/core/endpoints/mailEndpoints.d.mts +2 -0
  149. package/dist/core/endpoints/mailEndpoints.d.ts +2 -0
  150. package/dist/core/endpoints/mailEndpoints.d.ts.map +1 -1
  151. package/dist/core/endpoints/mercenaryEndpoints.d.mts +1 -1
  152. package/dist/core/endpoints/mercenaryEndpoints.d.ts +1 -1
  153. package/dist/core/endpoints/metaEndpoints.d.mts +23 -8
  154. package/dist/core/endpoints/metaEndpoints.d.ts +23 -8
  155. package/dist/core/endpoints/metaEndpoints.d.ts.map +1 -1
  156. package/dist/core/endpoints/militaryCampaignEndpoints.d.mts +78 -49
  157. package/dist/core/endpoints/militaryCampaignEndpoints.d.ts +78 -49
  158. package/dist/core/endpoints/militaryCampaignEndpoints.d.ts.map +1 -1
  159. package/dist/core/endpoints/paragonHubEndpoints.d.mts +5 -5
  160. package/dist/core/endpoints/paragonHubEndpoints.d.ts +5 -5
  161. package/dist/core/endpoints/skyhookEndpoints.d.mts +10 -8
  162. package/dist/core/endpoints/skyhookEndpoints.d.ts +10 -8
  163. package/dist/core/endpoints/skyhookEndpoints.d.ts.map +1 -1
  164. package/dist/core/logger/DefaultLogger.d.mts +20 -1
  165. package/dist/core/logger/DefaultLogger.d.ts +20 -1
  166. package/dist/core/logger/DefaultLogger.d.ts.map +1 -1
  167. package/dist/core/logger/ILogger.d.mts +9 -0
  168. package/dist/core/logger/ILogger.d.ts +9 -0
  169. package/dist/core/logger/ILogger.d.ts.map +1 -1
  170. package/dist/core/logger/NoopLogger.d.ts.map +1 -1
  171. package/dist/core/logger/clientLog.d.ts.map +1 -1
  172. package/dist/core/logger/loggerUtil.d.ts.map +1 -1
  173. package/dist/core/logger/redactLog.d.ts +23 -0
  174. package/dist/core/logger/redactLog.d.ts.map +1 -0
  175. package/dist/core/logger/resolveLogger.d.ts +3 -3
  176. package/dist/core/logger/resolveLogger.d.ts.map +1 -1
  177. package/dist/core/pagination/AsyncPaginationIterator.d.ts.map +1 -1
  178. package/dist/core/pagination/CursorPaginationHandler.d.mts +2 -1
  179. package/dist/core/pagination/CursorPaginationHandler.d.ts +2 -1
  180. package/dist/core/pagination/CursorPaginationHandler.d.ts.map +1 -1
  181. package/dist/core/ports/CacheStore.d.mts +32 -0
  182. package/dist/core/ports/CacheStore.d.ts +32 -0
  183. package/dist/core/ports/CacheStore.d.ts.map +1 -0
  184. package/dist/core/ports/Clock.d.mts +13 -0
  185. package/dist/core/ports/Clock.d.ts +13 -0
  186. package/dist/core/ports/Clock.d.ts.map +1 -0
  187. package/dist/core/ports/HttpTransport.d.mts +7 -0
  188. package/dist/core/ports/HttpTransport.d.ts +7 -0
  189. package/dist/core/ports/HttpTransport.d.ts.map +1 -0
  190. package/dist/core/ports/Identity.d.mts +31 -0
  191. package/dist/core/ports/Identity.d.ts +31 -0
  192. package/dist/core/ports/Identity.d.ts.map +1 -0
  193. package/dist/core/ports/Logger.d.mts +17 -0
  194. package/dist/core/ports/Logger.d.ts +17 -0
  195. package/dist/core/ports/Logger.d.ts.map +1 -0
  196. package/dist/core/ports/OperationTransport.d.mts +42 -0
  197. package/dist/core/ports/OperationTransport.d.ts +42 -0
  198. package/dist/core/ports/OperationTransport.d.ts.map +1 -0
  199. package/dist/core/ports/TokenProvider.d.mts +7 -0
  200. package/dist/core/ports/TokenProvider.d.ts +7 -0
  201. package/dist/core/ports/TokenProvider.d.ts.map +1 -0
  202. package/dist/core/ports/index.d.mts +14 -0
  203. package/dist/core/ports/index.d.ts +14 -0
  204. package/dist/core/ports/index.d.ts.map +1 -0
  205. package/dist/core/rateLimiter/RateLimiter.d.mts +11 -4
  206. package/dist/core/rateLimiter/RateLimiter.d.ts +11 -4
  207. package/dist/core/rateLimiter/RateLimiter.d.ts.map +1 -1
  208. package/dist/core/requestPipeline/cachePolicy.d.ts +5 -3
  209. package/dist/core/requestPipeline/cachePolicy.d.ts.map +1 -1
  210. package/dist/core/requestPipeline/fetchExecution.d.ts +3 -1
  211. package/dist/core/requestPipeline/fetchExecution.d.ts.map +1 -1
  212. package/dist/core/requestPipeline/headers.d.ts +1 -1
  213. package/dist/core/requestPipeline/headers.d.ts.map +1 -1
  214. package/dist/core/requestPipeline/index.d.ts +3 -5
  215. package/dist/core/requestPipeline/index.d.ts.map +1 -1
  216. package/dist/core/requestPipeline/paginationOrchestration.d.ts +1 -1
  217. package/dist/core/requestPipeline/paginationOrchestration.d.ts.map +1 -1
  218. package/dist/core/requestPipeline/statusHandling.d.ts +3 -3
  219. package/dist/core/requestPipeline/statusHandling.d.ts.map +1 -1
  220. package/dist/core/util/callerIdentity.d.ts +10 -0
  221. package/dist/core/util/callerIdentity.d.ts.map +1 -0
  222. package/dist/core/util/concurrency.d.ts +2 -2
  223. package/dist/core/util/concurrency.d.ts.map +1 -1
  224. package/dist/core/util/error.d.mts +92 -3
  225. package/dist/core/util/error.d.ts +92 -3
  226. package/dist/core/util/error.d.ts.map +1 -1
  227. package/dist/core/util/retry.d.mts +4 -4
  228. package/dist/core/util/retry.d.ts +4 -4
  229. package/dist/core/util/retry.d.ts.map +1 -1
  230. package/dist/core/util/validation.d.ts +6 -0
  231. package/dist/core/util/validation.d.ts.map +1 -1
  232. package/dist/errors.d.mts +2 -3
  233. package/dist/errors.d.ts +2 -3
  234. package/dist/errors.d.ts.map +1 -1
  235. package/dist/errors.js +29 -3
  236. package/dist/errors.js.map +1 -1
  237. package/dist/errors.mjs +28 -2
  238. package/dist/generated/operations.generated.d.mts +9379 -0
  239. package/dist/generated/operations.generated.d.ts +9379 -0
  240. package/dist/generated/operations.generated.d.ts.map +1 -0
  241. package/dist/index.d.mts +4 -4
  242. package/dist/index.d.ts +4 -4
  243. package/dist/index.d.ts.map +1 -1
  244. package/dist/index.js +699 -2865
  245. package/dist/index.js.map +1 -1
  246. package/dist/index.mjs +359 -2525
  247. package/dist/index.mjs.map +1 -1
  248. package/dist/schemas/character.d.mts +5 -0
  249. package/dist/schemas/character.d.ts +5 -0
  250. package/dist/schemas/character.d.ts.map +1 -1
  251. package/dist/schemas/contacts.d.mts +2 -0
  252. package/dist/schemas/contacts.d.ts +2 -0
  253. package/dist/schemas/contacts.d.ts.map +1 -1
  254. package/dist/schemas/corporation.d.mts +24 -3
  255. package/dist/schemas/corporation.d.ts +24 -3
  256. package/dist/schemas/corporation.d.ts.map +1 -1
  257. package/dist/schemas/fittings.d.mts +4 -0
  258. package/dist/schemas/fittings.d.ts +4 -0
  259. package/dist/schemas/fittings.d.ts.map +1 -1
  260. package/dist/schemas/fleet.d.mts +8 -0
  261. package/dist/schemas/fleet.d.ts +8 -0
  262. package/dist/schemas/fleet.d.ts.map +1 -1
  263. package/dist/schemas/index.js +24 -2
  264. package/dist/schemas/index.js.map +1 -1
  265. package/dist/schemas/index.mjs +23 -1
  266. package/dist/schemas/industry.d.mts +2 -2
  267. package/dist/schemas/industry.d.ts +2 -2
  268. package/dist/schemas/mail.d.mts +4 -0
  269. package/dist/schemas/mail.d.ts +4 -0
  270. package/dist/schemas/mail.d.ts.map +1 -1
  271. package/dist/schemas/mercenary.d.mts +1 -1
  272. package/dist/schemas/mercenary.d.ts +1 -1
  273. package/dist/schemas/meta.d.mts +18 -9
  274. package/dist/schemas/meta.d.ts +18 -9
  275. package/dist/schemas/meta.d.ts.map +1 -1
  276. package/dist/schemas/military-campaigns.d.mts +54 -10
  277. package/dist/schemas/military-campaigns.d.ts +54 -10
  278. package/dist/schemas/military-campaigns.d.ts.map +1 -1
  279. package/dist/schemas/paragon-hub.d.mts +4 -4
  280. package/dist/schemas/paragon-hub.d.ts +4 -4
  281. package/dist/schemas/skyhooks.d.mts +18 -6
  282. package/dist/schemas/skyhooks.d.ts +18 -6
  283. package/dist/schemas/skyhooks.d.ts.map +1 -1
  284. package/dist/sde/clock.d.ts +11 -0
  285. package/dist/sde/clock.d.ts.map +1 -0
  286. package/dist/sde/domain/characters/schemas.d.ts +149 -0
  287. package/dist/sde/domain/characters/schemas.d.ts.map +1 -0
  288. package/dist/sde/domain/characters/types.d.mts +163 -0
  289. package/dist/sde/domain/characters/types.d.ts +163 -0
  290. package/dist/sde/domain/characters/types.d.ts.map +1 -0
  291. package/dist/sde/domain/content/schemas.d.ts +84 -0
  292. package/dist/sde/domain/content/schemas.d.ts.map +1 -0
  293. package/dist/sde/domain/content/types.d.mts +91 -0
  294. package/dist/sde/domain/content/types.d.ts +91 -0
  295. package/dist/sde/domain/content/types.d.ts.map +1 -0
  296. package/dist/sde/domain/corporations/schemas.d.ts +113 -0
  297. package/dist/sde/domain/corporations/schemas.d.ts.map +1 -0
  298. package/dist/sde/domain/corporations/types.d.mts +118 -0
  299. package/dist/sde/domain/corporations/types.d.ts +118 -0
  300. package/dist/sde/domain/corporations/types.d.ts.map +1 -0
  301. package/dist/sde/domain/dogma/schemas.d.ts +76 -0
  302. package/dist/sde/domain/dogma/schemas.d.ts.map +1 -0
  303. package/dist/sde/domain/dogma/types.d.mts +80 -0
  304. package/dist/sde/domain/dogma/types.d.ts +80 -0
  305. package/dist/sde/domain/dogma/types.d.ts.map +1 -0
  306. package/dist/sde/domain/industry/schemas.d.ts +204 -0
  307. package/dist/sde/domain/industry/schemas.d.ts.map +1 -0
  308. package/dist/sde/domain/industry/types.d.mts +88 -0
  309. package/dist/sde/domain/industry/types.d.ts +88 -0
  310. package/dist/sde/domain/industry/types.d.ts.map +1 -0
  311. package/dist/sde/domain/market/schemas.d.ts +24 -0
  312. package/dist/sde/domain/market/schemas.d.ts.map +1 -0
  313. package/dist/sde/domain/market/types.d.mts +25 -0
  314. package/dist/sde/domain/market/types.d.ts +25 -0
  315. package/dist/sde/domain/market/types.d.ts.map +1 -0
  316. package/dist/sde/domain/schemas.d.ts +15 -0
  317. package/dist/sde/domain/schemas.d.ts.map +1 -0
  318. package/dist/sde/domain/skins/schemas.d.ts +109 -0
  319. package/dist/sde/domain/skins/schemas.d.ts.map +1 -0
  320. package/dist/sde/domain/skins/types.d.mts +121 -0
  321. package/dist/sde/domain/skins/types.d.ts +121 -0
  322. package/dist/sde/domain/skins/types.d.ts.map +1 -0
  323. package/dist/sde/domain/types/schemas.d.ts +163 -0
  324. package/dist/sde/domain/types/schemas.d.ts.map +1 -0
  325. package/dist/sde/domain/types/types.d.mts +182 -0
  326. package/dist/sde/domain/types/types.d.ts +182 -0
  327. package/dist/sde/domain/types/types.d.ts.map +1 -0
  328. package/dist/sde/domain/types.d.mts +16 -0
  329. package/dist/sde/domain/types.d.ts +16 -0
  330. package/dist/sde/domain/types.d.ts.map +1 -0
  331. package/dist/sde/domain/ui/schemas.d.ts +42 -0
  332. package/dist/sde/domain/ui/schemas.d.ts.map +1 -0
  333. package/dist/sde/domain/ui/types.d.mts +45 -0
  334. package/dist/sde/domain/ui/types.d.ts +45 -0
  335. package/dist/sde/domain/ui/types.d.ts.map +1 -0
  336. package/dist/sde/domain/universe/schemas.d.ts +239 -0
  337. package/dist/sde/domain/universe/schemas.d.ts.map +1 -0
  338. package/dist/sde/domain/universe/types.d.mts +206 -0
  339. package/dist/sde/domain/universe/types.d.ts +206 -0
  340. package/dist/sde/domain/universe/types.d.ts.map +1 -0
  341. package/dist/sde/domain/version/schemas.d.ts +11 -0
  342. package/dist/sde/domain/version/schemas.d.ts.map +1 -0
  343. package/dist/sde/errors.d.mts +1 -1
  344. package/dist/sde/errors.d.ts +1 -1
  345. package/dist/sde/errors.d.ts.map +1 -1
  346. package/dist/sde/index.d.mts +7 -6
  347. package/dist/sde/index.d.ts +7 -6
  348. package/dist/sde/index.d.ts.map +1 -1
  349. package/dist/sde/index.js +31 -21
  350. package/dist/sde/index.js.map +1 -1
  351. package/dist/sde/index.mjs +26 -16
  352. package/dist/sde/index.mjs.map +1 -1
  353. package/dist/sde/ingestion/SdeDatabaseBuilder.d.ts +11 -0
  354. package/dist/sde/ingestion/SdeDatabaseBuilder.d.ts.map +1 -1
  355. package/dist/sde/ingestion/SdeDownloader.d.ts +2 -2
  356. package/dist/sde/ingestion/SdeDownloader.d.ts.map +1 -1
  357. package/dist/sde/memory.d.mts +5 -5
  358. package/dist/sde/memory.d.ts +5 -5
  359. package/dist/sde/memory.d.ts.map +1 -1
  360. package/dist/sde/memory.js +2 -2
  361. package/dist/sde/memory.mjs +1 -1
  362. package/dist/sde/{IStaticDataProvider.d.mts → ports/IStaticDataProvider.d.mts} +9 -2
  363. package/dist/sde/{IStaticDataProvider.d.ts → ports/IStaticDataProvider.d.ts} +9 -2
  364. package/dist/sde/ports/IStaticDataProvider.d.ts.map +1 -0
  365. package/dist/sde/{MemorySdeProvider.d.mts → providers/memory/MemorySdeProvider.d.mts} +3 -3
  366. package/dist/sde/{MemorySdeProvider.d.ts → providers/memory/MemorySdeProvider.d.ts} +3 -3
  367. package/dist/sde/providers/memory/MemorySdeProvider.d.ts.map +1 -0
  368. package/dist/sde/providers/order.d.ts +10 -0
  369. package/dist/sde/providers/order.d.ts.map +1 -0
  370. package/dist/sde/{SdeDataProvider.d.mts → providers/yaml/SdeDataProvider.d.mts} +14 -5
  371. package/dist/sde/{SdeDataProvider.d.ts → providers/yaml/SdeDataProvider.d.ts} +14 -5
  372. package/dist/sde/providers/yaml/SdeDataProvider.d.ts.map +1 -0
  373. package/dist/sde/{SdeTestDataFactory.d.mts → testing/SdeTestDataFactory.d.mts} +3 -3
  374. package/dist/sde/{SdeTestDataFactory.d.ts → testing/SdeTestDataFactory.d.ts} +3 -3
  375. package/dist/sde/testing/SdeTestDataFactory.d.ts.map +1 -0
  376. package/dist/sde/version.d.mts +1 -1
  377. package/dist/sde/version.d.ts +1 -1
  378. package/dist/sde/version.d.ts.map +1 -1
  379. package/dist/testing/TestDataFactory.d.mts +21 -3
  380. package/dist/testing/TestDataFactory.d.ts +21 -3
  381. package/dist/testing/TestDataFactory.d.ts.map +1 -1
  382. package/dist/testing/index.d.mts +1 -0
  383. package/dist/testing/index.d.ts +1 -0
  384. package/dist/testing/index.d.ts.map +1 -1
  385. package/dist/testing/index.js +157 -10
  386. package/dist/testing/index.js.map +1 -1
  387. package/dist/testing/index.mjs +155 -8
  388. package/dist/testing/index.mjs.map +1 -1
  389. package/dist/testing/mockTransport.d.mts +87 -0
  390. package/dist/testing/mockTransport.d.ts +87 -0
  391. package/dist/testing/mockTransport.d.ts.map +1 -0
  392. package/dist/types/generated/esi-spec.generated.d.mts +230 -10
  393. package/dist/types/generated/esi-spec.generated.d.ts +230 -10
  394. package/dist/types/generated/esi-spec.generated.d.ts.map +1 -1
  395. package/dist/types/military-campaigns.d.mts +4 -1
  396. package/dist/types/military-campaigns.d.ts +4 -1
  397. package/dist/types/military-campaigns.d.ts.map +1 -1
  398. package/dist/types/skyhooks.d.mts +2 -1
  399. package/dist/types/skyhooks.d.ts +2 -1
  400. package/dist/types/skyhooks.d.ts.map +1 -1
  401. package/package.json +167 -131
  402. package/dist/chunk-3ZI5A37L.mjs.map +0 -1
  403. package/dist/chunk-BBSHKVPI.js.map +0 -1
  404. package/dist/chunk-D5L5HZVF.mjs +0 -417
  405. package/dist/chunk-D5L5HZVF.mjs.map +0 -1
  406. package/dist/chunk-MSJHIJXA.js.map +0 -1
  407. package/dist/chunk-R7D7M2LQ.mjs.map +0 -1
  408. package/dist/chunk-SAQBXXTM.js.map +0 -1
  409. package/dist/chunk-VZS32UQ3.mjs.map +0 -1
  410. package/dist/chunk-XIB2OXEZ.js +0 -417
  411. package/dist/chunk-XIB2OXEZ.js.map +0 -1
  412. package/dist/config/jest/globalSetup.d.ts +0 -2
  413. package/dist/config/jest/globalSetup.d.ts.map +0 -1
  414. package/dist/config/jest/globalTeardown.d.ts +0 -2
  415. package/dist/config/jest/globalTeardown.d.ts.map +0 -1
  416. package/dist/config/jest/jest.setup.d.ts +0 -3
  417. package/dist/config/jest/jest.setup.d.ts.map +0 -1
  418. package/dist/core/ClientRegistry.d.mts +0 -45
  419. package/dist/core/ClientRegistry.d.ts +0 -45
  420. package/dist/core/ClientRegistry.d.ts.map +0 -1
  421. package/dist/core/logger/logger.d.ts +0 -12
  422. package/dist/core/logger/logger.d.ts.map +0 -1
  423. package/dist/sde/IStaticDataProvider.d.ts.map +0 -1
  424. package/dist/sde/MemorySdeProvider.d.ts.map +0 -1
  425. package/dist/sde/SdeDataProvider.d.ts.map +0 -1
  426. package/dist/sde/SdeTestDataFactory.d.ts.map +0 -1
  427. package/dist/sde/schemas.d.ts +0 -1121
  428. package/dist/sde/schemas.d.ts.map +0 -1
  429. package/dist/sde/types.d.mts +0 -1039
  430. package/dist/sde/types.d.ts +0 -1039
  431. package/dist/sde/types.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -8,9 +8,43 @@ import {
8
8
  isCharacterNotFound,
9
9
  isSsoError,
10
10
  isTokenRevoked
11
- } from "./chunk-R7D7M2LQ.mjs";
11
+ } from "./chunk-MGOE2YNH.mjs";
12
+ import {
13
+ ApiClient,
14
+ CircuitBreaker,
15
+ ETagCacheManager,
16
+ RateLimiter,
17
+ RequestDeduplicator,
18
+ RetryStrategy,
19
+ USER_AGENT,
20
+ configureApiClient,
21
+ createDefaultLogger,
22
+ evictRejectedResponse,
23
+ fetchAllPages,
24
+ fetchPages,
25
+ getLogger,
26
+ handleRequest,
27
+ logDebug,
28
+ logDebug2,
29
+ logError,
30
+ logFatal,
31
+ logInfo,
32
+ logInfo2,
33
+ logTrace,
34
+ logWarn,
35
+ logWarn2,
36
+ parseWarning,
37
+ redactingLogger,
38
+ resolveCache,
39
+ setLogger,
40
+ toPinoLogger,
41
+ validateBaseUrl,
42
+ validatePathParam,
43
+ validateQueryParam
44
+ } from "./chunk-KIY3XA5Q.mjs";
12
45
  import {
13
46
  AccessListSchema,
47
+ AddedContactIdsSchema,
14
48
  AgentResearchSchema,
15
49
  AllianceIconSchema,
16
50
  AllianceInfoSchema,
@@ -24,6 +58,7 @@ import {
24
58
  CalendarEventAttendeeSchema,
25
59
  CalendarEventDetailSchema,
26
60
  CalendarEventSchema,
61
+ CharacterAffiliationSchema,
27
62
  CharacterAssetSchema,
28
63
  CharacterAttributesSchema,
29
64
  CharacterFleetInfoSchema,
@@ -33,6 +68,7 @@ import {
33
68
  CharacterMarketOrderHistorySchema,
34
69
  CharacterMarketOrderSchema,
35
70
  CharacterMilitaryCampaignObjectiveSchema,
71
+ CharacterMilitaryCampaignObjectivesResponseSchema,
36
72
  CharacterOnlineSchema,
37
73
  CharacterPortraitSchema,
38
74
  CharacterRoleSchema,
@@ -78,6 +114,7 @@ import {
78
114
  CorporationTitleSchema,
79
115
  CorporationWalletDivisionSchema,
80
116
  CorporationWalletTransactionSchema,
117
+ CspaChargeCostSchema,
81
118
  CustomsOfficeSchema,
82
119
  DogmaAttributeSchema,
83
120
  DogmaDynamicItemSchema,
@@ -91,9 +128,12 @@ import {
91
128
  FactionWarfareStatsSchema,
92
129
  FactionWarfareSystemSchema,
93
130
  FactionWarfareWarSchema,
131
+ FittingCreatedSchema,
94
132
  FittingSchema,
95
133
  FleetInfoSchema,
96
134
  FleetMemberSchema,
135
+ FleetSquadCreatedSchema,
136
+ FleetWingCreatedSchema,
97
137
  FleetWingSchema,
98
138
  FreelanceJobDetailSchema,
99
139
  FreelanceJobParticipantsListingSchema,
@@ -113,6 +153,8 @@ import {
113
153
  LoyaltyPointsSchema,
114
154
  LoyaltyStoreOfferSchema,
115
155
  MailHeaderSchema,
156
+ MailIdSchema,
157
+ MailLabelIdSchema,
116
158
  MailLabelsResponseSchema,
117
159
  MailMessageSchema,
118
160
  MailingListSchema,
@@ -130,7 +172,9 @@ import {
130
172
  MetaNameSchema,
131
173
  MetaStatusSchema,
132
174
  MilitaryCampaignObjectiveSchema,
175
+ MilitaryCampaignObjectivesResponseSchema,
133
176
  MilitaryCampaignSchema,
177
+ MilitaryCampaignsResponseSchema,
134
178
  MiningLedgerEntrySchema,
135
179
  MiningObserverEntrySchema,
136
180
  MiningObserverSchema,
@@ -147,7 +191,7 @@ import {
147
191
  PublicContractItemSchema,
148
192
  PublicContractSchema,
149
193
  RaceSchema,
150
- RaidableSkyhookSchema,
194
+ RaidableSkyhooksResponseSchema,
151
195
  RegionInfoSchema,
152
196
  SchematicInfoSchema,
153
197
  SearchResultSchema,
@@ -173,1506 +217,39 @@ import {
173
217
  WalletTransactionSchema,
174
218
  WarSchema,
175
219
  schemas_exports
176
- } from "./chunk-VZS32UQ3.mjs";
220
+ } from "./chunk-HXS7ZVEL.mjs";
177
221
  import {
178
- CircuitBreaker,
179
222
  CircuitOpenError,
223
+ EsiConfigurationError,
180
224
  EsiError,
225
+ EsiFaultError,
226
+ EsiNetworkError,
227
+ EsiPaginationError,
228
+ EsiParseError,
229
+ EsiTokenRefreshError,
181
230
  EsiValidationError,
182
231
  TimeoutError,
183
- buildError,
184
- createDefaultLogger,
185
- getLogger,
186
232
  isCircuitOpen,
233
+ isConfigurationError,
187
234
  isEsiError,
235
+ isFaultError,
188
236
  isForbidden,
237
+ isNetworkError,
189
238
  isNotFound,
239
+ isPaginationError,
240
+ isParseError,
190
241
  isRateLimited,
191
242
  isRetryable,
192
243
  isServerError,
193
244
  isTimeout,
245
+ isTokenRefreshError,
194
246
  isUnauthorized,
195
247
  isValidationError,
196
- logDebug,
197
- logDebug2,
198
- logError,
199
- logError2,
200
- logFatal,
201
- logInfo,
202
- logInfo2,
203
- logTrace,
204
- logWarn,
205
- logWarn2,
206
248
  sanitizeUrl,
207
- setLogger,
208
- toPinoLogger
209
- } from "./chunk-D5L5HZVF.mjs";
249
+ toEsiError
250
+ } from "./chunk-JNFQXEWZ.mjs";
210
251
  import "./chunk-JIW4BXLP.mjs";
211
252
 
212
- // src/core/middleware/Middleware.ts
213
- var MiddlewareManager = class {
214
- requestInterceptors = [];
215
- responseInterceptors = [];
216
- addRequestInterceptor(fn) {
217
- this.requestInterceptors.push(fn);
218
- return () => {
219
- this.requestInterceptors = this.requestInterceptors.filter(
220
- (i) => i !== fn
221
- );
222
- };
223
- }
224
- addResponseInterceptor(fn) {
225
- this.responseInterceptors.push(fn);
226
- return () => {
227
- this.responseInterceptors = this.responseInterceptors.filter(
228
- (i) => i !== fn
229
- );
230
- };
231
- }
232
- async applyRequestInterceptors(context) {
233
- let ctx = context;
234
- for (const interceptor of this.requestInterceptors) {
235
- ctx = await interceptor(ctx);
236
- }
237
- return ctx;
238
- }
239
- async applyResponseInterceptors(context) {
240
- let ctx = context;
241
- for (const interceptor of this.responseInterceptors) {
242
- ctx = await interceptor(ctx);
243
- }
244
- return ctx;
245
- }
246
- hasInterceptors() {
247
- return this.requestInterceptors.length > 0 || this.responseInterceptors.length > 0;
248
- }
249
- clear() {
250
- this.requestInterceptors = [];
251
- this.responseInterceptors = [];
252
- }
253
- };
254
-
255
- // src/core/ApiClient.ts
256
- var ApiClient = class {
257
- constructor(clientId, link, accessToken) {
258
- this.clientId = clientId;
259
- this.link = link;
260
- this.accessToken = accessToken;
261
- this.link = this.link.replace(/\/$/, "");
262
- }
263
- clientId;
264
- link;
265
- accessToken;
266
- datasource;
267
- tokenProvider;
268
- refreshInFlight;
269
- middleware = new MiddlewareManager();
270
- cache = null;
271
- rateLimiter = null;
272
- circuitBreaker = null;
273
- timeout = 3e4;
274
- deduplicator = null;
275
- retryConfig = null;
276
- retryStrategy = null;
277
- validateResponse = true;
278
- validateRequest = false;
279
- language;
280
- compatibilityDate;
281
- fetchFn = null;
282
- logger = null;
283
- getTimeout() {
284
- return this.timeout;
285
- }
286
- setTimeout(timeout) {
287
- this.timeout = timeout;
288
- }
289
- getCache() {
290
- return this.cache;
291
- }
292
- setCache(cache) {
293
- this.cache = cache;
294
- }
295
- getRateLimiter() {
296
- return this.rateLimiter;
297
- }
298
- setRateLimiter(limiter) {
299
- this.rateLimiter = limiter;
300
- }
301
- getCircuitBreaker() {
302
- return this.circuitBreaker;
303
- }
304
- setCircuitBreaker(cb) {
305
- this.circuitBreaker = cb;
306
- }
307
- getDeduplicator() {
308
- return this.deduplicator;
309
- }
310
- setDeduplicator(dedup) {
311
- this.deduplicator = dedup;
312
- }
313
- getRetryConfig() {
314
- return this.retryConfig;
315
- }
316
- setRetryConfig(config) {
317
- this.retryConfig = config;
318
- }
319
- getRetryStrategy() {
320
- return this.retryStrategy;
321
- }
322
- setRetryStrategy(strategy) {
323
- this.retryStrategy = strategy;
324
- }
325
- getValidateResponse() {
326
- return this.validateResponse;
327
- }
328
- setValidateResponse(validate) {
329
- this.validateResponse = validate;
330
- }
331
- getValidateRequest() {
332
- return this.validateRequest;
333
- }
334
- setValidateRequest(validate) {
335
- this.validateRequest = validate;
336
- }
337
- getFetch() {
338
- return this.fetchFn ?? globalThis.fetch;
339
- }
340
- setFetch(fn) {
341
- this.fetchFn = fn;
342
- }
343
- getMiddleware() {
344
- return this.middleware;
345
- }
346
- addRequestInterceptor(fn) {
347
- return this.middleware.addRequestInterceptor(fn);
348
- }
349
- addResponseInterceptor(fn) {
350
- return this.middleware.addResponseInterceptor(fn);
351
- }
352
- getAuthorizationHeader() {
353
- return this.accessToken ? `Bearer ${this.accessToken}` : void 0;
354
- }
355
- getLink() {
356
- return this.link;
357
- }
358
- getDatasource() {
359
- return this.datasource;
360
- }
361
- setDatasource(datasource) {
362
- this.datasource = datasource;
363
- }
364
- getLanguage() {
365
- return this.language;
366
- }
367
- setLanguage(language) {
368
- this.language = language;
369
- }
370
- getCompatibilityDate() {
371
- return this.compatibilityDate;
372
- }
373
- setCompatibilityDate(date) {
374
- this.compatibilityDate = date;
375
- }
376
- setAccessToken(token) {
377
- this.accessToken = token;
378
- }
379
- setTokenProvider(provider) {
380
- this.tokenProvider = provider;
381
- }
382
- getLogger() {
383
- return this.logger;
384
- }
385
- setLogger(logger) {
386
- this.logger = logger;
387
- }
388
- hasTokenProvider() {
389
- return this.tokenProvider !== void 0;
390
- }
391
- toJSON() {
392
- return {
393
- link: this.link,
394
- datasource: this.datasource,
395
- timeout: this.timeout,
396
- hasCache: this.cache !== null,
397
- hasRateLimiter: this.rateLimiter !== null,
398
- hasCircuitBreaker: this.circuitBreaker !== null,
399
- hasDeduplicator: this.deduplicator !== null,
400
- hasTokenProvider: this.tokenProvider !== void 0,
401
- validateResponse: this.validateResponse,
402
- validateRequest: this.validateRequest,
403
- language: this.language,
404
- compatibilityDate: this.compatibilityDate
405
- };
406
- }
407
- async refreshToken() {
408
- if (!this.tokenProvider) {
409
- throw new Error("No token provider configured");
410
- }
411
- if (this.refreshInFlight) {
412
- return this.refreshInFlight;
413
- }
414
- this.refreshInFlight = this.tokenProvider().then(
415
- (token) => {
416
- this.accessToken = token;
417
- this.refreshInFlight = void 0;
418
- return token;
419
- },
420
- (err) => {
421
- this.refreshInFlight = void 0;
422
- throw err;
423
- }
424
- );
425
- return this.refreshInFlight;
426
- }
427
- };
428
-
429
- // src/core/cache/cacheKey.ts
430
- import { createHash } from "crypto";
431
- function scopeToIdentity(key, client, requiresAuth) {
432
- if (!requiresAuth) return key;
433
- const authHeader = client.getAuthorizationHeader();
434
- if (!authHeader) return key;
435
- const hash = createHash("sha256").update(authHeader).digest("hex").slice(0, 16);
436
- return `${hash}:${key}`;
437
- }
438
- function buildCacheKey(url, client, requiresAuth = false) {
439
- return scopeToIdentity(url, client, requiresAuth);
440
- }
441
- function buildDedupeKey(endpoint, client, requiresAuth = false) {
442
- return scopeToIdentity(endpoint, client, requiresAuth);
443
- }
444
-
445
- // src/core/constants.ts
446
- var PACKAGE_NAME = "esi.ts";
447
- var PACKAGE_VERSION = "10.2.0";
448
- var USER_AGENT = `${PACKAGE_NAME}/${PACKAGE_VERSION}`;
449
- var COMPATIBILITY_DATE = "2026-05-19";
450
-
451
- // src/core/requestPipeline/headers.ts
452
- var parseCacheControlTtl = (headers) => {
453
- const cacheControl = headers["cache-control"] ?? headers["Cache-Control"];
454
- if (!cacheControl) return void 0;
455
- const match = /max-age=(\d+)/.exec(cacheControl);
456
- return match ? parseInt(match[1], 10) * 1e3 : void 0;
457
- };
458
- function buildRequestHeaders(client, url, method, requiresAuth, useETag, body, resolveCache2) {
459
- const headers = {
460
- Accept: "application/json",
461
- "Accept-Encoding": "gzip, deflate, br",
462
- "User-Agent": USER_AGENT,
463
- "X-Compatibility-Date": client.getCompatibilityDate() ?? COMPATIBILITY_DATE
464
- };
465
- const language = client.getLanguage();
466
- if (language) {
467
- headers["Accept-Language"] = language;
468
- }
469
- if (requiresAuth) {
470
- const authHeader = client.getAuthorizationHeader();
471
- if (!authHeader) {
472
- throw buildError(
473
- [
474
- "Authorization header is required for this endpoint but no access token is configured",
475
- "Fix: set ESI_ACCESS_TOKEN in your environment (see .env.example), or call client.setAccessToken(token), or pass accessToken to the EsiClient constructor"
476
- ].join(" \u2014 "),
477
- "NO_AUTH_TOKEN"
478
- );
479
- }
480
- headers["Authorization"] = authHeader;
481
- }
482
- const cache = resolveCache2(client);
483
- if (useETag && method === "GET" && cache) {
484
- const key = buildCacheKey(url, client, requiresAuth);
485
- const cachedETag = cache.getETag(key);
486
- if (cachedETag) {
487
- headers["If-None-Match"] = cachedETag;
488
- logDebug2(client, `Adding If-None-Match header: ${cachedETag}`, {
489
- etag: cachedETag
490
- });
491
- }
492
- }
493
- if (body) {
494
- headers["Content-Type"] = "application/json";
495
- }
496
- return headers;
497
- }
498
-
499
- // src/core/util/stringUtil.ts
500
- function camelToSnake(s) {
501
- return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
502
- }
503
-
504
- // src/core/endpoints/esi-cache-ttls.generated.ts
505
- var esiCacheTtls = {
506
- "GET:alliances": 3600,
507
- "GET:alliances/{alliance_id}": 3600,
508
- "GET:alliances/{alliance_id}/contacts": 300,
509
- "GET:alliances/{alliance_id}/contacts/labels": 300,
510
- "GET:alliances/{alliance_id}/corporations": 3600,
511
- "GET:characters/{character_id}": 86400,
512
- "GET:characters/{character_id}/access-lists": 300,
513
- "GET:characters/{character_id}/access-lists/{access_list_id}": 300,
514
- "GET:characters/{character_id}/agents_research": 3600,
515
- "GET:characters/{character_id}/assets": 3600,
516
- "GET:characters/{character_id}/attributes": 120,
517
- "GET:characters/{character_id}/blueprints": 3600,
518
- "GET:characters/{character_id}/calendar": 5,
519
- "GET:characters/{character_id}/calendar/{event_id}": 5,
520
- "PUT:characters/{character_id}/calendar/{event_id}": 5,
521
- "GET:characters/{character_id}/calendar/{event_id}/attendees": 600,
522
- "GET:characters/{character_id}/clones": 120,
523
- "GET:characters/{character_id}/contacts": 300,
524
- "GET:characters/{character_id}/contacts/labels": 300,
525
- "GET:characters/{character_id}/contracts": 300,
526
- "GET:characters/{character_id}/contracts/{contract_id}/bids": 300,
527
- "GET:characters/{character_id}/contracts/{contract_id}/items": 3600,
528
- "GET:characters/{character_id}/corporationhistory": 86400,
529
- "GET:characters/{character_id}/fatigue": 300,
530
- "GET:characters/{character_id}/fittings": 300,
531
- "GET:characters/{character_id}/fleet": 60,
532
- "GET:characters/{character_id}/freelance-jobs": 60,
533
- "GET:characters/{character_id}/freelance-jobs/{job_id}/participation": 60,
534
- "GET:characters/{character_id}/implants": 120,
535
- "GET:characters/{character_id}/industry/jobs": 300,
536
- "GET:characters/{character_id}/killmails/recent": 300,
537
- "GET:characters/{character_id}/location": 5,
538
- "GET:characters/{character_id}/loyalty/points": 3600,
539
- "GET:characters/{character_id}/mail": 30,
540
- "GET:characters/{character_id}/mail/{mail_id}": 30,
541
- "GET:characters/{character_id}/mail/labels": 30,
542
- "GET:characters/{character_id}/mail/lists": 120,
543
- "GET:characters/{character_id}/medals": 3600,
544
- "GET:characters/{character_id}/mercenary-tactical-operations": 300,
545
- "GET:characters/{character_id}/mercenary-tactical-operations/{operation_id}": 300,
546
- "GET:characters/{character_id}/mining": 600,
547
- "GET:characters/{character_id}/notifications": 600,
548
- "GET:characters/{character_id}/notifications/contacts": 600,
549
- "GET:characters/{character_id}/online": 60,
550
- "GET:characters/{character_id}/orders": 1200,
551
- "GET:characters/{character_id}/orders/history": 3600,
552
- "GET:characters/{character_id}/planets": 600,
553
- "GET:characters/{character_id}/planets/{planet_id}": 600,
554
- "GET:characters/{character_id}/roles": 3600,
555
- "GET:characters/{character_id}/search": 3600,
556
- "GET:characters/{character_id}/ship": 5,
557
- "GET:characters/{character_id}/skillqueue": 60,
558
- "GET:characters/{character_id}/skills": 60,
559
- "GET:characters/{character_id}/standings": 3600,
560
- "GET:characters/{character_id}/structures/mercenary-dens": 3600,
561
- "GET:characters/{character_id}/structures/mercenary-dens/{mercenary_den_id}": 3600,
562
- "GET:characters/{character_id}/titles": 3600,
563
- "GET:characters/{character_id}/wallet": 120,
564
- "GET:characters/{character_id}/wallet/journal": 3600,
565
- "GET:characters/{character_id}/wallet/transactions": 3600,
566
- "POST:characters/affiliation": 3600,
567
- "GET:contracts/public/{region_id}": 1800,
568
- "GET:contracts/public/bids/{contract_id}": 300,
569
- "GET:contracts/public/items/{contract_id}": 3600,
570
- "GET:corporation/{corporation_id}/mining/extractions": 1800,
571
- "GET:corporation/{corporation_id}/mining/observers": 3600,
572
- "GET:corporation/{corporation_id}/mining/observers/{observer_id}": 3600,
573
- "GET:corporations/{corporation_id}": 3600,
574
- "GET:corporations/{corporation_id}/alliancehistory": 3600,
575
- "GET:corporations/{corporation_id}/assets": 3600,
576
- "GET:corporations/{corporation_id}/blueprints": 3600,
577
- "GET:corporations/{corporation_id}/contacts": 300,
578
- "GET:corporations/{corporation_id}/contacts/labels": 300,
579
- "GET:corporations/{corporation_id}/containers/logs": 600,
580
- "GET:corporations/{corporation_id}/contracts": 300,
581
- "GET:corporations/{corporation_id}/contracts/{contract_id}/bids": 3600,
582
- "GET:corporations/{corporation_id}/contracts/{contract_id}/items": 3600,
583
- "GET:corporations/{corporation_id}/customs_offices": 3600,
584
- "GET:corporations/{corporation_id}/divisions": 3600,
585
- "GET:corporations/{corporation_id}/facilities": 3600,
586
- "GET:corporations/{corporation_id}/icons": 3600,
587
- "GET:corporations/{corporation_id}/industry/jobs": 300,
588
- "GET:corporations/{corporation_id}/killmails/recent": 300,
589
- "GET:corporations/{corporation_id}/medals": 3600,
590
- "GET:corporations/{corporation_id}/medals/issued": 3600,
591
- "GET:corporations/{corporation_id}/members": 3600,
592
- "GET:corporations/{corporation_id}/members/limit": 3600,
593
- "GET:corporations/{corporation_id}/members/titles": 3600,
594
- "GET:corporations/{corporation_id}/membertracking": 3600,
595
- "GET:corporations/{corporation_id}/orders": 1200,
596
- "GET:corporations/{corporation_id}/orders/history": 3600,
597
- "GET:corporations/{corporation_id}/projects/{project_id}": 60,
598
- "GET:corporations/{corporation_id}/projects/{project_id}/contribution/{character_id}": 60,
599
- "GET:corporations/{corporation_id}/roles": 3600,
600
- "GET:corporations/{corporation_id}/roles/history": 3600,
601
- "GET:corporations/{corporation_id}/shareholders": 3600,
602
- "GET:corporations/{corporation_id}/standings": 3600,
603
- "GET:corporations/{corporation_id}/starbases": 3600,
604
- "GET:corporations/{corporation_id}/starbases/{starbase_id}": 3600,
605
- "GET:corporations/{corporation_id}/structures": 3600,
606
- "GET:corporations/{corporation_id}/structures/skyhooks": 3600,
607
- "GET:corporations/{corporation_id}/structures/skyhooks/{skyhook_id}": 3600,
608
- "GET:corporations/{corporation_id}/structures/sovereignty-hubs": 3600,
609
- "GET:corporations/{corporation_id}/structures/sovereignty-hubs/{sovereignty_hub_id}": 3600,
610
- "GET:corporations/{corporation_id}/titles": 3600,
611
- "GET:corporations/{corporation_id}/wallets": 300,
612
- "GET:corporations/{corporation_id}/wallets/{division}/journal": 3600,
613
- "GET:corporations/{corporation_id}/wallets/{division}/transactions": 3600,
614
- "GET:fleets/{fleet_id}": 5,
615
- "GET:fleets/{fleet_id}/members": 5,
616
- "GET:fleets/{fleet_id}/wings": 5,
617
- "GET:freelance-jobs/{job_id}": 60,
618
- "GET:fw/systems": 1800,
619
- "GET:incursions": 300,
620
- "GET:industry/facilities": 3600,
621
- "GET:industry/systems": 3600,
622
- "GET:insurance/prices": 3600,
623
- "GET:killmails/{killmail_id}/{killmail_hash}": 2592e3,
624
- "GET:markets/{region_id}/orders": 300,
625
- "GET:markets/{region_id}/types": 600,
626
- "GET:markets/prices": 3600,
627
- "GET:markets/structures/{structure_id}": 300,
628
- "GET:meta/changelog": 600,
629
- "GET:meta/compatibility-dates": 600,
630
- "GET:skyhooks/raidable": 300,
631
- "GET:sovereignty/campaigns": 5,
632
- "GET:sovereignty/systems": 300,
633
- "GET:status": 30,
634
- "GET:universe/schematics/{schematic_id}": 3600,
635
- "GET:universe/structures": 3600,
636
- "GET:universe/structures/{structure_id}": 3600,
637
- "GET:universe/system_jumps": 3600,
638
- "GET:universe/system_kills": 3600,
639
- "GET:wars": 3600,
640
- "GET:wars/{war_id}": 3600,
641
- "GET:wars/{war_id}/killmails": 3600
642
- };
643
-
644
- // src/core/requestPipeline/cachePolicy.ts
645
- var STALE_RETENTION_MS = 60 * 60 * 1e3;
646
- function retentionTtl(freshnessTtlMs) {
647
- return freshnessTtlMs === void 0 ? void 0 : freshnessTtlMs + STALE_RETENTION_MS;
648
- }
649
- function lookupSpecTtl(method, templatePath) {
650
- const normalized = templatePath.replace(/\/$/, "").replace(/\{(\w+)\}/g, (_, name) => `{${camelToSnake(name)}}`);
651
- const key = `${method}:${normalized}`;
652
- const seconds = esiCacheTtls[key];
653
- return typeof seconds === "number" ? seconds * 1e3 : void 0;
654
- }
655
- function trySpecAwareCacheHit(client, url, method, templatePath, resolveCache2, requiresAuth = false) {
656
- if (method !== "GET" || !templatePath) return null;
657
- const specTtlMs = lookupSpecTtl(method, templatePath);
658
- if (!specTtlMs) return null;
659
- const cache = resolveCache2(client);
660
- if (!cache) return null;
661
- const key = buildCacheKey(url, client, requiresAuth);
662
- const entry = cache.get(key);
663
- if (!entry) return null;
664
- const age = Date.now() - entry.timestamp;
665
- if (age < specTtlMs) {
666
- logDebug2(
667
- client,
668
- `Spec-aware cache hit for ${url} (age=${Math.round(age / 1e3)}s, ttl=${Math.round(specTtlMs / 1e3)}s)`,
669
- { method, templatePath }
670
- );
671
- return {
672
- headers: entry.headers,
673
- body: entry.data,
674
- status: 200,
675
- fromCache: true,
676
- cacheHitType: "spec-ttl"
677
- };
678
- }
679
- return null;
680
- }
681
- function hasCachedEntry(client, url, resolveCache2, requiresAuth = false) {
682
- const cache = resolveCache2(client);
683
- return !!cache && cache.has(buildCacheKey(url, client, requiresAuth));
684
- }
685
- function tryStaleCacheResponse(client, url, parsed, resolveCache2, requiresAuth = false) {
686
- const cache = resolveCache2(client);
687
- if (!cache) return null;
688
- const key = buildCacheKey(url, client, requiresAuth);
689
- const cachedEntry = cache.get(key);
690
- if (!cachedEntry) return null;
691
- return {
692
- headers: { ...cachedEntry.headers, ...parsed.raw },
693
- body: cachedEntry.data,
694
- status: 200,
695
- fromCache: true,
696
- stale: true,
697
- cacheHitType: "stale-on-error"
698
- };
699
- }
700
- var RECENT_WRITES = 64;
701
- var writeLogs = /* @__PURE__ */ new WeakMap();
702
- function writeLogFor(cache) {
703
- let log = writeLogs.get(cache);
704
- if (!log) {
705
- log = { generation: 0, recent: [] };
706
- writeLogs.set(cache, log);
707
- }
708
- return log;
709
- }
710
- function currentWriteGeneration(client, resolveCache2) {
711
- const cache = resolveCache2(client);
712
- return cache ? writeLogFor(cache).generation : 0;
713
- }
714
- function invalidatedSince(cache, generation, key) {
715
- const log = writeLogFor(cache);
716
- if (log.generation === generation) return false;
717
- if (log.generation - generation > log.recent.length) return true;
718
- return log.recent.some(
719
- (write) => write.generation > generation && key.includes(write.path)
720
- );
721
- }
722
- function cacheResponse(client, url, method, endpoint, parsed, data, useETag, resolveCache2, templatePath, requiresAuth = false, sentAtWriteGeneration) {
723
- const cache = resolveCache2(client);
724
- if (useETag && method === "GET" && cache && parsed.etag) {
725
- const key = buildCacheKey(url, client, requiresAuth);
726
- if (sentAtWriteGeneration !== void 0 && invalidatedSince(cache, sentAtWriteGeneration, key)) {
727
- logDebug2(
728
- client,
729
- `Not caching ${url}: a write invalidated it while the request was in flight`,
730
- { method }
731
- );
732
- return;
733
- }
734
- const headerTtl = parseCacheControlTtl(parsed.raw);
735
- const specTtlMs = templatePath ? lookupSpecTtl(method, templatePath) : void 0;
736
- const freshnessTtl = specTtlMs ?? headerTtl;
737
- const ttl = retentionTtl(freshnessTtl);
738
- cache.set(key, parsed.etag, data, parsed.raw, ttl);
739
- const ttlInfo = freshnessTtl !== void 0 ? ` (ttl=${freshnessTtl}ms, kept for ${ttl}ms)` : "";
740
- logDebug2(
741
- client,
742
- `Cached response for ${url} with ETag ${parsed.etag}${ttlInfo}`,
743
- {
744
- method,
745
- etag: parsed.etag
746
- }
747
- );
748
- }
749
- invalidateAfterWrite(client, method, endpoint, resolveCache2);
750
- }
751
- function evictRejectedResponse(client, endpoint, requiresAuth, resolveCache2) {
752
- const cache = resolveCache2(client);
753
- if (!cache) return;
754
- const url = `${client.getLink()}/${endpoint}`;
755
- if (cache.delete(buildCacheKey(url, client, requiresAuth))) {
756
- logDebug2(
757
- client,
758
- `Evicted cached response for ${url} after it failed validation`
759
- );
760
- }
761
- }
762
- function invalidateAfterWrite(client, method, endpoint, resolveCache2) {
763
- if (method === "GET") return;
764
- const path2 = endpoint.split("?")[0];
765
- client.getDeduplicator()?.detachByPath?.(path2);
766
- const cache = resolveCache2(client);
767
- if (cache) {
768
- cache.deleteByPath(path2);
769
- const log = writeLogFor(cache);
770
- log.generation += 1;
771
- log.recent.push({ generation: log.generation, path: path2 });
772
- if (log.recent.length > RECENT_WRITES) log.recent.shift();
773
- }
774
- }
775
-
776
- // src/core/requestPipeline/statusHandling.ts
777
- var STATUS_MESSAGES = {
778
- 201: "Created",
779
- 204: "No Content",
780
- 304: "Not Modified",
781
- 400: "Bad Request",
782
- 401: "Unauthorized",
783
- 403: "Forbidden",
784
- 404: "Resource not found",
785
- 420: "Error Limited",
786
- 422: "Unprocessable Entity",
787
- 429: "Too many requests",
788
- 500: "Internal server error",
789
- 502: "Bad Gateway",
790
- 503: "Service Unavailable",
791
- 504: "Gateway Timeout",
792
- 520: "Internal server error, did the request terminate too soon?"
793
- };
794
- function statusMessage(response) {
795
- return STATUS_MESSAGES[response.status] || response.statusText || `HTTP ${response.status}`;
796
- }
797
- function handleEarlyStatus(client, status, url, parsed, useETag, resolveCache2, requiresAuth = false) {
798
- if (status === 201) {
799
- return { headers: parsed.raw, body: void 0, status: 201 };
800
- }
801
- if (status === 204) {
802
- logInfo2(client, `No Content for endpoint: ${url}`, { status });
803
- return { headers: parsed.raw, body: void 0, status: 204 };
804
- }
805
- if (status === 304) {
806
- const cache = resolveCache2(client);
807
- if (useETag && cache) {
808
- const key = buildCacheKey(url, client, requiresAuth);
809
- const cachedEntry = cache.get(key);
810
- if (cachedEntry) {
811
- logInfo2(client, `Cache hit (304) for endpoint: ${url}`, {
812
- status,
813
- cacheHitType: "etag-304"
814
- });
815
- const headers = {
816
- ...cachedEntry.headers,
817
- ...parsed.raw
818
- };
819
- if ("etag" in parsed.raw) headers["etag"] = cachedEntry.etag;
820
- cache.set(
821
- key,
822
- cachedEntry.etag,
823
- cachedEntry.data,
824
- headers,
825
- cachedEntry.ttl
826
- );
827
- return {
828
- headers,
829
- body: cachedEntry.data,
830
- status: 304,
831
- fromCache: true,
832
- cacheHitType: "etag-304"
833
- };
834
- }
835
- }
836
- throw new EsiError(
837
- 304,
838
- "Not Modified \u2014 no cached data available",
839
- url,
840
- parsed.requestId ?? void 0
841
- );
842
- }
843
- return null;
844
- }
845
- var MAX_REASON_LENGTH = 200;
846
- async function readEsiErrorReason(response) {
847
- try {
848
- const parsed = JSON.parse(await response.text());
849
- const reason = typeof parsed === "object" && parsed !== null ? parsed.error : void 0;
850
- if (typeof reason !== "string") return void 0;
851
- const trimmed = reason.trim();
852
- return trimmed ? trimmed.slice(0, MAX_REASON_LENGTH) : void 0;
853
- } catch {
854
- return void 0;
855
- }
856
- }
857
- function handleErrorResponse(client, response, url, parsed, useETag, resolveCache2, requiresAuth = false, esiReason) {
858
- const text = statusMessage(response);
859
- const errorMessage = esiReason ? `${text}: ${esiReason}` : text;
860
- if (response.status >= 500 && useETag) {
861
- const staleResult = tryStaleCacheResponse(
862
- client,
863
- url,
864
- parsed,
865
- resolveCache2,
866
- requiresAuth
867
- );
868
- if (staleResult) {
869
- logWarn2(client, `${errorMessage} for ${url} \u2014 serving stale cache`, {
870
- status: response.status
871
- });
872
- return { ...staleResult, status: response.status };
873
- }
874
- }
875
- if (response.status === 420 || response.status === 429) {
876
- logWarn2(client, `Rate limited (${response.status}) on ${url}`, {
877
- status: response.status
878
- });
879
- }
880
- let message = errorMessage;
881
- if (response.status === 401) {
882
- message = `${errorMessage} \u2014 the access token was missing, expired, or lacks the required ESI scope. Fix: verify ESI_ACCESS_TOKEN, or configure onTokenRefresh for automatic refresh on 401`;
883
- } else if (response.status === 403) {
884
- message = `${errorMessage} \u2014 your access token does not have the OAuth scopes required for this endpoint. Check the scopes on your EVE SSO application`;
885
- }
886
- throw new EsiError(
887
- response.status,
888
- message,
889
- url,
890
- parsed.requestId ?? void 0
891
- );
892
- }
893
- function wrapError(error, client) {
894
- if (error instanceof EsiError || error instanceof CircuitOpenError) {
895
- throw error;
896
- }
897
- if (error instanceof Error) {
898
- logError2(client, `Unexpected error: ${error.message}`);
899
- throw buildError(error.message, "ESIJS_ERROR");
900
- }
901
- logError2(client, `Unexpected error: ${String(error)}`);
902
- throw buildError(String(error), "ESIJS_ERROR");
903
- }
904
-
905
- // src/core/util/retry.ts
906
- function retryDelay(attempt, baseMs, maxMs) {
907
- const exponential = baseMs === 0 ? 0 : baseMs * Math.pow(2, attempt);
908
- const jitter = exponential * (0.75 + Math.random() * 0.5);
909
- return Math.min(jitter, maxMs);
910
- }
911
-
912
- // src/core/util/sleep.ts
913
- function sleep(ms) {
914
- return new Promise((resolve2) => setTimeout(resolve2, ms));
915
- }
916
-
917
- // src/core/RetryStrategy.ts
918
- var RetryStrategy = class {
919
- maxRetries;
920
- baseDelayMs;
921
- maxDelayMs;
922
- retryMutations;
923
- constructor(config) {
924
- this.maxRetries = config?.maxRetries ?? 0;
925
- this.baseDelayMs = config?.baseDelayMs ?? 1e3;
926
- this.maxDelayMs = config?.maxDelayMs ?? 3e4;
927
- this.retryMutations = config?.retryMutations ?? false;
928
- }
929
- async execute(operation, context) {
930
- const canRetryMethod = context.method === "GET" || this.retryMutations;
931
- let lastError;
932
- let refreshAttempted = false;
933
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
934
- try {
935
- return await operation();
936
- } catch (error) {
937
- if (error instanceof CircuitOpenError) {
938
- throw error;
939
- }
940
- if (!refreshAttempted && error instanceof EsiError && error.statusCode === 401 && context.requiresAuth && context.refreshToken) {
941
- refreshAttempted = true;
942
- logInfo2(context.client, "Received 401, attempting token refresh...", {
943
- endpoint: context.endpoint
944
- });
945
- try {
946
- await context.refreshToken();
947
- } catch (refreshError) {
948
- if (refreshError instanceof EsiError || refreshError instanceof CircuitOpenError) {
949
- throw refreshError;
950
- }
951
- const msg = refreshError instanceof Error ? refreshError.message : String(refreshError);
952
- logError2(context.client, `Token refresh failed: ${msg}`, {
953
- endpoint: context.endpoint
954
- });
955
- throw buildError(
956
- `Token refresh failed: ${msg}`,
957
- "TOKEN_REFRESH_FAILED"
958
- );
959
- }
960
- logInfo2(context.client, "Token refreshed, retrying request", {
961
- endpoint: context.endpoint
962
- });
963
- attempt--;
964
- continue;
965
- }
966
- if (error instanceof EsiError && error.retryable && canRetryMethod && attempt < this.maxRetries) {
967
- const delay = retryDelay(attempt, this.baseDelayMs, this.maxDelayMs);
968
- logWarn2(
969
- context.client,
970
- `Request to ${context.endpoint} failed (${error.statusCode}), retrying in ${Math.round(delay)}ms (attempt ${attempt + 1}/${this.maxRetries})`,
971
- { method: context.method, statusCode: error.statusCode }
972
- );
973
- await sleep(delay);
974
- lastError = error;
975
- continue;
976
- }
977
- throw error;
978
- }
979
- }
980
- throw lastError;
981
- }
982
- };
983
-
984
- // src/core/requestPipeline/dependencies.ts
985
- function resolveCache(client) {
986
- return client.getCache();
987
- }
988
- function resolveRateLimiter(client) {
989
- const limiter = client.getRateLimiter();
990
- if (!limiter) {
991
- throw buildError(
992
- "No rate limiter configured on ApiClient. Set one via apiClient.setRateLimiter(new RateLimiter()).",
993
- "CONFIGURATION_ERROR"
994
- );
995
- }
996
- return limiter;
997
- }
998
- function resolveCircuitBreaker(client) {
999
- return client.getCircuitBreaker();
1000
- }
1001
- function resolveRetryStrategy(client) {
1002
- return client.getRetryStrategy() ?? new RetryStrategy(client.getRetryConfig() ?? void 0);
1003
- }
1004
-
1005
- // src/core/pagination/PaginationHandler.ts
1006
- var PaginationHandler = class {
1007
- static DEFAULT_OPTIONS = {
1008
- maxPages: 1e3,
1009
- stopOnEmptyPage: true
1010
- };
1011
- /**
1012
- * Fetch remaining pages (2..totalPages) and combine with first page data.
1013
- * The caller has already fetched page 1 and knows the total page count.
1014
- */
1015
- static async fetchRemainingPages(client, endpoint, method, requiresAuth, firstPageData, totalPages, body, options, pageFetch, templatePath) {
1016
- const opts = { ...this.DEFAULT_OPTIONS, ...options };
1017
- const rateLimiter = client.getRateLimiter();
1018
- const allData = [...firstPageData];
1019
- const effectiveMaxPage = Math.min(totalPages, opts.maxPages);
1020
- if (effectiveMaxPage <= 1) {
1021
- return allData;
1022
- }
1023
- logInfo2(client, `Fetching pages 2-${effectiveMaxPage} for ${endpoint}...`, {
1024
- method,
1025
- totalPages
1026
- });
1027
- for (let page = 2; page <= effectiveMaxPage; page++) {
1028
- try {
1029
- if (rateLimiter) await rateLimiter.checkRateLimit(templatePath, method);
1030
- const pageData = await this.fetchPageWithRetry(
1031
- client,
1032
- endpoint,
1033
- method,
1034
- requiresAuth,
1035
- page,
1036
- pageFetch
1037
- );
1038
- if (opts.stopOnEmptyPage && (!pageData || pageData.length === 0)) {
1039
- logWarn2(client, `Page ${page} is empty. Stopping pagination.`, {
1040
- page
1041
- });
1042
- break;
1043
- }
1044
- allData.push(...pageData);
1045
- logInfo2(
1046
- client,
1047
- `Fetched page ${page}/${effectiveMaxPage} (${pageData.length} items)`,
1048
- { page, items: pageData.length }
1049
- );
1050
- } catch (error) {
1051
- logError2(
1052
- client,
1053
- `Failed to fetch page ${page}: ${error instanceof Error ? error.message : String(error)}`,
1054
- { page }
1055
- );
1056
- throw error instanceof Error ? error : new Error(`Failed to fetch page ${page}: ${String(error)}`);
1057
- }
1058
- }
1059
- logInfo2(
1060
- client,
1061
- `Pagination complete. Fetched ${allData.length} total items from up to ${effectiveMaxPage} pages.`,
1062
- { totalItems: allData.length }
1063
- );
1064
- return allData;
1065
- }
1066
- /**
1067
- * Fetch a single page with retry logic.
1068
- *
1069
- * Delegates to the configured `IRetryStrategy` (exponential backoff
1070
- * with jitter) instead of implementing a custom retry loop.
1071
- */
1072
- static async fetchPageWithRetry(client, endpoint, method, requiresAuth, page, pageFetch) {
1073
- const retryStrategy = resolveRetryStrategy(client);
1074
- const paginatedEndpoint = this.buildPaginatedEndpoint(endpoint, page);
1075
- return retryStrategy.execute(
1076
- () => {
1077
- logInfo2(
1078
- client,
1079
- `Fetching page ${page} via pipeline: ${paginatedEndpoint}`,
1080
- { page }
1081
- );
1082
- return pageFetch(paginatedEndpoint);
1083
- },
1084
- {
1085
- client,
1086
- endpoint: paginatedEndpoint,
1087
- method,
1088
- requiresAuth,
1089
- refreshToken: client.hasTokenProvider() ? () => client.refreshToken().then(() => {
1090
- }) : void 0
1091
- }
1092
- );
1093
- }
1094
- /**
1095
- * Build a paginated endpoint path.
1096
- * Preserves any existing query params on the endpoint and appends page=N.
1097
- */
1098
- static buildPaginatedEndpoint(endpoint, page) {
1099
- const separator = endpoint.includes("?") ? "&" : "?";
1100
- return `${endpoint}${separator}page=${page}`;
1101
- }
1102
- };
1103
-
1104
- // src/core/requestPipeline/paginationOrchestration.ts
1105
- function handleCursorPagination(parsed, data) {
1106
- if (!parsed.hasCursorPagination) return null;
1107
- const cursors = {
1108
- before: parsed.cursorBefore,
1109
- after: parsed.cursorAfter
1110
- };
1111
- return { headers: parsed.raw, body: data, status: 200, cursors };
1112
- }
1113
- async function handleOffsetPagination(client, endpoint, method, requiresAuth, parsed, data, body, url, useETag, pageFetch, resolveCache2, templatePath, sentAtWriteGeneration) {
1114
- const totalPages = parsed.xPages;
1115
- if (totalPages <= 1) {
1116
- return { headers: parsed.raw, body: data, status: 200 };
1117
- }
1118
- logInfo2(
1119
- client,
1120
- `Found ${totalPages} pages, fetching additional pages with rate limiting...`,
1121
- { endpoint, totalPages }
1122
- );
1123
- try {
1124
- const firstPageData = Array.isArray(data) ? data : [data];
1125
- const allData = await PaginationHandler.fetchRemainingPages(
1126
- client,
1127
- endpoint,
1128
- method,
1129
- requiresAuth,
1130
- firstPageData,
1131
- totalPages,
1132
- body,
1133
- {
1134
- maxPages: Math.min(totalPages, 1e3),
1135
- stopOnEmptyPage: true
1136
- },
1137
- pageFetch,
1138
- templatePath
1139
- );
1140
- cacheResponse(
1141
- client,
1142
- url,
1143
- method,
1144
- endpoint,
1145
- parsed,
1146
- allData,
1147
- useETag,
1148
- resolveCache2,
1149
- templatePath,
1150
- requiresAuth,
1151
- sentAtWriteGeneration
1152
- );
1153
- return { headers: parsed.raw, body: allData, status: 200 };
1154
- } catch (paginationError) {
1155
- const msg = paginationError instanceof Error ? paginationError.message : String(paginationError);
1156
- logWarn2(client, `Pagination failed for ${url}: ${msg}`, {
1157
- url,
1158
- endpoint,
1159
- error: msg
1160
- });
1161
- if (paginationError instanceof EsiError || paginationError instanceof CircuitOpenError) {
1162
- throw paginationError;
1163
- }
1164
- throw buildError(
1165
- `Pagination incomplete for ${url}: ${msg}`,
1166
- "PAGINATION_INCOMPLETE",
1167
- url
1168
- );
1169
- }
1170
- }
1171
-
1172
- // src/core/requestPipeline/middlewareBridge.ts
1173
- async function applyRequestMiddleware(client, url, endpoint, method, headers, body) {
1174
- const middleware = client.getMiddleware();
1175
- if (!middleware.hasInterceptors()) {
1176
- return { url, headers, body };
1177
- }
1178
- const reqCtx = {
1179
- url,
1180
- endpoint,
1181
- method,
1182
- headers: { ...headers },
1183
- body
1184
- };
1185
- const modified = await middleware.applyRequestInterceptors(reqCtx);
1186
- return {
1187
- url: modified.url,
1188
- headers: modified.headers,
1189
- body: modified.body
1190
- };
1191
- }
1192
- async function applyResponseInterceptors(client, result, url, endpoint, method, startTime) {
1193
- const middleware = client.getMiddleware();
1194
- if (!middleware.hasInterceptors()) return result;
1195
- const responseCtx = {
1196
- url,
1197
- endpoint,
1198
- method,
1199
- status: result.status ?? 200,
1200
- headers: result.headers,
1201
- body: result.body,
1202
- durationMs: Date.now() - startTime,
1203
- fromCache: result.fromCache ?? false
1204
- };
1205
- const modified = await middleware.applyResponseInterceptors(responseCtx);
1206
- return {
1207
- ...result,
1208
- headers: modified.headers,
1209
- body: modified.body
1210
- };
1211
- }
1212
-
1213
- // src/core/util/headersUtil.ts
1214
- function parseWarning(value) {
1215
- if (!value) return null;
1216
- const match = /^(\d{3}) - "([^"]+)"$/.exec(value) ?? /^(\d{3}) - ([^ ].+[^ ])$/.exec(value);
1217
- if (!match) return null;
1218
- const [, code, message] = match;
1219
- return { code: parseInt(code, 10), message };
1220
- }
1221
- function parseHeaders(fetchHeaders) {
1222
- const raw = {};
1223
- fetchHeaders.forEach((value, key) => {
1224
- raw[key.toLowerCase()] = value;
1225
- });
1226
- const cursorBefore = raw["x-cursor-before"] ?? null;
1227
- const cursorAfter = raw["x-cursor-after"] ?? null;
1228
- return {
1229
- raw,
1230
- xPages: parseInt(raw["x-pages"] ?? "1", 10),
1231
- etag: raw["etag"] ?? null,
1232
- cacheControl: raw["cache-control"] ?? null,
1233
- expires: raw["expires"] ?? null,
1234
- lastModified: raw["last-modified"] ?? null,
1235
- cursorBefore,
1236
- cursorAfter,
1237
- hasCursorPagination: "x-cursor-before" in raw || "x-cursor-after" in raw,
1238
- warning: parseWarning(raw["warning"]),
1239
- requestId: raw["x-esi-request-id"] ?? null,
1240
- date: raw["date"] ?? null,
1241
- contentLanguage: raw["content-language"] ?? null
1242
- };
1243
- }
1244
-
1245
- // src/core/requestPipeline/fetchExecution.ts
1246
- function isAbortError(err) {
1247
- return typeof err === "object" && err !== null && err.name === "AbortError";
1248
- }
1249
- function networkError(err, url) {
1250
- const reason = err instanceof Error ? err.message : String(err);
1251
- return Object.assign(
1252
- new EsiError(0, `Network request failed: ${reason}`, url),
1253
- { cause: err }
1254
- );
1255
- }
1256
- async function bufferBody(response) {
1257
- if (typeof response.text !== "function") return;
1258
- const text = await response.text();
1259
- Object.defineProperties(response, {
1260
- text: { value: () => Promise.resolve(text), configurable: true },
1261
- json: {
1262
- value: () => Promise.resolve(text).then((t) => JSON.parse(t)),
1263
- configurable: true
1264
- }
1265
- });
1266
- }
1267
- async function executeSingleFetch(client, endpoint, method, body, requiresAuth, useETag, resolveCache2, resolveRateLimiter2, resolveCircuitBreaker2, requestTimeout, templatePath) {
1268
- const rawUrl = `${client.getLink()}/${endpoint}`;
1269
- const builtHeaders = buildRequestHeaders(
1270
- client,
1271
- rawUrl,
1272
- method,
1273
- requiresAuth,
1274
- useETag,
1275
- body,
1276
- resolveCache2
1277
- );
1278
- const req = await applyRequestMiddleware(
1279
- client,
1280
- rawUrl,
1281
- endpoint,
1282
- method,
1283
- builtHeaders,
1284
- body
1285
- );
1286
- const options = {
1287
- method,
1288
- headers: req.headers,
1289
- body: req.body ? JSON.stringify(req.body) : void 0
1290
- };
1291
- const url = req.url;
1292
- logInfo2(client, `Hitting endpoint: ${url}`, { method, endpoint });
1293
- const cb = resolveCircuitBreaker2(client);
1294
- const cbKey = cb && templatePath && cb.getKeyStrategy?.() === "template" ? templatePath : endpoint;
1295
- if (cb) cb.checkCircuit(cbKey);
1296
- let cbRecorded = false;
1297
- try {
1298
- const rateLimiter = resolveRateLimiter2(client);
1299
- await rateLimiter.checkRateLimit(templatePath, method, req.headers);
1300
- const timeoutMs = requestTimeout ?? client.getTimeout();
1301
- const controller = new AbortController();
1302
- const timer = globalThis.setTimeout(() => controller.abort(), timeoutMs);
1303
- options.signal = controller.signal;
1304
- let response;
1305
- try {
1306
- response = await client.getFetch()(url, options);
1307
- await bufferBody(response);
1308
- } catch (err) {
1309
- clearTimeout(timer);
1310
- if (cb) {
1311
- cb.recordFailure(cbKey, 0);
1312
- cbRecorded = true;
1313
- }
1314
- if (isAbortError(err)) {
1315
- throw new TimeoutError(timeoutMs, url);
1316
- }
1317
- throw networkError(err, url);
1318
- }
1319
- clearTimeout(timer);
1320
- const parsed = parseHeaders(response.headers);
1321
- rateLimiter.updateFromResponse(
1322
- parsed.raw,
1323
- response.status,
1324
- templatePath,
1325
- method,
1326
- req.headers
1327
- );
1328
- if (cb) {
1329
- if (response.status >= 500 || response.status === 420 || response.status === 429) {
1330
- cb.recordFailure(cbKey, response.status);
1331
- } else {
1332
- cb.recordSuccess(cbKey);
1333
- }
1334
- cbRecorded = true;
1335
- }
1336
- if (parsed.warning) {
1337
- logWarn2(
1338
- client,
1339
- `ESI Warning ${parsed.warning.code}: ${parsed.warning.message}`,
1340
- {
1341
- url,
1342
- warningCode: parsed.warning.code
1343
- }
1344
- );
1345
- }
1346
- return { response, parsed, url };
1347
- } finally {
1348
- if (cb && !cbRecorded) {
1349
- cb.recordFailure(cbKey, 0);
1350
- }
1351
- }
1352
- }
1353
- async function parseJsonBody(client, response, _url) {
1354
- try {
1355
- return await response.json();
1356
- } catch (jsonError) {
1357
- const msg = jsonError instanceof Error ? jsonError.message : String(jsonError);
1358
- logError2(client, `Failed to parse JSON response: ${msg}`, { url: _url });
1359
- throw buildError(`Invalid JSON response: ${msg}`, "JSON_PARSE_ERROR");
1360
- }
1361
- }
1362
- async function fetchOnePage(client, endpoint, method, body, requiresAuth, useETag, resolveCache2, resolveRateLimiter2, resolveCircuitBreaker2, requestTimeout, templatePath) {
1363
- const { response, parsed, url } = await executeSingleFetch(
1364
- client,
1365
- endpoint,
1366
- method,
1367
- body,
1368
- requiresAuth,
1369
- useETag,
1370
- resolveCache2,
1371
- resolveRateLimiter2,
1372
- resolveCircuitBreaker2,
1373
- requestTimeout,
1374
- templatePath
1375
- );
1376
- if (!response.ok) {
1377
- const text = statusMessage(response);
1378
- const reason = await readEsiErrorReason(response);
1379
- throw new EsiError(
1380
- response.status,
1381
- reason ? `${text}: ${reason}` : text,
1382
- url,
1383
- parsed.requestId ?? void 0
1384
- );
1385
- }
1386
- const data = await parseJsonBody(client, response, url);
1387
- return { data, parsed, url };
1388
- }
1389
-
1390
- // src/core/ApiRequestHandler.ts
1391
- var executeRequest = async (client, endpoint, method, body, requiresAuth = false, useETag = true, requestTimeout, templatePath) => {
1392
- const startTime = Date.now();
1393
- const finish = (r) => {
1394
- r.responseTimeMs = Date.now() - startTime;
1395
- const rawUrl = `${client.getLink()}/${endpoint}`;
1396
- return applyResponseInterceptors(
1397
- client,
1398
- r,
1399
- rawUrl,
1400
- endpoint,
1401
- method,
1402
- startTime
1403
- );
1404
- };
1405
- try {
1406
- const writeGeneration = currentWriteGeneration(client, resolveCache);
1407
- const revalidating = useETag && method === "GET" && hasCachedEntry(
1408
- client,
1409
- `${client.getLink()}/${endpoint}`,
1410
- resolveCache,
1411
- requiresAuth
1412
- );
1413
- const { response, parsed, url } = await executeSingleFetch(
1414
- client,
1415
- endpoint,
1416
- method,
1417
- body,
1418
- requiresAuth,
1419
- useETag,
1420
- resolveCache,
1421
- resolveRateLimiter,
1422
- resolveCircuitBreaker,
1423
- requestTimeout,
1424
- templatePath
1425
- );
1426
- if (response.status === 201 || response.status === 204) {
1427
- invalidateAfterWrite(client, method, endpoint, resolveCache);
1428
- }
1429
- if (response.status === 201) {
1430
- let data2;
1431
- try {
1432
- data2 = await response.json();
1433
- } catch {
1434
- data2 = void 0;
1435
- }
1436
- return finish({ headers: parsed.raw, body: data2, status: 201 });
1437
- }
1438
- if (response.status === 304 && revalidating && !hasCachedEntry(client, url, resolveCache, requiresAuth)) {
1439
- return await executeRequest(
1440
- client,
1441
- endpoint,
1442
- method,
1443
- body,
1444
- requiresAuth,
1445
- useETag,
1446
- requestTimeout,
1447
- templatePath
1448
- );
1449
- }
1450
- const earlyResult = handleEarlyStatus(
1451
- client,
1452
- response.status,
1453
- url,
1454
- parsed,
1455
- useETag,
1456
- resolveCache,
1457
- requiresAuth
1458
- );
1459
- if (earlyResult) return finish(earlyResult);
1460
- if (!response.ok) {
1461
- const staleOrThrow = handleErrorResponse(
1462
- client,
1463
- response,
1464
- url,
1465
- parsed,
1466
- useETag,
1467
- resolveCache,
1468
- requiresAuth,
1469
- await readEsiErrorReason(response)
1470
- );
1471
- return finish(staleOrThrow);
1472
- }
1473
- const data = await parseJsonBody(client, response, url);
1474
- if (parsed.xPages <= 1 || parsed.hasCursorPagination) {
1475
- cacheResponse(
1476
- client,
1477
- url,
1478
- method,
1479
- endpoint,
1480
- parsed,
1481
- data,
1482
- useETag,
1483
- resolveCache,
1484
- templatePath,
1485
- requiresAuth,
1486
- writeGeneration
1487
- );
1488
- }
1489
- const cursorResult = handleCursorPagination(parsed, data);
1490
- if (cursorResult) return finish(cursorResult);
1491
- const pageFetch = async (paginatedEndpoint) => {
1492
- const result = await fetchOnePage(
1493
- client,
1494
- paginatedEndpoint,
1495
- method,
1496
- body,
1497
- requiresAuth,
1498
- false,
1499
- resolveCache,
1500
- resolveRateLimiter,
1501
- resolveCircuitBreaker,
1502
- requestTimeout,
1503
- templatePath
1504
- );
1505
- return Array.isArray(result.data) ? result.data : [result.data];
1506
- };
1507
- const paginatedResult = await handleOffsetPagination(
1508
- client,
1509
- endpoint,
1510
- method,
1511
- requiresAuth,
1512
- parsed,
1513
- data,
1514
- body,
1515
- url,
1516
- useETag,
1517
- pageFetch,
1518
- resolveCache,
1519
- templatePath,
1520
- writeGeneration
1521
- );
1522
- return finish(paginatedResult);
1523
- } catch (error) {
1524
- wrapError(error, client);
1525
- }
1526
- };
1527
- var handleSinglePageRequest = async (client, endpoint, method, body, requiresAuth = false, templatePath, requestTimeout) => {
1528
- const doExecute = () => fetchOnePage(
1529
- client,
1530
- endpoint,
1531
- method,
1532
- body,
1533
- requiresAuth,
1534
- true,
1535
- resolveCache,
1536
- resolveRateLimiter,
1537
- resolveCircuitBreaker,
1538
- requestTimeout,
1539
- templatePath
1540
- ).then(({ data, parsed }) => ({
1541
- headers: parsed.raw,
1542
- body: data
1543
- }));
1544
- const retryStrategy = resolveRetryStrategy(client);
1545
- return retryStrategy.execute(doExecute, {
1546
- client,
1547
- endpoint,
1548
- method: "GET",
1549
- requiresAuth,
1550
- refreshToken: client.hasTokenProvider() ? () => client.refreshToken().then(() => {
1551
- }) : void 0
1552
- });
1553
- };
1554
- var handleRequest = async (client, endpoint, method, body, requiresAuth = false, useETag = true, templatePath, requestTimeout) => {
1555
- const rawUrl = `${client.getLink()}/${endpoint}`;
1556
- const startTime = Date.now();
1557
- const specCacheHit = () => {
1558
- const hit = trySpecAwareCacheHit(
1559
- client,
1560
- rawUrl,
1561
- method,
1562
- templatePath,
1563
- resolveCache,
1564
- requiresAuth
1565
- );
1566
- return hit ? applyResponseInterceptors(
1567
- client,
1568
- hit,
1569
- rawUrl,
1570
- endpoint,
1571
- method,
1572
- startTime
1573
- ) : null;
1574
- };
1575
- const specHit = specCacheHit();
1576
- if (specHit) return specHit;
1577
- const doExecute = () => executeRequest(
1578
- client,
1579
- endpoint,
1580
- method,
1581
- body,
1582
- requiresAuth,
1583
- useETag,
1584
- requestTimeout,
1585
- templatePath
1586
- );
1587
- const dedup = client.getDeduplicator();
1588
- const canDedup = dedup && method === "GET" && !body;
1589
- let attempted = false;
1590
- const operation = () => {
1591
- const retryHit = attempted ? specCacheHit() : null;
1592
- attempted = true;
1593
- if (retryHit) return retryHit;
1594
- return canDedup ? dedup.dedupe(
1595
- buildDedupeKey(endpoint, client, requiresAuth),
1596
- doExecute
1597
- ) : doExecute();
1598
- };
1599
- const retryStrategy = resolveRetryStrategy(client);
1600
- return retryStrategy.execute(operation, {
1601
- client,
1602
- endpoint,
1603
- method,
1604
- requiresAuth,
1605
- refreshToken: client.hasTokenProvider() ? () => client.refreshToken().then(() => {
1606
- }) : void 0
1607
- });
1608
- };
1609
-
1610
- // src/core/util/validation.ts
1611
- var UNSAFE_PATH_CHARS = /[/\\?#@!$&'()*+,;=<>{}|^`]/;
1612
- function validatePathParam(paramName, value) {
1613
- if (value === null || value === void 0 || value === "") {
1614
- throw buildError(
1615
- `Path parameter '${paramName}' must not be empty`,
1616
- "VALIDATION_ERROR"
1617
- );
1618
- }
1619
- const str = `${value}`;
1620
- if (UNSAFE_PATH_CHARS.test(str)) {
1621
- throw buildError(
1622
- `Path parameter '${paramName}' contains invalid characters`,
1623
- "VALIDATION_ERROR"
1624
- );
1625
- }
1626
- if (typeof value === "number" && !Number.isFinite(value)) {
1627
- throw buildError(
1628
- `Path parameter '${paramName}' must be a finite number`,
1629
- "VALIDATION_ERROR"
1630
- );
1631
- }
1632
- return str;
1633
- }
1634
- var ALLOWED_ESI_HOSTS = ["esi.evetech.net"];
1635
- function validateBaseUrl(url, allowCustomHost) {
1636
- let parsed;
1637
- try {
1638
- parsed = new URL(url);
1639
- } catch {
1640
- throw buildError(`Invalid base URL: ${url}`, "VALIDATION_ERROR");
1641
- }
1642
- if (parsed.protocol !== "https:") {
1643
- throw buildError("Base URL must use HTTPS protocol", "VALIDATION_ERROR");
1644
- }
1645
- if (!allowCustomHost && !ALLOWED_ESI_HOSTS.includes(parsed.hostname)) {
1646
- throw buildError(
1647
- `Base URL host '${parsed.hostname}' is not in the allowlist. Allowed hosts: ${ALLOWED_ESI_HOSTS.join(", ")}. Set unsafeAllowCustomHost to bypass this check.`,
1648
- "VALIDATION_ERROR"
1649
- );
1650
- }
1651
- return url.replace(/\/$/, "");
1652
- }
1653
- function validateQueryParam(paramName, value) {
1654
- if (value === null || value === void 0) {
1655
- throw buildError(
1656
- `Query parameter '${paramName}' must not be null or undefined`,
1657
- "VALIDATION_ERROR"
1658
- );
1659
- }
1660
- const str = `${value}`;
1661
- if (typeof value === "number" && !Number.isFinite(value)) {
1662
- throw buildError(
1663
- `Query parameter '${paramName}' must be a finite number`,
1664
- "VALIDATION_ERROR"
1665
- );
1666
- }
1667
- if (str.length > 2e3) {
1668
- throw buildError(
1669
- `Query parameter '${paramName}' exceeds maximum length`,
1670
- "VALIDATION_ERROR"
1671
- );
1672
- }
1673
- return str;
1674
- }
1675
-
1676
253
  // src/core/endpoints/buildEndpointPath.ts
1677
254
  function buildEndpointPath(def, args, datasource) {
1678
255
  let argIndex = 0;
@@ -1850,9 +427,15 @@ function createClient(apiClient, endpoints, options) {
1850
427
  body,
1851
428
  def.requiresAuth,
1852
429
  true,
1853
- def.path
430
+ def.path,
431
+ void 0,
432
+ def.textResponse,
433
+ def.emptyWhenNoContent
1854
434
  );
1855
435
  let responseBody = response.body;
436
+ if (responseBody === void 0 && def.emptyWhenNoContent) {
437
+ responseBody = [];
438
+ }
1856
439
  if (def.responseSchema && apiClient.getValidateResponse()) {
1857
440
  const result = def.responseSchema.safeParse(responseBody);
1858
441
  if (!result.success) {
@@ -1878,11 +461,7 @@ function createClient(apiClient, endpoints, options) {
1878
461
  return responseBody;
1879
462
  } catch (err) {
1880
463
  if (safeMode) {
1881
- const error = err instanceof EsiError ? err : new EsiError(
1882
- 0,
1883
- err instanceof Error ? err.message : String(err)
1884
- );
1885
- return { ok: false, error };
464
+ return { ok: false, error: toEsiError(err) };
1886
465
  }
1887
466
  throw err;
1888
467
  }
@@ -1912,119 +491,12 @@ async function fetchAllCursorPages(fetcher, getItems, getCursor) {
1912
491
  return allData;
1913
492
  }
1914
493
 
1915
- // src/core/pagination/AsyncPaginationIterator.ts
1916
- function extractArray(body) {
1917
- if (Array.isArray(body)) return body;
1918
- if (body !== void 0 && body !== null) return [body];
1919
- return [];
1920
- }
1921
- function validatePageBody(body, schema, url, validate) {
1922
- if (!schema || !validate) return body;
1923
- const result = schema.safeParse(body);
1924
- if (!result.success) {
1925
- throw new EsiValidationError(url, result.error);
1926
- }
1927
- return result.data;
1928
- }
1929
- async function fetchAllPages(client, endpoint, method, requiresAuth = false, body, templatePath, responseSchema, concurrency = 8) {
1930
- const validate = client.getValidateResponse();
1931
- const firstResponse = await handleSinglePageRequest(
1932
- client,
1933
- endpoint,
1934
- method,
1935
- body,
1936
- requiresAuth,
1937
- templatePath
1938
- );
1939
- const firstBody = validatePageBody(
1940
- firstResponse.body,
1941
- responseSchema,
1942
- `${client.getLink()}/${endpoint}`,
1943
- validate
1944
- );
1945
- const totalPages = parseInt(firstResponse.headers["x-pages"] || "1", 10);
1946
- const result = extractArray(firstBody);
1947
- if (totalPages <= 1) return result;
1948
- const remaining = Array.from({ length: totalPages - 1 }, (_, i) => i + 2);
1949
- for (let i = 0; i < remaining.length; i += concurrency) {
1950
- const batch = remaining.slice(i, i + concurrency);
1951
- const pages = await Promise.all(
1952
- batch.map(async (page) => {
1953
- const sep = endpoint.includes("?") ? "&" : "?";
1954
- const pagedEndpoint = `${endpoint}${sep}page=${page}`;
1955
- logInfo2(
1956
- client,
1957
- `Fetching page ${page}/${totalPages}: ${pagedEndpoint}`,
1958
- { page, totalPages }
1959
- );
1960
- const response = await handleSinglePageRequest(
1961
- client,
1962
- pagedEndpoint,
1963
- method,
1964
- body,
1965
- requiresAuth,
1966
- templatePath
1967
- );
1968
- return validatePageBody(
1969
- response.body,
1970
- responseSchema,
1971
- `${client.getLink()}/${pagedEndpoint}`,
1972
- validate
1973
- );
1974
- })
1975
- );
1976
- for (const pageBody of pages) {
1977
- result.push(...extractArray(pageBody));
1978
- }
1979
- }
1980
- return result;
1981
- }
1982
- async function* fetchPages(client, endpoint, method, requiresAuth = false, body, templatePath, responseSchema) {
1983
- const validate = client.getValidateResponse();
1984
- const firstResponse = await handleSinglePageRequest(
1985
- client,
1986
- endpoint,
1987
- method,
1988
- body,
1989
- requiresAuth,
1990
- templatePath
1991
- );
1992
- const firstBody = validatePageBody(
1993
- firstResponse.body,
1994
- responseSchema,
1995
- `${client.getLink()}/${endpoint}`,
1996
- validate
494
+ // src/clients/BaseEsiClient.ts
495
+ function notPageable(endpointName) {
496
+ return new TypeError(
497
+ `${endpointName} returns a text document and cannot be paged; call it directly.`
1997
498
  );
1998
- const totalPages = parseInt(firstResponse.headers["x-pages"] || "1", 10);
1999
- yield { data: extractArray(firstBody), page: 1, totalPages };
2000
- for (let page = 2; page <= totalPages; page++) {
2001
- const sep = endpoint.includes("?") ? "&" : "?";
2002
- const pagedEndpoint = `${endpoint}${sep}page=${page}`;
2003
- logInfo2(client, `Fetching page ${page}/${totalPages}: ${pagedEndpoint}`, {
2004
- page,
2005
- totalPages
2006
- });
2007
- const response = await handleSinglePageRequest(
2008
- client,
2009
- pagedEndpoint,
2010
- method,
2011
- body,
2012
- requiresAuth,
2013
- templatePath
2014
- );
2015
- const pageBody = validatePageBody(
2016
- response.body,
2017
- responseSchema,
2018
- `${client.getLink()}/${pagedEndpoint}`,
2019
- validate
2020
- );
2021
- const pageData = extractArray(pageBody);
2022
- if (pageData.length === 0) break;
2023
- yield { data: pageData, page, totalPages };
2024
- }
2025
499
  }
2026
-
2027
- // src/clients/BaseEsiClient.ts
2028
500
  var BaseEsiClient = class {
2029
501
  api;
2030
502
  _client;
@@ -2038,6 +510,7 @@ var BaseEsiClient = class {
2038
510
  }
2039
511
  streamEndpoint(endpointName, ...args) {
2040
512
  const def = this._endpoints[endpointName];
513
+ if (def.textResponse) throw notPageable(endpointName);
2041
514
  const { path: path2, body } = buildEndpointPath(
2042
515
  def,
2043
516
  args,
@@ -2055,6 +528,7 @@ var BaseEsiClient = class {
2055
528
  }
2056
529
  fetchAllEndpoint(endpointName, args, concurrency) {
2057
530
  const def = this._endpoints[endpointName];
531
+ if (def.textResponse) return Promise.reject(notPageable(endpointName));
2058
532
  const { path: path2, body } = buildEndpointPath(
2059
533
  def,
2060
534
  args,
@@ -2169,6 +643,7 @@ var contactEndpoints = {
2169
643
  addContacts: {
2170
644
  path: "characters/{characterId}/contacts",
2171
645
  method: "POST",
646
+ responseSchema: AddedContactIdsSchema,
2172
647
  requiresAuth: true,
2173
648
  pathParams: ["characterId"],
2174
649
  queryParams: { standing: "standing" },
@@ -2320,6 +795,7 @@ var assetEndpoints = {
2320
795
  postCorporationAssetLocations: {
2321
796
  path: "corporations/{corporationId}/assets/locations/",
2322
797
  method: "POST",
798
+ responseSchema: z3.array(AssetLocationSchema),
2323
799
  requiresAuth: true,
2324
800
  pathParams: ["corporationId"],
2325
801
  bodyBuilder: (itemIds) => itemIds
@@ -2327,6 +803,7 @@ var assetEndpoints = {
2327
803
  postCorporationAssetNames: {
2328
804
  path: "corporations/{corporationId}/assets/names/",
2329
805
  method: "POST",
806
+ responseSchema: z3.array(AssetNameSchema),
2330
807
  requiresAuth: true,
2331
808
  pathParams: ["corporationId"],
2332
809
  bodyBuilder: (itemIds) => itemIds
@@ -2637,12 +1114,14 @@ var characterEndpoints = {
2637
1114
  postCharacterAffiliation: {
2638
1115
  path: "characters/affiliation",
2639
1116
  method: "POST",
1117
+ responseSchema: z5.array(CharacterAffiliationSchema),
2640
1118
  requiresAuth: false,
2641
1119
  hasBody: true
2642
1120
  },
2643
1121
  calculateCspaChargeCost: {
2644
1122
  path: "characters/{characterId}/cspa/",
2645
1123
  method: "POST",
1124
+ responseSchema: CspaChargeCostSchema,
2646
1125
  requiresAuth: true,
2647
1126
  pathParams: ["characterId"],
2648
1127
  hasBody: true
@@ -3174,14 +1653,18 @@ var contractEndpoints = {
3174
1653
  method: "GET",
3175
1654
  requiresAuth: false,
3176
1655
  pathParams: ["contractId"],
3177
- responseSchema: z7.array(PublicContractBidSchema)
1656
+ responseSchema: z7.array(PublicContractBidSchema),
1657
+ // ESI answers an expired or accepted contract with no content.
1658
+ emptyWhenNoContent: true
3178
1659
  },
3179
1660
  getPublicContractItems: {
3180
1661
  path: "contracts/public/items/{contractId}",
3181
1662
  method: "GET",
3182
1663
  requiresAuth: false,
3183
1664
  pathParams: ["contractId"],
3184
- responseSchema: z7.array(PublicContractItemSchema)
1665
+ responseSchema: z7.array(PublicContractItemSchema),
1666
+ // ESI answers an expired or accepted contract with no content.
1667
+ emptyWhenNoContent: true
3185
1668
  }
3186
1669
  };
3187
1670
 
@@ -4250,6 +2733,7 @@ var fittingEndpoints = {
4250
2733
  createFitting: {
4251
2734
  path: "characters/{characterId}/fittings",
4252
2735
  method: "POST",
2736
+ responseSchema: FittingCreatedSchema,
4253
2737
  requiresAuth: true,
4254
2738
  pathParams: ["characterId"],
4255
2739
  hasBody: true
@@ -4388,6 +2872,7 @@ var fleetEndpoints = {
4388
2872
  createFleetWing: {
4389
2873
  path: "fleets/{fleetId}/wings/",
4390
2874
  method: "POST",
2875
+ responseSchema: FleetWingCreatedSchema,
4391
2876
  requiresAuth: true,
4392
2877
  pathParams: ["fleetId"],
4393
2878
  hasBody: true
@@ -4408,6 +2893,7 @@ var fleetEndpoints = {
4408
2893
  createFleetSquad: {
4409
2894
  path: "fleets/{fleetId}/wings/{wingId}/squads/",
4410
2895
  method: "POST",
2896
+ responseSchema: FleetSquadCreatedSchema,
4411
2897
  requiresAuth: true,
4412
2898
  pathParams: ["fleetId", "wingId"]
4413
2899
  }
@@ -5127,6 +3613,7 @@ var mailEndpoints = {
5127
3613
  sendMail: {
5128
3614
  path: "characters/{characterId}/mail/",
5129
3615
  method: "POST",
3616
+ responseSchema: MailIdSchema,
5130
3617
  requiresAuth: true,
5131
3618
  pathParams: ["characterId"],
5132
3619
  hasBody: true,
@@ -5176,6 +3663,7 @@ var mailEndpoints = {
5176
3663
  createMailLabel: {
5177
3664
  path: "characters/{characterId}/mail/labels/",
5178
3665
  method: "POST",
3666
+ responseSchema: MailLabelIdSchema,
5179
3667
  requiresAuth: true,
5180
3668
  pathParams: ["characterId"],
5181
3669
  hasBody: true
@@ -6740,6 +5228,13 @@ var metaEndpoints = {
6740
5228
  requiresAuth: false,
6741
5229
  responseSchema: z27.record(z27.string(), z27.unknown())
6742
5230
  },
5231
+ getOpenApiYaml: {
5232
+ path: "meta/openapi.yaml",
5233
+ method: "GET",
5234
+ requiresAuth: false,
5235
+ responseSchema: z27.string(),
5236
+ textResponse: { accept: "application/yaml, text/yaml, text/plain" }
5237
+ },
6743
5238
  getChangelog: {
6744
5239
  path: "meta/changelog",
6745
5240
  method: "GET",
@@ -6786,38 +5281,13 @@ var MetaClient = class extends BaseEsiClient {
6786
5281
  *
6787
5282
  * @returns The full ESI OpenAPI specification as a YAML string
6788
5283
  */
6789
- async getOpenApiYaml() {
6790
- const url = `${this._client.getLink()}/meta/openapi.yaml`;
6791
- logInfo2(this._client, `Hitting endpoint: ${url}`, { method: "GET" });
6792
- try {
6793
- const response = await fetch(url, {
6794
- method: "GET",
6795
- headers: {
6796
- accept: "text/yaml, application/x-yaml, text/plain",
6797
- "User-Agent": USER_AGENT,
6798
- "X-Compatibility-Date": COMPATIBILITY_DATE
6799
- }
6800
- });
6801
- if (!response.ok) {
6802
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
6803
- }
6804
- return await response.text();
6805
- } catch (error) {
6806
- if (error instanceof Error) {
6807
- logError2(this._client, `Error fetching YAML: ${error.message}`, {
6808
- url
6809
- });
6810
- throw error;
6811
- } else {
6812
- logError2(this._client, `Unexpected error: ${String(error)}`, { url });
6813
- throw new Error(String(error));
6814
- }
6815
- }
5284
+ getOpenApiYaml() {
5285
+ return this.api.getOpenApiYaml();
6816
5286
  }
6817
5287
  /**
6818
5288
  * Retrieves the ESI changelog data.
6819
5289
  *
6820
- * @returns The changelog keyed by compatibility date
5290
+ * @returns `{ changelog }`: the change entries keyed by compatibility date
6821
5291
  */
6822
5292
  getChangelog() {
6823
5293
  return this.api.getChangelog();
@@ -6833,7 +5303,8 @@ var MetaClient = class extends BaseEsiClient {
6833
5303
  /**
6834
5304
  * Retrieves the ESI name.
6835
5305
  *
6836
- * @returns An object containing the ESI name
5306
+ * @returns `{ current, history }`: the name ESI has now and the dated names
5307
+ * it had before
6837
5308
  */
6838
5309
  getName() {
6839
5310
  return this.api.getName();
@@ -6993,7 +5464,7 @@ var skyhookEndpoints = {
6993
5464
  path: "skyhooks/raidable",
6994
5465
  method: "GET",
6995
5466
  requiresAuth: false,
6996
- responseSchema: z28.array(RaidableSkyhookSchema)
5467
+ responseSchema: RaidableSkyhooksResponseSchema
6997
5468
  },
6998
5469
  getSkyhookDetail: {
6999
5470
  path: "corporations/{corporationId}/structures/skyhooks/{skyhookId}",
@@ -7039,7 +5510,8 @@ var SkyhooksClient = class extends BaseEsiClient {
7039
5510
  /**
7040
5511
  * Retrieves the rolling list of skyhooks that are currently or becoming raidable across New Eden.
7041
5512
  *
7042
- * @returns A list of raidable skyhooks
5513
+ * @returns ESI's response as sent: `skyhooks`, one entry per skyhook with its
5514
+ * planet, solar system and theft vulnerability window
7043
5515
  */
7044
5516
  getRaidableSkyhooks() {
7045
5517
  return this.api.getRaidableSkyhooks();
@@ -7312,13 +5784,12 @@ var ParagonHubClient = class extends BaseEsiClient {
7312
5784
  };
7313
5785
 
7314
5786
  // src/core/endpoints/militaryCampaignEndpoints.ts
7315
- import { z as z31 } from "zod";
7316
5787
  var militaryCampaignEndpoints = {
7317
5788
  getMilitaryCampaigns: {
7318
5789
  path: "military-campaigns",
7319
5790
  method: "GET",
7320
5791
  requiresAuth: false,
7321
- responseSchema: z31.array(MilitaryCampaignSchema)
5792
+ responseSchema: MilitaryCampaignsResponseSchema
7322
5793
  },
7323
5794
  getMilitaryCampaign: {
7324
5795
  path: "military-campaigns/{campaignId}",
@@ -7332,7 +5803,8 @@ var militaryCampaignEndpoints = {
7332
5803
  method: "GET",
7333
5804
  requiresAuth: false,
7334
5805
  pathParams: ["campaignId"],
7335
- responseSchema: z31.array(MilitaryCampaignObjectiveSchema)
5806
+ queryParams: { after: "after", before: "before", limit: "limit" },
5807
+ responseSchema: MilitaryCampaignObjectivesResponseSchema
7336
5808
  },
7337
5809
  getMilitaryCampaignObjective: {
7338
5810
  path: "military-campaigns/{campaignId}/objectives/{objectiveId}",
@@ -7346,7 +5818,8 @@ var militaryCampaignEndpoints = {
7346
5818
  method: "GET",
7347
5819
  requiresAuth: true,
7348
5820
  pathParams: ["characterId"],
7349
- responseSchema: z31.array(CharacterMilitaryCampaignObjectiveSchema)
5821
+ queryParams: { after: "after", before: "before", limit: "limit" },
5822
+ responseSchema: CharacterMilitaryCampaignObjectivesResponseSchema
7350
5823
  },
7351
5824
  getCharacterMilitaryCampaignObjective: {
7352
5825
  path: "characters/{characterId}/military-campaigns/objectives/{objectiveId}",
@@ -7365,7 +5838,7 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7365
5838
  /**
7366
5839
  * Retrieves a list of all active, completed, and expired military campaigns.
7367
5840
  *
7368
- * @returns An array of military campaigns
5841
+ * @returns `{ campaigns }`, one entry per campaign
7369
5842
  */
7370
5843
  getMilitaryCampaigns() {
7371
5844
  return this.api.getMilitaryCampaigns();
@@ -7383,10 +5856,18 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7383
5856
  * Retrieves all objectives for a specific military campaign.
7384
5857
  *
7385
5858
  * @param campaignId - The UUID of the military campaign
7386
- * @returns An array of objectives for the campaign
7387
- */
7388
- getMilitaryCampaignObjectives(campaignId) {
7389
- return this.api.getMilitaryCampaignObjectives(campaignId);
5859
+ * @param after - `cursor.after` from a previous page, for the page after it
5860
+ * @param before - `cursor.before` from a previous page, for the page before it
5861
+ * @param limit - Maximum number of objectives on the page
5862
+ * @returns `{ objectives, cursor }` for one page of the campaign's objectives
5863
+ */
5864
+ getMilitaryCampaignObjectives(campaignId, after, before, limit) {
5865
+ return this.api.getMilitaryCampaignObjectives(
5866
+ campaignId,
5867
+ after,
5868
+ before,
5869
+ limit
5870
+ );
7390
5871
  }
7391
5872
  /**
7392
5873
  * Retrieves detailed information about a specific objective in a military campaign.
@@ -7402,11 +5883,20 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7402
5883
  * Retrieves a character's participated objectives across military campaigns.
7403
5884
  *
7404
5885
  * @param characterId - The ID of the character
7405
- * @returns An array of the character's campaign objective participations
5886
+ * @param after - `cursor.after` from a previous page, for the page after it
5887
+ * @param before - `cursor.before` from a previous page, for the page before it
5888
+ * @param limit - Maximum number of objectives on the page
5889
+ * @returns `{ objectives, cursor }` for one page of the character's campaign
5890
+ * objective participations
7406
5891
  * @requires Authentication with scope esi.activity.char:read
7407
5892
  */
7408
- getCharacterMilitaryCampaignObjectives(characterId) {
7409
- return this.api.getCharacterMilitaryCampaignObjectives(characterId);
5893
+ getCharacterMilitaryCampaignObjectives(characterId, after, before, limit) {
5894
+ return this.api.getCharacterMilitaryCampaignObjectives(
5895
+ characterId,
5896
+ after,
5897
+ before,
5898
+ limit
5899
+ );
7410
5900
  }
7411
5901
  /**
7412
5902
  * Retrieves a character's participation details for a specific campaign objective.
@@ -7424,7 +5914,7 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7424
5914
  }
7425
5915
  };
7426
5916
 
7427
- // src/core/ClientRegistry.ts
5917
+ // src/clients/ClientRegistry.ts
7428
5918
  var clientFactories = {
7429
5919
  alliance: AllianceClient,
7430
5920
  assets: AssetsClient,
@@ -7517,6 +6007,9 @@ var EsiDiagnostics = class {
7517
6007
 
7518
6008
  // src/core/BatchRequestHandler.ts
7519
6009
  async function batchFetch(keys, fetcher, options = {}) {
6010
+ return batchFetchFor(null, keys, fetcher, options);
6011
+ }
6012
+ async function batchFetchFor(client, keys, fetcher, options = {}) {
7520
6013
  const concurrency = options.concurrency ?? 20;
7521
6014
  const results = /* @__PURE__ */ new Map();
7522
6015
  const errors = /* @__PURE__ */ new Map();
@@ -7524,7 +6017,7 @@ async function batchFetch(keys, fetcher, options = {}) {
7524
6017
  let running = 0;
7525
6018
  let index = 0;
7526
6019
  logInfo2(
7527
- null,
6020
+ client,
7528
6021
  `Batch fetch: ${keys.length} items, concurrency=${concurrency}`,
7529
6022
  {
7530
6023
  total: keys.length,
@@ -7550,7 +6043,7 @@ async function batchFetch(keys, fetcher, options = {}) {
7550
6043
  }
7551
6044
  if (completed === keys.length) {
7552
6045
  logDebug2(
7553
- null,
6046
+ client,
7554
6047
  `Batch complete: ${results.size} succeeded, ${errors.size} failed`,
7555
6048
  { succeeded: results.size, failed: errors.size }
7556
6049
  );
@@ -7569,12 +6062,15 @@ async function batchFetch(keys, fetcher, options = {}) {
7569
6062
  });
7570
6063
  }
7571
6064
  async function batchPost(ids, poster, chunkSize = 1e3) {
6065
+ return batchPostFor(null, ids, poster, chunkSize);
6066
+ }
6067
+ async function batchPostFor(client, ids, poster, chunkSize = 1e3) {
7572
6068
  const chunks = [];
7573
6069
  for (let i = 0; i < ids.length; i += chunkSize) {
7574
6070
  chunks.push(ids.slice(i, i + chunkSize));
7575
6071
  }
7576
6072
  logInfo2(
7577
- null,
6073
+ client,
7578
6074
  `Batch POST: ${ids.length} IDs in ${chunks.length} chunks of ${chunkSize}`,
7579
6075
  { total: ids.length, chunks: chunks.length, chunkSize }
7580
6076
  );
@@ -7586,859 +6082,6 @@ async function batchPost(ids, poster, chunkSize = 1e3) {
7586
6082
  return results;
7587
6083
  }
7588
6084
 
7589
- // src/core/cache/ETagCacheManager.ts
7590
- var ETagCacheManager = class {
7591
- cache = /* @__PURE__ */ new Map();
7592
- config;
7593
- cleanupTimer;
7594
- hits = 0;
7595
- misses = 0;
7596
- client = null;
7597
- setClient(client) {
7598
- this.client = client;
7599
- }
7600
- log(level, message, context) {
7601
- const ctx = context && Object.keys(context).length > 0 ? context : void 0;
7602
- const emit = level === "info" ? logInfo2 : logDebug2;
7603
- emit(this.client, message, ctx);
7604
- }
7605
- constructor(config = {}) {
7606
- this.config = {
7607
- maxEntries: config.maxEntries ?? 1e3,
7608
- defaultTtl: config.defaultTtl ?? 5 * 60 * 1e3,
7609
- // 5 minutes default
7610
- cleanupInterval: config.cleanupInterval ?? 60 * 1e3
7611
- // 1 minute cleanup
7612
- };
7613
- this.startCleanupTimer();
7614
- this.log(
7615
- "info",
7616
- `ETag cache manager initialized with ${this.config.maxEntries} max entries`,
7617
- { maxEntries: this.config.maxEntries }
7618
- );
7619
- }
7620
- /**
7621
- * Get cached data if ETag matches
7622
- */
7623
- get(url) {
7624
- const entry = this.cache.get(url);
7625
- if (!entry) {
7626
- this.misses++;
7627
- return null;
7628
- }
7629
- if (this.isExpired(entry)) {
7630
- this.cache.delete(url);
7631
- this.misses++;
7632
- this.log("debug", `Cache entry expired for ${url}`, { url });
7633
- return null;
7634
- }
7635
- this.hits++;
7636
- this.log("debug", `Cache hit for ${url} with ETag ${entry.etag}`, { url });
7637
- return entry;
7638
- }
7639
- /**
7640
- * Get ETag for a URL (for If-None-Match header)
7641
- */
7642
- getETag(url) {
7643
- const entry = this.get(url);
7644
- return entry ? entry.etag : null;
7645
- }
7646
- /**
7647
- * Set cache entry
7648
- */
7649
- set(url, etag, data, headers, customTtl) {
7650
- if (!this.cache.has(url) && this.cache.size >= this.config.maxEntries) {
7651
- this.evictOldest();
7652
- }
7653
- const entry = {
7654
- etag,
7655
- data,
7656
- headers,
7657
- timestamp: Date.now(),
7658
- ttl: customTtl ?? this.config.defaultTtl
7659
- };
7660
- this.cache.set(url, entry);
7661
- this.log("debug", `Cached response for ${url} with ETag ${etag}`, { url });
7662
- }
7663
- /**
7664
- * Check if cached data exists and is valid
7665
- */
7666
- has(url) {
7667
- const entry = this.cache.get(url);
7668
- return entry !== void 0 && !this.isExpired(entry);
7669
- }
7670
- /**
7671
- * Clear specific cache entry
7672
- */
7673
- delete(url) {
7674
- return this.cache.delete(url);
7675
- }
7676
- /**
7677
- * Delete all cache entries whose URL contains the given path segment
7678
- */
7679
- deleteByPath(pathSegment) {
7680
- let count = 0;
7681
- for (const key of this.cache.keys()) {
7682
- if (key.includes(pathSegment)) {
7683
- this.cache.delete(key);
7684
- count++;
7685
- }
7686
- }
7687
- if (count > 0) {
7688
- this.log(
7689
- "debug",
7690
- `Invalidated ${count} cache entries matching ${pathSegment}`,
7691
- {
7692
- count
7693
- }
7694
- );
7695
- }
7696
- return count;
7697
- }
7698
- /**
7699
- * Clear all cache entries
7700
- */
7701
- clear() {
7702
- this.cache.clear();
7703
- this.hits = 0;
7704
- this.misses = 0;
7705
- this.log("info", "ETag cache cleared");
7706
- }
7707
- /**
7708
- * Get cache statistics
7709
- */
7710
- getStats() {
7711
- let oldest = Infinity;
7712
- let newest = -Infinity;
7713
- for (const entry of this.cache.values()) {
7714
- if (entry.timestamp < oldest) oldest = entry.timestamp;
7715
- if (entry.timestamp > newest) newest = entry.timestamp;
7716
- }
7717
- const total = this.hits + this.misses;
7718
- return {
7719
- totalEntries: this.cache.size,
7720
- maxEntries: this.config.maxEntries,
7721
- hits: this.hits,
7722
- misses: this.misses,
7723
- hitRate: total > 0 ? this.hits / total : 0,
7724
- oldestEntry: this.cache.size > 0 ? oldest : null,
7725
- newestEntry: this.cache.size > 0 ? newest : null
7726
- };
7727
- }
7728
- /**
7729
- * Update cache configuration
7730
- */
7731
- updateConfig(newConfig) {
7732
- this.config = { ...this.config, ...newConfig };
7733
- this.log("info", "ETag cache configuration updated", {
7734
- maxEntries: this.config.maxEntries
7735
- });
7736
- }
7737
- /**
7738
- * Cleanup expired entries
7739
- */
7740
- cleanup() {
7741
- const beforeSize = this.cache.size;
7742
- for (const [url, entry] of this.cache.entries()) {
7743
- if (this.isExpired(entry)) {
7744
- this.cache.delete(url);
7745
- }
7746
- }
7747
- const cleanedCount = beforeSize - this.cache.size;
7748
- if (cleanedCount > 0) {
7749
- this.log("debug", `Cleaned up ${cleanedCount} expired cache entries`, {
7750
- cleanedCount
7751
- });
7752
- }
7753
- return cleanedCount;
7754
- }
7755
- /**
7756
- * Shutdown cache manager
7757
- */
7758
- shutdown() {
7759
- if (this.cleanupTimer) {
7760
- clearInterval(this.cleanupTimer);
7761
- }
7762
- this.log("info", "ETag cache manager shut down");
7763
- }
7764
- isExpired(entry) {
7765
- if (!entry.ttl) return false;
7766
- return Date.now() - entry.timestamp > entry.ttl;
7767
- }
7768
- evictOldest() {
7769
- let oldestKey = null;
7770
- let oldestTime = Infinity;
7771
- for (const [key, entry] of this.cache.entries()) {
7772
- if (entry.timestamp < oldestTime) {
7773
- oldestTime = entry.timestamp;
7774
- oldestKey = key;
7775
- }
7776
- }
7777
- if (oldestKey) {
7778
- this.cache.delete(oldestKey);
7779
- this.log("debug", `Evicted oldest cache entry: ${oldestKey}`, {
7780
- url: oldestKey
7781
- });
7782
- }
7783
- }
7784
- startCleanupTimer() {
7785
- this.cleanupTimer = setInterval(() => {
7786
- this.cleanup();
7787
- }, this.config.cleanupInterval);
7788
- this.cleanupTimer.unref();
7789
- }
7790
- };
7791
-
7792
- // src/core/endpoints/esi-rate-limit-groups.generated.ts
7793
- var esiRateLimitGroups = {
7794
- "GET:alliances/{alliance_id}/contacts": { group: "alliance-social", maxTokens: 300, windowSizeMs: 9e5 },
7795
- "GET:alliances/{alliance_id}/contacts/labels": { group: "alliance-social", maxTokens: 300, windowSizeMs: 9e5 },
7796
- "GET:characters/{character_id}/access-lists": { group: "char-access", maxTokens: 600, windowSizeMs: 9e5 },
7797
- "GET:characters/{character_id}/access-lists/{access_list_id}": { group: "char-access", maxTokens: 600, windowSizeMs: 9e5 },
7798
- "GET:characters/{character_id}/agents_research": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7799
- "GET:characters/{character_id}/assets": { group: "char-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7800
- "POST:characters/{character_id}/assets/locations": { group: "char-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7801
- "POST:characters/{character_id}/assets/names": { group: "char-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7802
- "GET:characters/{character_id}/attributes": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7803
- "GET:characters/{character_id}/blueprints": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7804
- "GET:characters/{character_id}/calendar": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7805
- "GET:characters/{character_id}/calendar/{event_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7806
- "PUT:characters/{character_id}/calendar/{event_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7807
- "GET:characters/{character_id}/calendar/{event_id}/attendees": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7808
- "GET:characters/{character_id}/clones": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7809
- "GET:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7810
- "POST:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7811
- "PUT:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7812
- "DELETE:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7813
- "GET:characters/{character_id}/contacts/labels": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7814
- "GET:characters/{character_id}/contracts": { group: "char-contract", maxTokens: 600, windowSizeMs: 9e5 },
7815
- "GET:characters/{character_id}/contracts/{contract_id}/bids": { group: "char-contract", maxTokens: 600, windowSizeMs: 9e5 },
7816
- "GET:characters/{character_id}/contracts/{contract_id}/items": { group: "char-contract", maxTokens: 600, windowSizeMs: 9e5 },
7817
- "POST:characters/{character_id}/cspa": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7818
- "GET:characters/{character_id}/fatigue": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7819
- "GET:characters/{character_id}/fittings": { group: "fitting", maxTokens: 150, windowSizeMs: 9e5 },
7820
- "POST:characters/{character_id}/fittings": { group: "fitting", maxTokens: 150, windowSizeMs: 9e5 },
7821
- "DELETE:characters/{character_id}/fittings/{fitting_id}": { group: "fitting", maxTokens: 150, windowSizeMs: 9e5 },
7822
- "GET:characters/{character_id}/fleet": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7823
- "GET:characters/{character_id}/freelance-jobs": { group: "char-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7824
- "GET:characters/{character_id}/freelance-jobs/{job_id}/participation": { group: "char-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7825
- "GET:characters/{character_id}/fw/stats": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7826
- "GET:characters/{character_id}/implants": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7827
- "GET:characters/{character_id}/industry/jobs": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7828
- "GET:characters/{character_id}/killmails/recent": { group: "char-killmail", maxTokens: 30, windowSizeMs: 9e5 },
7829
- "GET:characters/{character_id}/location": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7830
- "GET:characters/{character_id}/loyalty/points": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7831
- "GET:characters/{character_id}/mail": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7832
- "POST:characters/{character_id}/mail": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7833
- "GET:characters/{character_id}/mail/{mail_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7834
- "PUT:characters/{character_id}/mail/{mail_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7835
- "DELETE:characters/{character_id}/mail/{mail_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7836
- "GET:characters/{character_id}/mail/labels": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7837
- "POST:characters/{character_id}/mail/labels": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7838
- "DELETE:characters/{character_id}/mail/labels/{label_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7839
- "GET:characters/{character_id}/mail/lists": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7840
- "GET:characters/{character_id}/medals": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7841
- "GET:characters/{character_id}/mercenary-tactical-operations": { group: "char-activity", maxTokens: 150, windowSizeMs: 9e5 },
7842
- "GET:characters/{character_id}/mercenary-tactical-operations/{operation_id}": { group: "char-activity", maxTokens: 150, windowSizeMs: 9e5 },
7843
- "GET:characters/{character_id}/mining": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7844
- "GET:characters/{character_id}/notifications": { group: "char-notification", maxTokens: 15, windowSizeMs: 9e5 },
7845
- "GET:characters/{character_id}/notifications/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7846
- "GET:characters/{character_id}/online": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7847
- "GET:characters/{character_id}/planets": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7848
- "GET:characters/{character_id}/planets/{planet_id}": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7849
- "GET:characters/{character_id}/portrait": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7850
- "GET:characters/{character_id}/roles": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7851
- "GET:characters/{character_id}/ship": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7852
- "GET:characters/{character_id}/skillqueue": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7853
- "GET:characters/{character_id}/skills": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7854
- "GET:characters/{character_id}/standings": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7855
- "GET:characters/{character_id}/structures/mercenary-dens": { group: "char-structure", maxTokens: 30, windowSizeMs: 9e5 },
7856
- "GET:characters/{character_id}/structures/mercenary-dens/{mercenary_den_id}": { group: "char-structure", maxTokens: 30, windowSizeMs: 9e5 },
7857
- "GET:characters/{character_id}/titles": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7858
- "GET:characters/{character_id}/wallet": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7859
- "GET:characters/{character_id}/wallet/journal": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7860
- "GET:characters/{character_id}/wallet/transactions": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7861
- "GET:corporation/{corporation_id}/mining/extractions": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7862
- "GET:corporation/{corporation_id}/mining/observers": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7863
- "GET:corporation/{corporation_id}/mining/observers/{observer_id}": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7864
- "GET:corporations/{corporation_id}/assets": { group: "corp-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7865
- "POST:corporations/{corporation_id}/assets/locations": { group: "corp-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7866
- "POST:corporations/{corporation_id}/assets/names": { group: "corp-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7867
- "GET:corporations/{corporation_id}/blueprints": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7868
- "GET:corporations/{corporation_id}/contacts": { group: "corp-social", maxTokens: 300, windowSizeMs: 9e5 },
7869
- "GET:corporations/{corporation_id}/contacts/labels": { group: "corp-social", maxTokens: 300, windowSizeMs: 9e5 },
7870
- "GET:corporations/{corporation_id}/containers/logs": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7871
- "GET:corporations/{corporation_id}/contracts": { group: "corp-contract", maxTokens: 600, windowSizeMs: 9e5 },
7872
- "GET:corporations/{corporation_id}/contracts/{contract_id}/bids": { group: "corp-contract", maxTokens: 600, windowSizeMs: 9e5 },
7873
- "GET:corporations/{corporation_id}/contracts/{contract_id}/items": { group: "corp-contract", maxTokens: 600, windowSizeMs: 9e5 },
7874
- "GET:corporations/{corporation_id}/customs_offices": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7875
- "GET:corporations/{corporation_id}/divisions": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7876
- "GET:corporations/{corporation_id}/facilities": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7877
- "GET:corporations/{corporation_id}/freelance-jobs": { group: "corp-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7878
- "GET:corporations/{corporation_id}/freelance-jobs/{job_id}/participants": { group: "corp-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7879
- "GET:corporations/{corporation_id}/fw/stats": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7880
- "GET:corporations/{corporation_id}/industry/jobs": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7881
- "GET:corporations/{corporation_id}/killmails/recent": { group: "corp-killmail", maxTokens: 30, windowSizeMs: 9e5 },
7882
- "GET:corporations/{corporation_id}/medals": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7883
- "GET:corporations/{corporation_id}/medals/issued": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7884
- "GET:corporations/{corporation_id}/members": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7885
- "GET:corporations/{corporation_id}/members/limit": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7886
- "GET:corporations/{corporation_id}/members/titles": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7887
- "GET:corporations/{corporation_id}/membertracking": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7888
- "GET:corporations/{corporation_id}/projects": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7889
- "GET:corporations/{corporation_id}/projects/{project_id}": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7890
- "GET:corporations/{corporation_id}/projects/{project_id}/contribution/{character_id}": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7891
- "GET:corporations/{corporation_id}/projects/{project_id}/contributors": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7892
- "GET:corporations/{corporation_id}/roles": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7893
- "GET:corporations/{corporation_id}/roles/history": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7894
- "GET:corporations/{corporation_id}/shareholders": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7895
- "GET:corporations/{corporation_id}/standings": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7896
- "GET:corporations/{corporation_id}/starbases": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7897
- "GET:corporations/{corporation_id}/starbases/{starbase_id}": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7898
- "GET:corporations/{corporation_id}/structures": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7899
- "GET:corporations/{corporation_id}/structures/skyhooks": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7900
- "GET:corporations/{corporation_id}/structures/skyhooks/{skyhook_id}": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7901
- "GET:corporations/{corporation_id}/structures/sovereignty-hubs": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7902
- "GET:corporations/{corporation_id}/structures/sovereignty-hubs/{sovereignty_hub_id}": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7903
- "GET:corporations/{corporation_id}/titles": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7904
- "GET:corporations/{corporation_id}/wallets": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7905
- "GET:corporations/{corporation_id}/wallets/{division}/journal": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7906
- "GET:corporations/{corporation_id}/wallets/{division}/transactions": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7907
- "GET:fleets/{fleet_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7908
- "PUT:fleets/{fleet_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7909
- "GET:fleets/{fleet_id}/members": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7910
- "POST:fleets/{fleet_id}/members": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7911
- "PUT:fleets/{fleet_id}/members/{member_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7912
- "DELETE:fleets/{fleet_id}/members/{member_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7913
- "PUT:fleets/{fleet_id}/squads/{squad_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7914
- "DELETE:fleets/{fleet_id}/squads/{squad_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7915
- "GET:fleets/{fleet_id}/wings": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7916
- "POST:fleets/{fleet_id}/wings": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7917
- "PUT:fleets/{fleet_id}/wings/{wing_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7918
- "DELETE:fleets/{fleet_id}/wings/{wing_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7919
- "POST:fleets/{fleet_id}/wings/{wing_id}/squads": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7920
- "GET:freelance-jobs": { group: "freelance-job", maxTokens: 12e3, windowSizeMs: 9e5 },
7921
- "GET:freelance-jobs/{job_id}": { group: "freelance-job", maxTokens: 12e3, windowSizeMs: 9e5 },
7922
- "GET:fw/leaderboards": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7923
- "GET:fw/leaderboards/characters": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7924
- "GET:fw/leaderboards/corporations": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7925
- "GET:fw/stats": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7926
- "GET:fw/systems": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7927
- "GET:fw/wars": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7928
- "GET:incursions": { group: "incursion", maxTokens: 150, windowSizeMs: 9e5 },
7929
- "GET:industry/facilities": { group: "industry", maxTokens: 150, windowSizeMs: 9e5 },
7930
- "GET:industry/systems": { group: "industry", maxTokens: 150, windowSizeMs: 9e5 },
7931
- "GET:insurance/prices": { group: "insurance", maxTokens: 150, windowSizeMs: 9e5 },
7932
- "GET:killmails/{killmail_id}/{killmail_hash}": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 },
7933
- "GET:markets/{region_id}/orders": { group: "market-order", maxTokens: 12e3, windowSizeMs: 9e5 },
7934
- "GET:meta/changelog": { group: "meta", maxTokens: 150, windowSizeMs: 9e5 },
7935
- "GET:meta/compatibility-dates": { group: "meta", maxTokens: 150, windowSizeMs: 9e5 },
7936
- "GET:meta/status": { group: "meta", maxTokens: 150, windowSizeMs: 9e5 },
7937
- "POST:route/{origin_system_id}/{destination_system_id}": { group: "routes", maxTokens: 3600, windowSizeMs: 9e5 },
7938
- "GET:skyhooks/raidable": { group: "activity", maxTokens: 30, windowSizeMs: 9e5 },
7939
- "GET:sovereignty/campaigns": { group: "sovereignty", maxTokens: 600, windowSizeMs: 9e5 },
7940
- "GET:sovereignty/systems": { group: "sovereignty", maxTokens: 600, windowSizeMs: 9e5 },
7941
- "GET:status": { group: "status", maxTokens: 600, windowSizeMs: 9e5 },
7942
- "POST:ui/autopilot/waypoint": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7943
- "POST:ui/openwindow/contract": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7944
- "POST:ui/openwindow/information": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7945
- "POST:ui/openwindow/marketdetails": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7946
- "POST:ui/openwindow/newmail": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7947
- "GET:wars": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 },
7948
- "GET:wars/{war_id}": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 },
7949
- "GET:wars/{war_id}/killmails": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 }
7950
- };
7951
-
7952
- // src/core/rateLimiter/RateLimiter.ts
7953
- function getTokenCost(statusCode) {
7954
- if (statusCode >= 200 && statusCode < 300) return 2;
7955
- if (statusCode >= 300 && statusCode < 400) return 1;
7956
- if (statusCode >= 400 && statusCode < 500) return 5;
7957
- if (statusCode >= 500 && statusCode < 600) return 0;
7958
- return 2;
7959
- }
7960
- function retryAfterDeadline(value, now) {
7961
- const trimmed = value.trim();
7962
- if (/^\d+$/.test(trimmed)) return now + parseInt(trimmed, 10) * 1e3;
7963
- if (!/[A-Za-z]/.test(trimmed)) return void 0;
7964
- const date = Date.parse(trimmed);
7965
- return Number.isNaN(date) ? void 0 : date;
7966
- }
7967
- var DEFAULT_WINDOW_MS = 9e5;
7968
- var DEFAULT_ERROR_LIMIT = {
7969
- remain: 100,
7970
- reset: 0,
7971
- exhaustedUntil: 0
7972
- };
7973
- var RateLimiter = class _RateLimiter {
7974
- minDelayMs;
7975
- decelerationThreshold;
7976
- userKeyExtractor;
7977
- endpointOverrides;
7978
- lastRequestTime = 0;
7979
- minDelayChain = Promise.resolve();
7980
- isTestMode = false;
7981
- globalErrorLimit = { ...DEFAULT_ERROR_LIMIT };
7982
- defaultBuckets = /* @__PURE__ */ new Map();
7983
- userBuckets = null;
7984
- fallbackBucket;
7985
- lastCleanup = 0;
7986
- static CLEANUP_INTERVAL_MS = 6e4;
7987
- constructor(config) {
7988
- this.minDelayMs = config?.minDelayMs ?? 50;
7989
- this.decelerationThreshold = config?.decelerationThreshold ?? 0.2;
7990
- this.userKeyExtractor = config?.userKeyExtractor;
7991
- this.endpointOverrides = config?.endpointOverrides ?? {};
7992
- if (this.userKeyExtractor) {
7993
- this.userBuckets = /* @__PURE__ */ new Map();
7994
- }
7995
- this.fallbackBucket = this.createFallbackBucket();
7996
- }
7997
- createFallbackBucket() {
7998
- return {
7999
- group: "__fallback__",
8000
- remaining: -1,
8001
- limit: 0,
8002
- used: 0,
8003
- windowSizeMs: DEFAULT_WINDOW_MS,
8004
- blockedUntil: 0,
8005
- lastUpdated: 0
8006
- };
8007
- }
8008
- createBucketFromSpec(spec) {
8009
- return {
8010
- group: spec.group,
8011
- remaining: spec.maxTokens,
8012
- limit: spec.maxTokens,
8013
- used: 0,
8014
- windowSizeMs: spec.windowSizeMs,
8015
- blockedUntil: 0,
8016
- lastUpdated: 0
8017
- };
8018
- }
8019
- createBucketForGroup(groupName) {
8020
- return {
8021
- group: groupName,
8022
- remaining: -1,
8023
- limit: 0,
8024
- used: 0,
8025
- windowSizeMs: DEFAULT_WINDOW_MS,
8026
- blockedUntil: 0,
8027
- lastUpdated: 0
8028
- };
8029
- }
8030
- lookupGroupSpec(method, templatePath) {
8031
- if (!templatePath || !method) return void 0;
8032
- const normalized = templatePath.replace(/\/$/, "").replace(/\{(\w+)\}/g, (_, name) => `{${camelToSnake(name)}}`);
8033
- const key = `${method}:${normalized}`;
8034
- const override = this.endpointOverrides[key];
8035
- if (override) {
8036
- return {
8037
- group: `endpoint:${key}`,
8038
- maxTokens: override.maxTokens,
8039
- windowSizeMs: override.windowSizeMs
8040
- };
8041
- }
8042
- return esiRateLimitGroups[key];
8043
- }
8044
- resolveUserSet(requestHeaders) {
8045
- if (!this.userBuckets || !this.userKeyExtractor || !requestHeaders) {
8046
- return null;
8047
- }
8048
- const userKey = this.userKeyExtractor(requestHeaders);
8049
- let userSet = this.userBuckets.get(userKey);
8050
- if (!userSet) {
8051
- userSet = {
8052
- groups: /* @__PURE__ */ new Map(),
8053
- errorLimit: { ...DEFAULT_ERROR_LIMIT },
8054
- lastAccessed: Date.now()
8055
- };
8056
- this.userBuckets.set(userKey, userSet);
8057
- }
8058
- userSet.lastAccessed = Date.now();
8059
- return userSet;
8060
- }
8061
- resolveBucketMap(requestHeaders) {
8062
- const userSet = this.resolveUserSet(requestHeaders);
8063
- return userSet ? userSet.groups : this.defaultBuckets;
8064
- }
8065
- resolveErrorLimit(requestHeaders) {
8066
- const userSet = this.resolveUserSet(requestHeaders);
8067
- return userSet ? userSet.errorLimit : this.globalErrorLimit;
8068
- }
8069
- getBucket(templatePath, method, requestHeaders, groupNameOverride) {
8070
- const bucketMap = this.resolveBucketMap(requestHeaders);
8071
- const spec = this.lookupGroupSpec(method, templatePath);
8072
- const groupName = groupNameOverride ?? spec?.group;
8073
- if (!groupName) return this.fallbackBucket;
8074
- let bucket = bucketMap.get(groupName);
8075
- if (!bucket) {
8076
- bucket = spec ? this.createBucketFromSpec(spec) : this.createBucketForGroup(groupName);
8077
- bucketMap.set(groupName, bucket);
8078
- }
8079
- return bucket;
8080
- }
8081
- cleanupStaleUsers() {
8082
- if (!this.userBuckets) return;
8083
- const now = Date.now();
8084
- if (now - this.lastCleanup < _RateLimiter.CLEANUP_INTERVAL_MS) return;
8085
- this.lastCleanup = now;
8086
- for (const [userKey, userSet] of this.userBuckets) {
8087
- if (now - userSet.lastAccessed > DEFAULT_WINDOW_MS) {
8088
- this.userBuckets.delete(userKey);
8089
- }
8090
- }
8091
- }
8092
- updateFromResponse(headers, statusCode, templatePath, method, requestHeaders) {
8093
- if (this.isTestMode) return;
8094
- const now = Date.now();
8095
- const responseGroup = headers["x-ratelimit-group"] || void 0;
8096
- const bucket = this.getBucket(
8097
- templatePath,
8098
- method,
8099
- requestHeaders,
8100
- responseGroup
8101
- );
8102
- if ("x-ratelimit-remaining" in headers) {
8103
- bucket.remaining = parseInt(headers["x-ratelimit-remaining"], 10);
8104
- }
8105
- if ("x-ratelimit-limit" in headers) {
8106
- bucket.limit = parseInt(headers["x-ratelimit-limit"], 10);
8107
- }
8108
- if ("x-ratelimit-used" in headers) {
8109
- bucket.used = parseInt(headers["x-ratelimit-used"], 10);
8110
- }
8111
- bucket.lastUpdated = now;
8112
- if ("retry-after" in headers) {
8113
- const until = retryAfterDeadline(headers["retry-after"], now);
8114
- if (until !== void 0) bucket.blockedUntil = until;
8115
- }
8116
- if (statusCode === 420 || statusCode === 429) {
8117
- if (bucket.blockedUntil <= now) {
8118
- bucket.blockedUntil = now + 6e4;
8119
- }
8120
- }
8121
- const errorLimit = this.resolveErrorLimit(requestHeaders);
8122
- const reportedRemain = "x-esi-error-limit-remain" in headers ? parseInt(headers["x-esi-error-limit-remain"], 10) : void 0;
8123
- if (reportedRemain !== void 0 && reportedRemain > 0 && errorLimit.remain <= 0 && now < errorLimit.exhaustedUntil) {
8124
- return;
8125
- }
8126
- if (reportedRemain !== void 0) {
8127
- errorLimit.remain = reportedRemain;
8128
- }
8129
- if ("x-esi-error-limit-reset" in headers) {
8130
- errorLimit.reset = parseInt(headers["x-esi-error-limit-reset"], 10);
8131
- }
8132
- if (reportedRemain !== void 0 && reportedRemain <= 0) {
8133
- errorLimit.exhaustedUntil = now + errorLimit.reset * 1e3;
8134
- }
8135
- }
8136
- updateRateLimitInfo(headers) {
8137
- this.updateFromResponse(headers, 200);
8138
- }
8139
- async checkRateLimit(templatePath, method, requestHeaders) {
8140
- if (this.isTestMode) return;
8141
- this.cleanupStaleUsers();
8142
- let stillBlockedBucket;
8143
- for (let i = 0; i < 10; i++) {
8144
- const bucket2 = this.getBucket(templatePath, method, requestHeaders);
8145
- const now = Date.now();
8146
- if (bucket2.blockedUntil <= now) {
8147
- stillBlockedBucket = void 0;
8148
- break;
8149
- }
8150
- stillBlockedBucket = bucket2;
8151
- const waitedUntil = bucket2.blockedUntil;
8152
- const waitTime = waitedUntil - now;
8153
- logWarn2(
8154
- null,
8155
- `[ESI Rate Limit] Group '${bucket2.group}' blocked for ${Math.ceil(waitTime / 1e3)}s (420/429 received)`,
8156
- { group: bucket2.group, waitMs: waitTime }
8157
- );
8158
- await sleep(waitTime);
8159
- if (bucket2.blockedUntil <= waitedUntil) {
8160
- bucket2.blockedUntil = 0;
8161
- }
8162
- }
8163
- if (stillBlockedBucket && stillBlockedBucket.blockedUntil > Date.now()) {
8164
- const waitTime = stillBlockedBucket.blockedUntil - Date.now();
8165
- logWarn2(
8166
- null,
8167
- `[ESI Rate Limit] Group '${stillBlockedBucket.group}' still blocked after retry budget exhausted; aborting request instead of sending while blocked`,
8168
- { group: stillBlockedBucket.group }
8169
- );
8170
- throw new EsiError(
8171
- 429,
8172
- `Rate limit group '${stillBlockedBucket.group}' still blocked for ${Math.ceil(waitTime / 1e3)}s`
8173
- );
8174
- }
8175
- const errorLimit = this.resolveErrorLimit(requestHeaders);
8176
- if (errorLimit.remain <= 10 && errorLimit.remain > 0) {
8177
- const resetMs = errorLimit.reset * 1e3;
8178
- const delay = Math.min(resetMs, 5e3);
8179
- if (delay > 0) {
8180
- logWarn2(
8181
- null,
8182
- `[ESI Rate Limit] Legacy error limit low (${errorLimit.remain}), waiting ${delay}ms`,
8183
- { errorLimitRemain: errorLimit.remain }
8184
- );
8185
- await sleep(delay);
8186
- }
8187
- } else if (errorLimit.remain <= 0 && errorLimit.reset > 0) {
8188
- const waitTime = errorLimit.reset * 1e3;
8189
- logWarn2(
8190
- null,
8191
- `[ESI Rate Limit] Legacy error limit exhausted, waiting ${Math.ceil(waitTime / 1e3)}s`,
8192
- { errorLimitReset: errorLimit.reset }
8193
- );
8194
- await sleep(waitTime);
8195
- }
8196
- const bucket = this.getBucket(templatePath, method, requestHeaders);
8197
- if (bucket.remaining >= 0 && bucket.limit > 0) {
8198
- const ratio = bucket.remaining / bucket.limit;
8199
- if (bucket.remaining <= 0) {
8200
- logWarn2(
8201
- null,
8202
- `[ESI Rate Limit] Group '${bucket.group}' token bucket empty, waiting 1s`,
8203
- { group: bucket.group }
8204
- );
8205
- await sleep(1e3);
8206
- } else if (ratio <= this.decelerationThreshold) {
8207
- const extraDelay = Math.ceil(
8208
- (1 - ratio / this.decelerationThreshold) * 1e3
8209
- );
8210
- await sleep(extraDelay);
8211
- }
8212
- }
8213
- await this.enforceMinDelay();
8214
- }
8215
- /**
8216
- * Serializes min-delay waits so concurrent callers cannot all read the same
8217
- * lastRequestTime and fire together after sleeping.
8218
- */
8219
- async enforceMinDelay() {
8220
- if (this.isTestMode) {
8221
- this.lastRequestTime = Date.now();
8222
- return;
8223
- }
8224
- const run = async () => {
8225
- const now = Date.now();
8226
- const timeSinceLastRequest = now - this.lastRequestTime;
8227
- if (timeSinceLastRequest < this.minDelayMs) {
8228
- await sleep(this.minDelayMs - timeSinceLastRequest);
8229
- }
8230
- this.lastRequestTime = Date.now();
8231
- };
8232
- const scheduled = this.minDelayChain.then(run, run);
8233
- this.minDelayChain = scheduled.then(
8234
- () => void 0,
8235
- () => void 0
8236
- );
8237
- await scheduled;
8238
- }
8239
- getStatus() {
8240
- let worstBucket = this.fallbackBucket;
8241
- let worstRatio = Infinity;
8242
- const checkBucket = (bucket) => {
8243
- if (bucket.limit > 0) {
8244
- const ratio = bucket.remaining / bucket.limit;
8245
- if (ratio < worstRatio) {
8246
- worstRatio = ratio;
8247
- worstBucket = bucket;
8248
- }
8249
- }
8250
- };
8251
- for (const bucket of this.defaultBuckets.values()) {
8252
- checkBucket(bucket);
8253
- }
8254
- if (this.userBuckets) {
8255
- for (const userSet of this.userBuckets.values()) {
8256
- for (const bucket of userSet.groups.values()) {
8257
- checkBucket(bucket);
8258
- }
8259
- }
8260
- }
8261
- return {
8262
- remaining: worstBucket.remaining,
8263
- limit: worstBucket.limit,
8264
- used: worstBucket.used,
8265
- group: worstBucket.group === "__fallback__" ? null : worstBucket.group,
8266
- errorLimitRemain: this.globalErrorLimit.remain,
8267
- errorLimitReset: this.globalErrorLimit.reset,
8268
- retryAfter: worstBucket.blockedUntil > Date.now() ? Math.ceil((worstBucket.blockedUntil - Date.now()) / 1e3) : null,
8269
- blockedUntil: worstBucket.blockedUntil
8270
- };
8271
- }
8272
- getGroupStatus(group) {
8273
- const bucket = this.defaultBuckets.get(group);
8274
- if (!bucket) return void 0;
8275
- return {
8276
- group: bucket.group,
8277
- remaining: bucket.remaining,
8278
- limit: bucket.limit,
8279
- used: bucket.used,
8280
- windowSizeMs: bucket.windowSizeMs,
8281
- blockedUntil: bucket.blockedUntil
8282
- };
8283
- }
8284
- getAllGroupStatuses() {
8285
- const result = /* @__PURE__ */ new Map();
8286
- for (const [name, bucket] of this.defaultBuckets) {
8287
- result.set(name, {
8288
- group: bucket.group,
8289
- remaining: bucket.remaining,
8290
- limit: bucket.limit,
8291
- used: bucket.used,
8292
- windowSizeMs: bucket.windowSizeMs,
8293
- blockedUntil: bucket.blockedUntil
8294
- });
8295
- }
8296
- return result;
8297
- }
8298
- static getTokenCost(statusCode) {
8299
- return getTokenCost(statusCode);
8300
- }
8301
- isBlocked(group) {
8302
- const now = Date.now();
8303
- if (group) {
8304
- const bucket = this.defaultBuckets.get(group);
8305
- return bucket ? bucket.blockedUntil > now : false;
8306
- }
8307
- if (this.fallbackBucket.blockedUntil > now) return true;
8308
- for (const bucket of this.defaultBuckets.values()) {
8309
- if (bucket.blockedUntil > now) return true;
8310
- }
8311
- return false;
8312
- }
8313
- setTestMode(enabled) {
8314
- this.isTestMode = enabled;
8315
- }
8316
- reset() {
8317
- this.defaultBuckets.clear();
8318
- if (this.userBuckets) this.userBuckets.clear();
8319
- this.fallbackBucket = this.createFallbackBucket();
8320
- this.globalErrorLimit = { ...DEFAULT_ERROR_LIMIT };
8321
- this.lastRequestTime = 0;
8322
- this.minDelayChain = Promise.resolve();
8323
- this.lastCleanup = 0;
8324
- }
8325
- };
8326
-
8327
- // src/core/RequestDeduplicator.ts
8328
- var RequestDeduplicator = class {
8329
- inflight = /* @__PURE__ */ new Map();
8330
- client = null;
8331
- setClient(client) {
8332
- this.client = client;
8333
- }
8334
- async dedupe(key, execute) {
8335
- const existing = this.inflight.get(key);
8336
- if (existing) {
8337
- if (this.client) {
8338
- logDebug2(this.client, `[Dedup] Coalescing request: ${key}`);
8339
- }
8340
- return existing;
8341
- }
8342
- const promise = execute().finally(() => {
8343
- this.inflight.delete(key);
8344
- });
8345
- this.inflight.set(key, promise);
8346
- return promise;
8347
- }
8348
- /**
8349
- * Drop the in-flight entries whose key contains `pathSegment`, so a call
8350
- * made after a write cannot join a request sent before it.
8351
- *
8352
- * The requests themselves keep running and whoever already joined them still
8353
- * gets their answer. Only the map entry goes, which is what new callers look
8354
- * in. Matching is `includes`, the same rule ETagCacheManager.deleteByPath
8355
- * uses, so one written path invalidates the cache and detaches the reads of
8356
- * it by the same test.
8357
- */
8358
- detachByPath(pathSegment) {
8359
- let count = 0;
8360
- for (const key of this.inflight.keys()) {
8361
- if (key.includes(pathSegment)) {
8362
- this.inflight.delete(key);
8363
- count += 1;
8364
- }
8365
- }
8366
- if (count > 0 && this.client) {
8367
- logDebug2(
8368
- this.client,
8369
- `[Dedup] Detached ${count} in-flight request(s) matching ${pathSegment} after a write`
8370
- );
8371
- }
8372
- return count;
8373
- }
8374
- get pending() {
8375
- return this.inflight.size;
8376
- }
8377
- clear() {
8378
- this.inflight.clear();
8379
- }
8380
- };
8381
-
8382
- // src/core/configureApiClient.ts
8383
- function configureApiClient(client, config) {
8384
- let deduplicator = null;
8385
- client.setRateLimiter(new RateLimiter(config?.rateLimiterConfig));
8386
- if (config?.enableRequestDeduplication !== false) {
8387
- deduplicator = new RequestDeduplicator();
8388
- deduplicator.setClient(client);
8389
- client.setDeduplicator(deduplicator);
8390
- }
8391
- if (config?.enableETagCache !== false) {
8392
- const cache = new ETagCacheManager(config?.etagCacheConfig);
8393
- cache.setClient(client);
8394
- client.setCache(cache);
8395
- }
8396
- if (config?.enableCircuitBreaker) {
8397
- const cb = new CircuitBreaker(config.circuitBreakerConfig);
8398
- cb.setClient(client);
8399
- client.setCircuitBreaker(cb);
8400
- }
8401
- if (config?.retryConfig) {
8402
- client.setRetryConfig(config.retryConfig);
8403
- } else if (config?.retryAttempts !== void 0) {
8404
- client.setRetryConfig({ maxRetries: config.retryAttempts });
8405
- } else {
8406
- client.setRetryConfig({
8407
- maxRetries: 3,
8408
- baseDelayMs: 1e3,
8409
- maxDelayMs: 3e4
8410
- });
8411
- }
8412
- if (config?.retryStrategy) {
8413
- client.setRetryStrategy(config.retryStrategy);
8414
- }
8415
- if (config?.requestInterceptors) {
8416
- for (const interceptor of config.requestInterceptors) {
8417
- client.addRequestInterceptor(interceptor);
8418
- }
8419
- }
8420
- if (config?.responseInterceptors) {
8421
- for (const interceptor of config.responseInterceptors) {
8422
- client.addResponseInterceptor(interceptor);
8423
- }
8424
- }
8425
- if (config?.validateResponse !== void 0) {
8426
- client.setValidateResponse(config.validateResponse);
8427
- }
8428
- if (config?.validateRequest !== void 0) {
8429
- client.setValidateRequest(config.validateRequest);
8430
- }
8431
- if (config?.timeout !== void 0) {
8432
- client.setTimeout(config.timeout);
8433
- }
8434
- if (config?.logger) {
8435
- client.setLogger(config.logger);
8436
- } else if (config?.logLevel) {
8437
- client.setLogger(createDefaultLogger(config.logLevel));
8438
- }
8439
- return { deduplicator };
8440
- }
8441
-
8442
6085
  // src/EsiClient.ts
8443
6086
  var EsiClient = class {
8444
6087
  apiClient;
@@ -8473,8 +6116,7 @@ var EsiClient = class {
8473
6116
  const result = configureApiClient(this.apiClient, config);
8474
6117
  this.deduplicator = result.deduplicator;
8475
6118
  this.etagCacheEnabled = config?.enableETagCache !== false;
8476
- const clientLogger = this.apiClient.getLogger() ?? getLogger();
8477
- clientLogger.info("EsiClient initialized successfully", {
6119
+ logInfo2(this.apiClient, "EsiClient initialized successfully", {
8478
6120
  baseUrl,
8479
6121
  clientId: config?.clientId
8480
6122
  });
@@ -8611,11 +6253,12 @@ var EsiClient = class {
8611
6253
  }
8612
6254
  setAccessToken(token) {
8613
6255
  this.apiClient.setAccessToken(token);
8614
- (this.apiClient.getLogger() ?? getLogger()).info("Access token updated");
6256
+ logInfo2(this.apiClient, "Access token updated");
8615
6257
  }
8616
6258
  setTokenProvider(provider) {
8617
6259
  this.apiClient.setTokenProvider(provider);
8618
- (this.apiClient.getLogger() ?? getLogger()).info(
6260
+ logInfo2(
6261
+ this.apiClient,
8619
6262
  provider ? "Token provider configured" : "Token provider removed"
8620
6263
  );
8621
6264
  }
@@ -8645,10 +6288,10 @@ var EsiClient = class {
8645
6288
  this.diagnostics.resetCircuitBreaker(endpoint);
8646
6289
  }
8647
6290
  async batch(keys, fetcher, options) {
8648
- return batchFetch(keys, fetcher, options);
6291
+ return batchFetchFor(this.apiClient, keys, fetcher, options);
8649
6292
  }
8650
6293
  async batchPost(ids, poster, chunkSize) {
8651
- return batchPost(ids, poster, chunkSize);
6294
+ return batchPostFor(this.apiClient, ids, poster, chunkSize);
8652
6295
  }
8653
6296
  shutdown() {
8654
6297
  const cache = this.apiClient.getCache();
@@ -8663,9 +6306,7 @@ var EsiClient = class {
8663
6306
  this.deduplicator.clear();
8664
6307
  }
8665
6308
  this.clients.clear();
8666
- (this.apiClient.getLogger() ?? getLogger()).info(
8667
- "EsiClient shutdown completed"
8668
- );
6309
+ logInfo2(this.apiClient, "EsiClient shutdown completed");
8669
6310
  }
8670
6311
  };
8671
6312
  var _defaultClient = null;
@@ -8711,7 +6352,8 @@ var CustomEsiClient = class {
8711
6352
  for (const name of this.enabledClients) {
8712
6353
  this.clients.set(name, createClientInstance(name, this.apiClient));
8713
6354
  }
8714
- (this.apiClient.getLogger() ?? getLogger()).info(
6355
+ logInfo2(
6356
+ this.apiClient,
8715
6357
  `CustomEsiClient initialized with clients: ${config.clients.join(", ")}`,
8716
6358
  { clients: config.clients }
8717
6359
  );
@@ -8830,6 +6472,18 @@ var CustomEsiClient = class {
8830
6472
  get accessLists() {
8831
6473
  return this.getClient("accessLists");
8832
6474
  }
6475
+ get corporationProjects() {
6476
+ return this.getClient("corporationProjects");
6477
+ }
6478
+ get cosmetics() {
6479
+ return this.getClient("cosmetics");
6480
+ }
6481
+ get paragonHub() {
6482
+ return this.getClient("paragonHub");
6483
+ }
6484
+ get militaryCampaigns() {
6485
+ return this.getClient("militaryCampaigns");
6486
+ }
8833
6487
  shutdown() {
8834
6488
  const cache = this.apiClient.getCache();
8835
6489
  if (cache) {
@@ -8843,66 +6497,167 @@ var CustomEsiClient = class {
8843
6497
  this.deduplicator.clear();
8844
6498
  }
8845
6499
  this.clients.clear();
8846
- (this.apiClient.getLogger() ?? getLogger()).info(
8847
- "CustomEsiClient shutdown completed"
8848
- );
6500
+ logInfo2(this.apiClient, "CustomEsiClient shutdown completed");
8849
6501
  }
8850
6502
  };
8851
6503
  var EsiApiFactory = class {
6504
+ /**
6505
+ * A standalone `AllianceClient` on its own `ApiClient`.
6506
+ *
6507
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6508
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6509
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6510
+ * authenticated ones. For an alliance's public record:
6511
+ * `esi.public.alliance(allianceId).get()`.
6512
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6513
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6514
+ */
8852
6515
  static createAllianceClient(config) {
8853
6516
  return createClientInstance(
8854
6517
  "alliance",
8855
6518
  this.buildApiClient(config)
8856
6519
  );
8857
6520
  }
6521
+ /**
6522
+ * A standalone `CharacterClient` on its own `ApiClient`.
6523
+ *
6524
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6525
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6526
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6527
+ * authenticated ones. For a character's public record:
6528
+ * `esi.public.character(characterId).get()`.
6529
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6530
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6531
+ */
8858
6532
  static createCharacterClient(config) {
8859
6533
  return createClientInstance(
8860
6534
  "characters",
8861
6535
  this.buildApiClient(config)
8862
6536
  );
8863
6537
  }
6538
+ /**
6539
+ * A standalone `CorporationsClient` on its own `ApiClient`.
6540
+ *
6541
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6542
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6543
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6544
+ * authenticated ones. For a corporation's public record:
6545
+ * `esi.public.corporation(corporationId).get()`.
6546
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6547
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6548
+ */
8864
6549
  static createCorporationClient(config) {
8865
6550
  return createClientInstance(
8866
6551
  "corporations",
8867
6552
  this.buildApiClient(config)
8868
6553
  );
8869
6554
  }
6555
+ /**
6556
+ * A standalone `MarketClient` on its own `ApiClient`.
6557
+ *
6558
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6559
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6560
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6561
+ * authenticated ones. For a region's sell orders, every page followed:
6562
+ * `esi.public.market(regionId).orders.get({ order_type: 'sell' })`.
6563
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6564
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6565
+ */
8870
6566
  static createMarketClient(config) {
8871
6567
  return createClientInstance(
8872
6568
  "market",
8873
6569
  this.buildApiClient(config)
8874
6570
  );
8875
6571
  }
6572
+ /**
6573
+ * A standalone `UniverseClient` on its own `ApiClient`.
6574
+ *
6575
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6576
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6577
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6578
+ * authenticated ones. For a type:
6579
+ * `esi.public.universe.types(typeId).get()`.
6580
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6581
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6582
+ */
8876
6583
  static createUniverseClient(config) {
8877
6584
  return createClientInstance(
8878
6585
  "universe",
8879
6586
  this.buildApiClient(config)
8880
6587
  );
8881
6588
  }
6589
+ /**
6590
+ * A standalone `FleetClient` on its own `ApiClient`.
6591
+ *
6592
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6593
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6594
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6595
+ * authenticated ones. For a fleet, as its member:
6596
+ * `esi.as(identity).fleet(fleetId).get()`.
6597
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6598
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6599
+ */
8882
6600
  static createFleetClient(config) {
8883
6601
  return createClientInstance(
8884
6602
  "fleets",
8885
6603
  this.buildApiClient(config)
8886
6604
  );
8887
6605
  }
6606
+ /**
6607
+ * A standalone `AssetsClient` on its own `ApiClient`.
6608
+ *
6609
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6610
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6611
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6612
+ * authenticated ones. For a character's assets:
6613
+ * `esi.as(identity).character(characterId).assets.get()`.
6614
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6615
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6616
+ */
8888
6617
  static createAssetsClient(config) {
8889
6618
  return createClientInstance(
8890
6619
  "assets",
8891
6620
  this.buildApiClient(config)
8892
6621
  );
8893
6622
  }
6623
+ /**
6624
+ * A standalone `WalletClient` on its own `ApiClient`.
6625
+ *
6626
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6627
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6628
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6629
+ * authenticated ones. For a character's wallet balance:
6630
+ * `esi.as(identity).character(characterId).wallet.get()`.
6631
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6632
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6633
+ */
8894
6634
  static createWalletClient(config) {
8895
6635
  return createClientInstance(
8896
6636
  "wallet",
8897
6637
  this.buildApiClient(config)
8898
6638
  );
8899
6639
  }
6640
+ /**
6641
+ * A standalone `MailClient` on its own `ApiClient`.
6642
+ *
6643
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Use the
6644
+ * shared runtime from `@lgriffin/esi.ts/client`: `createEsi({ userAgent })`
6645
+ * once, then `esi.public` for public operations and `esi.as(identity)` for
6646
+ * authenticated ones. For a character's mail headers:
6647
+ * `esi.as(identity).character(characterId).mail.get()`.
6648
+ * To stay on the legacy client meanwhile, `EsiApiFactory.createClient(type)`
6649
+ * is not deprecated. See guides/MULTI-CHARACTER.md.
6650
+ */
8900
6651
  static createMailClient(config) {
8901
6652
  return createClientInstance(
8902
6653
  "mail",
8903
6654
  this.buildApiClient(config)
8904
6655
  );
8905
6656
  }
6657
+ /**
6658
+ * Any of the registered domain clients, by name, on its own `ApiClient`.
6659
+ * Not deprecated; use it to stay on the legacy domain clients.
6660
+ */
8906
6661
  static createClient(clientType, config) {
8907
6662
  return createClientInstance(clientType, this.buildApiClient(config));
8908
6663
  }
@@ -8919,6 +6674,9 @@ var EsiApiFactory = class {
8919
6674
  if (config?.language) {
8920
6675
  client.setLanguage(config.language);
8921
6676
  }
6677
+ if (config?.compatibilityDate) {
6678
+ client.setCompatibilityDate(config.compatibilityDate);
6679
+ }
8922
6680
  if (config?.onTokenRefresh) {
8923
6681
  client.setTokenProvider(config.onTokenRefresh);
8924
6682
  }
@@ -9007,7 +6765,13 @@ var ApiClientBuilder = class {
9007
6765
  }
9008
6766
  build() {
9009
6767
  const client = new ApiClient(this.clientId, this.link, this.accessToken);
9010
- client.setRateLimiter(this.rateLimiter ?? new RateLimiter());
6768
+ if (this.rateLimiter) {
6769
+ client.setRateLimiter(this.rateLimiter);
6770
+ } else {
6771
+ const rateLimiter = new RateLimiter();
6772
+ rateLimiter.setClient(client);
6773
+ client.setRateLimiter(rateLimiter);
6774
+ }
9011
6775
  if (this.cache) client.setCache(this.cache);
9012
6776
  if (this.circuitBreaker) client.setCircuitBreaker(this.circuitBreaker);
9013
6777
  if (this._timeout !== void 0) client.setTimeout(this._timeout);
@@ -9041,6 +6805,8 @@ var esiEndpointScopes = {
9041
6805
  "GET:characters/{character_id}/contracts": ["esi-contracts.read_character_contracts.v1"],
9042
6806
  "GET:characters/{character_id}/contracts/{contract_id}/bids": ["esi-contracts.read_character_contracts.v1"],
9043
6807
  "GET:characters/{character_id}/contracts/{contract_id}/items": ["esi-contracts.read_character_contracts.v1"],
6808
+ "GET:characters/{character_id}/cosmetics/skinr": ["esi.cosmetic.char:read"],
6809
+ "GET:characters/{character_id}/cosmetics/skinr/components": ["esi.cosmetic.char:read"],
9044
6810
  "POST:characters/{character_id}/cspa": ["esi-characters.read_contacts.v1"],
9045
6811
  "GET:characters/{character_id}/fatigue": ["esi-characters.read_fatigue.v1"],
9046
6812
  "GET:characters/{character_id}/fittings": ["esi-fittings.read_fittings.v1"],
@@ -9067,12 +6833,15 @@ var esiEndpointScopes = {
9067
6833
  "GET:characters/{character_id}/medals": ["esi-characters.read_medals.v1"],
9068
6834
  "GET:characters/{character_id}/mercenary-tactical-operations": ["esi-activities.read_character.v1"],
9069
6835
  "GET:characters/{character_id}/mercenary-tactical-operations/{operation_id}": ["esi-activities.read_character.v1"],
6836
+ "GET:characters/{character_id}/military-campaigns/objectives": ["esi.activity.char:read"],
6837
+ "GET:characters/{character_id}/military-campaigns/objectives/{objective_id}": ["esi.activity.char:read"],
9070
6838
  "GET:characters/{character_id}/mining": ["esi-industry.read_character_mining.v1"],
9071
6839
  "GET:characters/{character_id}/notifications": ["esi-characters.read_notifications.v1"],
9072
6840
  "GET:characters/{character_id}/notifications/contacts": ["esi-characters.read_notifications.v1"],
9073
6841
  "GET:characters/{character_id}/online": ["esi-location.read_online.v1"],
9074
6842
  "GET:characters/{character_id}/orders": ["esi-markets.read_character_orders.v1"],
9075
6843
  "GET:characters/{character_id}/orders/history": ["esi-markets.read_character_orders.v1"],
6844
+ "GET:characters/{character_id}/paragon-hub/skinr": ["esi.cosmetic.char:read"],
9076
6845
  "GET:characters/{character_id}/planets": ["esi-planets.manage_planets.v1"],
9077
6846
  "GET:characters/{character_id}/planets/{planet_id}": ["esi-planets.manage_planets.v1"],
9078
6847
  "GET:characters/{character_id}/roles": ["esi-characters.read_corporation_roles.v1"],
@@ -9149,6 +6918,9 @@ var esiEndpointScopes = {
9149
6918
  "DELETE:fleets/{fleet_id}/wings/{wing_id}": ["esi-fleets.write_fleet.v1"],
9150
6919
  "POST:fleets/{fleet_id}/wings/{wing_id}/squads": ["esi-fleets.write_fleet.v1"],
9151
6920
  "GET:markets/structures/{structure_id}": ["esi-markets.structure_markets.v1"],
6921
+ "GET:paragon-hub/skinr/alliances/{alliance_id}": ["esi.cosmetic.char:read"],
6922
+ "GET:paragon-hub/skinr/characters/{character_id}": ["esi.cosmetic.char:read"],
6923
+ "GET:paragon-hub/skinr/corporations/{corporation_id}": ["esi.cosmetic.char:read"],
9152
6924
  "POST:ui/autopilot/waypoint": ["esi-ui.write_waypoint.v1"],
9153
6925
  "POST:ui/openwindow/contract": ["esi-ui.open_window.v1"],
9154
6926
  "POST:ui/openwindow/information": ["esi-ui.open_window.v1"],
@@ -9166,7 +6938,8 @@ var noopLogger = {
9166
6938
  warn: noop,
9167
6939
  info: noop,
9168
6940
  debug: noop,
9169
- trace: noop
6941
+ trace: noop,
6942
+ isLevelEnabled: () => false
9170
6943
  };
9171
6944
  function createNoopLogger() {
9172
6945
  return noopLogger;
@@ -9367,7 +7140,7 @@ function resolveLimit(requested) {
9367
7140
  }
9368
7141
  async function runWithConcurrency(items, worker, options = {}) {
9369
7142
  const limit = resolveLimit(options.concurrency);
9370
- const results = new Array(items.length);
7143
+ const results = [];
9371
7144
  let nextIndex = 0;
9372
7145
  let completed = 0;
9373
7146
  async function runOne() {
@@ -9447,8 +7220,8 @@ function decodeAccessToken(token) {
9447
7220
  characterId,
9448
7221
  characterName: typeof claims.name === "string" ? claims.name : "",
9449
7222
  scopes: parseScopes(claims.scp),
9450
- expiresAt: typeof claims.exp === "number" ? claims.exp * 1e3 : void 0,
9451
- ownerHash: typeof claims.owner === "string" ? claims.owner : void 0,
7223
+ ...typeof claims.exp === "number" && { expiresAt: claims.exp * 1e3 },
7224
+ ...typeof claims.owner === "string" && { ownerHash: claims.owner },
9452
7225
  claims
9453
7226
  };
9454
7227
  }
@@ -9501,7 +7274,8 @@ var EsiTokenManager = class {
9501
7274
  sso;
9502
7275
  refreshSkewMs;
9503
7276
  autoRefresh;
9504
- logger;
7277
+ /** The logger passed in config, if any; see `logger` below. */
7278
+ configuredLogger;
9505
7279
  now;
9506
7280
  hooks;
9507
7281
  inFlight = /* @__PURE__ */ new Map();
@@ -9511,6 +7285,17 @@ var EsiTokenManager = class {
9511
7285
  * is stale and must not be persisted over the newer state.
9512
7286
  */
9513
7287
  generations = /* @__PURE__ */ new Map();
7288
+ /** One `Identity` per character, so `esi.as()` returns one view per character. */
7289
+ identities = /* @__PURE__ */ new Map();
7290
+ /**
7291
+ * Resolved at each log call rather than at construction, so a global
7292
+ * `setLogger()` made after the manager was built still reaches it. Lines
7293
+ * are redacted like the pipeline's, since an SSO error message can carry
7294
+ * a URL.
7295
+ */
7296
+ get logger() {
7297
+ return redactingLogger(this.configuredLogger ?? getLogger());
7298
+ }
9514
7299
  constructor(config) {
9515
7300
  this.storage = config.storage ?? new MemoryTokenStorage();
9516
7301
  this.sso = config.ssoClient ?? new EveSsoClient({
@@ -9521,7 +7306,7 @@ var EsiTokenManager = class {
9521
7306
  });
9522
7307
  this.refreshSkewMs = config.refreshSkewMs ?? 6e4;
9523
7308
  this.autoRefresh = config.autoRefresh ?? true;
9524
- this.logger = config.logger ?? getLogger();
7309
+ this.configuredLogger = config.logger;
9525
7310
  this.now = config.now ?? (() => Date.now());
9526
7311
  this.hooks = {
9527
7312
  onRefresh: config.onRefresh,
@@ -9677,9 +7462,46 @@ var EsiTokenManager = class {
9677
7462
  return refreshed.accessToken;
9678
7463
  };
9679
7464
  }
7465
+ /**
7466
+ * The character as an `Identity` for `esi.as()` on the shared
7467
+ * runtime (`@lgriffin/esi.ts/client`). Before each request the view gets
7468
+ * the stored token, refreshed first when it is stale; after a 401 it gets a
7469
+ * token refreshed through SSO. Nothing is looked up until a request needs
7470
+ * it, so an unknown character fails at the request, not here. The same
7471
+ * object comes back for the same character, so `esi.as()` memoises one
7472
+ * view per character rather than one per call.
7473
+ */
7474
+ identity(characterId) {
7475
+ const known = this.identities.get(characterId);
7476
+ if (known) return known;
7477
+ const identity = Object.freeze({
7478
+ characterId,
7479
+ accessToken: () => this.getToken(characterId),
7480
+ refreshAccessToken: async () => (await this.refresh(characterId)).accessToken
7481
+ });
7482
+ this.identities.set(characterId, identity);
7483
+ return identity;
7484
+ }
9680
7485
  /**
9681
7486
  * An {@link EsiClient} whose access token and refresh provider are bound to
9682
7487
  * the character. The token is validated (and refreshed if stale) first.
7488
+ *
7489
+ * @deprecated Since 11.0.0; removal is 12.0.0 at the earliest. Each client
7490
+ * this returns has its own rate limiter, error budget and cache. Build one
7491
+ * runtime with `createEsi({ userAgent })` from `@lgriffin/esi.ts/client` and
7492
+ * call `esi.as(this.identity(characterId))` for a per-character view over
7493
+ * it; `esi.shutdown()` replaces each client's `shutdown()`. See
7494
+ * guides/MULTI-CHARACTER.md, "Moving from `EsiTokenManager.createClient`".
7495
+ *
7496
+ * @example
7497
+ * ```ts
7498
+ * // Before
7499
+ * const client = await tokens.createClient(id, { userAgent });
7500
+ * await client.wallet.getCharacterWallet(id);
7501
+ * // After
7502
+ * const esi = createEsi({ userAgent }); // once per application
7503
+ * await esi.as(tokens.identity(id)).character(id).wallet.get();
7504
+ * ```
9683
7505
  */
9684
7506
  async createClient(characterId, config = {}) {
9685
7507
  const accessToken = await this.getToken(characterId);
@@ -9978,12 +7800,12 @@ var FileTokenStorage = class {
9978
7800
  };
9979
7801
 
9980
7802
  // src/auth/pkce.ts
9981
- import { createHash as createHash2, randomBytes } from "crypto";
7803
+ import { createHash, randomBytes } from "crypto";
9982
7804
  function generateCodeVerifier() {
9983
7805
  return randomBytes(32).toString("base64url");
9984
7806
  }
9985
7807
  function codeChallengeFromVerifier(codeVerifier) {
9986
- return createHash2("sha256").update(codeVerifier).digest("base64url");
7808
+ return createHash("sha256").update(codeVerifier).digest("base64url");
9987
7809
  }
9988
7810
  function generatePkcePair() {
9989
7811
  const codeVerifier = generateCodeVerifier();
@@ -10023,10 +7845,16 @@ export {
10023
7845
  EsiApiFactory,
10024
7846
  EsiClient,
10025
7847
  EsiClientBuilder,
7848
+ EsiConfigurationError,
10026
7849
  EsiDiagnostics,
10027
7850
  EsiError,
7851
+ EsiFaultError,
7852
+ EsiNetworkError,
7853
+ EsiPaginationError,
7854
+ EsiParseError,
10028
7855
  esi_spec_generated_exports as EsiSpec,
10029
7856
  EsiTokenManager,
7857
+ EsiTokenRefreshError,
10030
7858
  EsiValidationError,
10031
7859
  EveSsoClient,
10032
7860
  FactionClient,
@@ -10086,14 +7914,20 @@ export {
10086
7914
  isAuthError,
10087
7915
  isCharacterNotFound,
10088
7916
  isCircuitOpen,
7917
+ isConfigurationError,
10089
7918
  isEsiError,
7919
+ isFaultError,
10090
7920
  isForbidden,
7921
+ isNetworkError,
10091
7922
  isNotFound,
7923
+ isPaginationError,
7924
+ isParseError,
10092
7925
  isRateLimited,
10093
7926
  isRetryable,
10094
7927
  isServerError,
10095
7928
  isSsoError,
10096
7929
  isTimeout,
7930
+ isTokenRefreshError,
10097
7931
  isTokenRevoked,
10098
7932
  isUnauthorized,
10099
7933
  isValidationError,