apx-toolkit
Version:
Automatically discover APIs and generate complete integration packages: code in 12 languages, TypeScript types, test suites, SDK packages, API documentation, mock servers, performance reports, and contract tests. Saves 2-4 weeks of work in seconds.
143 lines • 4.21 kB
JavaScript
/**
* Rate Limit Detector
* Automatically detects rate limiting information from API responses
* Makes the tool a developer's dream by providing rate limit awareness
*/
/**
* Detects rate limiting information from response headers
*/
export function detectRateLimits(response) {
const headers = response.headers();
const rateLimitInfo = {};
// Common rate limit header patterns
const headerPatterns = {
limit: [
'x-ratelimit-limit',
'x-rate-limit-limit',
'ratelimit-limit',
'rate-limit-limit',
],
remaining: [
'x-ratelimit-remaining',
'x-rate-limit-remaining',
'ratelimit-remaining',
'rate-limit-remaining',
],
reset: [
'x-ratelimit-reset',
'x-rate-limit-reset',
'ratelimit-reset',
'rate-limit-reset',
],
resetAfter: [
'x-ratelimit-reset-after',
'x-rate-limit-reset-after',
'retry-after',
],
retryAfter: [
'retry-after',
'x-retry-after',
],
};
// Check for limit
for (const pattern of headerPatterns.limit) {
const value = findHeader(headers, pattern);
if (value) {
const num = parseInt(value, 10);
if (!isNaN(num)) {
rateLimitInfo.limit = num;
break;
}
}
}
// Check for remaining
for (const pattern of headerPatterns.remaining) {
const value = findHeader(headers, pattern);
if (value) {
const num = parseInt(value, 10);
if (!isNaN(num)) {
rateLimitInfo.remaining = num;
break;
}
}
}
// Check for reset timestamp
for (const pattern of headerPatterns.reset) {
const value = findHeader(headers, pattern);
if (value) {
const num = parseInt(value, 10);
if (!isNaN(num)) {
rateLimitInfo.reset = num;
break;
}
}
}
// Check for reset after (seconds)
for (const pattern of headerPatterns.resetAfter) {
const value = findHeader(headers, pattern);
if (value) {
const num = parseFloat(value);
if (!isNaN(num)) {
rateLimitInfo.resetAfter = num;
break;
}
}
}
// Check for retry after
for (const pattern of headerPatterns.retryAfter) {
const value = findHeader(headers, pattern);
if (value) {
const num = parseFloat(value);
if (!isNaN(num)) {
rateLimitInfo.retryAfter = num;
break;
}
}
}
// Only return if we found at least one rate limit indicator
if (Object.keys(rateLimitInfo).length > 0) {
return rateLimitInfo;
}
return undefined;
}
/**
* Finds header value (case-insensitive)
*/
function findHeader(headers, pattern) {
const lowerPattern = pattern.toLowerCase();
// Direct match
if (headers[lowerPattern]) {
return headers[lowerPattern];
}
// Case-insensitive search
for (const [key, value] of Object.entries(headers)) {
if (key.toLowerCase() === lowerPattern) {
return value;
}
}
return undefined;
}
/**
* Formats rate limit info for documentation
*/
export function formatRateLimitInfo(rateLimit) {
const parts = [];
if (rateLimit.limit !== undefined) {
parts.push(`Limit: ${rateLimit.limit}`);
}
if (rateLimit.remaining !== undefined) {
parts.push(`Remaining: ${rateLimit.remaining}`);
}
if (rateLimit.reset !== undefined) {
const resetDate = new Date(rateLimit.reset * 1000);
parts.push(`Resets at: ${resetDate.toISOString()}`);
}
if (rateLimit.resetAfter !== undefined) {
parts.push(`Resets in: ${rateLimit.resetAfter}s`);
}
if (rateLimit.retryAfter !== undefined) {
parts.push(`Retry after: ${rateLimit.retryAfter}s`);
}
return parts.join(', ');
}
//# sourceMappingURL=rate-limit-detector.js.map