From cae6a453d07de780504aea5d4fe38c0173d4c423 Mon Sep 17 00:00:00 2001 From: Rosie Val Date: Thu, 6 Aug 2026 11:58:23 -0400 Subject: [PATCH] ServerDrawer: make rawFindAll non-blocking (rawFindAllAsync) --- plugins/server-drawer/src/lib/rawFind.ts | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/plugins/server-drawer/src/lib/rawFind.ts b/plugins/server-drawer/src/lib/rawFind.ts index c8e3d2e..740bfcc 100644 --- a/plugins/server-drawer/src/lib/rawFind.ts +++ b/plugins/server-drawer/src/lib/rawFind.ts @@ -71,6 +71,59 @@ export function rawFindAll(predicate: (exports: any) => boolean): T[] { return results; } +/** + * Async batched scan: does the same as rawFindAll but yields between batches so the UI thread + * isn't blocked for long. Returns a Promise of the matching exports array. + */ +export async function rawFindAllAsync( + predicate: (exports: any) => boolean, + opts?: { batchSize?: number; pauseMs?: number; maxProcessed?: number }, +): Promise { + const modules = window?.modules; + if (!modules) return []; + + const keys = Object.keys(modules); + const batchSize = opts?.batchSize ?? 200; + const pauseMs = opts?.pauseMs ?? 0; // 0 uses setTimeout(...,0) to yield + const maxProcessed = opts?.maxProcessed ?? Infinity; + + const results: T[] = []; + const seen = new Set(); + let processed = 0; + + for (let i = 0; i < keys.length; i += batchSize) { + const end = Math.min(i + batchSize, keys.length); + for (let j = i; j < end; j++) { + if (processed++ >= maxProcessed) return results; + const def = modules[keys[j]]; + if (!def?.isInitialized) continue; + const exports = def.publicModule?.exports; + if (!exports) continue; + try { + if (predicate(exports) && !seen.has(exports)) { + results.push(exports as any); + seen.add(exports); + } + const dflt = exports.default; + if (dflt != null && predicate(dflt) && !seen.has(dflt)) { + results.push(dflt as any); + seen.add(dflt); + } + } catch { + // ignore + } + } + // yield to event loop so UI can update + if (pauseMs === 0) { + await new Promise((r) => setTimeout(r, 0)); + } else if (pauseMs > 0) { + await new Promise((r) => setTimeout(r, pauseMs)); + } + } + + return results; +} + export function rawFindByTypeName(name: string): T | undefined { return rawFind((m) => m?.name === name || m?.displayName === name || m?.type?.name === name || m?.type?.displayName === name); }