vies-checker
Version:
Modern European VIES VAT number validator with full TypeScript support
91 lines • 3.17 kB
JavaScript
import { ViesError } from '../errors.js';
/**
* Delays execution for a specified number of milliseconds
* @param ms - Milliseconds to delay
*/
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Checks if an error is a network error that might be retryable
*/
function isNetworkError(error) {
return (error instanceof TypeError ||
(error instanceof Error &&
(error.message.includes('fetch') ||
error.message.includes('network') ||
error.message.includes('ECONNREFUSED') ||
error.message.includes('ETIMEDOUT'))));
}
/**
* Validates the VIES response and throws appropriate errors
* @param response - The VIES API response
* @throws {ViesError} If the response contains an error state
*/
function validateResponse(response) {
const errorStates = [
'GLOBAL_MAX_CONCURRENT_REQ',
'MS_MAX_CONCURRENT_REQ',
'SERVICE_UNAVAILABLE',
'MS_UNAVAILABLE',
'TIMEOUT',
];
if (errorStates.includes(response.userError)) {
throw new ViesError(response.userError);
}
}
/**
* Makes a request to the VIES API with timeout and retry support
*
* @param country - Two-letter EU country code
* @param vatNumber - VAT number to validate
* @param options - Request options (timeout, retries)
* @returns VIES API response
* @throws {ViesError} On API errors or validation failures
*
* @example
* ```typescript
* const response = await fetchVies('LU', '26375245', { timeout: 5000 });
* ```
*/
export default async function fetchVies(country, vatNumber, options = {}) {
const { timeout = 10000, retries = 0 } = options;
const url = `https://ec.europa.eu/taxation_customs/vies/rest-api/ms/${country}/vat/${vatNumber}`;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
method: 'GET',
signal: controller.signal,
headers: {
Accept: 'application/json',
},
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new ViesError('SERVICE_UNAVAILABLE', `HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
validateResponse(data);
return data;
}
catch (error) {
clearTimeout(timeoutId);
// Handle abort/timeout
if (error instanceof Error && error.name === 'AbortError') {
throw new ViesError('TIMEOUT', 'Request timed out');
}
// Propagate ViesError
if (error instanceof ViesError) {
throw error;
}
// Retry logic for network errors
if (retries > 0 && isNetworkError(error)) {
await delay(1000); // Simple backoff
return fetchVies(country, vatNumber, { timeout, retries: retries - 1 });
}
// Wrap unknown errors
throw new ViesError('SERVICE_UNAVAILABLE', error instanceof Error ? error.message : 'Unknown error occurred');
}
}
//# sourceMappingURL=request.js.map