@http-client-toolkit/core 0.0.1

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.
@@ -0,0 +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 * 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 * 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 axios, { AxiosError } from 'axios';\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\ninterface RateLimitHeaderConfig {\n retryAfter: Array<string>;\n limit: Array<string>;\n remaining: Array<string>;\n reset: Array<string>;\n combined: Array<string>;\n}\n\nexport class HttpClient implements HttpClientContract {\n private _http;\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._http = axios.create();\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: Record<string, unknown> | undefined,\n names: Array<string>,\n ): string | undefined {\n if (!headers) {\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: 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<void> {\n const rateLimit = this.stores.rateLimit as AdaptiveRateLimitStore;\n const startedAt = Date.now();\n\n if (this.options.throwOnRateLimit) {\n const canProceed = await rateLimit.canProceed(resource, priority);\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;\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 rateLimit.canProceed(resource, priority))) {\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\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 error = err as AxiosError<{ message?: string }>;\n const statusCode = error.response?.status;\n const errorMessage = error.response?.data?.message;\n const message = `${error.message}${errorMessage ? `, ${errorMessage}` : ''}`;\n\n return new HttpClientError(message, statusCode);\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 if (this.stores.rateLimit) {\n await this.enforceStoreRateLimit(resource, priority, signal);\n }\n\n // 4. Execute the actual HTTP request\n const response = await this._http.get(url, { signal });\n this.applyServerRateLimitHints(\n url,\n response.headers as Record<string, unknown>,\n response.status,\n );\n\n // 5. Apply response transformer if provided\n let data = response.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) {\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 const axiosError = error as AxiosError;\n if (axiosError.response) {\n this.applyServerRateLimitHints(\n url,\n axiosError.response.headers as Record<string, unknown>,\n axiosError.response.status,\n );\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 throw this.generateClientError(error);\n }\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@http-client-toolkit/core",
3
+ "description": "Core HTTP client with pluggable caching, deduplication, and rate limiting",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/AllyMurray/http-client-toolkit.git"
7
+ },
8
+ "author": {
9
+ "name": "Ally Murray",
10
+ "email": "allymurray88@gmail.com",
11
+ "organization": false
12
+ },
13
+ "devDependencies": {
14
+ "@types/node": "20",
15
+ "eslint": "^9.39.0",
16
+ "nock": "14.0.5",
17
+ "tsup": "8.5.0",
18
+ "typescript": "5.8.3",
19
+ "vitest": "^3.2.4",
20
+ "@repo/tsup-config": "0.0.1",
21
+ "@repo/eslint-config": "0.0.1",
22
+ "@repo/vitest-config": "0.0.1"
23
+ },
24
+ "dependencies": {
25
+ "axios": "1.13.5",
26
+ "zod": "3.25.71"
27
+ },
28
+ "keywords": [
29
+ "http-client",
30
+ "caching",
31
+ "deduplication",
32
+ "rate-limiting",
33
+ "http-toolkit"
34
+ ],
35
+ "engines": {
36
+ "node": ">= 20.0.0"
37
+ },
38
+ "main": "./lib/index.cjs",
39
+ "license": "ISC",
40
+ "sideEffects": false,
41
+ "files": [
42
+ "lib/**"
43
+ ],
44
+ "homepage": "https://github.com/AllyMurray/http-client-toolkit#readme",
45
+ "version": "0.0.1",
46
+ "bugs": {
47
+ "url": "https://github.com/AllyMurray/http-client-toolkit/issues"
48
+ },
49
+ "types": "./lib/index.d.ts",
50
+ "type": "module",
51
+ "module": "./lib/index.js",
52
+ "exports": {
53
+ ".": {
54
+ "import": {
55
+ "types": "./lib/index.d.ts",
56
+ "default": "./lib/index.js"
57
+ },
58
+ "require": {
59
+ "types": "./lib/index.d.cts",
60
+ "default": "./lib/index.cjs"
61
+ }
62
+ }
63
+ },
64
+ "publishConfig": {
65
+ "access": "public"
66
+ },
67
+ "scripts": {
68
+ "build": "tsup && npm run test",
69
+ "lint": "eslint --fix src && prettier --write .",
70
+ "test": "vitest run --dir=src",
71
+ "test:coverage": "vitest run --dir=src --coverage",
72
+ "test:watch": "vitest --dir=src",
73
+ "dev": "tsup --watch",
74
+ "clean": "rimraf lib dist node_modules .turbo"
75
+ }
76
+ }