lib/entry-response-cap.mjs
Rama main · réplica de lectura del repositorio original.
// Per-entry response cap 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.
/**
* Apply an entry's `max_response_mb` to the ctx a provider fetches with.
*
* fetchJson / fetchText / fetchResponse refuse a body over
* DEFAULT_MAX_BODY_BYTES (_http.mjs) unless the call passes `maxBytes`. A
* board that is legitimately bigger sets `max_response_mb` on its own
* portals.yml entry; the setting is the user's, so it wins over a `maxBytes`
* the provider passes, and every other entry keeps the default. An entry
* without the key leaves the ctx as it is. So does a value that is not a YAML
* number (a quoted string, a boolean, a list) or that does not come to a whole
* positive finite byte count, with a warning naming the entry.
*
* @param {object} ctx - The per-entry ctx; its fetchers are replaced in place.
* @param {{ name?: string, max_response_mb?: unknown }} entry
* @returns {object} The same ctx.
*/
export function applyEntryResponseCap(ctx, entry) {
const raw = entry?.max_response_mb;
if (raw === undefined || raw === null) return ctx;
const maxBytes = typeof raw === 'number' ? Math.floor(raw * 1024 * 1024) : NaN;
if (!Number.isFinite(maxBytes) || maxBytes < 1) {
console.error(`⚠️ ${entry?.name}: max_response_mb must be a positive number, 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, maxBytes })};
}
return ctx;
}