import * as NodeFSP from "node:fs/promises"; import * as NodeNet from "node:net"; import * as NodePath from "node:path"; import * as NodeTimersPromises from "node:timers/promises"; const defaultTcpHosts = ["127.0.0.1", "localhost", "::1"]; async function fileExists(filePath) { try { await NodeFSP.access(filePath); return true; } catch { return false; } } function tcpPortIsReady({ host, port, connectTimeoutMs = 500 }) { return new Promise((resolveReady) => { const socket = NodeNet.createConnection({ host, port }); let settled = false; const finish = (ready) => { if (settled) { return; } settled = true; socket.removeAllListeners(); socket.destroy(); resolveReady(ready); }; socket.once("connect", () => { finish(true); }); socket.once("timeout", () => { finish(false); }); socket.once("error", () => { finish(false); }); socket.setTimeout(connectTimeoutMs); }); } async function resolvePendingResources({ baseDir, files, tcpPort, tcpHosts, connectTimeoutMs }) { const pendingFiles = []; for (const relativeFilePath of files) { const ready = await fileExists(NodePath.resolve(baseDir, relativeFilePath)); if (!ready) { pendingFiles.push(relativeFilePath); } } let tcpReady = false; for (const host of tcpHosts) { tcpReady = await tcpPortIsReady({ host, port: tcpPort, connectTimeoutMs, }); if (tcpReady) { break; } } return { pendingFiles, tcpReady, }; } export async function waitForResources({ baseDir, files = [], intervalMs = 100, timeoutMs = 120_000, tcpHost, tcpPort, connectTimeoutMs = 500, }) { if (!Number.isInteger(tcpPort) || tcpPort <= 0) { throw new TypeError("waitForResources requires a positive integer tcpPort"); } const startedAt = Date.now(); const tcpHosts = tcpHost ? [tcpHost] : defaultTcpHosts; while (true) { const { pendingFiles, tcpReady } = await resolvePendingResources({ baseDir, files, tcpPort, tcpHosts, connectTimeoutMs, }); if (pendingFiles.length === 0 && tcpReady) { return; } if (Date.now() - startedAt >= timeoutMs) { const pendingResources = []; if (!tcpReady) { pendingResources.push(tcpHost ? `tcp:${tcpHost}:${tcpPort}` : `tcp:${tcpPort}`); } for (const filePath of pendingFiles) { pendingResources.push(`file:${filePath}`); } throw new Error( `Timed out waiting for desktop dev resources after ${timeoutMs}ms: ${pendingResources.join(", ")}`, ); } await NodeTimersPromises.setTimeout(intervalMs); } }