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