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