lib/entry-timeout.mjs
Rama main · réplica de lectura del repositorio original.
// Per-entry request timeout for portals.yml boards. Side-effect free on purpose: scan.mjs loads the
// data root's .env when imported, so audit-portals.mjs takes this helper from here, not from scan.mjs.
// setTimeout rewrites a longer delay to 1ms, which would abort every request of the entry.
const MAX_TIMER_MS = 2_147_483_647;
/**
* Apply an entry's `timeout_ms` to the ctx a provider fetches with.
*
* A board that returns its whole catalogue in one response can need more time
* than its provider allows, and the scan then reports it as a network error. Such
* a board sets `timeout_ms` on its own portals.yml entry. The setting is the
* user's, so it wins over a `timeoutMs` the provider passes, and every other
* entry keeps its timeout. An entry without the key leaves the ctx as it is. So
* does a value that is not a whole YAML number from 1 to 2147483647, with a
* warning naming the entry.
*
* @param {object} ctx - The per-entry ctx; its fetchers are replaced in place.
* @param {{ name?: string, timeout_ms?: unknown }} entry
* @returns {object} The same ctx.
*/
export function applyEntryTimeout(ctx, entry) {
const raw = entry?.timeout_ms;
if (raw === undefined || raw === null) return ctx;
if (!Number.isInteger(raw) || raw < 1 || raw > MAX_TIMER_MS) {
console.error(
`⚠️ ${entry?.name}: timeout_ms must be a whole number from 1 to ${MAX_TIMER_MS}, got ${JSON.stringify(raw)} — ignored`,
);
return ctx;
}
for (const method of ["fetchJson", "fetchText", "fetchResponse"]) {
const original = ctx[method];
if (typeof original !== "function") continue;
ctx[method] = function (url, opts = {}) {
return original.call(this, url, { ...opts, timeoutMs: raw });
};
}
return ctx;
}