/** * Minimum-interval limiter: callers are released one after another with at least `intervalMs` * between two slots (Nominatim policy: max. 1 request per second). Clock is injectable for tests. */ export type Clock = { now: () => number; sleep: (ms: number) => Promise }; const realClock: Clock = { now: () => Date.now(), sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)) }; export function createIntervalLimiter(intervalMs: number, clock: Clock = realClock) { let next = 0; return { /** Waits for the next free slot and returns its timestamp. */ async acquire(): Promise { const now = clock.now(); const slot = Math.max(now, next); next = slot + intervalMs; if (slot > now) await clock.sleep(slot - now); return slot; }, }; } /** Process-wide limiter for all Nominatim requests of this process (worker, backfill script). */ export const nominatimLimiter = createIntervalLimiter(1_000);