@http-client-toolkit/core 0.1.0 → 0.2.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/lib/index.cjs +437 -4
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +183 -1
- package/lib/index.d.ts +183 -1
- package/lib/index.js +426 -5
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors/http-client-error.ts","../src/stores/rate-limit-store.ts","../src/stores/request-hasher.ts","../src/stores/rate-limit-config.ts","../src/stores/adaptive-capacity-calculator.ts","../src/http-client/http-client.ts"],"names":["baseUserCapacity"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base error class for HTTP client errors.\n * Consumers can extend this for domain-specific error handling.\n */\nexport class HttpClientError extends Error {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = 'HttpClientError';\n this.statusCode = statusCode;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Priority level for API requests\n */\nexport type RequestPriority = 'user' | 'background';\n\n/**\n * Adaptive configuration schema with validation and defaults\n */\nexport const AdaptiveConfigSchema = z\n .object({\n monitoringWindowMs: z\n .number()\n .positive()\n .default(15 * 60 * 1000), // 15 minutes\n highActivityThreshold: z.number().min(0).default(10), // requests per window\n moderateActivityThreshold: z.number().min(0).default(3),\n recalculationIntervalMs: z.number().positive().default(30000), // 30 seconds\n sustainedInactivityThresholdMs: z\n .number()\n .positive()\n .default(30 * 60 * 1000), // 30 minutes\n backgroundPauseOnIncreasingTrend: z.boolean().default(true),\n maxUserScaling: z.number().positive().default(2.0), // don't exceed 2x capacity\n minUserReserved: z.number().min(0).default(5), // requests minimum\n })\n .refine(\n (data) => {\n return data.moderateActivityThreshold < data.highActivityThreshold;\n },\n {\n message:\n 'moderateActivityThreshold must be less than highActivityThreshold',\n },\n );\n\n/**\n * Configuration for adaptive rate limiting\n */\nexport type AdaptiveConfig = z.infer<typeof AdaptiveConfigSchema>;\n\n/**\n * Interface for rate limiting API requests per resource\n */\nexport interface RateLimitStore {\n /**\n * Atomically acquire capacity for a request if the implementation supports it.\n * When present and returning true, callers should treat the request as already\n * recorded for rate-limit accounting.\n */\n acquire?(resource: string): Promise<boolean>;\n\n /**\n * Check if a request to a resource can proceed based on rate limits\n * @param resource The resource name (e.g., 'issues', 'characters')\n * @returns True if the request can proceed, false if rate limited\n */\n canProceed(resource: string): Promise<boolean>;\n\n /**\n * Record a request to a resource for rate limiting tracking\n * @param resource The resource name (e.g., 'issues', 'characters')\n */\n record(resource: string): Promise<void>;\n\n /**\n * Get the current rate limit status for a resource\n * @param resource The resource name\n * @returns Rate limit information including remaining requests and reset time\n */\n getStatus(resource: string): Promise<{\n remaining: number;\n resetTime: Date;\n limit: number;\n }>;\n\n /**\n * Reset rate limits for a resource (useful for testing)\n * @param resource The resource name\n */\n reset(resource: string): Promise<void>;\n\n /**\n * Get the time in milliseconds until the next request can be made\n * @param resource The resource name\n * @returns Milliseconds to wait, or 0 if no waiting is needed\n */\n getWaitTime(resource: string): Promise<number>;\n}\n\n/**\n * Enhanced interface for adaptive rate limiting stores with priority support\n */\nexport interface AdaptiveRateLimitStore extends RateLimitStore {\n /**\n * Atomically acquire capacity for a request if the implementation supports it.\n */\n acquire?(resource: string, priority?: RequestPriority): Promise<boolean>;\n\n /**\n * Check if a request to a resource can proceed based on rate limits\n * @param resource The resource name (e.g., 'issues', 'characters')\n * @param priority The priority level of the request (defaults to 'background')\n * @returns True if the request can proceed, false if rate limited\n */\n canProceed(resource: string, priority?: RequestPriority): Promise<boolean>;\n\n /**\n * Record a request to a resource for rate limiting tracking\n * @param resource The resource name (e.g., 'issues', 'characters')\n * @param priority The priority level of the request (defaults to 'background')\n */\n record(resource: string, priority?: RequestPriority): Promise<void>;\n\n /**\n * Get the current rate limit status for a resource\n * @param resource The resource name\n * @returns Rate limit information including remaining requests and reset time\n */\n getStatus(resource: string): Promise<{\n remaining: number;\n resetTime: Date;\n limit: number;\n adaptive?: {\n userReserved: number;\n backgroundMax: number;\n backgroundPaused: boolean;\n recentUserActivity: number;\n reason: string;\n };\n }>;\n\n /**\n * Get the time in milliseconds until the next request can be made\n * @param resource The resource name\n * @param priority The priority level of the request (defaults to 'background')\n * @returns Milliseconds to wait, or 0 if no waiting is needed\n */\n getWaitTime(resource: string, priority?: RequestPriority): Promise<number>;\n}\n","import { createHash } from 'crypto';\n\n/**\n * Creates a consistent hash for API requests to use as cache/dedupe keys\n * @param endpoint The API endpoint\n * @param params The request parameters\n * @returns A SHA-256 hash of the request\n */\nexport function hashRequest(\n endpoint: string,\n params: Record<string, unknown> = {},\n): string {\n const requestString = JSON.stringify({\n endpoint,\n params: sortObject(params),\n });\n\n return createHash('sha256').update(requestString).digest('hex');\n}\n\n/**\n * Normalises and sorts an object for hashing purposes.\n *\n * The ComicVine API transmits all query parameters as strings. To avoid cache\n * misses caused by treating `10` and `'10'` as different values we normalise\n * primitive types (number and boolean) to their string representation **before**\n * sorting. `undefined` values are intentionally kept as `undefined` so that\n * they are dropped by `JSON.stringify`, maintaining the existing behaviour\n * where an omitted parameter and an `undefined` parameter produce the same\n * hash.\n */\nfunction sortObject(obj: unknown): unknown {\n // Handle primitives first\n if (obj === null) {\n return null;\n }\n\n const objType = typeof obj;\n\n if (objType === 'undefined' || objType === 'string') {\n return obj;\n }\n\n if (objType === 'number' || objType === 'boolean') {\n // Convert to string so that 10 and '10' (or true and 'true') hash equally\n return String(obj);\n }\n\n // Recursively process arrays\n if (Array.isArray(obj)) {\n return obj.map(sortObject);\n }\n\n // For objects – sort keys and recurse\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj as Record<string, unknown>).sort();\n\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n const normalisedValue = sortObject(value);\n\n // Skip keys whose value normalises to undefined so omitted & undefined match\n if (normalisedValue !== undefined) {\n sorted[key] = normalisedValue;\n }\n }\n\n return sorted;\n}\n","/**\n * Configuration for per-resource rate limiting.\n *\n * This interface is shared by all store implementations (e.g. in-memory,\n * SQLite) so that callers can use a single canonical type.\n */\nexport interface RateLimitConfig {\n /** Number of requests allowed per time window */\n limit: number;\n /** Duration of the window in milliseconds */\n windowMs: number;\n}\n\n/**\n * Default rate-limit window: 60 requests per minute.\n *\n * Store implementations can reference this to avoid duplicating magic numbers.\n */\nexport const DEFAULT_RATE_LIMIT: RateLimitConfig = {\n limit: 60,\n windowMs: 60_000,\n};\n","import { z } from 'zod';\nimport { AdaptiveConfigSchema } from './rate-limit-store.js';\n\ninterface ActivityMetrics {\n recentUserRequests: Array<number>;\n recentBackgroundRequests: Array<number>;\n userActivityTrend: 'increasing' | 'stable' | 'decreasing' | 'none';\n}\n\ninterface DynamicCapacityResult {\n userReserved: number;\n backgroundMax: number;\n backgroundPaused: boolean;\n reason: string;\n}\n\n/**\n * Calculates dynamic capacity allocation based on real-time user activity patterns\n */\nexport class AdaptiveCapacityCalculator {\n public readonly config: z.infer<typeof AdaptiveConfigSchema>;\n\n constructor(config: Partial<z.input<typeof AdaptiveConfigSchema>> = {}) {\n // Zod handles validation and applies defaults automatically\n this.config = AdaptiveConfigSchema.parse(config);\n }\n\n calculateDynamicCapacity(\n resource: string,\n totalLimit: number,\n activityMetrics: ActivityMetrics,\n ): DynamicCapacityResult {\n const recentUserActivity = this.getRecentActivity(\n activityMetrics.recentUserRequests,\n );\n const activityTrend = this.calculateActivityTrend(\n activityMetrics.recentUserRequests,\n );\n\n // Strategy 1: High Activity - Pause Background\n if (recentUserActivity >= this.config.highActivityThreshold) {\n const userCapacity = Math.min(\n totalLimit * 0.9,\n Math.floor(totalLimit * 0.5 * this.config.maxUserScaling), // 50% base * scaling factor\n );\n\n return {\n userReserved: userCapacity,\n backgroundMax: totalLimit - userCapacity,\n backgroundPaused:\n this.config.backgroundPauseOnIncreasingTrend &&\n activityTrend === 'increasing',\n reason: `High user activity (${recentUserActivity} requests/${this.config.monitoringWindowMs / 60000}min) - prioritizing users`,\n };\n }\n\n // Strategy 2: Moderate Activity - Balanced Scaling\n if (recentUserActivity >= this.config.moderateActivityThreshold) {\n const userMultiplier = this.getUserMultiplier(\n recentUserActivity,\n activityTrend,\n );\n const baseUserCapacity = Math.floor(totalLimit * 0.4); // 40% base allocation\n const dynamicUserCapacity = Math.min(\n totalLimit * 0.7,\n baseUserCapacity * userMultiplier,\n );\n\n return {\n userReserved: dynamicUserCapacity,\n backgroundMax: totalLimit - dynamicUserCapacity,\n backgroundPaused: false,\n reason: `Moderate user activity - dynamic scaling (${userMultiplier.toFixed(1)}x user capacity)`,\n };\n }\n\n // Strategy 3: Low/No Activity - Background Scale Up\n if (recentUserActivity === 0) {\n // If there have never been any requests at all (fresh start), use default capacity allocation\n if (\n activityMetrics.recentUserRequests.length === 0 &&\n activityMetrics.recentBackgroundRequests.length === 0\n ) {\n const baseUserCapacity = Math.floor(totalLimit * 0.3); // 30% base for initial state\n return {\n userReserved: Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundMax:\n totalLimit -\n Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundPaused: false,\n reason: 'Initial state - default capacity allocation',\n };\n }\n\n // If there have never been user requests (only background), use background scale up\n if (activityMetrics.recentUserRequests.length === 0) {\n return {\n userReserved: this.config.minUserReserved, // Minimal safety buffer\n backgroundMax: totalLimit - this.config.minUserReserved,\n backgroundPaused: false,\n reason:\n 'No user activity yet - background scale up with minimal user buffer',\n };\n }\n\n // There have been user requests before, check for sustained inactivity\n const sustainedInactivity = this.getSustainedInactivityPeriod(\n activityMetrics.recentUserRequests,\n );\n\n if (sustainedInactivity > this.config.sustainedInactivityThresholdMs) {\n return {\n userReserved: 0, // No reservation - background gets everything!\n backgroundMax: totalLimit, // Full capacity available\n backgroundPaused: false,\n reason: `Sustained zero activity (${Math.floor(sustainedInactivity / 60000)}+ min) - full capacity to background`,\n };\n } else {\n return {\n userReserved: this.config.minUserReserved, // Minimal safety buffer\n backgroundMax: totalLimit - this.config.minUserReserved,\n backgroundPaused: false,\n reason:\n 'Recent zero activity - background scale up with minimal user buffer',\n };\n }\n }\n\n // Strategy 4: Very Low Activity - Gradual Background Scale Up\n const baseUserCapacity = Math.floor(totalLimit * 0.3); // 30% base for very low activity\n return {\n userReserved: Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundMax:\n totalLimit - Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundPaused: false,\n reason: `Low user activity (${recentUserActivity} requests/${this.config.monitoringWindowMs / 60000}min) - background scale up`,\n };\n }\n\n getRecentActivity(requests: Array<number>): number {\n const cutoff = Date.now() - this.config.monitoringWindowMs;\n return requests.filter((timestamp) => timestamp > cutoff).length;\n }\n\n calculateActivityTrend(\n requests: Array<number>,\n ): 'increasing' | 'stable' | 'decreasing' | 'none' {\n const now = Date.now();\n const windowSize = this.config.monitoringWindowMs / 3; // Use 1/3 of monitoring window for trend\n const recent = requests.filter((t) => t > now - windowSize).length;\n const previous = requests.filter(\n (t) => t > now - 2 * windowSize && t <= now - windowSize,\n ).length;\n\n if (recent === 0 && previous === 0) return 'none';\n if (recent > previous * 1.5) return 'increasing';\n if (recent < previous * 0.5) return 'decreasing';\n return 'stable';\n }\n\n private getUserMultiplier(activity: number, trend: string): number {\n let base = Math.min(\n this.config.maxUserScaling,\n 1 + activity / this.config.highActivityThreshold,\n );\n\n // Adjust based on trend\n if (trend === 'increasing') base *= 1.2;\n if (trend === 'decreasing') base *= 0.8;\n\n return Math.max(1.0, base);\n }\n\n private getSustainedInactivityPeriod(requests: Array<number>): number {\n if (requests.length === 0) {\n // This should not be called when there are no requests (handled above)\n return 0;\n }\n\n const lastRequest = Math.max(...requests);\n return Date.now() - lastRequest;\n }\n}\n\n// Export types for use in other modules\nexport type { ActivityMetrics, DynamicCapacityResult };\n","import { HttpClientError } from '../errors/http-client-error.js';\nimport {\n CacheStore,\n DedupeStore,\n RateLimitStore,\n AdaptiveRateLimitStore,\n RequestPriority,\n hashRequest,\n} from '../stores/index.js';\nimport { HttpClientContract } from '../types/index.js';\n\nconst DEFAULT_RATE_LIMIT_HEADER_NAMES = {\n retryAfter: ['retry-after'],\n limit: ['ratelimit-limit', 'x-ratelimit-limit', 'rate-limit-limit'],\n remaining: [\n 'ratelimit-remaining',\n 'x-ratelimit-remaining',\n 'rate-limit-remaining',\n ],\n reset: ['ratelimit-reset', 'x-ratelimit-reset', 'rate-limit-reset'],\n combined: ['ratelimit'],\n} as const;\n\n/**\n * Wait for a specified period while supporting cancellation via AbortSignal.\n *\n * If the signal is aborted before the timeout completes the promise rejects\n * with an `Error` whose name is set to `AbortError`, mimicking DOMException in\n * browser environments without depending on it. This allows callers to use a\n * single `AbortController` for both the rate-limit wait *and* the subsequent\n * HTTP request.\n */\nfunction wait(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n resolve();\n }, ms);\n\n function onAbort() {\n clearTimeout(timer);\n const err = new Error('Aborted');\n err.name = 'AbortError';\n reject(err);\n }\n\n if (signal) {\n if (signal.aborted) {\n onAbort();\n } else {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n }\n });\n}\n\nexport interface HttpClientStores {\n cache?: CacheStore;\n dedupe?: DedupeStore;\n rateLimit?: RateLimitStore | AdaptiveRateLimitStore;\n}\n\nexport interface HttpClientOptions {\n /**\n * Default cache TTL in seconds\n */\n defaultCacheTTL?: number;\n /**\n * Whether to throw errors on rate limit violations\n */\n throwOnRateLimit?: boolean;\n /**\n * Maximum time to wait for rate limit in milliseconds\n */\n maxWaitTime?: number;\n /**\n * Optional response transformer applied to the raw response data.\n * Use this for converting snake_case to camelCase, etc.\n */\n responseTransformer?: (data: unknown) => unknown;\n /**\n * Optional error handler to convert errors into domain-specific error types.\n * If not provided, a generic HttpClientError is thrown.\n */\n errorHandler?: (error: unknown) => Error;\n /**\n * Optional response validator/handler called after transformation.\n * Use this to inspect the response and throw domain-specific errors\n * based on response content (e.g., API-level error codes).\n */\n responseHandler?: (data: unknown) => unknown;\n /**\n * Configure rate-limit response header names for standards and custom APIs.\n */\n rateLimitHeaders?: {\n retryAfter?: Array<string>;\n limit?: Array<string>;\n remaining?: Array<string>;\n reset?: Array<string>;\n combined?: Array<string>;\n };\n}\n\ninterface RateLimitHeaderConfig {\n retryAfter: Array<string>;\n limit: Array<string>;\n remaining: Array<string>;\n reset: Array<string>;\n combined: Array<string>;\n}\n\ninterface ParsedResponseBody {\n data: unknown;\n}\n\ntype ErrorWithResponse = {\n message: string;\n response: {\n status: number;\n data: unknown;\n headers: Headers;\n };\n};\n\nexport class HttpClient implements HttpClientContract {\n private stores: HttpClientStores;\n private serverCooldowns = new Map<string, number>();\n private options: Required<\n Pick<\n HttpClientOptions,\n 'defaultCacheTTL' | 'throwOnRateLimit' | 'maxWaitTime'\n >\n > &\n Pick<\n HttpClientOptions,\n 'responseTransformer' | 'errorHandler' | 'responseHandler'\n > & {\n rateLimitHeaders: RateLimitHeaderConfig;\n };\n\n constructor(stores: HttpClientStores = {}, options: HttpClientOptions = {}) {\n this.stores = stores;\n this.options = {\n defaultCacheTTL: options.defaultCacheTTL ?? 3600,\n throwOnRateLimit: options.throwOnRateLimit ?? true,\n maxWaitTime: options.maxWaitTime ?? 60000,\n responseTransformer: options.responseTransformer,\n errorHandler: options.errorHandler,\n responseHandler: options.responseHandler,\n rateLimitHeaders: this.normalizeRateLimitHeaders(\n options.rateLimitHeaders,\n ),\n };\n }\n\n private normalizeRateLimitHeaders(\n customHeaders?: HttpClientOptions['rateLimitHeaders'],\n ): RateLimitHeaderConfig {\n return {\n retryAfter: this.normalizeHeaderNames(\n customHeaders?.retryAfter,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.retryAfter,\n ),\n limit: this.normalizeHeaderNames(\n customHeaders?.limit,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.limit,\n ),\n remaining: this.normalizeHeaderNames(\n customHeaders?.remaining,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.remaining,\n ),\n reset: this.normalizeHeaderNames(\n customHeaders?.reset,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.reset,\n ),\n combined: this.normalizeHeaderNames(\n customHeaders?.combined,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.combined,\n ),\n };\n }\n\n private normalizeHeaderNames(\n providedNames: Array<string> | undefined,\n defaultNames: ReadonlyArray<string>,\n ): Array<string> {\n if (!providedNames || providedNames.length === 0) {\n return [...defaultNames];\n }\n\n const customNames = providedNames\n .map((name) => name.trim().toLowerCase())\n .filter(Boolean);\n\n if (customNames.length === 0) {\n return [...defaultNames];\n }\n\n return [...new Set([...customNames, ...defaultNames])];\n }\n\n /**\n * Infer the resource name from the endpoint URL\n * @param url The full URL or endpoint path\n * @returns The resource name for rate limiting\n */\n private inferResource(url: string): string {\n try {\n const urlObj = new URL(url);\n // Use the first meaningful path segment as the resource name\n const segments = urlObj.pathname.split('/').filter(Boolean);\n return segments[segments.length - 1] || 'unknown';\n } catch {\n return 'unknown';\n }\n }\n\n /**\n * Extract endpoint and params from URL for request hashing\n * @param url The full URL\n * @returns Object with endpoint and params for hashing\n */\n private parseUrlForHashing(url: string): {\n endpoint: string;\n params: Record<string, unknown>;\n } {\n const urlObj = new URL(url);\n const endpoint = `${urlObj.origin}${urlObj.pathname}`;\n const params: Record<string, unknown> = {};\n\n urlObj.searchParams.forEach((value, key) => {\n const existing = params[key];\n\n // Keep repeated query keys as arrays so semantically distinct URLs like\n // `?tag=a&tag=b` and `?tag=b` do not hash to the same cache/dedupe key.\n if (existing === undefined) {\n params[key] = value;\n return;\n }\n\n if (Array.isArray(existing)) {\n existing.push(value);\n return;\n }\n\n params[key] = [existing, value];\n });\n\n return { endpoint, params };\n }\n\n private getOriginScope(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return 'unknown';\n }\n }\n\n private getHeaderValue(\n headers: Headers | Record<string, unknown> | undefined,\n names: Array<string>,\n ): string | undefined {\n if (!headers) {\n return undefined;\n }\n\n if (headers instanceof Headers) {\n for (const rawName of names) {\n const value = headers.get(rawName);\n if (value !== null) {\n return value;\n }\n }\n return undefined;\n }\n\n for (const rawName of names) {\n const name = rawName.toLowerCase();\n const value = headers[name] ?? headers[rawName];\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (Array.isArray(value) && value.length > 0) {\n const first = value.find((entry) => typeof entry === 'string');\n if (typeof first === 'string') {\n return first;\n }\n }\n }\n\n return undefined;\n }\n\n private parseIntegerHeader(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number.parseInt(value.trim(), 10);\n if (!Number.isFinite(parsed) || parsed < 0) {\n return undefined;\n }\n\n return parsed;\n }\n\n private parseRetryAfterMs(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const numeric = Number.parseInt(value.trim(), 10);\n if (Number.isFinite(numeric) && numeric >= 0) {\n return numeric * 1000;\n }\n\n const dateMs = Date.parse(value);\n if (!Number.isFinite(dateMs)) {\n return undefined;\n }\n\n return Math.max(0, dateMs - Date.now());\n }\n\n private parseResetMs(value: string | undefined): number | undefined {\n const parsed = this.parseIntegerHeader(value);\n if (parsed === undefined) {\n return undefined;\n }\n\n if (parsed === 0) {\n return 0;\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n\n if (parsed > nowSeconds + 1) {\n return Math.max(0, (parsed - nowSeconds) * 1000);\n }\n\n return parsed * 1000;\n }\n\n private parseCombinedRateLimitHeader(value: string | undefined): {\n remaining?: number;\n resetMs?: number;\n } {\n if (!value) {\n return {};\n }\n\n const remainingMatch = value.match(/(?:^|[;,])\\s*r\\s*=\\s*(\\d+)/i);\n const resetMatch = value.match(/(?:^|[;,])\\s*t\\s*=\\s*(\\d+)/i);\n\n return {\n remaining: remainingMatch\n ? this.parseIntegerHeader(remainingMatch[1])\n : undefined,\n resetMs: resetMatch ? this.parseResetMs(resetMatch[1]) : undefined,\n };\n }\n\n private applyServerRateLimitHints(\n url: string,\n headers: Headers | Record<string, unknown> | undefined,\n statusCode?: number,\n ): void {\n if (!headers) {\n return;\n }\n\n const config = this.options.rateLimitHeaders;\n const retryAfterRaw = this.getHeaderValue(headers, config.retryAfter);\n const resetRaw = this.getHeaderValue(headers, config.reset);\n const remainingRaw = this.getHeaderValue(headers, config.remaining);\n const combinedRaw = this.getHeaderValue(headers, config.combined);\n\n const retryAfterMs = this.parseRetryAfterMs(retryAfterRaw);\n const resetMs = this.parseResetMs(resetRaw);\n const remaining = this.parseIntegerHeader(remainingRaw);\n const combined = this.parseCombinedRateLimitHeader(combinedRaw);\n\n const effectiveRemaining = remaining ?? combined.remaining;\n const effectiveResetMs = resetMs ?? combined.resetMs;\n const hasRateLimitErrorStatus = statusCode === 429 || statusCode === 503;\n\n let waitMs: number | undefined;\n\n if (retryAfterMs !== undefined) {\n waitMs = retryAfterMs;\n } else if (\n effectiveResetMs !== undefined &&\n (hasRateLimitErrorStatus ||\n (effectiveRemaining !== undefined && effectiveRemaining <= 0))\n ) {\n waitMs = effectiveResetMs;\n }\n\n if (waitMs === undefined || waitMs <= 0) {\n return;\n }\n\n const scope = this.getOriginScope(url);\n this.serverCooldowns.set(scope, Date.now() + waitMs);\n }\n\n private async enforceServerCooldown(\n url: string,\n signal?: AbortSignal,\n ): Promise<void> {\n const scope = this.getOriginScope(url);\n const startedAt = Date.now();\n\n // Re-check cooldown after each sleep so we never proceed while a server\n // cooldown is still active. This avoids bypassing limits when cooldown\n // duration is longer than maxWaitTime.\n while (true) {\n const cooldownUntil = this.serverCooldowns.get(scope);\n if (!cooldownUntil) {\n return;\n }\n\n const waitMs = cooldownUntil - Date.now();\n if (waitMs <= 0) {\n this.serverCooldowns.delete(scope);\n return;\n }\n\n if (this.options.throwOnRateLimit) {\n throw new Error(\n `Rate limit exceeded for origin '${scope}'. Wait ${waitMs}ms before retrying.`,\n );\n }\n\n const elapsedMs = Date.now() - startedAt;\n const remainingWaitBudgetMs = this.options.maxWaitTime - elapsedMs;\n\n if (remainingWaitBudgetMs <= 0) {\n throw new Error(\n `Rate limit wait exceeded maxWaitTime (${this.options.maxWaitTime}ms) for origin '${scope}'.`,\n );\n }\n\n await wait(Math.min(waitMs, remainingWaitBudgetMs), signal);\n }\n }\n\n private async enforceStoreRateLimit(\n resource: string,\n priority: RequestPriority,\n signal?: AbortSignal,\n ): Promise<boolean> {\n const rateLimit = this.stores.rateLimit as AdaptiveRateLimitStore;\n const startedAt = Date.now();\n const hasAtomicAcquire = typeof rateLimit.acquire === 'function';\n\n const canProceedNow = async (): Promise<boolean> => {\n if (hasAtomicAcquire) {\n return rateLimit.acquire!(resource, priority);\n }\n return rateLimit.canProceed(resource, priority);\n };\n\n if (this.options.throwOnRateLimit) {\n const canProceed = await canProceedNow();\n if (!canProceed) {\n const waitTime = await rateLimit.getWaitTime(resource, priority);\n throw new Error(\n `Rate limit exceeded for resource '${resource}'. Wait ${waitTime}ms before retrying.`,\n );\n }\n return hasAtomicAcquire;\n }\n\n // Keep polling + waiting until the store explicitly allows the request or\n // we exhaust maxWaitTime. A single one-off sleep can otherwise let a request\n // through while still over limit.\n while (!(await canProceedNow())) {\n const suggestedWaitMs = await rateLimit.getWaitTime(resource, priority);\n const elapsedMs = Date.now() - startedAt;\n const remainingWaitBudgetMs = this.options.maxWaitTime - elapsedMs;\n\n if (remainingWaitBudgetMs <= 0) {\n throw new Error(\n `Rate limit wait exceeded maxWaitTime (${this.options.maxWaitTime}ms) for resource '${resource}'.`,\n );\n }\n\n // If a store reports \"blocked\" but no wait time, use a tiny backoff to\n // avoid a tight CPU loop while still converging quickly.\n const waitTime =\n suggestedWaitMs > 0\n ? Math.min(suggestedWaitMs, remainingWaitBudgetMs)\n : Math.min(25, remainingWaitBudgetMs);\n\n await wait(waitTime, signal);\n }\n\n return hasAtomicAcquire;\n }\n\n private generateClientError(err: unknown): Error {\n // If a custom error handler is provided, use it\n if (this.options.errorHandler) {\n return this.options.errorHandler(err);\n }\n\n if (err instanceof HttpClientError) {\n return err;\n }\n\n const responseError = err as Partial<ErrorWithResponse>;\n const statusCode =\n typeof responseError.response?.status === 'number'\n ? responseError.response.status\n : undefined;\n\n const responseData = responseError.response?.data;\n const derivedResponseMessage =\n typeof responseData === 'object' && responseData !== null\n ? (responseData as { message?: unknown }).message\n : undefined;\n const responseMessage =\n typeof derivedResponseMessage === 'string'\n ? derivedResponseMessage\n : undefined;\n\n const errorMessage =\n err instanceof Error\n ? err.message\n : typeof (err as { message?: unknown }).message === 'string'\n ? (err as { message: string }).message\n : 'Unknown error';\n const message = `${errorMessage}${responseMessage ? `, ${responseMessage}` : ''}`;\n\n return new HttpClientError(message, statusCode);\n }\n\n private async parseResponseBody(\n response: Response,\n ): Promise<ParsedResponseBody> {\n if (response.status === 204 || response.status === 205) {\n return { data: undefined };\n }\n\n const rawBody = await response.text();\n if (!rawBody) {\n return { data: undefined };\n }\n\n const contentType =\n response.headers.get('content-type')?.toLowerCase() ?? '';\n const shouldAttemptJsonParsing =\n contentType.includes('application/json') ||\n contentType.includes('+json') ||\n rawBody.trimStart().startsWith('{') ||\n rawBody.trimStart().startsWith('[');\n\n if (!shouldAttemptJsonParsing) {\n return { data: rawBody };\n }\n\n try {\n const parsed = JSON.parse(rawBody) as unknown;\n if (typeof parsed === 'object' && parsed !== null) {\n return { data: parsed };\n }\n\n return { data: parsed };\n } catch {\n return { data: rawBody };\n }\n }\n\n async get<Result>(\n url: string,\n options: { signal?: AbortSignal; priority?: RequestPriority } = {},\n ): Promise<Result> {\n const { signal, priority = 'background' } = options;\n const { endpoint, params } = this.parseUrlForHashing(url);\n const hash = hashRequest(endpoint, params);\n const resource = this.inferResource(url);\n\n try {\n await this.enforceServerCooldown(url, signal);\n\n // 1. Cache - check for cached response\n if (this.stores.cache) {\n const cachedResult = await this.stores.cache.get(hash);\n if (cachedResult !== undefined) {\n return cachedResult as Result;\n }\n }\n\n // 2. Deduplication - check for in-progress request\n if (this.stores.dedupe) {\n const existingResult = await this.stores.dedupe.waitFor(hash);\n if (existingResult !== undefined) {\n return existingResult as Result;\n }\n\n if (this.stores.dedupe.registerOrJoin) {\n const registration = await this.stores.dedupe.registerOrJoin(hash);\n\n if (!registration.isOwner) {\n const joinedResult = await this.stores.dedupe.waitFor(hash);\n if (joinedResult !== undefined) {\n return joinedResult as Result;\n }\n }\n } else {\n await this.stores.dedupe.register(hash);\n }\n }\n\n // 3. Rate limiting - check if request can proceed\n let alreadyRecordedRateLimit = false;\n if (this.stores.rateLimit) {\n alreadyRecordedRateLimit = await this.enforceStoreRateLimit(\n resource,\n priority,\n signal,\n );\n }\n\n // 4. Execute the actual HTTP request\n const response = await fetch(url, { signal });\n this.applyServerRateLimitHints(url, response.headers, response.status);\n\n const parsedBody = await this.parseResponseBody(response);\n\n if (!response.ok) {\n const error: ErrorWithResponse = {\n message: `Request failed with status ${response.status}`,\n response: {\n status: response.status,\n data: parsedBody.data,\n headers: response.headers,\n },\n };\n throw error;\n }\n\n // 5. Apply response transformer if provided\n let data: unknown = parsedBody.data;\n if (this.options.responseTransformer && data) {\n data = this.options.responseTransformer(data);\n }\n\n // 6. Apply response handler if provided (for domain-specific validation)\n if (this.options.responseHandler) {\n data = this.options.responseHandler(data);\n }\n\n const result = data as Result;\n\n // 7. Record the request for rate limiting\n if (this.stores.rateLimit && !alreadyRecordedRateLimit) {\n const rateLimit = this.stores.rateLimit as AdaptiveRateLimitStore;\n await rateLimit.record(resource, priority);\n }\n\n // 8. Cache the result\n if (this.stores.cache) {\n await this.stores.cache.set(hash, result, this.options.defaultCacheTTL);\n }\n\n // 9. Mark deduplication as complete\n if (this.stores.dedupe) {\n await this.stores.dedupe.complete(hash, result);\n }\n\n return result;\n } catch (error) {\n // Mark deduplication as failed\n if (this.stores.dedupe) {\n await this.stores.dedupe.fail(hash, error as Error);\n }\n\n // Allow callers to detect aborts distinctly – do not wrap AbortError.\n if (error instanceof Error && error.name === 'AbortError') {\n throw error;\n }\n\n // Already a processed error from the !response.ok branch above\n if (error instanceof HttpClientError) {\n throw error;\n }\n\n throw this.generateClientError(error);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/cache/cache-control-parser.ts","../src/cache/cache-entry.ts","../src/cache/freshness.ts","../src/cache/vary.ts","../src/errors/http-client-error.ts","../src/stores/rate-limit-store.ts","../src/stores/request-hasher.ts","../src/stores/rate-limit-config.ts","../src/stores/adaptive-capacity-calculator.ts","../src/http-client/http-client.ts"],"names":["baseUserCapacity","result"],"mappings":"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","file":"index.js","sourcesContent":["export interface CacheControlDirectives {\n maxAge?: number;\n sMaxAge?: number;\n noCache: boolean;\n noStore: boolean;\n mustRevalidate: boolean;\n proxyRevalidate: boolean;\n public: boolean;\n private: boolean;\n immutable: boolean;\n staleWhileRevalidate?: number;\n staleIfError?: number;\n}\n\nconst EMPTY_DIRECTIVES: CacheControlDirectives = {\n noCache: false,\n noStore: false,\n mustRevalidate: false,\n proxyRevalidate: false,\n public: false,\n private: false,\n immutable: false,\n};\n\n/**\n * Parse a numeric directive value. Returns undefined for non-finite\n * or negative values so callers can safely treat undefined as \"absent\".\n */\nfunction parseSeconds(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined;\n const n = Number.parseInt(raw.trim(), 10);\n return Number.isFinite(n) && n >= 0 ? n : undefined;\n}\n\n/**\n * Parse a Cache-Control header value into structured directives.\n *\n * Lenient: unrecognised directives are silently ignored, malformed\n * numeric values result in undefined (treated as absent).\n */\nexport function parseCacheControl(\n header: string | null | undefined,\n): CacheControlDirectives {\n if (!header) return { ...EMPTY_DIRECTIVES };\n\n const result: CacheControlDirectives = { ...EMPTY_DIRECTIVES };\n\n for (const part of header.split(',')) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n\n const eqIdx = trimmed.indexOf('=');\n const key = (eqIdx === -1 ? trimmed : trimmed.slice(0, eqIdx))\n .trim()\n .toLowerCase();\n const value = eqIdx === -1 ? undefined : trimmed.slice(eqIdx + 1).trim();\n\n switch (key) {\n case 'max-age':\n result.maxAge = parseSeconds(value);\n break;\n case 's-maxage':\n result.sMaxAge = parseSeconds(value);\n break;\n case 'no-cache':\n result.noCache = true;\n break;\n case 'no-store':\n result.noStore = true;\n break;\n case 'must-revalidate':\n result.mustRevalidate = true;\n break;\n case 'proxy-revalidate':\n result.proxyRevalidate = true;\n break;\n case 'public':\n result.public = true;\n break;\n case 'private':\n result.private = true;\n break;\n case 'immutable':\n result.immutable = true;\n break;\n case 'stale-while-revalidate':\n result.staleWhileRevalidate = parseSeconds(value);\n break;\n case 'stale-if-error':\n result.staleIfError = parseSeconds(value);\n break;\n // Unknown directives silently ignored\n }\n }\n\n return result;\n}\n","import {\n parseCacheControl,\n type CacheControlDirectives,\n} from './cache-control-parser.js';\n\nexport interface CacheEntryMetadata {\n /** ETag response header, for If-None-Match conditional requests */\n etag?: string;\n /** Last-Modified response header, for If-Modified-Since conditional requests */\n lastModified?: string;\n /** Parsed Cache-Control directives */\n cacheControl: CacheControlDirectives;\n /**\n * Date response header as epoch ms.\n * Falls back to storedAt if the server didn't send Date.\n */\n responseDate: number;\n /** Epoch ms when this entry was written to the cache */\n storedAt: number;\n /** Value of the Age response header at receipt time (seconds) */\n ageHeader: number;\n /** Raw Vary header value (e.g. \"Accept, Accept-Encoding\") */\n varyHeaders?: string;\n /** Captured request header values for Vary matching */\n varyValues?: Record<string, string | undefined>;\n /** HTTP status code of the original response */\n statusCode: number;\n /**\n * Expires header as epoch ms. Used as freshness fallback\n * when Cache-Control max-age is absent.\n */\n expires?: number;\n}\n\nexport interface CacheEntry<T = unknown> {\n /** Discriminant field for the isCacheEntry type guard */\n __cacheEntry: true;\n /** The actual response value the caller requested */\n value: T;\n /** RFC 9111 metadata for freshness/revalidation decisions */\n metadata: CacheEntryMetadata;\n}\n\n/**\n * Type guard: distinguishes a CacheEntry envelope from a raw cached value.\n *\n * When respectCacheHeaders is enabled on a cache that previously stored raw\n * values, those old entries will fail this check and be treated as cache misses.\n */\nexport function isCacheEntry<T>(value: unknown): value is CacheEntry<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<string, unknown>).__cacheEntry === true &&\n 'value' in value &&\n 'metadata' in value\n );\n}\n\n/**\n * Parse an HTTP-date string (RFC 7231) into epoch ms.\n * Returns undefined if the value is missing or unparseable.\n *\n * Handles:\n * - IMF-fixdate: \"Sun, 06 Nov 1994 08:49:37 GMT\"\n * - RFC 850: \"Sunday, 06-Nov-94 08:49:37 GMT\"\n * - asctime: \"Sun Nov 6 08:49:37 1994\"\n * - \"0\" (treated as already-expired per Expires spec)\n */\nexport function parseHttpDate(\n value: string | null | undefined,\n): number | undefined {\n if (value === null || value === undefined) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n // Expires: 0 means \"already expired\" per RFC 9111 §5.3\n if (trimmed === '0') return 0;\n const ms = Date.parse(trimmed);\n return Number.isFinite(ms) ? ms : undefined;\n}\n\n/**\n * Create a CacheEntry from a response value and the HTTP response headers.\n *\n * Call this after response body parsing + transformation + validation,\n * right before storing in the cache.\n */\nexport function createCacheEntry<T>(\n value: T,\n headers: Headers,\n statusCode: number,\n): CacheEntry<T> {\n const now = Date.now();\n const dateMs = parseHttpDate(headers.get('date')) ?? now;\n const ageRaw = headers.get('age');\n const ageHeader =\n ageRaw !== null ? Number.parseInt(ageRaw.trim(), 10) || 0 : 0;\n\n return {\n __cacheEntry: true,\n value,\n metadata: {\n etag: headers.get('etag') ?? undefined,\n lastModified: headers.get('last-modified') ?? undefined,\n cacheControl: parseCacheControl(headers.get('cache-control')),\n responseDate: dateMs,\n storedAt: now,\n ageHeader,\n varyHeaders: headers.get('vary') ?? undefined,\n statusCode,\n expires: parseHttpDate(headers.get('expires')),\n },\n };\n}\n\n/**\n * Refresh a cache entry after receiving a 304 Not Modified response.\n *\n * Updates metadata from the 304 response headers while keeping the\n * existing cached value (body). Per RFC 9111 §4.3.4, the 304 response\n * headers replace the stored headers.\n */\nexport function refreshCacheEntry<T>(\n existing: CacheEntry<T>,\n newHeaders: Headers,\n): CacheEntry<T> {\n const now = Date.now();\n const dateMs = parseHttpDate(newHeaders.get('date')) ?? now;\n const ageRaw = newHeaders.get('age');\n const ageHeader =\n ageRaw !== null ? Number.parseInt(ageRaw.trim(), 10) || 0 : 0;\n\n // 304 can carry updated Cache-Control, ETag, Expires, Date, Vary.\n // Fields not present in the 304 keep their existing values.\n const newCacheControl = newHeaders.get('cache-control');\n const newEtag = newHeaders.get('etag');\n const newLastModified = newHeaders.get('last-modified');\n const newExpires = newHeaders.get('expires');\n const newVary = newHeaders.get('vary');\n\n return {\n __cacheEntry: true,\n value: existing.value,\n metadata: {\n ...existing.metadata,\n cacheControl: newCacheControl\n ? parseCacheControl(newCacheControl)\n : existing.metadata.cacheControl,\n etag: newEtag ?? existing.metadata.etag,\n lastModified: newLastModified ?? existing.metadata.lastModified,\n responseDate: dateMs,\n storedAt: now,\n ageHeader,\n expires:\n newExpires !== null\n ? parseHttpDate(newExpires)\n : existing.metadata.expires,\n varyHeaders: newVary ?? existing.metadata.varyHeaders,\n // statusCode stays the same (the original 200, not 304)\n },\n };\n}\n","import type { CacheEntryMetadata } from './cache-entry.js';\n\nexport type FreshnessStatus =\n | 'fresh'\n | 'stale'\n | 'must-revalidate'\n | 'stale-while-revalidate'\n | 'stale-if-error'\n | 'no-cache';\n\n/**\n * Calculate the freshness lifetime of a cache entry in seconds.\n *\n * Priority order for a private cache (RFC 9111 §4.2.2):\n * 1. max-age (s-maxage is ignored — shared-cache-only)\n * 2. Expires − Date\n * 3. Heuristic: 10% of (Date − Last-Modified)\n * 4. 0 (treat as immediately stale)\n */\nexport function calculateFreshnessLifetime(\n metadata: CacheEntryMetadata,\n): number {\n const { cacheControl } = metadata;\n\n // 1. max-age\n if (cacheControl.maxAge !== undefined) {\n return cacheControl.maxAge;\n }\n\n // 2. Expires − Date\n if (metadata.expires !== undefined) {\n // Expires: 0 means already expired\n if (metadata.expires === 0) return 0;\n const delta = (metadata.expires - metadata.responseDate) / 1000;\n return Math.max(0, delta);\n }\n\n // 3. Heuristic: 10% of (Date − Last-Modified)\n if (metadata.lastModified) {\n const lastModMs = Date.parse(metadata.lastModified);\n if (Number.isFinite(lastModMs)) {\n const age = (metadata.responseDate - lastModMs) / 1000;\n if (age > 0) {\n return Math.floor(age * 0.1);\n }\n }\n }\n\n // 4. No freshness info — treat as immediately stale\n return 0;\n}\n\n/**\n * Calculate the current age of a cache entry in seconds.\n *\n * Per RFC 9111 §4.2.3:\n * apparent_age = max(0, response_time − date_value)\n * corrected_age_value = age_value + response_delay\n * corrected_initial = max(apparent_age, corrected_age_value)\n * resident_time = now − response_time\n * current_age = corrected_initial + resident_time\n *\n * We approximate response_delay as 0 since we don't track request_time.\n * This is conservative (slightly underestimates age).\n */\nexport function calculateCurrentAge(\n metadata: CacheEntryMetadata,\n now?: number,\n): number {\n const currentTime = now ?? Date.now();\n const responseTime = metadata.storedAt; // closest proxy for response_time\n\n // apparent_age = max(0, response_time − date_value) in seconds\n const apparentAge = Math.max(\n 0,\n (responseTime - metadata.responseDate) / 1000,\n );\n\n // corrected_age_value = age_header + response_delay (response_delay ≈ 0)\n const correctedAgeValue = metadata.ageHeader;\n\n // corrected_initial_age = max(apparent_age, corrected_age_value)\n const correctedInitialAge = Math.max(apparentAge, correctedAgeValue);\n\n // resident_time = now − response_time (in seconds)\n const residentTime = (currentTime - responseTime) / 1000;\n\n return correctedInitialAge + residentTime;\n}\n\n/**\n * Determine the freshness status of a cache entry.\n *\n * Returns the most specific applicable status, used by HttpClient\n * to decide whether to serve from cache, revalidate, or re-fetch.\n */\nexport function getFreshnessStatus(\n metadata: CacheEntryMetadata,\n now?: number,\n): FreshnessStatus {\n const { cacheControl } = metadata;\n\n // no-cache: always revalidate, even if \"fresh\" by age\n if (cacheControl.noCache) {\n return 'no-cache';\n }\n\n const freshnessLifetime = calculateFreshnessLifetime(metadata);\n const currentAge = calculateCurrentAge(metadata, now);\n\n // Still fresh\n if (freshnessLifetime > currentAge) {\n return 'fresh';\n }\n\n // Stale. Determine which stale state applies.\n const staleness = currentAge - freshnessLifetime;\n\n // must-revalidate: cannot serve stale under any circumstances\n if (cacheControl.mustRevalidate) {\n return 'must-revalidate';\n }\n\n // stale-while-revalidate: can serve stale if within the SWR window\n if (\n cacheControl.staleWhileRevalidate !== undefined &&\n staleness <= cacheControl.staleWhileRevalidate\n ) {\n return 'stale-while-revalidate';\n }\n\n // stale-if-error: can serve stale on error if within the SIE window\n if (\n cacheControl.staleIfError !== undefined &&\n staleness <= cacheControl.staleIfError\n ) {\n return 'stale-if-error';\n }\n\n return 'stale';\n}\n\n/**\n * Calculate the TTL to pass to CacheStore.set().\n *\n * This must be long enough to cover the freshness lifetime PLUS any\n * stale-serving windows (SWR, SIE), so the entry remains available\n * in the store during those windows.\n *\n * Falls back to defaultTTL when no cache headers provide a lifetime.\n */\nexport function calculateStoreTTL(\n metadata: CacheEntryMetadata,\n defaultTTL: number,\n): number {\n const freshness = calculateFreshnessLifetime(metadata);\n\n // If no cache headers gave us a freshness lifetime, use the default\n if (freshness === 0 && metadata.cacheControl.maxAge === undefined) {\n // No explicit freshness info and heuristic returned 0.\n // Use defaultTTL so the entry doesn't expire immediately.\n return defaultTTL;\n }\n\n // Add stale-serving windows so the store doesn't evict entries\n // that are still serveable under SWR or SIE.\n const swrWindow = metadata.cacheControl.staleWhileRevalidate ?? 0;\n const sieWindow = metadata.cacheControl.staleIfError ?? 0;\n const staleWindow = Math.max(swrWindow, sieWindow);\n\n return freshness + staleWindow;\n}\n","/**\n * Parse a Vary header value into normalised (lowercased) header names.\n * Returns ['*'] for Vary: * (meaning the response varies on everything).\n */\nexport function parseVaryHeader(\n varyHeader: string | null | undefined,\n): Array<string> {\n if (!varyHeader) return [];\n const trimmed = varyHeader.trim();\n if (trimmed === '*') return ['*'];\n return trimmed\n .split(',')\n .map((f) => f.trim().toLowerCase())\n .filter(Boolean);\n}\n\n/**\n * Extract the values of Vary-listed headers from a request.\n * Stored alongside the cache entry so we can compare on lookup.\n */\nexport function captureVaryValues(\n varyFields: Array<string>,\n requestHeaders: Record<string, string | undefined>,\n): Record<string, string | undefined> {\n const values: Record<string, string | undefined> = {};\n for (const field of varyFields) {\n // Normalise to lowercase for matching\n const lower = field.toLowerCase();\n values[lower] = requestHeaders[lower] ?? requestHeaders[field];\n }\n return values;\n}\n\n/**\n * Check whether a cached entry's Vary values match the current request.\n *\n * Returns false if:\n * - Vary includes '*' (never matches — always revalidate)\n * - Any Vary-listed header has a different value in the current request\n */\nexport function varyMatches(\n cachedVaryValues: Record<string, string | undefined> | undefined,\n cachedVaryHeader: string | undefined,\n currentRequestHeaders: Record<string, string | undefined>,\n): boolean {\n if (!cachedVaryHeader) return true; // No Vary = always matches\n const fields = parseVaryHeader(cachedVaryHeader);\n if (fields.length === 0) return true;\n if (fields[0] === '*') return false; // Vary: * never matches\n\n if (!cachedVaryValues) return false; // Had Vary but no stored values — miss\n\n for (const field of fields) {\n const lower = field.toLowerCase();\n const cachedVal = cachedVaryValues[lower];\n const currentVal =\n currentRequestHeaders[lower] ?? currentRequestHeaders[field];\n if (cachedVal !== currentVal) return false;\n }\n return true;\n}\n","/**\n * Base error class for HTTP client errors.\n * Consumers can extend this for domain-specific error handling.\n */\nexport class HttpClientError extends Error {\n public readonly statusCode?: number;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = 'HttpClientError';\n this.statusCode = statusCode;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Priority level for API requests\n */\nexport type RequestPriority = 'user' | 'background';\n\n/**\n * Adaptive configuration schema with validation and defaults\n */\nexport const AdaptiveConfigSchema = z\n .object({\n monitoringWindowMs: z\n .number()\n .positive()\n .default(15 * 60 * 1000), // 15 minutes\n highActivityThreshold: z.number().min(0).default(10), // requests per window\n moderateActivityThreshold: z.number().min(0).default(3),\n recalculationIntervalMs: z.number().positive().default(30000), // 30 seconds\n sustainedInactivityThresholdMs: z\n .number()\n .positive()\n .default(30 * 60 * 1000), // 30 minutes\n backgroundPauseOnIncreasingTrend: z.boolean().default(true),\n maxUserScaling: z.number().positive().default(2.0), // don't exceed 2x capacity\n minUserReserved: z.number().min(0).default(5), // requests minimum\n })\n .refine(\n (data) => {\n return data.moderateActivityThreshold < data.highActivityThreshold;\n },\n {\n message:\n 'moderateActivityThreshold must be less than highActivityThreshold',\n },\n );\n\n/**\n * Configuration for adaptive rate limiting\n */\nexport type AdaptiveConfig = z.infer<typeof AdaptiveConfigSchema>;\n\n/**\n * Interface for rate limiting API requests per resource\n */\nexport interface RateLimitStore {\n /**\n * Atomically acquire capacity for a request if the implementation supports it.\n * When present and returning true, callers should treat the request as already\n * recorded for rate-limit accounting.\n */\n acquire?(resource: string): Promise<boolean>;\n\n /**\n * Check if a request to a resource can proceed based on rate limits\n * @param resource The resource name (e.g., 'issues', 'characters')\n * @returns True if the request can proceed, false if rate limited\n */\n canProceed(resource: string): Promise<boolean>;\n\n /**\n * Record a request to a resource for rate limiting tracking\n * @param resource The resource name (e.g., 'issues', 'characters')\n */\n record(resource: string): Promise<void>;\n\n /**\n * Get the current rate limit status for a resource\n * @param resource The resource name\n * @returns Rate limit information including remaining requests and reset time\n */\n getStatus(resource: string): Promise<{\n remaining: number;\n resetTime: Date;\n limit: number;\n }>;\n\n /**\n * Reset rate limits for a resource (useful for testing)\n * @param resource The resource name\n */\n reset(resource: string): Promise<void>;\n\n /**\n * Get the time in milliseconds until the next request can be made\n * @param resource The resource name\n * @returns Milliseconds to wait, or 0 if no waiting is needed\n */\n getWaitTime(resource: string): Promise<number>;\n}\n\n/**\n * Enhanced interface for adaptive rate limiting stores with priority support\n */\nexport interface AdaptiveRateLimitStore extends RateLimitStore {\n /**\n * Atomically acquire capacity for a request if the implementation supports it.\n */\n acquire?(resource: string, priority?: RequestPriority): Promise<boolean>;\n\n /**\n * Check if a request to a resource can proceed based on rate limits\n * @param resource The resource name (e.g., 'issues', 'characters')\n * @param priority The priority level of the request (defaults to 'background')\n * @returns True if the request can proceed, false if rate limited\n */\n canProceed(resource: string, priority?: RequestPriority): Promise<boolean>;\n\n /**\n * Record a request to a resource for rate limiting tracking\n * @param resource The resource name (e.g., 'issues', 'characters')\n * @param priority The priority level of the request (defaults to 'background')\n */\n record(resource: string, priority?: RequestPriority): Promise<void>;\n\n /**\n * Get the current rate limit status for a resource\n * @param resource The resource name\n * @returns Rate limit information including remaining requests and reset time\n */\n getStatus(resource: string): Promise<{\n remaining: number;\n resetTime: Date;\n limit: number;\n adaptive?: {\n userReserved: number;\n backgroundMax: number;\n backgroundPaused: boolean;\n recentUserActivity: number;\n reason: string;\n };\n }>;\n\n /**\n * Get the time in milliseconds until the next request can be made\n * @param resource The resource name\n * @param priority The priority level of the request (defaults to 'background')\n * @returns Milliseconds to wait, or 0 if no waiting is needed\n */\n getWaitTime(resource: string, priority?: RequestPriority): Promise<number>;\n}\n","import { createHash } from 'crypto';\n\n/**\n * Creates a consistent hash for API requests to use as cache/dedupe keys\n * @param endpoint The API endpoint\n * @param params The request parameters\n * @returns A SHA-256 hash of the request\n */\nexport function hashRequest(\n endpoint: string,\n params: Record<string, unknown> = {},\n): string {\n const requestString = JSON.stringify({\n endpoint,\n params: sortObject(params),\n });\n\n return createHash('sha256').update(requestString).digest('hex');\n}\n\n/**\n * Normalises and sorts an object for hashing purposes.\n *\n * The ComicVine API transmits all query parameters as strings. To avoid cache\n * misses caused by treating `10` and `'10'` as different values we normalise\n * primitive types (number and boolean) to their string representation **before**\n * sorting. `undefined` values are intentionally kept as `undefined` so that\n * they are dropped by `JSON.stringify`, maintaining the existing behaviour\n * where an omitted parameter and an `undefined` parameter produce the same\n * hash.\n */\nfunction sortObject(obj: unknown): unknown {\n // Handle primitives first\n if (obj === null) {\n return null;\n }\n\n const objType = typeof obj;\n\n if (objType === 'undefined' || objType === 'string') {\n return obj;\n }\n\n if (objType === 'number' || objType === 'boolean') {\n // Convert to string so that 10 and '10' (or true and 'true') hash equally\n return String(obj);\n }\n\n // Recursively process arrays\n if (Array.isArray(obj)) {\n return obj.map(sortObject);\n }\n\n // For objects – sort keys and recurse\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj as Record<string, unknown>).sort();\n\n for (const key of keys) {\n const value = (obj as Record<string, unknown>)[key];\n const normalisedValue = sortObject(value);\n\n // Skip keys whose value normalises to undefined so omitted & undefined match\n if (normalisedValue !== undefined) {\n sorted[key] = normalisedValue;\n }\n }\n\n return sorted;\n}\n","/**\n * Configuration for per-resource rate limiting.\n *\n * This interface is shared by all store implementations (e.g. in-memory,\n * SQLite) so that callers can use a single canonical type.\n */\nexport interface RateLimitConfig {\n /** Number of requests allowed per time window */\n limit: number;\n /** Duration of the window in milliseconds */\n windowMs: number;\n}\n\n/**\n * Default rate-limit window: 60 requests per minute.\n *\n * Store implementations can reference this to avoid duplicating magic numbers.\n */\nexport const DEFAULT_RATE_LIMIT: RateLimitConfig = {\n limit: 60,\n windowMs: 60_000,\n};\n","import { z } from 'zod';\nimport { AdaptiveConfigSchema } from './rate-limit-store.js';\n\ninterface ActivityMetrics {\n recentUserRequests: Array<number>;\n recentBackgroundRequests: Array<number>;\n userActivityTrend: 'increasing' | 'stable' | 'decreasing' | 'none';\n}\n\ninterface DynamicCapacityResult {\n userReserved: number;\n backgroundMax: number;\n backgroundPaused: boolean;\n reason: string;\n}\n\n/**\n * Calculates dynamic capacity allocation based on real-time user activity patterns\n */\nexport class AdaptiveCapacityCalculator {\n public readonly config: z.infer<typeof AdaptiveConfigSchema>;\n\n constructor(config: Partial<z.input<typeof AdaptiveConfigSchema>> = {}) {\n // Zod handles validation and applies defaults automatically\n this.config = AdaptiveConfigSchema.parse(config);\n }\n\n calculateDynamicCapacity(\n resource: string,\n totalLimit: number,\n activityMetrics: ActivityMetrics,\n ): DynamicCapacityResult {\n const recentUserActivity = this.getRecentActivity(\n activityMetrics.recentUserRequests,\n );\n const activityTrend = this.calculateActivityTrend(\n activityMetrics.recentUserRequests,\n );\n\n // Strategy 1: High Activity - Pause Background\n if (recentUserActivity >= this.config.highActivityThreshold) {\n const userCapacity = Math.min(\n totalLimit * 0.9,\n Math.floor(totalLimit * 0.5 * this.config.maxUserScaling), // 50% base * scaling factor\n );\n\n return {\n userReserved: userCapacity,\n backgroundMax: totalLimit - userCapacity,\n backgroundPaused:\n this.config.backgroundPauseOnIncreasingTrend &&\n activityTrend === 'increasing',\n reason: `High user activity (${recentUserActivity} requests/${this.config.monitoringWindowMs / 60000}min) - prioritizing users`,\n };\n }\n\n // Strategy 2: Moderate Activity - Balanced Scaling\n if (recentUserActivity >= this.config.moderateActivityThreshold) {\n const userMultiplier = this.getUserMultiplier(\n recentUserActivity,\n activityTrend,\n );\n const baseUserCapacity = Math.floor(totalLimit * 0.4); // 40% base allocation\n const dynamicUserCapacity = Math.min(\n totalLimit * 0.7,\n baseUserCapacity * userMultiplier,\n );\n\n return {\n userReserved: dynamicUserCapacity,\n backgroundMax: totalLimit - dynamicUserCapacity,\n backgroundPaused: false,\n reason: `Moderate user activity - dynamic scaling (${userMultiplier.toFixed(1)}x user capacity)`,\n };\n }\n\n // Strategy 3: Low/No Activity - Background Scale Up\n if (recentUserActivity === 0) {\n // If there have never been any requests at all (fresh start), use default capacity allocation\n if (\n activityMetrics.recentUserRequests.length === 0 &&\n activityMetrics.recentBackgroundRequests.length === 0\n ) {\n const baseUserCapacity = Math.floor(totalLimit * 0.3); // 30% base for initial state\n return {\n userReserved: Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundMax:\n totalLimit -\n Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundPaused: false,\n reason: 'Initial state - default capacity allocation',\n };\n }\n\n // If there have never been user requests (only background), use background scale up\n if (activityMetrics.recentUserRequests.length === 0) {\n return {\n userReserved: this.config.minUserReserved, // Minimal safety buffer\n backgroundMax: totalLimit - this.config.minUserReserved,\n backgroundPaused: false,\n reason:\n 'No user activity yet - background scale up with minimal user buffer',\n };\n }\n\n // There have been user requests before, check for sustained inactivity\n const sustainedInactivity = this.getSustainedInactivityPeriod(\n activityMetrics.recentUserRequests,\n );\n\n if (sustainedInactivity > this.config.sustainedInactivityThresholdMs) {\n return {\n userReserved: 0, // No reservation - background gets everything!\n backgroundMax: totalLimit, // Full capacity available\n backgroundPaused: false,\n reason: `Sustained zero activity (${Math.floor(sustainedInactivity / 60000)}+ min) - full capacity to background`,\n };\n } else {\n return {\n userReserved: this.config.minUserReserved, // Minimal safety buffer\n backgroundMax: totalLimit - this.config.minUserReserved,\n backgroundPaused: false,\n reason:\n 'Recent zero activity - background scale up with minimal user buffer',\n };\n }\n }\n\n // Strategy 4: Very Low Activity - Gradual Background Scale Up\n const baseUserCapacity = Math.floor(totalLimit * 0.3); // 30% base for very low activity\n return {\n userReserved: Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundMax:\n totalLimit - Math.max(baseUserCapacity, this.config.minUserReserved),\n backgroundPaused: false,\n reason: `Low user activity (${recentUserActivity} requests/${this.config.monitoringWindowMs / 60000}min) - background scale up`,\n };\n }\n\n getRecentActivity(requests: Array<number>): number {\n const cutoff = Date.now() - this.config.monitoringWindowMs;\n return requests.filter((timestamp) => timestamp > cutoff).length;\n }\n\n calculateActivityTrend(\n requests: Array<number>,\n ): 'increasing' | 'stable' | 'decreasing' | 'none' {\n const now = Date.now();\n const windowSize = this.config.monitoringWindowMs / 3; // Use 1/3 of monitoring window for trend\n const recent = requests.filter((t) => t > now - windowSize).length;\n const previous = requests.filter(\n (t) => t > now - 2 * windowSize && t <= now - windowSize,\n ).length;\n\n if (recent === 0 && previous === 0) return 'none';\n if (recent > previous * 1.5) return 'increasing';\n if (recent < previous * 0.5) return 'decreasing';\n return 'stable';\n }\n\n private getUserMultiplier(activity: number, trend: string): number {\n let base = Math.min(\n this.config.maxUserScaling,\n 1 + activity / this.config.highActivityThreshold,\n );\n\n // Adjust based on trend\n if (trend === 'increasing') base *= 1.2;\n if (trend === 'decreasing') base *= 0.8;\n\n return Math.max(1.0, base);\n }\n\n private getSustainedInactivityPeriod(requests: Array<number>): number {\n if (requests.length === 0) {\n // This should not be called when there are no requests (handled above)\n return 0;\n }\n\n const lastRequest = Math.max(...requests);\n return Date.now() - lastRequest;\n }\n}\n\n// Export types for use in other modules\nexport type { ActivityMetrics, DynamicCapacityResult };\n","import {\n parseCacheControl,\n createCacheEntry,\n refreshCacheEntry,\n isCacheEntry,\n getFreshnessStatus,\n calculateStoreTTL,\n type CacheEntry,\n} from '../cache/index.js';\nimport { HttpClientError } from '../errors/http-client-error.js';\nimport {\n CacheStore,\n DedupeStore,\n RateLimitStore,\n AdaptiveRateLimitStore,\n RequestPriority,\n hashRequest,\n} from '../stores/index.js';\nimport { HttpClientContract } from '../types/index.js';\n\nconst DEFAULT_RATE_LIMIT_HEADER_NAMES = {\n retryAfter: ['retry-after'],\n limit: ['ratelimit-limit', 'x-ratelimit-limit', 'rate-limit-limit'],\n remaining: [\n 'ratelimit-remaining',\n 'x-ratelimit-remaining',\n 'rate-limit-remaining',\n ],\n reset: ['ratelimit-reset', 'x-ratelimit-reset', 'rate-limit-reset'],\n combined: ['ratelimit'],\n} as const;\n\n/**\n * Wait for a specified period while supporting cancellation via AbortSignal.\n *\n * If the signal is aborted before the timeout completes the promise rejects\n * with an `Error` whose name is set to `AbortError`, mimicking DOMException in\n * browser environments without depending on it. This allows callers to use a\n * single `AbortController` for both the rate-limit wait *and* the subsequent\n * HTTP request.\n */\nfunction wait(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n resolve();\n }, ms);\n\n function onAbort() {\n clearTimeout(timer);\n const err = new Error('Aborted');\n err.name = 'AbortError';\n reject(err);\n }\n\n if (signal) {\n if (signal.aborted) {\n onAbort();\n } else {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n }\n });\n}\n\nexport interface HttpClientStores {\n cache?: CacheStore;\n dedupe?: DedupeStore;\n rateLimit?: RateLimitStore | AdaptiveRateLimitStore;\n}\n\nexport interface HttpClientOptions {\n /**\n * Default cache TTL in seconds\n */\n defaultCacheTTL?: number;\n /**\n * Whether to throw errors on rate limit violations\n */\n throwOnRateLimit?: boolean;\n /**\n * Maximum time to wait for rate limit in milliseconds\n */\n maxWaitTime?: number;\n /**\n * Optional response transformer applied to the raw response data.\n * Use this for converting snake_case to camelCase, etc.\n */\n responseTransformer?: (data: unknown) => unknown;\n /**\n * Optional error handler to convert errors into domain-specific error types.\n * If not provided, a generic HttpClientError is thrown.\n */\n errorHandler?: (error: unknown) => Error;\n /**\n * Optional response validator/handler called after transformation.\n * Use this to inspect the response and throw domain-specific errors\n * based on response content (e.g., API-level error codes).\n */\n responseHandler?: (data: unknown) => unknown;\n /**\n * Configure rate-limit response header names for standards and custom APIs.\n */\n rateLimitHeaders?: {\n retryAfter?: Array<string>;\n limit?: Array<string>;\n remaining?: Array<string>;\n reset?: Array<string>;\n combined?: Array<string>;\n };\n /**\n * When true, the client respects HTTP cache headers (Cache-Control, ETag,\n * Last-Modified, Expires) per RFC 9111. When false (default), caching uses\n * only the static defaultCacheTTL.\n */\n respectCacheHeaders?: boolean;\n /**\n * Override specific cache header behaviors. Only applies when\n * respectCacheHeaders is true.\n */\n cacheHeaderOverrides?: {\n /** Cache responses even when Cache-Control: no-store is set */\n ignoreNoStore?: boolean;\n /** Skip revalidation even when Cache-Control: no-cache is set */\n ignoreNoCache?: boolean;\n /** Minimum TTL in seconds — floor on header-derived freshness */\n minimumTTL?: number;\n /** Maximum TTL in seconds — cap on header-derived freshness */\n maximumTTL?: number;\n };\n}\n\ninterface RateLimitHeaderConfig {\n retryAfter: Array<string>;\n limit: Array<string>;\n remaining: Array<string>;\n reset: Array<string>;\n combined: Array<string>;\n}\n\ninterface ParsedResponseBody {\n data: unknown;\n}\n\ntype ErrorWithResponse = {\n message: string;\n response: {\n status: number;\n data: unknown;\n headers: Headers;\n };\n};\n\nexport class HttpClient implements HttpClientContract {\n private stores: HttpClientStores;\n private serverCooldowns = new Map<string, number>();\n private pendingRevalidations: Array<Promise<void>> = [];\n private options: Required<\n Pick<\n HttpClientOptions,\n | 'defaultCacheTTL'\n | 'throwOnRateLimit'\n | 'maxWaitTime'\n | 'respectCacheHeaders'\n >\n > &\n Pick<\n HttpClientOptions,\n | 'responseTransformer'\n | 'errorHandler'\n | 'responseHandler'\n | 'cacheHeaderOverrides'\n > & {\n rateLimitHeaders: RateLimitHeaderConfig;\n };\n\n constructor(stores: HttpClientStores = {}, options: HttpClientOptions = {}) {\n this.stores = stores;\n this.options = {\n defaultCacheTTL: options.defaultCacheTTL ?? 3600,\n throwOnRateLimit: options.throwOnRateLimit ?? true,\n maxWaitTime: options.maxWaitTime ?? 60000,\n respectCacheHeaders: options.respectCacheHeaders ?? false,\n responseTransformer: options.responseTransformer,\n errorHandler: options.errorHandler,\n responseHandler: options.responseHandler,\n cacheHeaderOverrides: options.cacheHeaderOverrides,\n rateLimitHeaders: this.normalizeRateLimitHeaders(\n options.rateLimitHeaders,\n ),\n };\n }\n\n private normalizeRateLimitHeaders(\n customHeaders?: HttpClientOptions['rateLimitHeaders'],\n ): RateLimitHeaderConfig {\n return {\n retryAfter: this.normalizeHeaderNames(\n customHeaders?.retryAfter,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.retryAfter,\n ),\n limit: this.normalizeHeaderNames(\n customHeaders?.limit,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.limit,\n ),\n remaining: this.normalizeHeaderNames(\n customHeaders?.remaining,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.remaining,\n ),\n reset: this.normalizeHeaderNames(\n customHeaders?.reset,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.reset,\n ),\n combined: this.normalizeHeaderNames(\n customHeaders?.combined,\n DEFAULT_RATE_LIMIT_HEADER_NAMES.combined,\n ),\n };\n }\n\n private normalizeHeaderNames(\n providedNames: Array<string> | undefined,\n defaultNames: ReadonlyArray<string>,\n ): Array<string> {\n if (!providedNames || providedNames.length === 0) {\n return [...defaultNames];\n }\n\n const customNames = providedNames\n .map((name) => name.trim().toLowerCase())\n .filter(Boolean);\n\n if (customNames.length === 0) {\n return [...defaultNames];\n }\n\n return [...new Set([...customNames, ...defaultNames])];\n }\n\n /**\n * Infer the resource name from the endpoint URL\n * @param url The full URL or endpoint path\n * @returns The resource name for rate limiting\n */\n private inferResource(url: string): string {\n try {\n const urlObj = new URL(url);\n // Use the first meaningful path segment as the resource name\n const segments = urlObj.pathname.split('/').filter(Boolean);\n return segments[segments.length - 1] || 'unknown';\n } catch {\n return 'unknown';\n }\n }\n\n /**\n * Extract endpoint and params from URL for request hashing\n * @param url The full URL\n * @returns Object with endpoint and params for hashing\n */\n private parseUrlForHashing(url: string): {\n endpoint: string;\n params: Record<string, unknown>;\n } {\n const urlObj = new URL(url);\n const endpoint = `${urlObj.origin}${urlObj.pathname}`;\n const params: Record<string, unknown> = {};\n\n urlObj.searchParams.forEach((value, key) => {\n const existing = params[key];\n\n // Keep repeated query keys as arrays so semantically distinct URLs like\n // `?tag=a&tag=b` and `?tag=b` do not hash to the same cache/dedupe key.\n if (existing === undefined) {\n params[key] = value;\n return;\n }\n\n if (Array.isArray(existing)) {\n existing.push(value);\n return;\n }\n\n params[key] = [existing, value];\n });\n\n return { endpoint, params };\n }\n\n private getOriginScope(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return 'unknown';\n }\n }\n\n private getHeaderValue(\n headers: Headers | Record<string, unknown> | undefined,\n names: Array<string>,\n ): string | undefined {\n if (!headers) {\n return undefined;\n }\n\n if (headers instanceof Headers) {\n for (const rawName of names) {\n const value = headers.get(rawName);\n if (value !== null) {\n return value;\n }\n }\n return undefined;\n }\n\n for (const rawName of names) {\n const name = rawName.toLowerCase();\n const value = headers[name] ?? headers[rawName];\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (Array.isArray(value) && value.length > 0) {\n const first = value.find((entry) => typeof entry === 'string');\n if (typeof first === 'string') {\n return first;\n }\n }\n }\n\n return undefined;\n }\n\n private parseIntegerHeader(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const parsed = Number.parseInt(value.trim(), 10);\n if (!Number.isFinite(parsed) || parsed < 0) {\n return undefined;\n }\n\n return parsed;\n }\n\n private parseRetryAfterMs(value: string | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const numeric = Number.parseInt(value.trim(), 10);\n if (Number.isFinite(numeric) && numeric >= 0) {\n return numeric * 1000;\n }\n\n const dateMs = Date.parse(value);\n if (!Number.isFinite(dateMs)) {\n return undefined;\n }\n\n return Math.max(0, dateMs - Date.now());\n }\n\n private parseResetMs(value: string | undefined): number | undefined {\n const parsed = this.parseIntegerHeader(value);\n if (parsed === undefined) {\n return undefined;\n }\n\n if (parsed === 0) {\n return 0;\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n\n if (parsed > nowSeconds + 1) {\n return Math.max(0, (parsed - nowSeconds) * 1000);\n }\n\n return parsed * 1000;\n }\n\n private parseCombinedRateLimitHeader(value: string | undefined): {\n remaining?: number;\n resetMs?: number;\n } {\n if (!value) {\n return {};\n }\n\n const remainingMatch = value.match(/(?:^|[;,])\\s*r\\s*=\\s*(\\d+)/i);\n const resetMatch = value.match(/(?:^|[;,])\\s*t\\s*=\\s*(\\d+)/i);\n\n return {\n remaining: remainingMatch\n ? this.parseIntegerHeader(remainingMatch[1])\n : undefined,\n resetMs: resetMatch ? this.parseResetMs(resetMatch[1]) : undefined,\n };\n }\n\n private applyServerRateLimitHints(\n url: string,\n headers: Headers | Record<string, unknown> | undefined,\n statusCode?: number,\n ): void {\n if (!headers) {\n return;\n }\n\n const config = this.options.rateLimitHeaders;\n const retryAfterRaw = this.getHeaderValue(headers, config.retryAfter);\n const resetRaw = this.getHeaderValue(headers, config.reset);\n const remainingRaw = this.getHeaderValue(headers, config.remaining);\n const combinedRaw = this.getHeaderValue(headers, config.combined);\n\n const retryAfterMs = this.parseRetryAfterMs(retryAfterRaw);\n const resetMs = this.parseResetMs(resetRaw);\n const remaining = this.parseIntegerHeader(remainingRaw);\n const combined = this.parseCombinedRateLimitHeader(combinedRaw);\n\n const effectiveRemaining = remaining ?? combined.remaining;\n const effectiveResetMs = resetMs ?? combined.resetMs;\n const hasRateLimitErrorStatus = statusCode === 429 || statusCode === 503;\n\n let waitMs: number | undefined;\n\n if (retryAfterMs !== undefined) {\n waitMs = retryAfterMs;\n } else if (\n effectiveResetMs !== undefined &&\n (hasRateLimitErrorStatus ||\n (effectiveRemaining !== undefined && effectiveRemaining <= 0))\n ) {\n waitMs = effectiveResetMs;\n }\n\n if (waitMs === undefined || waitMs <= 0) {\n return;\n }\n\n const scope = this.getOriginScope(url);\n this.serverCooldowns.set(scope, Date.now() + waitMs);\n }\n\n private async enforceServerCooldown(\n url: string,\n signal?: AbortSignal,\n ): Promise<void> {\n const scope = this.getOriginScope(url);\n const startedAt = Date.now();\n\n // Re-check cooldown after each sleep so we never proceed while a server\n // cooldown is still active. This avoids bypassing limits when cooldown\n // duration is longer than maxWaitTime.\n while (true) {\n const cooldownUntil = this.serverCooldowns.get(scope);\n if (!cooldownUntil) {\n return;\n }\n\n const waitMs = cooldownUntil - Date.now();\n if (waitMs <= 0) {\n this.serverCooldowns.delete(scope);\n return;\n }\n\n if (this.options.throwOnRateLimit) {\n throw new Error(\n `Rate limit exceeded for origin '${scope}'. Wait ${waitMs}ms before retrying.`,\n );\n }\n\n const elapsedMs = Date.now() - startedAt;\n const remainingWaitBudgetMs = this.options.maxWaitTime - elapsedMs;\n\n if (remainingWaitBudgetMs <= 0) {\n throw new Error(\n `Rate limit wait exceeded maxWaitTime (${this.options.maxWaitTime}ms) for origin '${scope}'.`,\n );\n }\n\n await wait(Math.min(waitMs, remainingWaitBudgetMs), signal);\n }\n }\n\n private async enforceStoreRateLimit(\n resource: string,\n priority: RequestPriority,\n signal?: AbortSignal,\n ): Promise<boolean> {\n const rateLimit = this.stores.rateLimit as AdaptiveRateLimitStore;\n const startedAt = Date.now();\n const hasAtomicAcquire = typeof rateLimit.acquire === 'function';\n\n const canProceedNow = async (): Promise<boolean> => {\n if (hasAtomicAcquire) {\n return rateLimit.acquire!(resource, priority);\n }\n return rateLimit.canProceed(resource, priority);\n };\n\n if (this.options.throwOnRateLimit) {\n const canProceed = await canProceedNow();\n if (!canProceed) {\n const waitTime = await rateLimit.getWaitTime(resource, priority);\n throw new Error(\n `Rate limit exceeded for resource '${resource}'. Wait ${waitTime}ms before retrying.`,\n );\n }\n return hasAtomicAcquire;\n }\n\n // Keep polling + waiting until the store explicitly allows the request or\n // we exhaust maxWaitTime. A single one-off sleep can otherwise let a request\n // through while still over limit.\n while (!(await canProceedNow())) {\n const suggestedWaitMs = await rateLimit.getWaitTime(resource, priority);\n const elapsedMs = Date.now() - startedAt;\n const remainingWaitBudgetMs = this.options.maxWaitTime - elapsedMs;\n\n if (remainingWaitBudgetMs <= 0) {\n throw new Error(\n `Rate limit wait exceeded maxWaitTime (${this.options.maxWaitTime}ms) for resource '${resource}'.`,\n );\n }\n\n // If a store reports \"blocked\" but no wait time, use a tiny backoff to\n // avoid a tight CPU loop while still converging quickly.\n const waitTime =\n suggestedWaitMs > 0\n ? Math.min(suggestedWaitMs, remainingWaitBudgetMs)\n : Math.min(25, remainingWaitBudgetMs);\n\n await wait(waitTime, signal);\n }\n\n return hasAtomicAcquire;\n }\n\n /**\n * Wait for all pending background revalidations to complete.\n * Primarily useful in tests to avoid dangling promises.\n */\n async flushRevalidations(): Promise<void> {\n await Promise.allSettled(this.pendingRevalidations);\n this.pendingRevalidations = [];\n }\n\n private async backgroundRevalidate(\n url: string,\n hash: string,\n entry: CacheEntry<unknown>,\n ): Promise<void> {\n const headers = new Headers();\n if (entry.metadata.etag) {\n headers.set('If-None-Match', entry.metadata.etag);\n }\n if (entry.metadata.lastModified) {\n headers.set('If-Modified-Since', entry.metadata.lastModified);\n }\n\n try {\n const response = await fetch(url, { headers });\n this.applyServerRateLimitHints(url, response.headers, response.status);\n\n if (response.status === 304) {\n const refreshed = refreshCacheEntry(entry, response.headers);\n const ttl = this.clampTTL(\n calculateStoreTTL(refreshed.metadata, this.options.defaultCacheTTL),\n );\n await this.stores.cache?.set(hash, refreshed, ttl);\n return;\n }\n\n if (response.ok) {\n const parsedBody = await this.parseResponseBody(response);\n let data: unknown = parsedBody.data;\n if (this.options.responseTransformer && data) {\n data = this.options.responseTransformer(data);\n }\n if (this.options.responseHandler) {\n data = this.options.responseHandler(data);\n }\n const newEntry = createCacheEntry(\n data,\n response.headers,\n response.status,\n );\n const ttl = this.clampTTL(\n calculateStoreTTL(newEntry.metadata, this.options.defaultCacheTTL),\n );\n await this.stores.cache?.set(hash, newEntry, ttl);\n }\n } catch {\n // Background revalidation failures are silently ignored.\n // The stale entry remains in the cache and will be served until\n // it falls out of the stale-while-revalidate window.\n }\n }\n\n private clampTTL(ttl: number): number {\n const overrides = this.options.cacheHeaderOverrides;\n if (!overrides) return ttl;\n let clamped = ttl;\n if (overrides.minimumTTL !== undefined) {\n clamped = Math.max(clamped, overrides.minimumTTL);\n }\n if (overrides.maximumTTL !== undefined) {\n clamped = Math.min(clamped, overrides.maximumTTL);\n }\n return clamped;\n }\n\n private isServerErrorOrNetworkFailure(error: unknown): boolean {\n if (typeof error === 'object' && error !== null && 'response' in error) {\n const status = (error as ErrorWithResponse).response?.status;\n if (typeof status === 'number' && status >= 500) return true;\n }\n if (error instanceof TypeError) return true;\n return false;\n }\n\n private generateClientError(err: unknown): Error {\n // If a custom error handler is provided, use it\n if (this.options.errorHandler) {\n return this.options.errorHandler(err);\n }\n\n if (err instanceof HttpClientError) {\n return err;\n }\n\n const responseError = err as Partial<ErrorWithResponse>;\n const statusCode =\n typeof responseError.response?.status === 'number'\n ? responseError.response.status\n : undefined;\n\n const responseData = responseError.response?.data;\n const derivedResponseMessage =\n typeof responseData === 'object' && responseData !== null\n ? (responseData as { message?: unknown }).message\n : undefined;\n const responseMessage =\n typeof derivedResponseMessage === 'string'\n ? derivedResponseMessage\n : undefined;\n\n const errorMessage =\n err instanceof Error\n ? err.message\n : typeof (err as { message?: unknown }).message === 'string'\n ? (err as { message: string }).message\n : 'Unknown error';\n const message = `${errorMessage}${responseMessage ? `, ${responseMessage}` : ''}`;\n\n return new HttpClientError(message, statusCode);\n }\n\n private async parseResponseBody(\n response: Response,\n ): Promise<ParsedResponseBody> {\n if (response.status === 204 || response.status === 205) {\n return { data: undefined };\n }\n\n const rawBody = await response.text();\n if (!rawBody) {\n return { data: undefined };\n }\n\n const contentType =\n response.headers.get('content-type')?.toLowerCase() ?? '';\n const shouldAttemptJsonParsing =\n contentType.includes('application/json') ||\n contentType.includes('+json') ||\n rawBody.trimStart().startsWith('{') ||\n rawBody.trimStart().startsWith('[');\n\n if (!shouldAttemptJsonParsing) {\n return { data: rawBody };\n }\n\n try {\n const parsed = JSON.parse(rawBody) as unknown;\n if (typeof parsed === 'object' && parsed !== null) {\n return { data: parsed };\n }\n\n return { data: parsed };\n } catch {\n return { data: rawBody };\n }\n }\n\n async get<Result>(\n url: string,\n options: { signal?: AbortSignal; priority?: RequestPriority } = {},\n ): Promise<Result> {\n const { signal, priority = 'background' } = options;\n const { endpoint, params } = this.parseUrlForHashing(url);\n const hash = hashRequest(endpoint, params);\n const resource = this.inferResource(url);\n\n // Track stale entry for conditional requests and stale-if-error fallback\n let staleEntry: CacheEntry<unknown> | undefined;\n let staleCandidate: CacheEntry<unknown> | undefined;\n\n try {\n await this.enforceServerCooldown(url, signal);\n\n // 1. Cache — check for cached response\n if (this.stores.cache) {\n const cachedResult = await this.stores.cache.get(hash);\n\n if (cachedResult !== undefined) {\n // RFC 9111 cache header path\n if (this.options.respectCacheHeaders && isCacheEntry(cachedResult)) {\n const entry = cachedResult as CacheEntry<unknown>;\n const status = getFreshnessStatus(entry.metadata);\n\n switch (status) {\n case 'fresh':\n return entry.value as Result;\n\n case 'no-cache':\n if (this.options.cacheHeaderOverrides?.ignoreNoCache) {\n return entry.value as Result;\n }\n staleEntry = entry;\n break;\n\n case 'must-revalidate':\n staleEntry = entry;\n break;\n\n case 'stale-while-revalidate': {\n // Serve stale immediately, revalidate in background\n const revalidation = this.backgroundRevalidate(\n url,\n hash,\n entry,\n );\n this.pendingRevalidations.push(revalidation);\n // Cleanup resolved promises periodically\n revalidation.finally(() => {\n this.pendingRevalidations = this.pendingRevalidations.filter(\n (p) => p !== revalidation,\n );\n });\n return entry.value as Result;\n }\n\n case 'stale-if-error':\n // Attempt fresh fetch, fall back to stale on error\n staleCandidate = entry;\n staleEntry = entry; // Also use for conditional request\n break;\n\n case 'stale':\n staleEntry = entry;\n break;\n }\n } else if (!this.options.respectCacheHeaders) {\n // Original behavior: raw value, no envelope\n return cachedResult as Result;\n }\n // else: respectCacheHeaders is on but value is a legacy raw entry.\n // Treat as cache miss — re-fetch and store in new envelope format.\n }\n }\n\n // 2. Deduplication — check for in-progress request\n if (this.stores.dedupe) {\n const existingResult = await this.stores.dedupe.waitFor(hash);\n if (existingResult !== undefined) {\n return existingResult as Result;\n }\n\n if (this.stores.dedupe.registerOrJoin) {\n const registration = await this.stores.dedupe.registerOrJoin(hash);\n\n if (!registration.isOwner) {\n const joinedResult = await this.stores.dedupe.waitFor(hash);\n if (joinedResult !== undefined) {\n return joinedResult as Result;\n }\n }\n } else {\n await this.stores.dedupe.register(hash);\n }\n }\n\n // 3. Rate limiting — check if request can proceed\n let alreadyRecordedRateLimit = false;\n if (this.stores.rateLimit) {\n alreadyRecordedRateLimit = await this.enforceStoreRateLimit(\n resource,\n priority,\n signal,\n );\n }\n\n // 4. Execute the actual HTTP request\n // Build conditional headers when we have a stale entry\n const fetchInit: RequestInit = { signal };\n if (this.options.respectCacheHeaders && staleEntry) {\n const conditionalHeaders = new Headers();\n if (staleEntry.metadata.etag) {\n conditionalHeaders.set('If-None-Match', staleEntry.metadata.etag);\n }\n if (staleEntry.metadata.lastModified) {\n conditionalHeaders.set(\n 'If-Modified-Since',\n staleEntry.metadata.lastModified,\n );\n }\n // Only add headers if we actually have validators\n if ([...conditionalHeaders].length > 0) {\n fetchInit.headers = conditionalHeaders;\n }\n }\n\n const response = await fetch(url, fetchInit);\n this.applyServerRateLimitHints(url, response.headers, response.status);\n\n // Handle 304 Not Modified — must be checked BEFORE !response.ok\n if (\n this.options.respectCacheHeaders &&\n response.status === 304 &&\n staleEntry\n ) {\n const refreshed = refreshCacheEntry(staleEntry, response.headers);\n const ttl = this.clampTTL(\n calculateStoreTTL(refreshed.metadata, this.options.defaultCacheTTL),\n );\n\n if (this.stores.cache) {\n await this.stores.cache.set(hash, refreshed, ttl);\n }\n\n const result = refreshed.value as Result;\n\n if (this.stores.dedupe) {\n await this.stores.dedupe.complete(hash, result);\n }\n\n return result;\n }\n\n const parsedBody = await this.parseResponseBody(response);\n\n if (!response.ok) {\n const error: ErrorWithResponse = {\n message: `Request failed with status ${response.status}`,\n response: {\n status: response.status,\n data: parsedBody.data,\n headers: response.headers,\n },\n };\n throw error;\n }\n\n // 5. Apply response transformer if provided\n let data: unknown = parsedBody.data;\n if (this.options.responseTransformer && data) {\n data = this.options.responseTransformer(data);\n }\n\n // 6. Apply response handler if provided (for domain-specific validation)\n if (this.options.responseHandler) {\n data = this.options.responseHandler(data);\n }\n\n const result = data as Result;\n\n // 7. Record the request for rate limiting\n if (this.stores.rateLimit && !alreadyRecordedRateLimit) {\n const rateLimit = this.stores.rateLimit as AdaptiveRateLimitStore;\n await rateLimit.record(resource, priority);\n }\n\n // 8. Cache the result\n if (this.stores.cache) {\n if (this.options.respectCacheHeaders) {\n // RFC 9111 cache storage path\n const cc = parseCacheControl(response.headers.get('cache-control'));\n const shouldStore =\n !cc.noStore || this.options.cacheHeaderOverrides?.ignoreNoStore;\n\n if (shouldStore) {\n const entry = createCacheEntry(\n result,\n response.headers,\n response.status,\n );\n const ttl = this.clampTTL(\n calculateStoreTTL(entry.metadata, this.options.defaultCacheTTL),\n );\n await this.stores.cache.set(hash, entry, ttl);\n }\n } else {\n // Original behavior\n await this.stores.cache.set(\n hash,\n result,\n this.options.defaultCacheTTL,\n );\n }\n }\n\n // 9. Mark deduplication as complete\n if (this.stores.dedupe) {\n await this.stores.dedupe.complete(hash, result);\n }\n\n return result;\n } catch (error) {\n // stale-if-error fallback: serve stale entry when origin fails\n if (\n this.options.respectCacheHeaders &&\n staleCandidate &&\n this.isServerErrorOrNetworkFailure(error)\n ) {\n const result = staleCandidate.value as Result;\n\n if (this.stores.dedupe) {\n await this.stores.dedupe.complete(hash, result);\n }\n\n return result;\n }\n\n // Mark deduplication as failed\n if (this.stores.dedupe) {\n await this.stores.dedupe.fail(hash, error as Error);\n }\n\n // Allow callers to detect aborts distinctly – do not wrap AbortError.\n if (error instanceof Error && error.name === 'AbortError') {\n throw error;\n }\n\n // Already a processed error from the !response.ok branch above\n if (error instanceof HttpClientError) {\n throw error;\n }\n\n throw this.generateClientError(error);\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"tsup": "8.5.0",
|
|
18
18
|
"typescript": "5.8.3",
|
|
19
19
|
"vitest": "^3.2.4",
|
|
20
|
-
"@repo/tsup-config": "0.0.1",
|
|
21
20
|
"@repo/eslint-config": "0.0.1",
|
|
21
|
+
"@repo/tsup-config": "0.0.1",
|
|
22
22
|
"@repo/vitest-config": "0.0.1"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"lib/**"
|
|
42
42
|
],
|
|
43
43
|
"homepage": "https://github.com/AllyMurray/http-client-toolkit#readme",
|
|
44
|
-
"version": "0.
|
|
44
|
+
"version": "0.2.0",
|
|
45
45
|
"bugs": {
|
|
46
46
|
"url": "https://github.com/AllyMurray/http-client-toolkit/issues"
|
|
47
47
|
},
|