77 lines
2.8 KiB
JavaScript
77 lines
2.8 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.representApiClient = void 0;
|
|
const env_1 = require("../../../config/env");
|
|
const logger_1 = require("../../../utils/logger");
|
|
// --- In-memory sliding window rate limiter (55/min, under 60/min API limit) ---
|
|
const RATE_LIMIT = 55;
|
|
const RATE_WINDOW_MS = 60_000;
|
|
const requestTimestamps = [];
|
|
function checkRateLimit() {
|
|
const now = Date.now();
|
|
// Remove timestamps outside the window
|
|
while (requestTimestamps.length > 0 && requestTimestamps[0] < now - RATE_WINDOW_MS) {
|
|
requestTimestamps.shift();
|
|
}
|
|
return requestTimestamps.length < RATE_LIMIT;
|
|
}
|
|
function recordRequest() {
|
|
requestTimestamps.push(Date.now());
|
|
}
|
|
// --- API Client ---
|
|
class RepresentApiClient {
|
|
baseUrl;
|
|
constructor() {
|
|
this.baseUrl = env_1.env.REPRESENT_API_URL;
|
|
}
|
|
async getByPostalCode(code) {
|
|
if (!checkRateLimit()) {
|
|
throw new Error('Represent API rate limit reached. Please try again in a minute.');
|
|
}
|
|
const url = `${this.baseUrl}/postcodes/${code}/`;
|
|
logger_1.logger.debug(`Represent API request: ${url}`);
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
try {
|
|
recordRequest();
|
|
const response = await fetch(url, {
|
|
signal: controller.signal,
|
|
headers: { Accept: 'application/json' },
|
|
});
|
|
if (!response.ok) {
|
|
const text = await response.text().catch(() => '');
|
|
throw new Error(`Represent API error ${response.status}: ${text}`);
|
|
}
|
|
return (await response.json());
|
|
}
|
|
finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|
|
async testConnection() {
|
|
try {
|
|
const url = `${this.baseUrl}/boundary-sets/?limit=1`;
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
try {
|
|
const response = await fetch(url, {
|
|
signal: controller.signal,
|
|
headers: { Accept: 'application/json' },
|
|
});
|
|
if (!response.ok) {
|
|
return { ok: false, message: `HTTP ${response.status}` };
|
|
}
|
|
return { ok: true, message: 'Represent API is reachable' };
|
|
}
|
|
finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|
|
catch (err) {
|
|
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
return { ok: false, message };
|
|
}
|
|
}
|
|
}
|
|
exports.representApiClient = new RepresentApiClient();
|
|
//# sourceMappingURL=represent-api.client.js.map
|