@lgriffin/esi.ts 10.2.1 → 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 (428) hide show
  1. package/CHANGELOG.md +399 -33
  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/pagination/CursorPaginationHandler.d.mts +2 -1
  176. package/dist/core/pagination/CursorPaginationHandler.d.ts +2 -1
  177. package/dist/core/pagination/CursorPaginationHandler.d.ts.map +1 -1
  178. package/dist/core/ports/CacheStore.d.mts +32 -0
  179. package/dist/core/ports/CacheStore.d.ts +32 -0
  180. package/dist/core/ports/CacheStore.d.ts.map +1 -0
  181. package/dist/core/ports/Clock.d.mts +13 -0
  182. package/dist/core/ports/Clock.d.ts +13 -0
  183. package/dist/core/ports/Clock.d.ts.map +1 -0
  184. package/dist/core/ports/HttpTransport.d.mts +7 -0
  185. package/dist/core/ports/HttpTransport.d.ts +7 -0
  186. package/dist/core/ports/HttpTransport.d.ts.map +1 -0
  187. package/dist/core/ports/Identity.d.mts +31 -0
  188. package/dist/core/ports/Identity.d.ts +31 -0
  189. package/dist/core/ports/Identity.d.ts.map +1 -0
  190. package/dist/core/ports/Logger.d.mts +17 -0
  191. package/dist/core/ports/Logger.d.ts +17 -0
  192. package/dist/core/ports/Logger.d.ts.map +1 -0
  193. package/dist/core/ports/OperationTransport.d.mts +42 -0
  194. package/dist/core/ports/OperationTransport.d.ts +42 -0
  195. package/dist/core/ports/OperationTransport.d.ts.map +1 -0
  196. package/dist/core/ports/TokenProvider.d.mts +7 -0
  197. package/dist/core/ports/TokenProvider.d.ts +7 -0
  198. package/dist/core/ports/TokenProvider.d.ts.map +1 -0
  199. package/dist/core/ports/index.d.mts +14 -0
  200. package/dist/core/ports/index.d.ts +14 -0
  201. package/dist/core/ports/index.d.ts.map +1 -0
  202. package/dist/core/rateLimiter/RateLimiter.d.mts +11 -4
  203. package/dist/core/rateLimiter/RateLimiter.d.ts +11 -4
  204. package/dist/core/rateLimiter/RateLimiter.d.ts.map +1 -1
  205. package/dist/core/requestPipeline/cachePolicy.d.ts +5 -3
  206. package/dist/core/requestPipeline/cachePolicy.d.ts.map +1 -1
  207. package/dist/core/requestPipeline/fetchExecution.d.ts +3 -1
  208. package/dist/core/requestPipeline/fetchExecution.d.ts.map +1 -1
  209. package/dist/core/requestPipeline/headers.d.ts +1 -1
  210. package/dist/core/requestPipeline/headers.d.ts.map +1 -1
  211. package/dist/core/requestPipeline/index.d.ts +3 -5
  212. package/dist/core/requestPipeline/index.d.ts.map +1 -1
  213. package/dist/core/requestPipeline/paginationOrchestration.d.ts +1 -1
  214. package/dist/core/requestPipeline/paginationOrchestration.d.ts.map +1 -1
  215. package/dist/core/requestPipeline/statusHandling.d.ts +3 -3
  216. package/dist/core/requestPipeline/statusHandling.d.ts.map +1 -1
  217. package/dist/core/util/callerIdentity.d.ts +10 -0
  218. package/dist/core/util/callerIdentity.d.ts.map +1 -0
  219. package/dist/core/util/concurrency.d.ts +2 -2
  220. package/dist/core/util/concurrency.d.ts.map +1 -1
  221. package/dist/core/util/error.d.mts +92 -3
  222. package/dist/core/util/error.d.ts +92 -3
  223. package/dist/core/util/error.d.ts.map +1 -1
  224. package/dist/core/util/retry.d.mts +4 -4
  225. package/dist/core/util/retry.d.ts +4 -4
  226. package/dist/core/util/retry.d.ts.map +1 -1
  227. package/dist/core/util/validation.d.ts +6 -0
  228. package/dist/core/util/validation.d.ts.map +1 -1
  229. package/dist/errors.d.mts +2 -3
  230. package/dist/errors.d.ts +2 -3
  231. package/dist/errors.d.ts.map +1 -1
  232. package/dist/errors.js +29 -3
  233. package/dist/errors.js.map +1 -1
  234. package/dist/errors.mjs +28 -2
  235. package/dist/generated/operations.generated.d.mts +9379 -0
  236. package/dist/generated/operations.generated.d.ts +9379 -0
  237. package/dist/generated/operations.generated.d.ts.map +1 -0
  238. package/dist/index.d.mts +4 -4
  239. package/dist/index.d.ts +4 -4
  240. package/dist/index.d.ts.map +1 -1
  241. package/dist/index.js +699 -2864
  242. package/dist/index.js.map +1 -1
  243. package/dist/index.mjs +358 -2523
  244. package/dist/index.mjs.map +1 -1
  245. package/dist/schemas/character.d.mts +5 -0
  246. package/dist/schemas/character.d.ts +5 -0
  247. package/dist/schemas/character.d.ts.map +1 -1
  248. package/dist/schemas/contacts.d.mts +2 -0
  249. package/dist/schemas/contacts.d.ts +2 -0
  250. package/dist/schemas/contacts.d.ts.map +1 -1
  251. package/dist/schemas/corporation.d.mts +24 -3
  252. package/dist/schemas/corporation.d.ts +24 -3
  253. package/dist/schemas/corporation.d.ts.map +1 -1
  254. package/dist/schemas/fittings.d.mts +4 -0
  255. package/dist/schemas/fittings.d.ts +4 -0
  256. package/dist/schemas/fittings.d.ts.map +1 -1
  257. package/dist/schemas/fleet.d.mts +8 -0
  258. package/dist/schemas/fleet.d.ts +8 -0
  259. package/dist/schemas/fleet.d.ts.map +1 -1
  260. package/dist/schemas/index.js +24 -2
  261. package/dist/schemas/index.js.map +1 -1
  262. package/dist/schemas/index.mjs +23 -1
  263. package/dist/schemas/industry.d.mts +2 -2
  264. package/dist/schemas/industry.d.ts +2 -2
  265. package/dist/schemas/mail.d.mts +4 -0
  266. package/dist/schemas/mail.d.ts +4 -0
  267. package/dist/schemas/mail.d.ts.map +1 -1
  268. package/dist/schemas/mercenary.d.mts +1 -1
  269. package/dist/schemas/mercenary.d.ts +1 -1
  270. package/dist/schemas/meta.d.mts +18 -9
  271. package/dist/schemas/meta.d.ts +18 -9
  272. package/dist/schemas/meta.d.ts.map +1 -1
  273. package/dist/schemas/military-campaigns.d.mts +54 -10
  274. package/dist/schemas/military-campaigns.d.ts +54 -10
  275. package/dist/schemas/military-campaigns.d.ts.map +1 -1
  276. package/dist/schemas/paragon-hub.d.mts +4 -4
  277. package/dist/schemas/paragon-hub.d.ts +4 -4
  278. package/dist/schemas/skyhooks.d.mts +18 -6
  279. package/dist/schemas/skyhooks.d.ts +18 -6
  280. package/dist/schemas/skyhooks.d.ts.map +1 -1
  281. package/dist/sde/clock.d.ts +11 -0
  282. package/dist/sde/clock.d.ts.map +1 -0
  283. package/dist/sde/domain/characters/schemas.d.ts +149 -0
  284. package/dist/sde/domain/characters/schemas.d.ts.map +1 -0
  285. package/dist/sde/domain/characters/types.d.mts +163 -0
  286. package/dist/sde/domain/characters/types.d.ts +163 -0
  287. package/dist/sde/domain/characters/types.d.ts.map +1 -0
  288. package/dist/sde/domain/content/schemas.d.ts +84 -0
  289. package/dist/sde/domain/content/schemas.d.ts.map +1 -0
  290. package/dist/sde/domain/content/types.d.mts +91 -0
  291. package/dist/sde/domain/content/types.d.ts +91 -0
  292. package/dist/sde/domain/content/types.d.ts.map +1 -0
  293. package/dist/sde/domain/corporations/schemas.d.ts +113 -0
  294. package/dist/sde/domain/corporations/schemas.d.ts.map +1 -0
  295. package/dist/sde/domain/corporations/types.d.mts +118 -0
  296. package/dist/sde/domain/corporations/types.d.ts +118 -0
  297. package/dist/sde/domain/corporations/types.d.ts.map +1 -0
  298. package/dist/sde/domain/dogma/schemas.d.ts +76 -0
  299. package/dist/sde/domain/dogma/schemas.d.ts.map +1 -0
  300. package/dist/sde/domain/dogma/types.d.mts +80 -0
  301. package/dist/sde/domain/dogma/types.d.ts +80 -0
  302. package/dist/sde/domain/dogma/types.d.ts.map +1 -0
  303. package/dist/sde/domain/industry/schemas.d.ts +204 -0
  304. package/dist/sde/domain/industry/schemas.d.ts.map +1 -0
  305. package/dist/sde/domain/industry/types.d.mts +88 -0
  306. package/dist/sde/domain/industry/types.d.ts +88 -0
  307. package/dist/sde/domain/industry/types.d.ts.map +1 -0
  308. package/dist/sde/domain/market/schemas.d.ts +24 -0
  309. package/dist/sde/domain/market/schemas.d.ts.map +1 -0
  310. package/dist/sde/domain/market/types.d.mts +25 -0
  311. package/dist/sde/domain/market/types.d.ts +25 -0
  312. package/dist/sde/domain/market/types.d.ts.map +1 -0
  313. package/dist/sde/domain/schemas.d.ts +15 -0
  314. package/dist/sde/domain/schemas.d.ts.map +1 -0
  315. package/dist/sde/domain/skins/schemas.d.ts +109 -0
  316. package/dist/sde/domain/skins/schemas.d.ts.map +1 -0
  317. package/dist/sde/domain/skins/types.d.mts +121 -0
  318. package/dist/sde/domain/skins/types.d.ts +121 -0
  319. package/dist/sde/domain/skins/types.d.ts.map +1 -0
  320. package/dist/sde/domain/types/schemas.d.ts +163 -0
  321. package/dist/sde/domain/types/schemas.d.ts.map +1 -0
  322. package/dist/sde/domain/types/types.d.mts +182 -0
  323. package/dist/sde/domain/types/types.d.ts +182 -0
  324. package/dist/sde/domain/types/types.d.ts.map +1 -0
  325. package/dist/sde/domain/types.d.mts +16 -0
  326. package/dist/sde/domain/types.d.ts +16 -0
  327. package/dist/sde/domain/types.d.ts.map +1 -0
  328. package/dist/sde/domain/ui/schemas.d.ts +42 -0
  329. package/dist/sde/domain/ui/schemas.d.ts.map +1 -0
  330. package/dist/sde/domain/ui/types.d.mts +45 -0
  331. package/dist/sde/domain/ui/types.d.ts +45 -0
  332. package/dist/sde/domain/ui/types.d.ts.map +1 -0
  333. package/dist/sde/domain/universe/schemas.d.ts +239 -0
  334. package/dist/sde/domain/universe/schemas.d.ts.map +1 -0
  335. package/dist/sde/domain/universe/types.d.mts +206 -0
  336. package/dist/sde/domain/universe/types.d.ts +206 -0
  337. package/dist/sde/domain/universe/types.d.ts.map +1 -0
  338. package/dist/sde/domain/version/schemas.d.ts +11 -0
  339. package/dist/sde/domain/version/schemas.d.ts.map +1 -0
  340. package/dist/sde/errors.d.mts +1 -1
  341. package/dist/sde/errors.d.ts +1 -1
  342. package/dist/sde/errors.d.ts.map +1 -1
  343. package/dist/sde/index.d.mts +7 -6
  344. package/dist/sde/index.d.ts +7 -6
  345. package/dist/sde/index.d.ts.map +1 -1
  346. package/dist/sde/index.js +31 -21
  347. package/dist/sde/index.js.map +1 -1
  348. package/dist/sde/index.mjs +26 -16
  349. package/dist/sde/index.mjs.map +1 -1
  350. package/dist/sde/ingestion/SdeDatabaseBuilder.d.ts +11 -0
  351. package/dist/sde/ingestion/SdeDatabaseBuilder.d.ts.map +1 -1
  352. package/dist/sde/ingestion/SdeDownloader.d.ts +2 -2
  353. package/dist/sde/ingestion/SdeDownloader.d.ts.map +1 -1
  354. package/dist/sde/memory.d.mts +5 -5
  355. package/dist/sde/memory.d.ts +5 -5
  356. package/dist/sde/memory.d.ts.map +1 -1
  357. package/dist/sde/memory.js +2 -2
  358. package/dist/sde/memory.mjs +1 -1
  359. package/dist/sde/{IStaticDataProvider.d.mts → ports/IStaticDataProvider.d.mts} +9 -2
  360. package/dist/sde/{IStaticDataProvider.d.ts → ports/IStaticDataProvider.d.ts} +9 -2
  361. package/dist/sde/ports/IStaticDataProvider.d.ts.map +1 -0
  362. package/dist/sde/{MemorySdeProvider.d.mts → providers/memory/MemorySdeProvider.d.mts} +3 -3
  363. package/dist/sde/{MemorySdeProvider.d.ts → providers/memory/MemorySdeProvider.d.ts} +3 -3
  364. package/dist/sde/providers/memory/MemorySdeProvider.d.ts.map +1 -0
  365. package/dist/sde/providers/order.d.ts +10 -0
  366. package/dist/sde/providers/order.d.ts.map +1 -0
  367. package/dist/sde/{SdeDataProvider.d.mts → providers/yaml/SdeDataProvider.d.mts} +14 -5
  368. package/dist/sde/{SdeDataProvider.d.ts → providers/yaml/SdeDataProvider.d.ts} +14 -5
  369. package/dist/sde/providers/yaml/SdeDataProvider.d.ts.map +1 -0
  370. package/dist/sde/{SdeTestDataFactory.d.mts → testing/SdeTestDataFactory.d.mts} +3 -3
  371. package/dist/sde/{SdeTestDataFactory.d.ts → testing/SdeTestDataFactory.d.ts} +3 -3
  372. package/dist/sde/testing/SdeTestDataFactory.d.ts.map +1 -0
  373. package/dist/sde/version.d.mts +1 -1
  374. package/dist/sde/version.d.ts +1 -1
  375. package/dist/sde/version.d.ts.map +1 -1
  376. package/dist/testing/TestDataFactory.d.mts +21 -3
  377. package/dist/testing/TestDataFactory.d.ts +21 -3
  378. package/dist/testing/TestDataFactory.d.ts.map +1 -1
  379. package/dist/testing/index.d.mts +1 -0
  380. package/dist/testing/index.d.ts +1 -0
  381. package/dist/testing/index.d.ts.map +1 -1
  382. package/dist/testing/index.js +157 -10
  383. package/dist/testing/index.js.map +1 -1
  384. package/dist/testing/index.mjs +155 -8
  385. package/dist/testing/index.mjs.map +1 -1
  386. package/dist/testing/mockTransport.d.mts +87 -0
  387. package/dist/testing/mockTransport.d.ts +87 -0
  388. package/dist/testing/mockTransport.d.ts.map +1 -0
  389. package/dist/types/generated/esi-spec.generated.d.mts +230 -10
  390. package/dist/types/generated/esi-spec.generated.d.ts +230 -10
  391. package/dist/types/generated/esi-spec.generated.d.ts.map +1 -1
  392. package/dist/types/military-campaigns.d.mts +4 -1
  393. package/dist/types/military-campaigns.d.ts +4 -1
  394. package/dist/types/military-campaigns.d.ts.map +1 -1
  395. package/dist/types/skyhooks.d.mts +2 -1
  396. package/dist/types/skyhooks.d.ts +2 -1
  397. package/dist/types/skyhooks.d.ts.map +1 -1
  398. package/package.json +167 -131
  399. package/dist/chunk-3ZI5A37L.mjs.map +0 -1
  400. package/dist/chunk-4W66ONJI.mjs +0 -413
  401. package/dist/chunk-4W66ONJI.mjs.map +0 -1
  402. package/dist/chunk-BBSHKVPI.js.map +0 -1
  403. package/dist/chunk-MSJHIJXA.js.map +0 -1
  404. package/dist/chunk-N3B65VLB.js +0 -413
  405. package/dist/chunk-N3B65VLB.js.map +0 -1
  406. package/dist/chunk-R7D7M2LQ.mjs.map +0 -1
  407. package/dist/chunk-SAQBXXTM.js.map +0 -1
  408. package/dist/chunk-VZS32UQ3.mjs.map +0 -1
  409. package/dist/config/jest/globalSetup.d.ts +0 -2
  410. package/dist/config/jest/globalSetup.d.ts.map +0 -1
  411. package/dist/config/jest/globalTeardown.d.ts +0 -2
  412. package/dist/config/jest/globalTeardown.d.ts.map +0 -1
  413. package/dist/config/jest/jest.setup.d.ts +0 -3
  414. package/dist/config/jest/jest.setup.d.ts.map +0 -1
  415. package/dist/core/ClientRegistry.d.mts +0 -45
  416. package/dist/core/ClientRegistry.d.ts +0 -45
  417. package/dist/core/ClientRegistry.d.ts.map +0 -1
  418. package/dist/core/logger/logger.d.ts +0 -12
  419. package/dist/core/logger/logger.d.ts.map +0 -1
  420. package/dist/sde/IStaticDataProvider.d.ts.map +0 -1
  421. package/dist/sde/MemorySdeProvider.d.ts.map +0 -1
  422. package/dist/sde/SdeDataProvider.d.ts.map +0 -1
  423. package/dist/sde/SdeTestDataFactory.d.ts.map +0 -1
  424. package/dist/sde/schemas.d.ts +0 -1121
  425. package/dist/sde/schemas.d.ts.map +0 -1
  426. package/dist/sde/types.d.mts +0 -1039
  427. package/dist/sde/types.d.ts +0 -1039
  428. 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-4W66ONJI.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.1";
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,118 +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
- const remaining = Array.from({ length: totalPages - 1 }, (_, i) => i + 2);
1948
- for (let i = 0; i < remaining.length; i += concurrency) {
1949
- const batch = remaining.slice(i, i + concurrency);
1950
- const pages = await Promise.all(
1951
- batch.map(async (page) => {
1952
- const sep = endpoint.includes("?") ? "&" : "?";
1953
- const pagedEndpoint = `${endpoint}${sep}page=${page}`;
1954
- logInfo2(
1955
- client,
1956
- `Fetching page ${page}/${totalPages}: ${pagedEndpoint}`,
1957
- { page, totalPages }
1958
- );
1959
- const response = await handleSinglePageRequest(
1960
- client,
1961
- pagedEndpoint,
1962
- method,
1963
- body,
1964
- requiresAuth,
1965
- templatePath
1966
- );
1967
- return validatePageBody(
1968
- response.body,
1969
- responseSchema,
1970
- `${client.getLink()}/${pagedEndpoint}`,
1971
- validate
1972
- );
1973
- })
1974
- );
1975
- for (const pageBody of pages) {
1976
- result.push(...extractArray(pageBody));
1977
- }
1978
- }
1979
- return result;
1980
- }
1981
- async function* fetchPages(client, endpoint, method, requiresAuth = false, body, templatePath, responseSchema) {
1982
- const validate = client.getValidateResponse();
1983
- const firstResponse = await handleSinglePageRequest(
1984
- client,
1985
- endpoint,
1986
- method,
1987
- body,
1988
- requiresAuth,
1989
- templatePath
1990
- );
1991
- const firstBody = validatePageBody(
1992
- firstResponse.body,
1993
- responseSchema,
1994
- `${client.getLink()}/${endpoint}`,
1995
- 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.`
1996
498
  );
1997
- const totalPages = parseInt(firstResponse.headers["x-pages"] || "1", 10);
1998
- yield { data: extractArray(firstBody), page: 1, totalPages };
1999
- for (let page = 2; page <= totalPages; page++) {
2000
- const sep = endpoint.includes("?") ? "&" : "?";
2001
- const pagedEndpoint = `${endpoint}${sep}page=${page}`;
2002
- logInfo2(client, `Fetching page ${page}/${totalPages}: ${pagedEndpoint}`, {
2003
- page,
2004
- totalPages
2005
- });
2006
- const response = await handleSinglePageRequest(
2007
- client,
2008
- pagedEndpoint,
2009
- method,
2010
- body,
2011
- requiresAuth,
2012
- templatePath
2013
- );
2014
- const pageBody = validatePageBody(
2015
- response.body,
2016
- responseSchema,
2017
- `${client.getLink()}/${pagedEndpoint}`,
2018
- validate
2019
- );
2020
- const pageData = extractArray(pageBody);
2021
- if (pageData.length === 0) break;
2022
- yield { data: pageData, page, totalPages };
2023
- }
2024
499
  }
2025
-
2026
- // src/clients/BaseEsiClient.ts
2027
500
  var BaseEsiClient = class {
2028
501
  api;
2029
502
  _client;
@@ -2037,6 +510,7 @@ var BaseEsiClient = class {
2037
510
  }
2038
511
  streamEndpoint(endpointName, ...args) {
2039
512
  const def = this._endpoints[endpointName];
513
+ if (def.textResponse) throw notPageable(endpointName);
2040
514
  const { path: path2, body } = buildEndpointPath(
2041
515
  def,
2042
516
  args,
@@ -2054,6 +528,7 @@ var BaseEsiClient = class {
2054
528
  }
2055
529
  fetchAllEndpoint(endpointName, args, concurrency) {
2056
530
  const def = this._endpoints[endpointName];
531
+ if (def.textResponse) return Promise.reject(notPageable(endpointName));
2057
532
  const { path: path2, body } = buildEndpointPath(
2058
533
  def,
2059
534
  args,
@@ -2168,6 +643,7 @@ var contactEndpoints = {
2168
643
  addContacts: {
2169
644
  path: "characters/{characterId}/contacts",
2170
645
  method: "POST",
646
+ responseSchema: AddedContactIdsSchema,
2171
647
  requiresAuth: true,
2172
648
  pathParams: ["characterId"],
2173
649
  queryParams: { standing: "standing" },
@@ -2319,6 +795,7 @@ var assetEndpoints = {
2319
795
  postCorporationAssetLocations: {
2320
796
  path: "corporations/{corporationId}/assets/locations/",
2321
797
  method: "POST",
798
+ responseSchema: z3.array(AssetLocationSchema),
2322
799
  requiresAuth: true,
2323
800
  pathParams: ["corporationId"],
2324
801
  bodyBuilder: (itemIds) => itemIds
@@ -2326,6 +803,7 @@ var assetEndpoints = {
2326
803
  postCorporationAssetNames: {
2327
804
  path: "corporations/{corporationId}/assets/names/",
2328
805
  method: "POST",
806
+ responseSchema: z3.array(AssetNameSchema),
2329
807
  requiresAuth: true,
2330
808
  pathParams: ["corporationId"],
2331
809
  bodyBuilder: (itemIds) => itemIds
@@ -2636,12 +1114,14 @@ var characterEndpoints = {
2636
1114
  postCharacterAffiliation: {
2637
1115
  path: "characters/affiliation",
2638
1116
  method: "POST",
1117
+ responseSchema: z5.array(CharacterAffiliationSchema),
2639
1118
  requiresAuth: false,
2640
1119
  hasBody: true
2641
1120
  },
2642
1121
  calculateCspaChargeCost: {
2643
1122
  path: "characters/{characterId}/cspa/",
2644
1123
  method: "POST",
1124
+ responseSchema: CspaChargeCostSchema,
2645
1125
  requiresAuth: true,
2646
1126
  pathParams: ["characterId"],
2647
1127
  hasBody: true
@@ -3173,14 +1653,18 @@ var contractEndpoints = {
3173
1653
  method: "GET",
3174
1654
  requiresAuth: false,
3175
1655
  pathParams: ["contractId"],
3176
- responseSchema: z7.array(PublicContractBidSchema)
1656
+ responseSchema: z7.array(PublicContractBidSchema),
1657
+ // ESI answers an expired or accepted contract with no content.
1658
+ emptyWhenNoContent: true
3177
1659
  },
3178
1660
  getPublicContractItems: {
3179
1661
  path: "contracts/public/items/{contractId}",
3180
1662
  method: "GET",
3181
1663
  requiresAuth: false,
3182
1664
  pathParams: ["contractId"],
3183
- responseSchema: z7.array(PublicContractItemSchema)
1665
+ responseSchema: z7.array(PublicContractItemSchema),
1666
+ // ESI answers an expired or accepted contract with no content.
1667
+ emptyWhenNoContent: true
3184
1668
  }
3185
1669
  };
3186
1670
 
@@ -4249,6 +2733,7 @@ var fittingEndpoints = {
4249
2733
  createFitting: {
4250
2734
  path: "characters/{characterId}/fittings",
4251
2735
  method: "POST",
2736
+ responseSchema: FittingCreatedSchema,
4252
2737
  requiresAuth: true,
4253
2738
  pathParams: ["characterId"],
4254
2739
  hasBody: true
@@ -4387,6 +2872,7 @@ var fleetEndpoints = {
4387
2872
  createFleetWing: {
4388
2873
  path: "fleets/{fleetId}/wings/",
4389
2874
  method: "POST",
2875
+ responseSchema: FleetWingCreatedSchema,
4390
2876
  requiresAuth: true,
4391
2877
  pathParams: ["fleetId"],
4392
2878
  hasBody: true
@@ -4407,6 +2893,7 @@ var fleetEndpoints = {
4407
2893
  createFleetSquad: {
4408
2894
  path: "fleets/{fleetId}/wings/{wingId}/squads/",
4409
2895
  method: "POST",
2896
+ responseSchema: FleetSquadCreatedSchema,
4410
2897
  requiresAuth: true,
4411
2898
  pathParams: ["fleetId", "wingId"]
4412
2899
  }
@@ -5126,6 +3613,7 @@ var mailEndpoints = {
5126
3613
  sendMail: {
5127
3614
  path: "characters/{characterId}/mail/",
5128
3615
  method: "POST",
3616
+ responseSchema: MailIdSchema,
5129
3617
  requiresAuth: true,
5130
3618
  pathParams: ["characterId"],
5131
3619
  hasBody: true,
@@ -5175,6 +3663,7 @@ var mailEndpoints = {
5175
3663
  createMailLabel: {
5176
3664
  path: "characters/{characterId}/mail/labels/",
5177
3665
  method: "POST",
3666
+ responseSchema: MailLabelIdSchema,
5178
3667
  requiresAuth: true,
5179
3668
  pathParams: ["characterId"],
5180
3669
  hasBody: true
@@ -6739,6 +5228,13 @@ var metaEndpoints = {
6739
5228
  requiresAuth: false,
6740
5229
  responseSchema: z27.record(z27.string(), z27.unknown())
6741
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
+ },
6742
5238
  getChangelog: {
6743
5239
  path: "meta/changelog",
6744
5240
  method: "GET",
@@ -6785,38 +5281,13 @@ var MetaClient = class extends BaseEsiClient {
6785
5281
  *
6786
5282
  * @returns The full ESI OpenAPI specification as a YAML string
6787
5283
  */
6788
- async getOpenApiYaml() {
6789
- const url = `${this._client.getLink()}/meta/openapi.yaml`;
6790
- logInfo2(this._client, `Hitting endpoint: ${url}`, { method: "GET" });
6791
- try {
6792
- const response = await fetch(url, {
6793
- method: "GET",
6794
- headers: {
6795
- accept: "text/yaml, application/x-yaml, text/plain",
6796
- "User-Agent": USER_AGENT,
6797
- "X-Compatibility-Date": COMPATIBILITY_DATE
6798
- }
6799
- });
6800
- if (!response.ok) {
6801
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
6802
- }
6803
- return await response.text();
6804
- } catch (error) {
6805
- if (error instanceof Error) {
6806
- logError2(this._client, `Error fetching YAML: ${error.message}`, {
6807
- url
6808
- });
6809
- throw error;
6810
- } else {
6811
- logError2(this._client, `Unexpected error: ${String(error)}`, { url });
6812
- throw new Error(String(error));
6813
- }
6814
- }
5284
+ getOpenApiYaml() {
5285
+ return this.api.getOpenApiYaml();
6815
5286
  }
6816
5287
  /**
6817
5288
  * Retrieves the ESI changelog data.
6818
5289
  *
6819
- * @returns The changelog keyed by compatibility date
5290
+ * @returns `{ changelog }`: the change entries keyed by compatibility date
6820
5291
  */
6821
5292
  getChangelog() {
6822
5293
  return this.api.getChangelog();
@@ -6832,7 +5303,8 @@ var MetaClient = class extends BaseEsiClient {
6832
5303
  /**
6833
5304
  * Retrieves the ESI name.
6834
5305
  *
6835
- * @returns An object containing the ESI name
5306
+ * @returns `{ current, history }`: the name ESI has now and the dated names
5307
+ * it had before
6836
5308
  */
6837
5309
  getName() {
6838
5310
  return this.api.getName();
@@ -6992,7 +5464,7 @@ var skyhookEndpoints = {
6992
5464
  path: "skyhooks/raidable",
6993
5465
  method: "GET",
6994
5466
  requiresAuth: false,
6995
- responseSchema: z28.array(RaidableSkyhookSchema)
5467
+ responseSchema: RaidableSkyhooksResponseSchema
6996
5468
  },
6997
5469
  getSkyhookDetail: {
6998
5470
  path: "corporations/{corporationId}/structures/skyhooks/{skyhookId}",
@@ -7038,7 +5510,8 @@ var SkyhooksClient = class extends BaseEsiClient {
7038
5510
  /**
7039
5511
  * Retrieves the rolling list of skyhooks that are currently or becoming raidable across New Eden.
7040
5512
  *
7041
- * @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
7042
5515
  */
7043
5516
  getRaidableSkyhooks() {
7044
5517
  return this.api.getRaidableSkyhooks();
@@ -7311,13 +5784,12 @@ var ParagonHubClient = class extends BaseEsiClient {
7311
5784
  };
7312
5785
 
7313
5786
  // src/core/endpoints/militaryCampaignEndpoints.ts
7314
- import { z as z31 } from "zod";
7315
5787
  var militaryCampaignEndpoints = {
7316
5788
  getMilitaryCampaigns: {
7317
5789
  path: "military-campaigns",
7318
5790
  method: "GET",
7319
5791
  requiresAuth: false,
7320
- responseSchema: z31.array(MilitaryCampaignSchema)
5792
+ responseSchema: MilitaryCampaignsResponseSchema
7321
5793
  },
7322
5794
  getMilitaryCampaign: {
7323
5795
  path: "military-campaigns/{campaignId}",
@@ -7331,7 +5803,8 @@ var militaryCampaignEndpoints = {
7331
5803
  method: "GET",
7332
5804
  requiresAuth: false,
7333
5805
  pathParams: ["campaignId"],
7334
- responseSchema: z31.array(MilitaryCampaignObjectiveSchema)
5806
+ queryParams: { after: "after", before: "before", limit: "limit" },
5807
+ responseSchema: MilitaryCampaignObjectivesResponseSchema
7335
5808
  },
7336
5809
  getMilitaryCampaignObjective: {
7337
5810
  path: "military-campaigns/{campaignId}/objectives/{objectiveId}",
@@ -7345,7 +5818,8 @@ var militaryCampaignEndpoints = {
7345
5818
  method: "GET",
7346
5819
  requiresAuth: true,
7347
5820
  pathParams: ["characterId"],
7348
- responseSchema: z31.array(CharacterMilitaryCampaignObjectiveSchema)
5821
+ queryParams: { after: "after", before: "before", limit: "limit" },
5822
+ responseSchema: CharacterMilitaryCampaignObjectivesResponseSchema
7349
5823
  },
7350
5824
  getCharacterMilitaryCampaignObjective: {
7351
5825
  path: "characters/{characterId}/military-campaigns/objectives/{objectiveId}",
@@ -7364,7 +5838,7 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7364
5838
  /**
7365
5839
  * Retrieves a list of all active, completed, and expired military campaigns.
7366
5840
  *
7367
- * @returns An array of military campaigns
5841
+ * @returns `{ campaigns }`, one entry per campaign
7368
5842
  */
7369
5843
  getMilitaryCampaigns() {
7370
5844
  return this.api.getMilitaryCampaigns();
@@ -7382,10 +5856,18 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7382
5856
  * Retrieves all objectives for a specific military campaign.
7383
5857
  *
7384
5858
  * @param campaignId - The UUID of the military campaign
7385
- * @returns An array of objectives for the campaign
7386
- */
7387
- getMilitaryCampaignObjectives(campaignId) {
7388
- 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
+ );
7389
5871
  }
7390
5872
  /**
7391
5873
  * Retrieves detailed information about a specific objective in a military campaign.
@@ -7401,11 +5883,20 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7401
5883
  * Retrieves a character's participated objectives across military campaigns.
7402
5884
  *
7403
5885
  * @param characterId - The ID of the character
7404
- * @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
7405
5891
  * @requires Authentication with scope esi.activity.char:read
7406
5892
  */
7407
- getCharacterMilitaryCampaignObjectives(characterId) {
7408
- 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
+ );
7409
5900
  }
7410
5901
  /**
7411
5902
  * Retrieves a character's participation details for a specific campaign objective.
@@ -7423,7 +5914,7 @@ var MilitaryCampaignsClient = class extends BaseEsiClient {
7423
5914
  }
7424
5915
  };
7425
5916
 
7426
- // src/core/ClientRegistry.ts
5917
+ // src/clients/ClientRegistry.ts
7427
5918
  var clientFactories = {
7428
5919
  alliance: AllianceClient,
7429
5920
  assets: AssetsClient,
@@ -7516,6 +6007,9 @@ var EsiDiagnostics = class {
7516
6007
 
7517
6008
  // src/core/BatchRequestHandler.ts
7518
6009
  async function batchFetch(keys, fetcher, options = {}) {
6010
+ return batchFetchFor(null, keys, fetcher, options);
6011
+ }
6012
+ async function batchFetchFor(client, keys, fetcher, options = {}) {
7519
6013
  const concurrency = options.concurrency ?? 20;
7520
6014
  const results = /* @__PURE__ */ new Map();
7521
6015
  const errors = /* @__PURE__ */ new Map();
@@ -7523,7 +6017,7 @@ async function batchFetch(keys, fetcher, options = {}) {
7523
6017
  let running = 0;
7524
6018
  let index = 0;
7525
6019
  logInfo2(
7526
- null,
6020
+ client,
7527
6021
  `Batch fetch: ${keys.length} items, concurrency=${concurrency}`,
7528
6022
  {
7529
6023
  total: keys.length,
@@ -7549,7 +6043,7 @@ async function batchFetch(keys, fetcher, options = {}) {
7549
6043
  }
7550
6044
  if (completed === keys.length) {
7551
6045
  logDebug2(
7552
- null,
6046
+ client,
7553
6047
  `Batch complete: ${results.size} succeeded, ${errors.size} failed`,
7554
6048
  { succeeded: results.size, failed: errors.size }
7555
6049
  );
@@ -7568,12 +6062,15 @@ async function batchFetch(keys, fetcher, options = {}) {
7568
6062
  });
7569
6063
  }
7570
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) {
7571
6068
  const chunks = [];
7572
6069
  for (let i = 0; i < ids.length; i += chunkSize) {
7573
6070
  chunks.push(ids.slice(i, i + chunkSize));
7574
6071
  }
7575
6072
  logInfo2(
7576
- null,
6073
+ client,
7577
6074
  `Batch POST: ${ids.length} IDs in ${chunks.length} chunks of ${chunkSize}`,
7578
6075
  { total: ids.length, chunks: chunks.length, chunkSize }
7579
6076
  );
@@ -7585,859 +6082,6 @@ async function batchPost(ids, poster, chunkSize = 1e3) {
7585
6082
  return results;
7586
6083
  }
7587
6084
 
7588
- // src/core/cache/ETagCacheManager.ts
7589
- var ETagCacheManager = class {
7590
- cache = /* @__PURE__ */ new Map();
7591
- config;
7592
- cleanupTimer;
7593
- hits = 0;
7594
- misses = 0;
7595
- client = null;
7596
- setClient(client) {
7597
- this.client = client;
7598
- }
7599
- log(level, message, context) {
7600
- const ctx = context && Object.keys(context).length > 0 ? context : void 0;
7601
- const emit = level === "info" ? logInfo2 : logDebug2;
7602
- emit(this.client, message, ctx);
7603
- }
7604
- constructor(config = {}) {
7605
- this.config = {
7606
- maxEntries: config.maxEntries ?? 1e3,
7607
- defaultTtl: config.defaultTtl ?? 5 * 60 * 1e3,
7608
- // 5 minutes default
7609
- cleanupInterval: config.cleanupInterval ?? 60 * 1e3
7610
- // 1 minute cleanup
7611
- };
7612
- this.startCleanupTimer();
7613
- this.log(
7614
- "info",
7615
- `ETag cache manager initialized with ${this.config.maxEntries} max entries`,
7616
- { maxEntries: this.config.maxEntries }
7617
- );
7618
- }
7619
- /**
7620
- * Get cached data if ETag matches
7621
- */
7622
- get(url) {
7623
- const entry = this.cache.get(url);
7624
- if (!entry) {
7625
- this.misses++;
7626
- return null;
7627
- }
7628
- if (this.isExpired(entry)) {
7629
- this.cache.delete(url);
7630
- this.misses++;
7631
- this.log("debug", `Cache entry expired for ${url}`, { url });
7632
- return null;
7633
- }
7634
- this.hits++;
7635
- this.log("debug", `Cache hit for ${url} with ETag ${entry.etag}`, { url });
7636
- return entry;
7637
- }
7638
- /**
7639
- * Get ETag for a URL (for If-None-Match header)
7640
- */
7641
- getETag(url) {
7642
- const entry = this.get(url);
7643
- return entry ? entry.etag : null;
7644
- }
7645
- /**
7646
- * Set cache entry
7647
- */
7648
- set(url, etag, data, headers, customTtl) {
7649
- if (!this.cache.has(url) && this.cache.size >= this.config.maxEntries) {
7650
- this.evictOldest();
7651
- }
7652
- const entry = {
7653
- etag,
7654
- data,
7655
- headers,
7656
- timestamp: Date.now(),
7657
- ttl: customTtl ?? this.config.defaultTtl
7658
- };
7659
- this.cache.set(url, entry);
7660
- this.log("debug", `Cached response for ${url} with ETag ${etag}`, { url });
7661
- }
7662
- /**
7663
- * Check if cached data exists and is valid
7664
- */
7665
- has(url) {
7666
- const entry = this.cache.get(url);
7667
- return entry !== void 0 && !this.isExpired(entry);
7668
- }
7669
- /**
7670
- * Clear specific cache entry
7671
- */
7672
- delete(url) {
7673
- return this.cache.delete(url);
7674
- }
7675
- /**
7676
- * Delete all cache entries whose URL contains the given path segment
7677
- */
7678
- deleteByPath(pathSegment) {
7679
- let count = 0;
7680
- for (const key of this.cache.keys()) {
7681
- if (key.includes(pathSegment)) {
7682
- this.cache.delete(key);
7683
- count++;
7684
- }
7685
- }
7686
- if (count > 0) {
7687
- this.log(
7688
- "debug",
7689
- `Invalidated ${count} cache entries matching ${pathSegment}`,
7690
- {
7691
- count
7692
- }
7693
- );
7694
- }
7695
- return count;
7696
- }
7697
- /**
7698
- * Clear all cache entries
7699
- */
7700
- clear() {
7701
- this.cache.clear();
7702
- this.hits = 0;
7703
- this.misses = 0;
7704
- this.log("info", "ETag cache cleared");
7705
- }
7706
- /**
7707
- * Get cache statistics
7708
- */
7709
- getStats() {
7710
- let oldest = Infinity;
7711
- let newest = -Infinity;
7712
- for (const entry of this.cache.values()) {
7713
- if (entry.timestamp < oldest) oldest = entry.timestamp;
7714
- if (entry.timestamp > newest) newest = entry.timestamp;
7715
- }
7716
- const total = this.hits + this.misses;
7717
- return {
7718
- totalEntries: this.cache.size,
7719
- maxEntries: this.config.maxEntries,
7720
- hits: this.hits,
7721
- misses: this.misses,
7722
- hitRate: total > 0 ? this.hits / total : 0,
7723
- oldestEntry: this.cache.size > 0 ? oldest : null,
7724
- newestEntry: this.cache.size > 0 ? newest : null
7725
- };
7726
- }
7727
- /**
7728
- * Update cache configuration
7729
- */
7730
- updateConfig(newConfig) {
7731
- this.config = { ...this.config, ...newConfig };
7732
- this.log("info", "ETag cache configuration updated", {
7733
- maxEntries: this.config.maxEntries
7734
- });
7735
- }
7736
- /**
7737
- * Cleanup expired entries
7738
- */
7739
- cleanup() {
7740
- const beforeSize = this.cache.size;
7741
- for (const [url, entry] of this.cache.entries()) {
7742
- if (this.isExpired(entry)) {
7743
- this.cache.delete(url);
7744
- }
7745
- }
7746
- const cleanedCount = beforeSize - this.cache.size;
7747
- if (cleanedCount > 0) {
7748
- this.log("debug", `Cleaned up ${cleanedCount} expired cache entries`, {
7749
- cleanedCount
7750
- });
7751
- }
7752
- return cleanedCount;
7753
- }
7754
- /**
7755
- * Shutdown cache manager
7756
- */
7757
- shutdown() {
7758
- if (this.cleanupTimer) {
7759
- clearInterval(this.cleanupTimer);
7760
- }
7761
- this.log("info", "ETag cache manager shut down");
7762
- }
7763
- isExpired(entry) {
7764
- if (!entry.ttl) return false;
7765
- return Date.now() - entry.timestamp > entry.ttl;
7766
- }
7767
- evictOldest() {
7768
- let oldestKey = null;
7769
- let oldestTime = Infinity;
7770
- for (const [key, entry] of this.cache.entries()) {
7771
- if (entry.timestamp < oldestTime) {
7772
- oldestTime = entry.timestamp;
7773
- oldestKey = key;
7774
- }
7775
- }
7776
- if (oldestKey) {
7777
- this.cache.delete(oldestKey);
7778
- this.log("debug", `Evicted oldest cache entry: ${oldestKey}`, {
7779
- url: oldestKey
7780
- });
7781
- }
7782
- }
7783
- startCleanupTimer() {
7784
- this.cleanupTimer = setInterval(() => {
7785
- this.cleanup();
7786
- }, this.config.cleanupInterval);
7787
- this.cleanupTimer.unref();
7788
- }
7789
- };
7790
-
7791
- // src/core/endpoints/esi-rate-limit-groups.generated.ts
7792
- var esiRateLimitGroups = {
7793
- "GET:alliances/{alliance_id}/contacts": { group: "alliance-social", maxTokens: 300, windowSizeMs: 9e5 },
7794
- "GET:alliances/{alliance_id}/contacts/labels": { group: "alliance-social", maxTokens: 300, windowSizeMs: 9e5 },
7795
- "GET:characters/{character_id}/access-lists": { group: "char-access", maxTokens: 600, windowSizeMs: 9e5 },
7796
- "GET:characters/{character_id}/access-lists/{access_list_id}": { group: "char-access", maxTokens: 600, windowSizeMs: 9e5 },
7797
- "GET:characters/{character_id}/agents_research": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7798
- "GET:characters/{character_id}/assets": { group: "char-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7799
- "POST:characters/{character_id}/assets/locations": { group: "char-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7800
- "POST:characters/{character_id}/assets/names": { group: "char-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7801
- "GET:characters/{character_id}/attributes": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7802
- "GET:characters/{character_id}/blueprints": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7803
- "GET:characters/{character_id}/calendar": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7804
- "GET:characters/{character_id}/calendar/{event_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7805
- "PUT:characters/{character_id}/calendar/{event_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7806
- "GET:characters/{character_id}/calendar/{event_id}/attendees": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7807
- "GET:characters/{character_id}/clones": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7808
- "GET:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7809
- "POST:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7810
- "PUT:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7811
- "DELETE:characters/{character_id}/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7812
- "GET:characters/{character_id}/contacts/labels": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7813
- "GET:characters/{character_id}/contracts": { group: "char-contract", maxTokens: 600, windowSizeMs: 9e5 },
7814
- "GET:characters/{character_id}/contracts/{contract_id}/bids": { group: "char-contract", maxTokens: 600, windowSizeMs: 9e5 },
7815
- "GET:characters/{character_id}/contracts/{contract_id}/items": { group: "char-contract", maxTokens: 600, windowSizeMs: 9e5 },
7816
- "POST:characters/{character_id}/cspa": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7817
- "GET:characters/{character_id}/fatigue": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7818
- "GET:characters/{character_id}/fittings": { group: "fitting", maxTokens: 150, windowSizeMs: 9e5 },
7819
- "POST:characters/{character_id}/fittings": { group: "fitting", maxTokens: 150, windowSizeMs: 9e5 },
7820
- "DELETE:characters/{character_id}/fittings/{fitting_id}": { group: "fitting", maxTokens: 150, windowSizeMs: 9e5 },
7821
- "GET:characters/{character_id}/fleet": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7822
- "GET:characters/{character_id}/freelance-jobs": { group: "char-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7823
- "GET:characters/{character_id}/freelance-jobs/{job_id}/participation": { group: "char-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7824
- "GET:characters/{character_id}/fw/stats": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7825
- "GET:characters/{character_id}/implants": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7826
- "GET:characters/{character_id}/industry/jobs": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7827
- "GET:characters/{character_id}/killmails/recent": { group: "char-killmail", maxTokens: 30, windowSizeMs: 9e5 },
7828
- "GET:characters/{character_id}/location": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7829
- "GET:characters/{character_id}/loyalty/points": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7830
- "GET:characters/{character_id}/mail": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7831
- "POST:characters/{character_id}/mail": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7832
- "GET:characters/{character_id}/mail/{mail_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7833
- "PUT:characters/{character_id}/mail/{mail_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7834
- "DELETE:characters/{character_id}/mail/{mail_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7835
- "GET:characters/{character_id}/mail/labels": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7836
- "POST:characters/{character_id}/mail/labels": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7837
- "DELETE:characters/{character_id}/mail/labels/{label_id}": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7838
- "GET:characters/{character_id}/mail/lists": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7839
- "GET:characters/{character_id}/medals": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7840
- "GET:characters/{character_id}/mercenary-tactical-operations": { group: "char-activity", maxTokens: 150, windowSizeMs: 9e5 },
7841
- "GET:characters/{character_id}/mercenary-tactical-operations/{operation_id}": { group: "char-activity", maxTokens: 150, windowSizeMs: 9e5 },
7842
- "GET:characters/{character_id}/mining": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7843
- "GET:characters/{character_id}/notifications": { group: "char-notification", maxTokens: 15, windowSizeMs: 9e5 },
7844
- "GET:characters/{character_id}/notifications/contacts": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7845
- "GET:characters/{character_id}/online": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7846
- "GET:characters/{character_id}/planets": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7847
- "GET:characters/{character_id}/planets/{planet_id}": { group: "char-industry", maxTokens: 600, windowSizeMs: 9e5 },
7848
- "GET:characters/{character_id}/portrait": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7849
- "GET:characters/{character_id}/roles": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7850
- "GET:characters/{character_id}/ship": { group: "char-location", maxTokens: 1200, windowSizeMs: 9e5 },
7851
- "GET:characters/{character_id}/skillqueue": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7852
- "GET:characters/{character_id}/skills": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7853
- "GET:characters/{character_id}/standings": { group: "char-social", maxTokens: 600, windowSizeMs: 9e5 },
7854
- "GET:characters/{character_id}/structures/mercenary-dens": { group: "char-structure", maxTokens: 30, windowSizeMs: 9e5 },
7855
- "GET:characters/{character_id}/structures/mercenary-dens/{mercenary_den_id}": { group: "char-structure", maxTokens: 30, windowSizeMs: 9e5 },
7856
- "GET:characters/{character_id}/titles": { group: "char-detail", maxTokens: 600, windowSizeMs: 9e5 },
7857
- "GET:characters/{character_id}/wallet": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7858
- "GET:characters/{character_id}/wallet/journal": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7859
- "GET:characters/{character_id}/wallet/transactions": { group: "char-wallet", maxTokens: 150, windowSizeMs: 9e5 },
7860
- "GET:corporation/{corporation_id}/mining/extractions": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7861
- "GET:corporation/{corporation_id}/mining/observers": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7862
- "GET:corporation/{corporation_id}/mining/observers/{observer_id}": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7863
- "GET:corporations/{corporation_id}/assets": { group: "corp-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7864
- "POST:corporations/{corporation_id}/assets/locations": { group: "corp-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7865
- "POST:corporations/{corporation_id}/assets/names": { group: "corp-asset", maxTokens: 1800, windowSizeMs: 9e5 },
7866
- "GET:corporations/{corporation_id}/blueprints": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7867
- "GET:corporations/{corporation_id}/contacts": { group: "corp-social", maxTokens: 300, windowSizeMs: 9e5 },
7868
- "GET:corporations/{corporation_id}/contacts/labels": { group: "corp-social", maxTokens: 300, windowSizeMs: 9e5 },
7869
- "GET:corporations/{corporation_id}/containers/logs": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7870
- "GET:corporations/{corporation_id}/contracts": { group: "corp-contract", maxTokens: 600, windowSizeMs: 9e5 },
7871
- "GET:corporations/{corporation_id}/contracts/{contract_id}/bids": { group: "corp-contract", maxTokens: 600, windowSizeMs: 9e5 },
7872
- "GET:corporations/{corporation_id}/contracts/{contract_id}/items": { group: "corp-contract", maxTokens: 600, windowSizeMs: 9e5 },
7873
- "GET:corporations/{corporation_id}/customs_offices": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7874
- "GET:corporations/{corporation_id}/divisions": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7875
- "GET:corporations/{corporation_id}/facilities": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7876
- "GET:corporations/{corporation_id}/freelance-jobs": { group: "corp-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7877
- "GET:corporations/{corporation_id}/freelance-jobs/{job_id}/participants": { group: "corp-freelance-job", maxTokens: 300, windowSizeMs: 9e5 },
7878
- "GET:corporations/{corporation_id}/fw/stats": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7879
- "GET:corporations/{corporation_id}/industry/jobs": { group: "corp-industry", maxTokens: 600, windowSizeMs: 9e5 },
7880
- "GET:corporations/{corporation_id}/killmails/recent": { group: "corp-killmail", maxTokens: 30, windowSizeMs: 9e5 },
7881
- "GET:corporations/{corporation_id}/medals": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7882
- "GET:corporations/{corporation_id}/medals/issued": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7883
- "GET:corporations/{corporation_id}/members": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7884
- "GET:corporations/{corporation_id}/members/limit": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7885
- "GET:corporations/{corporation_id}/members/titles": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7886
- "GET:corporations/{corporation_id}/membertracking": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7887
- "GET:corporations/{corporation_id}/projects": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7888
- "GET:corporations/{corporation_id}/projects/{project_id}": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7889
- "GET:corporations/{corporation_id}/projects/{project_id}/contribution/{character_id}": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7890
- "GET:corporations/{corporation_id}/projects/{project_id}/contributors": { group: "corp-project", maxTokens: 600, windowSizeMs: 9e5 },
7891
- "GET:corporations/{corporation_id}/roles": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7892
- "GET:corporations/{corporation_id}/roles/history": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7893
- "GET:corporations/{corporation_id}/shareholders": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7894
- "GET:corporations/{corporation_id}/standings": { group: "corp-member", maxTokens: 300, windowSizeMs: 9e5 },
7895
- "GET:corporations/{corporation_id}/starbases": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7896
- "GET:corporations/{corporation_id}/starbases/{starbase_id}": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7897
- "GET:corporations/{corporation_id}/structures": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7898
- "GET:corporations/{corporation_id}/structures/skyhooks": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7899
- "GET:corporations/{corporation_id}/structures/skyhooks/{skyhook_id}": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7900
- "GET:corporations/{corporation_id}/structures/sovereignty-hubs": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7901
- "GET:corporations/{corporation_id}/structures/sovereignty-hubs/{sovereignty_hub_id}": { group: "corp-structure", maxTokens: 300, windowSizeMs: 9e5 },
7902
- "GET:corporations/{corporation_id}/titles": { group: "corp-detail", maxTokens: 300, windowSizeMs: 9e5 },
7903
- "GET:corporations/{corporation_id}/wallets": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7904
- "GET:corporations/{corporation_id}/wallets/{division}/journal": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7905
- "GET:corporations/{corporation_id}/wallets/{division}/transactions": { group: "corp-wallet", maxTokens: 300, windowSizeMs: 9e5 },
7906
- "GET:fleets/{fleet_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7907
- "PUT:fleets/{fleet_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7908
- "GET:fleets/{fleet_id}/members": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7909
- "POST:fleets/{fleet_id}/members": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7910
- "PUT:fleets/{fleet_id}/members/{member_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7911
- "DELETE:fleets/{fleet_id}/members/{member_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7912
- "PUT:fleets/{fleet_id}/squads/{squad_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7913
- "DELETE:fleets/{fleet_id}/squads/{squad_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7914
- "GET:fleets/{fleet_id}/wings": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7915
- "POST:fleets/{fleet_id}/wings": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7916
- "PUT:fleets/{fleet_id}/wings/{wing_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7917
- "DELETE:fleets/{fleet_id}/wings/{wing_id}": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7918
- "POST:fleets/{fleet_id}/wings/{wing_id}/squads": { group: "fleet", maxTokens: 1800, windowSizeMs: 9e5 },
7919
- "GET:freelance-jobs": { group: "freelance-job", maxTokens: 12e3, windowSizeMs: 9e5 },
7920
- "GET:freelance-jobs/{job_id}": { group: "freelance-job", maxTokens: 12e3, windowSizeMs: 9e5 },
7921
- "GET:fw/leaderboards": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7922
- "GET:fw/leaderboards/characters": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7923
- "GET:fw/leaderboards/corporations": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7924
- "GET:fw/stats": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7925
- "GET:fw/systems": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7926
- "GET:fw/wars": { group: "factional-warfare", maxTokens: 150, windowSizeMs: 9e5 },
7927
- "GET:incursions": { group: "incursion", maxTokens: 150, windowSizeMs: 9e5 },
7928
- "GET:industry/facilities": { group: "industry", maxTokens: 150, windowSizeMs: 9e5 },
7929
- "GET:industry/systems": { group: "industry", maxTokens: 150, windowSizeMs: 9e5 },
7930
- "GET:insurance/prices": { group: "insurance", maxTokens: 150, windowSizeMs: 9e5 },
7931
- "GET:killmails/{killmail_id}/{killmail_hash}": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 },
7932
- "GET:markets/{region_id}/orders": { group: "market-order", maxTokens: 12e3, windowSizeMs: 9e5 },
7933
- "GET:meta/changelog": { group: "meta", maxTokens: 150, windowSizeMs: 9e5 },
7934
- "GET:meta/compatibility-dates": { group: "meta", maxTokens: 150, windowSizeMs: 9e5 },
7935
- "GET:meta/status": { group: "meta", maxTokens: 150, windowSizeMs: 9e5 },
7936
- "POST:route/{origin_system_id}/{destination_system_id}": { group: "routes", maxTokens: 3600, windowSizeMs: 9e5 },
7937
- "GET:skyhooks/raidable": { group: "activity", maxTokens: 30, windowSizeMs: 9e5 },
7938
- "GET:sovereignty/campaigns": { group: "sovereignty", maxTokens: 600, windowSizeMs: 9e5 },
7939
- "GET:sovereignty/systems": { group: "sovereignty", maxTokens: 600, windowSizeMs: 9e5 },
7940
- "GET:status": { group: "status", maxTokens: 600, windowSizeMs: 9e5 },
7941
- "POST:ui/autopilot/waypoint": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7942
- "POST:ui/openwindow/contract": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7943
- "POST:ui/openwindow/information": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7944
- "POST:ui/openwindow/marketdetails": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7945
- "POST:ui/openwindow/newmail": { group: "ui", maxTokens: 900, windowSizeMs: 9e5 },
7946
- "GET:wars": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 },
7947
- "GET:wars/{war_id}": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 },
7948
- "GET:wars/{war_id}/killmails": { group: "killmail", maxTokens: 3600, windowSizeMs: 9e5 }
7949
- };
7950
-
7951
- // src/core/rateLimiter/RateLimiter.ts
7952
- function getTokenCost(statusCode) {
7953
- if (statusCode >= 200 && statusCode < 300) return 2;
7954
- if (statusCode >= 300 && statusCode < 400) return 1;
7955
- if (statusCode >= 400 && statusCode < 500) return 5;
7956
- if (statusCode >= 500 && statusCode < 600) return 0;
7957
- return 2;
7958
- }
7959
- function retryAfterDeadline(value, now) {
7960
- const trimmed = value.trim();
7961
- if (/^\d+$/.test(trimmed)) return now + parseInt(trimmed, 10) * 1e3;
7962
- if (!/[A-Za-z]/.test(trimmed)) return void 0;
7963
- const date = Date.parse(trimmed);
7964
- return Number.isNaN(date) ? void 0 : date;
7965
- }
7966
- var DEFAULT_WINDOW_MS = 9e5;
7967
- var DEFAULT_ERROR_LIMIT = {
7968
- remain: 100,
7969
- reset: 0,
7970
- exhaustedUntil: 0
7971
- };
7972
- var RateLimiter = class _RateLimiter {
7973
- minDelayMs;
7974
- decelerationThreshold;
7975
- userKeyExtractor;
7976
- endpointOverrides;
7977
- lastRequestTime = 0;
7978
- minDelayChain = Promise.resolve();
7979
- isTestMode = false;
7980
- globalErrorLimit = { ...DEFAULT_ERROR_LIMIT };
7981
- defaultBuckets = /* @__PURE__ */ new Map();
7982
- userBuckets = null;
7983
- fallbackBucket;
7984
- lastCleanup = 0;
7985
- static CLEANUP_INTERVAL_MS = 6e4;
7986
- constructor(config) {
7987
- this.minDelayMs = config?.minDelayMs ?? 50;
7988
- this.decelerationThreshold = config?.decelerationThreshold ?? 0.2;
7989
- this.userKeyExtractor = config?.userKeyExtractor;
7990
- this.endpointOverrides = config?.endpointOverrides ?? {};
7991
- if (this.userKeyExtractor) {
7992
- this.userBuckets = /* @__PURE__ */ new Map();
7993
- }
7994
- this.fallbackBucket = this.createFallbackBucket();
7995
- }
7996
- createFallbackBucket() {
7997
- return {
7998
- group: "__fallback__",
7999
- remaining: -1,
8000
- limit: 0,
8001
- used: 0,
8002
- windowSizeMs: DEFAULT_WINDOW_MS,
8003
- blockedUntil: 0,
8004
- lastUpdated: 0
8005
- };
8006
- }
8007
- createBucketFromSpec(spec) {
8008
- return {
8009
- group: spec.group,
8010
- remaining: spec.maxTokens,
8011
- limit: spec.maxTokens,
8012
- used: 0,
8013
- windowSizeMs: spec.windowSizeMs,
8014
- blockedUntil: 0,
8015
- lastUpdated: 0
8016
- };
8017
- }
8018
- createBucketForGroup(groupName) {
8019
- return {
8020
- group: groupName,
8021
- remaining: -1,
8022
- limit: 0,
8023
- used: 0,
8024
- windowSizeMs: DEFAULT_WINDOW_MS,
8025
- blockedUntil: 0,
8026
- lastUpdated: 0
8027
- };
8028
- }
8029
- lookupGroupSpec(method, templatePath) {
8030
- if (!templatePath || !method) return void 0;
8031
- const normalized = templatePath.replace(/\/$/, "").replace(/\{(\w+)\}/g, (_, name) => `{${camelToSnake(name)}}`);
8032
- const key = `${method}:${normalized}`;
8033
- const override = this.endpointOverrides[key];
8034
- if (override) {
8035
- return {
8036
- group: `endpoint:${key}`,
8037
- maxTokens: override.maxTokens,
8038
- windowSizeMs: override.windowSizeMs
8039
- };
8040
- }
8041
- return esiRateLimitGroups[key];
8042
- }
8043
- resolveUserSet(requestHeaders) {
8044
- if (!this.userBuckets || !this.userKeyExtractor || !requestHeaders) {
8045
- return null;
8046
- }
8047
- const userKey = this.userKeyExtractor(requestHeaders);
8048
- let userSet = this.userBuckets.get(userKey);
8049
- if (!userSet) {
8050
- userSet = {
8051
- groups: /* @__PURE__ */ new Map(),
8052
- errorLimit: { ...DEFAULT_ERROR_LIMIT },
8053
- lastAccessed: Date.now()
8054
- };
8055
- this.userBuckets.set(userKey, userSet);
8056
- }
8057
- userSet.lastAccessed = Date.now();
8058
- return userSet;
8059
- }
8060
- resolveBucketMap(requestHeaders) {
8061
- const userSet = this.resolveUserSet(requestHeaders);
8062
- return userSet ? userSet.groups : this.defaultBuckets;
8063
- }
8064
- resolveErrorLimit(requestHeaders) {
8065
- const userSet = this.resolveUserSet(requestHeaders);
8066
- return userSet ? userSet.errorLimit : this.globalErrorLimit;
8067
- }
8068
- getBucket(templatePath, method, requestHeaders, groupNameOverride) {
8069
- const bucketMap = this.resolveBucketMap(requestHeaders);
8070
- const spec = this.lookupGroupSpec(method, templatePath);
8071
- const groupName = groupNameOverride ?? spec?.group;
8072
- if (!groupName) return this.fallbackBucket;
8073
- let bucket = bucketMap.get(groupName);
8074
- if (!bucket) {
8075
- bucket = spec ? this.createBucketFromSpec(spec) : this.createBucketForGroup(groupName);
8076
- bucketMap.set(groupName, bucket);
8077
- }
8078
- return bucket;
8079
- }
8080
- cleanupStaleUsers() {
8081
- if (!this.userBuckets) return;
8082
- const now = Date.now();
8083
- if (now - this.lastCleanup < _RateLimiter.CLEANUP_INTERVAL_MS) return;
8084
- this.lastCleanup = now;
8085
- for (const [userKey, userSet] of this.userBuckets) {
8086
- if (now - userSet.lastAccessed > DEFAULT_WINDOW_MS) {
8087
- this.userBuckets.delete(userKey);
8088
- }
8089
- }
8090
- }
8091
- updateFromResponse(headers, statusCode, templatePath, method, requestHeaders) {
8092
- if (this.isTestMode) return;
8093
- const now = Date.now();
8094
- const responseGroup = headers["x-ratelimit-group"] || void 0;
8095
- const bucket = this.getBucket(
8096
- templatePath,
8097
- method,
8098
- requestHeaders,
8099
- responseGroup
8100
- );
8101
- if ("x-ratelimit-remaining" in headers) {
8102
- bucket.remaining = parseInt(headers["x-ratelimit-remaining"], 10);
8103
- }
8104
- if ("x-ratelimit-limit" in headers) {
8105
- bucket.limit = parseInt(headers["x-ratelimit-limit"], 10);
8106
- }
8107
- if ("x-ratelimit-used" in headers) {
8108
- bucket.used = parseInt(headers["x-ratelimit-used"], 10);
8109
- }
8110
- bucket.lastUpdated = now;
8111
- if ("retry-after" in headers) {
8112
- const until = retryAfterDeadline(headers["retry-after"], now);
8113
- if (until !== void 0) bucket.blockedUntil = until;
8114
- }
8115
- if (statusCode === 420 || statusCode === 429) {
8116
- if (bucket.blockedUntil <= now) {
8117
- bucket.blockedUntil = now + 6e4;
8118
- }
8119
- }
8120
- const errorLimit = this.resolveErrorLimit(requestHeaders);
8121
- const reportedRemain = "x-esi-error-limit-remain" in headers ? parseInt(headers["x-esi-error-limit-remain"], 10) : void 0;
8122
- if (reportedRemain !== void 0 && reportedRemain > 0 && errorLimit.remain <= 0 && now < errorLimit.exhaustedUntil) {
8123
- return;
8124
- }
8125
- if (reportedRemain !== void 0) {
8126
- errorLimit.remain = reportedRemain;
8127
- }
8128
- if ("x-esi-error-limit-reset" in headers) {
8129
- errorLimit.reset = parseInt(headers["x-esi-error-limit-reset"], 10);
8130
- }
8131
- if (reportedRemain !== void 0 && reportedRemain <= 0) {
8132
- errorLimit.exhaustedUntil = now + errorLimit.reset * 1e3;
8133
- }
8134
- }
8135
- updateRateLimitInfo(headers) {
8136
- this.updateFromResponse(headers, 200);
8137
- }
8138
- async checkRateLimit(templatePath, method, requestHeaders) {
8139
- if (this.isTestMode) return;
8140
- this.cleanupStaleUsers();
8141
- let stillBlockedBucket;
8142
- for (let i = 0; i < 10; i++) {
8143
- const bucket2 = this.getBucket(templatePath, method, requestHeaders);
8144
- const now = Date.now();
8145
- if (bucket2.blockedUntil <= now) {
8146
- stillBlockedBucket = void 0;
8147
- break;
8148
- }
8149
- stillBlockedBucket = bucket2;
8150
- const waitedUntil = bucket2.blockedUntil;
8151
- const waitTime = waitedUntil - now;
8152
- logWarn2(
8153
- null,
8154
- `[ESI Rate Limit] Group '${bucket2.group}' blocked for ${Math.ceil(waitTime / 1e3)}s (420/429 received)`,
8155
- { group: bucket2.group, waitMs: waitTime }
8156
- );
8157
- await sleep(waitTime);
8158
- if (bucket2.blockedUntil <= waitedUntil) {
8159
- bucket2.blockedUntil = 0;
8160
- }
8161
- }
8162
- if (stillBlockedBucket && stillBlockedBucket.blockedUntil > Date.now()) {
8163
- const waitTime = stillBlockedBucket.blockedUntil - Date.now();
8164
- logWarn2(
8165
- null,
8166
- `[ESI Rate Limit] Group '${stillBlockedBucket.group}' still blocked after retry budget exhausted; aborting request instead of sending while blocked`,
8167
- { group: stillBlockedBucket.group }
8168
- );
8169
- throw new EsiError(
8170
- 429,
8171
- `Rate limit group '${stillBlockedBucket.group}' still blocked for ${Math.ceil(waitTime / 1e3)}s`
8172
- );
8173
- }
8174
- const errorLimit = this.resolveErrorLimit(requestHeaders);
8175
- if (errorLimit.remain <= 10 && errorLimit.remain > 0) {
8176
- const resetMs = errorLimit.reset * 1e3;
8177
- const delay = Math.min(resetMs, 5e3);
8178
- if (delay > 0) {
8179
- logWarn2(
8180
- null,
8181
- `[ESI Rate Limit] Legacy error limit low (${errorLimit.remain}), waiting ${delay}ms`,
8182
- { errorLimitRemain: errorLimit.remain }
8183
- );
8184
- await sleep(delay);
8185
- }
8186
- } else if (errorLimit.remain <= 0 && errorLimit.reset > 0) {
8187
- const waitTime = errorLimit.reset * 1e3;
8188
- logWarn2(
8189
- null,
8190
- `[ESI Rate Limit] Legacy error limit exhausted, waiting ${Math.ceil(waitTime / 1e3)}s`,
8191
- { errorLimitReset: errorLimit.reset }
8192
- );
8193
- await sleep(waitTime);
8194
- }
8195
- const bucket = this.getBucket(templatePath, method, requestHeaders);
8196
- if (bucket.remaining >= 0 && bucket.limit > 0) {
8197
- const ratio = bucket.remaining / bucket.limit;
8198
- if (bucket.remaining <= 0) {
8199
- logWarn2(
8200
- null,
8201
- `[ESI Rate Limit] Group '${bucket.group}' token bucket empty, waiting 1s`,
8202
- { group: bucket.group }
8203
- );
8204
- await sleep(1e3);
8205
- } else if (ratio <= this.decelerationThreshold) {
8206
- const extraDelay = Math.ceil(
8207
- (1 - ratio / this.decelerationThreshold) * 1e3
8208
- );
8209
- await sleep(extraDelay);
8210
- }
8211
- }
8212
- await this.enforceMinDelay();
8213
- }
8214
- /**
8215
- * Serializes min-delay waits so concurrent callers cannot all read the same
8216
- * lastRequestTime and fire together after sleeping.
8217
- */
8218
- async enforceMinDelay() {
8219
- if (this.isTestMode) {
8220
- this.lastRequestTime = Date.now();
8221
- return;
8222
- }
8223
- const run = async () => {
8224
- const now = Date.now();
8225
- const timeSinceLastRequest = now - this.lastRequestTime;
8226
- if (timeSinceLastRequest < this.minDelayMs) {
8227
- await sleep(this.minDelayMs - timeSinceLastRequest);
8228
- }
8229
- this.lastRequestTime = Date.now();
8230
- };
8231
- const scheduled = this.minDelayChain.then(run, run);
8232
- this.minDelayChain = scheduled.then(
8233
- () => void 0,
8234
- () => void 0
8235
- );
8236
- await scheduled;
8237
- }
8238
- getStatus() {
8239
- let worstBucket = this.fallbackBucket;
8240
- let worstRatio = Infinity;
8241
- const checkBucket = (bucket) => {
8242
- if (bucket.limit > 0) {
8243
- const ratio = bucket.remaining / bucket.limit;
8244
- if (ratio < worstRatio) {
8245
- worstRatio = ratio;
8246
- worstBucket = bucket;
8247
- }
8248
- }
8249
- };
8250
- for (const bucket of this.defaultBuckets.values()) {
8251
- checkBucket(bucket);
8252
- }
8253
- if (this.userBuckets) {
8254
- for (const userSet of this.userBuckets.values()) {
8255
- for (const bucket of userSet.groups.values()) {
8256
- checkBucket(bucket);
8257
- }
8258
- }
8259
- }
8260
- return {
8261
- remaining: worstBucket.remaining,
8262
- limit: worstBucket.limit,
8263
- used: worstBucket.used,
8264
- group: worstBucket.group === "__fallback__" ? null : worstBucket.group,
8265
- errorLimitRemain: this.globalErrorLimit.remain,
8266
- errorLimitReset: this.globalErrorLimit.reset,
8267
- retryAfter: worstBucket.blockedUntil > Date.now() ? Math.ceil((worstBucket.blockedUntil - Date.now()) / 1e3) : null,
8268
- blockedUntil: worstBucket.blockedUntil
8269
- };
8270
- }
8271
- getGroupStatus(group) {
8272
- const bucket = this.defaultBuckets.get(group);
8273
- if (!bucket) return void 0;
8274
- return {
8275
- group: bucket.group,
8276
- remaining: bucket.remaining,
8277
- limit: bucket.limit,
8278
- used: bucket.used,
8279
- windowSizeMs: bucket.windowSizeMs,
8280
- blockedUntil: bucket.blockedUntil
8281
- };
8282
- }
8283
- getAllGroupStatuses() {
8284
- const result = /* @__PURE__ */ new Map();
8285
- for (const [name, bucket] of this.defaultBuckets) {
8286
- result.set(name, {
8287
- group: bucket.group,
8288
- remaining: bucket.remaining,
8289
- limit: bucket.limit,
8290
- used: bucket.used,
8291
- windowSizeMs: bucket.windowSizeMs,
8292
- blockedUntil: bucket.blockedUntil
8293
- });
8294
- }
8295
- return result;
8296
- }
8297
- static getTokenCost(statusCode) {
8298
- return getTokenCost(statusCode);
8299
- }
8300
- isBlocked(group) {
8301
- const now = Date.now();
8302
- if (group) {
8303
- const bucket = this.defaultBuckets.get(group);
8304
- return bucket ? bucket.blockedUntil > now : false;
8305
- }
8306
- if (this.fallbackBucket.blockedUntil > now) return true;
8307
- for (const bucket of this.defaultBuckets.values()) {
8308
- if (bucket.blockedUntil > now) return true;
8309
- }
8310
- return false;
8311
- }
8312
- setTestMode(enabled) {
8313
- this.isTestMode = enabled;
8314
- }
8315
- reset() {
8316
- this.defaultBuckets.clear();
8317
- if (this.userBuckets) this.userBuckets.clear();
8318
- this.fallbackBucket = this.createFallbackBucket();
8319
- this.globalErrorLimit = { ...DEFAULT_ERROR_LIMIT };
8320
- this.lastRequestTime = 0;
8321
- this.minDelayChain = Promise.resolve();
8322
- this.lastCleanup = 0;
8323
- }
8324
- };
8325
-
8326
- // src/core/RequestDeduplicator.ts
8327
- var RequestDeduplicator = class {
8328
- inflight = /* @__PURE__ */ new Map();
8329
- client = null;
8330
- setClient(client) {
8331
- this.client = client;
8332
- }
8333
- async dedupe(key, execute) {
8334
- const existing = this.inflight.get(key);
8335
- if (existing) {
8336
- if (this.client) {
8337
- logDebug2(this.client, `[Dedup] Coalescing request: ${key}`);
8338
- }
8339
- return existing;
8340
- }
8341
- const promise = execute().finally(() => {
8342
- this.inflight.delete(key);
8343
- });
8344
- this.inflight.set(key, promise);
8345
- return promise;
8346
- }
8347
- /**
8348
- * Drop the in-flight entries whose key contains `pathSegment`, so a call
8349
- * made after a write cannot join a request sent before it.
8350
- *
8351
- * The requests themselves keep running and whoever already joined them still
8352
- * gets their answer. Only the map entry goes, which is what new callers look
8353
- * in. Matching is `includes`, the same rule ETagCacheManager.deleteByPath
8354
- * uses, so one written path invalidates the cache and detaches the reads of
8355
- * it by the same test.
8356
- */
8357
- detachByPath(pathSegment) {
8358
- let count = 0;
8359
- for (const key of this.inflight.keys()) {
8360
- if (key.includes(pathSegment)) {
8361
- this.inflight.delete(key);
8362
- count += 1;
8363
- }
8364
- }
8365
- if (count > 0 && this.client) {
8366
- logDebug2(
8367
- this.client,
8368
- `[Dedup] Detached ${count} in-flight request(s) matching ${pathSegment} after a write`
8369
- );
8370
- }
8371
- return count;
8372
- }
8373
- get pending() {
8374
- return this.inflight.size;
8375
- }
8376
- clear() {
8377
- this.inflight.clear();
8378
- }
8379
- };
8380
-
8381
- // src/core/configureApiClient.ts
8382
- function configureApiClient(client, config) {
8383
- let deduplicator = null;
8384
- client.setRateLimiter(new RateLimiter(config?.rateLimiterConfig));
8385
- if (config?.enableRequestDeduplication !== false) {
8386
- deduplicator = new RequestDeduplicator();
8387
- deduplicator.setClient(client);
8388
- client.setDeduplicator(deduplicator);
8389
- }
8390
- if (config?.enableETagCache !== false) {
8391
- const cache = new ETagCacheManager(config?.etagCacheConfig);
8392
- cache.setClient(client);
8393
- client.setCache(cache);
8394
- }
8395
- if (config?.enableCircuitBreaker) {
8396
- const cb = new CircuitBreaker(config.circuitBreakerConfig);
8397
- cb.setClient(client);
8398
- client.setCircuitBreaker(cb);
8399
- }
8400
- if (config?.retryConfig) {
8401
- client.setRetryConfig(config.retryConfig);
8402
- } else if (config?.retryAttempts !== void 0) {
8403
- client.setRetryConfig({ maxRetries: config.retryAttempts });
8404
- } else {
8405
- client.setRetryConfig({
8406
- maxRetries: 3,
8407
- baseDelayMs: 1e3,
8408
- maxDelayMs: 3e4
8409
- });
8410
- }
8411
- if (config?.retryStrategy) {
8412
- client.setRetryStrategy(config.retryStrategy);
8413
- }
8414
- if (config?.requestInterceptors) {
8415
- for (const interceptor of config.requestInterceptors) {
8416
- client.addRequestInterceptor(interceptor);
8417
- }
8418
- }
8419
- if (config?.responseInterceptors) {
8420
- for (const interceptor of config.responseInterceptors) {
8421
- client.addResponseInterceptor(interceptor);
8422
- }
8423
- }
8424
- if (config?.validateResponse !== void 0) {
8425
- client.setValidateResponse(config.validateResponse);
8426
- }
8427
- if (config?.validateRequest !== void 0) {
8428
- client.setValidateRequest(config.validateRequest);
8429
- }
8430
- if (config?.timeout !== void 0) {
8431
- client.setTimeout(config.timeout);
8432
- }
8433
- if (config?.logger) {
8434
- client.setLogger(config.logger);
8435
- } else if (config?.logLevel) {
8436
- client.setLogger(createDefaultLogger(config.logLevel));
8437
- }
8438
- return { deduplicator };
8439
- }
8440
-
8441
6085
  // src/EsiClient.ts
8442
6086
  var EsiClient = class {
8443
6087
  apiClient;
@@ -8472,8 +6116,7 @@ var EsiClient = class {
8472
6116
  const result = configureApiClient(this.apiClient, config);
8473
6117
  this.deduplicator = result.deduplicator;
8474
6118
  this.etagCacheEnabled = config?.enableETagCache !== false;
8475
- const clientLogger = this.apiClient.getLogger() ?? getLogger();
8476
- clientLogger.info("EsiClient initialized successfully", {
6119
+ logInfo2(this.apiClient, "EsiClient initialized successfully", {
8477
6120
  baseUrl,
8478
6121
  clientId: config?.clientId
8479
6122
  });
@@ -8610,11 +6253,12 @@ var EsiClient = class {
8610
6253
  }
8611
6254
  setAccessToken(token) {
8612
6255
  this.apiClient.setAccessToken(token);
8613
- (this.apiClient.getLogger() ?? getLogger()).info("Access token updated");
6256
+ logInfo2(this.apiClient, "Access token updated");
8614
6257
  }
8615
6258
  setTokenProvider(provider) {
8616
6259
  this.apiClient.setTokenProvider(provider);
8617
- (this.apiClient.getLogger() ?? getLogger()).info(
6260
+ logInfo2(
6261
+ this.apiClient,
8618
6262
  provider ? "Token provider configured" : "Token provider removed"
8619
6263
  );
8620
6264
  }
@@ -8644,10 +6288,10 @@ var EsiClient = class {
8644
6288
  this.diagnostics.resetCircuitBreaker(endpoint);
8645
6289
  }
8646
6290
  async batch(keys, fetcher, options) {
8647
- return batchFetch(keys, fetcher, options);
6291
+ return batchFetchFor(this.apiClient, keys, fetcher, options);
8648
6292
  }
8649
6293
  async batchPost(ids, poster, chunkSize) {
8650
- return batchPost(ids, poster, chunkSize);
6294
+ return batchPostFor(this.apiClient, ids, poster, chunkSize);
8651
6295
  }
8652
6296
  shutdown() {
8653
6297
  const cache = this.apiClient.getCache();
@@ -8662,9 +6306,7 @@ var EsiClient = class {
8662
6306
  this.deduplicator.clear();
8663
6307
  }
8664
6308
  this.clients.clear();
8665
- (this.apiClient.getLogger() ?? getLogger()).info(
8666
- "EsiClient shutdown completed"
8667
- );
6309
+ logInfo2(this.apiClient, "EsiClient shutdown completed");
8668
6310
  }
8669
6311
  };
8670
6312
  var _defaultClient = null;
@@ -8710,7 +6352,8 @@ var CustomEsiClient = class {
8710
6352
  for (const name of this.enabledClients) {
8711
6353
  this.clients.set(name, createClientInstance(name, this.apiClient));
8712
6354
  }
8713
- (this.apiClient.getLogger() ?? getLogger()).info(
6355
+ logInfo2(
6356
+ this.apiClient,
8714
6357
  `CustomEsiClient initialized with clients: ${config.clients.join(", ")}`,
8715
6358
  { clients: config.clients }
8716
6359
  );
@@ -8829,6 +6472,18 @@ var CustomEsiClient = class {
8829
6472
  get accessLists() {
8830
6473
  return this.getClient("accessLists");
8831
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
+ }
8832
6487
  shutdown() {
8833
6488
  const cache = this.apiClient.getCache();
8834
6489
  if (cache) {
@@ -8842,66 +6497,167 @@ var CustomEsiClient = class {
8842
6497
  this.deduplicator.clear();
8843
6498
  }
8844
6499
  this.clients.clear();
8845
- (this.apiClient.getLogger() ?? getLogger()).info(
8846
- "CustomEsiClient shutdown completed"
8847
- );
6500
+ logInfo2(this.apiClient, "CustomEsiClient shutdown completed");
8848
6501
  }
8849
6502
  };
8850
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
+ */
8851
6515
  static createAllianceClient(config) {
8852
6516
  return createClientInstance(
8853
6517
  "alliance",
8854
6518
  this.buildApiClient(config)
8855
6519
  );
8856
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
+ */
8857
6532
  static createCharacterClient(config) {
8858
6533
  return createClientInstance(
8859
6534
  "characters",
8860
6535
  this.buildApiClient(config)
8861
6536
  );
8862
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
+ */
8863
6549
  static createCorporationClient(config) {
8864
6550
  return createClientInstance(
8865
6551
  "corporations",
8866
6552
  this.buildApiClient(config)
8867
6553
  );
8868
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
+ */
8869
6566
  static createMarketClient(config) {
8870
6567
  return createClientInstance(
8871
6568
  "market",
8872
6569
  this.buildApiClient(config)
8873
6570
  );
8874
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
+ */
8875
6583
  static createUniverseClient(config) {
8876
6584
  return createClientInstance(
8877
6585
  "universe",
8878
6586
  this.buildApiClient(config)
8879
6587
  );
8880
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
+ */
8881
6600
  static createFleetClient(config) {
8882
6601
  return createClientInstance(
8883
6602
  "fleets",
8884
6603
  this.buildApiClient(config)
8885
6604
  );
8886
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
+ */
8887
6617
  static createAssetsClient(config) {
8888
6618
  return createClientInstance(
8889
6619
  "assets",
8890
6620
  this.buildApiClient(config)
8891
6621
  );
8892
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
+ */
8893
6634
  static createWalletClient(config) {
8894
6635
  return createClientInstance(
8895
6636
  "wallet",
8896
6637
  this.buildApiClient(config)
8897
6638
  );
8898
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
+ */
8899
6651
  static createMailClient(config) {
8900
6652
  return createClientInstance(
8901
6653
  "mail",
8902
6654
  this.buildApiClient(config)
8903
6655
  );
8904
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
+ */
8905
6661
  static createClient(clientType, config) {
8906
6662
  return createClientInstance(clientType, this.buildApiClient(config));
8907
6663
  }
@@ -8918,6 +6674,9 @@ var EsiApiFactory = class {
8918
6674
  if (config?.language) {
8919
6675
  client.setLanguage(config.language);
8920
6676
  }
6677
+ if (config?.compatibilityDate) {
6678
+ client.setCompatibilityDate(config.compatibilityDate);
6679
+ }
8921
6680
  if (config?.onTokenRefresh) {
8922
6681
  client.setTokenProvider(config.onTokenRefresh);
8923
6682
  }
@@ -9006,7 +6765,13 @@ var ApiClientBuilder = class {
9006
6765
  }
9007
6766
  build() {
9008
6767
  const client = new ApiClient(this.clientId, this.link, this.accessToken);
9009
- 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
+ }
9010
6775
  if (this.cache) client.setCache(this.cache);
9011
6776
  if (this.circuitBreaker) client.setCircuitBreaker(this.circuitBreaker);
9012
6777
  if (this._timeout !== void 0) client.setTimeout(this._timeout);
@@ -9040,6 +6805,8 @@ var esiEndpointScopes = {
9040
6805
  "GET:characters/{character_id}/contracts": ["esi-contracts.read_character_contracts.v1"],
9041
6806
  "GET:characters/{character_id}/contracts/{contract_id}/bids": ["esi-contracts.read_character_contracts.v1"],
9042
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"],
9043
6810
  "POST:characters/{character_id}/cspa": ["esi-characters.read_contacts.v1"],
9044
6811
  "GET:characters/{character_id}/fatigue": ["esi-characters.read_fatigue.v1"],
9045
6812
  "GET:characters/{character_id}/fittings": ["esi-fittings.read_fittings.v1"],
@@ -9066,12 +6833,15 @@ var esiEndpointScopes = {
9066
6833
  "GET:characters/{character_id}/medals": ["esi-characters.read_medals.v1"],
9067
6834
  "GET:characters/{character_id}/mercenary-tactical-operations": ["esi-activities.read_character.v1"],
9068
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"],
9069
6838
  "GET:characters/{character_id}/mining": ["esi-industry.read_character_mining.v1"],
9070
6839
  "GET:characters/{character_id}/notifications": ["esi-characters.read_notifications.v1"],
9071
6840
  "GET:characters/{character_id}/notifications/contacts": ["esi-characters.read_notifications.v1"],
9072
6841
  "GET:characters/{character_id}/online": ["esi-location.read_online.v1"],
9073
6842
  "GET:characters/{character_id}/orders": ["esi-markets.read_character_orders.v1"],
9074
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"],
9075
6845
  "GET:characters/{character_id}/planets": ["esi-planets.manage_planets.v1"],
9076
6846
  "GET:characters/{character_id}/planets/{planet_id}": ["esi-planets.manage_planets.v1"],
9077
6847
  "GET:characters/{character_id}/roles": ["esi-characters.read_corporation_roles.v1"],
@@ -9148,6 +6918,9 @@ var esiEndpointScopes = {
9148
6918
  "DELETE:fleets/{fleet_id}/wings/{wing_id}": ["esi-fleets.write_fleet.v1"],
9149
6919
  "POST:fleets/{fleet_id}/wings/{wing_id}/squads": ["esi-fleets.write_fleet.v1"],
9150
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"],
9151
6924
  "POST:ui/autopilot/waypoint": ["esi-ui.write_waypoint.v1"],
9152
6925
  "POST:ui/openwindow/contract": ["esi-ui.open_window.v1"],
9153
6926
  "POST:ui/openwindow/information": ["esi-ui.open_window.v1"],
@@ -9165,7 +6938,8 @@ var noopLogger = {
9165
6938
  warn: noop,
9166
6939
  info: noop,
9167
6940
  debug: noop,
9168
- trace: noop
6941
+ trace: noop,
6942
+ isLevelEnabled: () => false
9169
6943
  };
9170
6944
  function createNoopLogger() {
9171
6945
  return noopLogger;
@@ -9446,8 +7220,8 @@ function decodeAccessToken(token) {
9446
7220
  characterId,
9447
7221
  characterName: typeof claims.name === "string" ? claims.name : "",
9448
7222
  scopes: parseScopes(claims.scp),
9449
- expiresAt: typeof claims.exp === "number" ? claims.exp * 1e3 : void 0,
9450
- 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 },
9451
7225
  claims
9452
7226
  };
9453
7227
  }
@@ -9500,7 +7274,8 @@ var EsiTokenManager = class {
9500
7274
  sso;
9501
7275
  refreshSkewMs;
9502
7276
  autoRefresh;
9503
- logger;
7277
+ /** The logger passed in config, if any; see `logger` below. */
7278
+ configuredLogger;
9504
7279
  now;
9505
7280
  hooks;
9506
7281
  inFlight = /* @__PURE__ */ new Map();
@@ -9510,6 +7285,17 @@ var EsiTokenManager = class {
9510
7285
  * is stale and must not be persisted over the newer state.
9511
7286
  */
9512
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
+ }
9513
7299
  constructor(config) {
9514
7300
  this.storage = config.storage ?? new MemoryTokenStorage();
9515
7301
  this.sso = config.ssoClient ?? new EveSsoClient({
@@ -9520,7 +7306,7 @@ var EsiTokenManager = class {
9520
7306
  });
9521
7307
  this.refreshSkewMs = config.refreshSkewMs ?? 6e4;
9522
7308
  this.autoRefresh = config.autoRefresh ?? true;
9523
- this.logger = config.logger ?? getLogger();
7309
+ this.configuredLogger = config.logger;
9524
7310
  this.now = config.now ?? (() => Date.now());
9525
7311
  this.hooks = {
9526
7312
  onRefresh: config.onRefresh,
@@ -9676,9 +7462,46 @@ var EsiTokenManager = class {
9676
7462
  return refreshed.accessToken;
9677
7463
  };
9678
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
+ }
9679
7485
  /**
9680
7486
  * An {@link EsiClient} whose access token and refresh provider are bound to
9681
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
+ * ```
9682
7505
  */
9683
7506
  async createClient(characterId, config = {}) {
9684
7507
  const accessToken = await this.getToken(characterId);
@@ -9977,12 +7800,12 @@ var FileTokenStorage = class {
9977
7800
  };
9978
7801
 
9979
7802
  // src/auth/pkce.ts
9980
- import { createHash as createHash2, randomBytes } from "crypto";
7803
+ import { createHash, randomBytes } from "crypto";
9981
7804
  function generateCodeVerifier() {
9982
7805
  return randomBytes(32).toString("base64url");
9983
7806
  }
9984
7807
  function codeChallengeFromVerifier(codeVerifier) {
9985
- return createHash2("sha256").update(codeVerifier).digest("base64url");
7808
+ return createHash("sha256").update(codeVerifier).digest("base64url");
9986
7809
  }
9987
7810
  function generatePkcePair() {
9988
7811
  const codeVerifier = generateCodeVerifier();
@@ -10022,10 +7845,16 @@ export {
10022
7845
  EsiApiFactory,
10023
7846
  EsiClient,
10024
7847
  EsiClientBuilder,
7848
+ EsiConfigurationError,
10025
7849
  EsiDiagnostics,
10026
7850
  EsiError,
7851
+ EsiFaultError,
7852
+ EsiNetworkError,
7853
+ EsiPaginationError,
7854
+ EsiParseError,
10027
7855
  esi_spec_generated_exports as EsiSpec,
10028
7856
  EsiTokenManager,
7857
+ EsiTokenRefreshError,
10029
7858
  EsiValidationError,
10030
7859
  EveSsoClient,
10031
7860
  FactionClient,
@@ -10085,14 +7914,20 @@ export {
10085
7914
  isAuthError,
10086
7915
  isCharacterNotFound,
10087
7916
  isCircuitOpen,
7917
+ isConfigurationError,
10088
7918
  isEsiError,
7919
+ isFaultError,
10089
7920
  isForbidden,
7921
+ isNetworkError,
10090
7922
  isNotFound,
7923
+ isPaginationError,
7924
+ isParseError,
10091
7925
  isRateLimited,
10092
7926
  isRetryable,
10093
7927
  isServerError,
10094
7928
  isSsoError,
10095
7929
  isTimeout,
7930
+ isTokenRefreshError,
10096
7931
  isTokenRevoked,
10097
7932
  isUnauthorized,
10098
7933
  isValidationError,