/** * Map `fn` over `items` with at most `limit` concurrent calls, preserving * result order regardless of completion order. * * Extracted from the files page so batch fan-out paths (delete, drag-move, * upload probing) and the shared resource-actions composable all use the * same bounded-concurrency primitive. */ export async function mapLimit( items: readonly T[], limit: number, fn: (item: T) => Promise ): Promise { const out = new Array(items.length); let next = 0; const worker = async () => { while (next < items.length) { const i = next++; out[i] = await fn(items[i]); } }; await Promise.all(Array.from({ length: Math.max(0, Math.min(limit, items.length)) }, worker)); return out; }