UNPKG

observation-js

Version:

A fully-typed TypeScript client for the waarneming.nl API.

102 lines (101 loc) 3.49 kB
/** * Base class for all errors thrown by the observation-js library. */ export class ObservationError extends Error { constructor(message) { super(message); this.name = 'ObservationError'; } } /** * Represents an error returned by the Waarneming.nl API. */ export class ApiError extends ObservationError { response; body; constructor(message, response, body) { super(message); this.name = 'ApiError'; this.response = response; this.body = body; } } /** * Represents an authentication-related error (e.g., 401 Unauthorized, 403 Forbidden). */ export class AuthenticationError extends ApiError { constructor(response, body) { super('Authentication failed', response, body); this.name = 'AuthenticationError'; } } /** * Represents a rate limiting error (429 Too Many Requests). * Contains information about retry timing if available. */ export class RateLimitError extends ApiError { retryAfter; // seconds to wait before retrying resetTime; // when the rate limit resets constructor(response, body) { const retryAfter = response.headers.get('Retry-After'); const resetHeader = response.headers.get('X-RateLimit-Reset'); let message = 'Rate limit exceeded. Please wait before making more requests.'; if (retryAfter) { message += ` Retry after ${retryAfter} seconds.`; } super(message, response, body); this.name = 'RateLimitError'; // Parse retry timing information this.retryAfter = retryAfter ? parseFloat(retryAfter) : undefined; this.resetTime = resetHeader ? new Date(parseInt(resetHeader, 10) * 1000) : undefined; } /** * Get the recommended delay in milliseconds before retrying */ getRetryDelayMs() { if (this.retryAfter) { return this.retryAfter * 1000; } // Default backoff: 60 seconds for rate limiting return 60000; } /** * Check if enough time has passed since the rate limit was hit to retry */ canRetryNow() { if (!this.resetTime) { return false; } return new Date() >= this.resetTime; } } /** * Utility function to handle rate limiting with automatic retry * @param operation - The operation to retry * @param maxRetries - Maximum number of retries (default: 3) * @returns Promise that resolves with the operation result */ export async function withRateLimitRetry(operation, maxRetries = 3) { let attempt = 0; while (attempt < maxRetries) { try { return await operation(); } catch (error) { attempt++; if (error instanceof RateLimitError) { if (attempt >= maxRetries) { throw new Error(`Rate limit exceeded after ${maxRetries} attempts. ` + `Please wait ${Math.round(error.getRetryDelayMs() / 1000)} seconds before trying again.`); } const delay = error.getRetryDelayMs(); console.warn(`Rate limit hit. Waiting ${Math.round(delay / 1000)}s before retry ${attempt + 1}/${maxRetries}...`); await new Promise(resolve => setTimeout(resolve, delay)); continue; } // For non-rate-limit errors, throw immediately throw error; } } throw new Error('Maximum retries exceeded'); }