Creates a BaseEPClient.
When shared is provided the constructor reuses those pre-built resources
instead of allocating new ones; this is the mechanism used by the facade to
ensure all sub-clients share one cache and one rate-limiter.
Client configuration (used when shared is absent)
Optionalshared: EPSharedResourcesPre-built shared resources (passed by facade to sub-clients)
Protected ReadonlybaseEuropean Parliament API base URL.
Protected ReadonlycacheLRU cache for API responses.
Private ReadonlycacheShared cache hit/miss counters (shared via EPSharedResources when used as sub-client).
Protected ReadonlyenableEnable automatic retry on transient failures.
Protected ReadonlymaxMaximum allowed response body size in bytes.
Protected ReadonlymaxMaximum number of retry attempts.
Protected ReadonlyrateToken bucket rate limiter.
Protected ReadonlytimeoutRequest timeout in milliseconds.
Private Static ReadonlyEMPTY_Empty JSON-LD shape returned for bodyless responses (HTTP 204, content-length: 0).
PrivatebuildBuilds the full request URL from endpoint + optional params.
Optionalparams: Record<string, unknown>Clears all entries from the LRU cache.
PrivateeffectiveProtectedevictEvicts a single cache entry matching the given endpoint and params. Sub-clients use this when they detect that a successfully-fetched payload is a content-pending sentinel that must not be served from cache for the remainder of the TTL — eviction lets availability recover as soon as the upstream document is enriched.
PrivatefetchWraps a fetch call with the configured retry policy.
Fully resolved request URL
Relative endpoint path (for error messages)
OptionalminimumTimeoutMs: numberOptional per-request minimum timeout (ms)
OptionalexternalSignal: AbortSignalOptional caller-provided cancellation signal
PrivatefetchExecutes the HTTP fetch with timeout/abort support and response size guard.
Fully resolved request URL
Relative endpoint path (for error messages)
OptionalminimumTimeoutMs: numberOptional per-request minimum timeout (ms).
When provided, the effective timeout is Math.max(minimumTimeoutMs, this.timeoutMs),
so it acts as a floor that the global timeout can still extend.
Use for known slow EP API endpoints (e.g. procedures/feed).
OptionalexternalSignal: AbortSignalOptional caller-provided cancellation signal.
When this signal fires mid-flight, the underlying fetch is aborted and
toAPIError converts the cancellation to an APIError with
statusCode: 0 (distinct from the timeout-driven 408 path).
ProtectedgetExecutes a cached, rate-limited GET request to the EP API.
Expected response type (extends Record<string, unknown>)
API endpoint path (relative to baseURL)
Optionalparams: Record<string, unknown>Optional query parameters
OptionalminimumTimeoutMs: numberOptional per-request minimum timeout in milliseconds.
When provided, the effective timeout is Math.max(minimumTimeoutMs, this.timeoutMs),
so the global timeout (set via --timeout or EP_REQUEST_TIMEOUT_MS) can still
extend it beyond the per-endpoint minimum.
Use for known slow EP API endpoints such as procedures/feed.
OptionalabortSignal: AbortSignalOptional caller-provided cancellation signal. When
already aborted on entry the request is rejected immediately before
consuming a rate-limiter token (so a cancelled fan-out does not starve
the bucket). When aborted mid-flight, the underlying fetch is
cancelled and the rejection is surfaced as APIError(..., 0, { cause }).
Promise resolving to the typed API response
PrivategetGenerates a deterministic cache key.
API endpoint path
Optionalparams: Record<string, unknown>Optional query parameters
JSON string used as cache key
Returns cache statistics for monitoring and debugging.
{ size, maxSize, hitRate, hits, misses }
PrivateissuePrivateparsePrivatereadPrivateshouldReturns true when an error should trigger a retry.
Retries on:
Does NOT retry on 4xx client errors (except 429), nor on cancellation (statusCode 0 — an aborted request must never be re-issued).
PrivatetoConverts a caught error to a typed APIError.
TimeoutError → APIError(..., 408) (the internal per-request
timeout fired before the response completed).AbortSignal →
APIError(..., 0, { cause: <signal.reason> }). Status 0 is distinct
from the timeout (408) and rate-limit (429) paths so callers can
distinguish budget cancellations from upstream failures and skip
retries via shouldRetryRequest.The caught error
Relative endpoint path (for error messages)
OptionalexternalSignal: AbortSignalThe caller-provided signal (if any). When the
signal is already aborted at the time of catch, the error is treated
as a cancellation regardless of its concrete shape (some runtimes
surface a generic AbortError rather than re-throwing signal.reason).
Private StaticparseParses a byte buffer as JSON-LD. Returns an empty JSON-LD shape for
zero-byte bodies (the EP API sends these for out-of-range offsets).
Non-empty bodies must contain valid JSON; any SyntaxError is allowed
to propagate so callers (including single-entity endpoints) fail fast
instead of receiving a misleading empty-list shape.
Private StaticparsePrivate StaticresolveResolves all EPClientConfig options to their final values with defaults applied. Extracted to keep constructor complexity within limits.
Private StaticvalidateValidates the Content-Type header of an API response. Throws if the response is not JSON (e.g. HTML error pages from reverse proxies). Cancels the response body before throwing to allow connection reuse.
A missing or empty Content-Type header is treated as acceptable because the EP API occasionally omits it on valid JSON responses, and rejecting those would cause false-negative failures.
Base class for European Parliament API sub-clients.
Holds the shared HTTP machinery: LRU cache, token-bucket rate limiter, timeout/abort controller, and retry logic. Sub-clients extend this class and call the protected
get()helper for all HTTP requests.