UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

132 lines (130 loc) 5.27 kB
import { colors, icons } from "../utils/theme.mjs"; import { linkify } from "../utils/linkify.mjs"; import chalk from "chalk"; //#region src/components/streaming-view.ts const orange = chalk.hex("#ffaa00"); const PLUGIN_PREFIX = "plugin:"; const getTimestamp = () => { const now = /* @__PURE__ */ new Date(); return `${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, "0")}:${now.getSeconds().toString().padStart(2, "0")}`; }; const write = (text) => process.stdout.write(`${text}\n`); const getServiceColor = (name) => { if (name.startsWith(PLUGIN_PREFIX)) return orange; if (name === "host") return colors.cyan; if (name === "ui" || name === "ui-ssr") return colors.magenta; if (name === "api") return colors.blue; return colors.white; }; const getDisplayName = (name) => { return name.startsWith(PLUGIN_PREFIX) ? name.slice(7).toUpperCase() : name.toUpperCase(); }; const isPlugin = (name) => name.startsWith(PLUGIN_PREFIX); const getSectionedProcesses = (processes) => { const plugins = processes.filter((p) => isPlugin(p.name)); const services = processes.filter((p) => !isPlugin(p.name)); const sections = []; if (plugins.length > 0) sections.push({ key: "plugins", title: "PLUGINS", processes: plugins }); if (services.length > 0) sections.push({ key: "services", title: "SERVICES", processes: services }); return sections; }; const getColumnWidths = (processes) => { return { name: Math.max(6, ...processes.map((p) => getDisplayName(p.name).length)), source: Math.max(10, ...processes.map((p) => p.source ? ` (${p.source})`.length : 0)) }; }; const getStatusIcon = (status) => { switch (status) { case "pending": return icons.pending; case "starting": return icons.scan; case "ready": return icons.ok; case "error": return icons.err; } }; function renderStreamingView(initialProcesses, description, env, onExit) { const processes = /* @__PURE__ */ new Map(); for (const p of initialProcesses) processes.set(p.name, { ...p }); let allReadyPrinted = false; const hostPort = initialProcesses.find((p) => p.name === "host")?.port || 3e3; const proxyTarget = env.API_PROXY; const sectionedProcesses = getSectionedProcesses(initialProcesses); const columnWidths = getColumnWidths(initialProcesses); const lastLogBySource = /* @__PURE__ */ new Map(); const headerLines = [ "", colors.cyan(`${"─".repeat(52)}`), ` ${icons.run} ${colors.cyan(description.toUpperCase())}`, colors.cyan(`${"─".repeat(52)}`), "" ]; if (proxyTarget) headerLines.push(orange(` ${icons.arrow} API PROXY → ${proxyTarget}`), ""); for (const section of sectionedProcesses) { headerLines.push(colors.cyan(` ${section.title}`)); for (const proc of section.processes) { const color = getServiceColor(proc.name); const sourceLabel = proc.source ? ` (${proc.source})` : ""; headerLines.push(`${colors.dim(`[${getTimestamp()}]`)} ${color(`[${getDisplayName(proc.name).padEnd(columnWidths.name)}]`)} ${icons.pending} waiting${sourceLabel.padEnd(columnWidths.source)}`); } headerLines.push(""); } console.log(headerLines.join("\n")); const checkAllReady = () => { if (allReadyPrinted) return; if (Array.from(processes.values()).every((p) => p.status === "ready")) { allReadyPrinted = true; const readyLines = [ "", colors.dim(`${"─".repeat(52)}`), colors.green(`${icons.ok} All ${processes.size} services ready`), colors.green(`${icons.arrow} http://localhost:${hostPort}`), colors.dim(`${"─".repeat(52)}`), "" ]; console.log(readyLines.join("\n")); } }; const updateProcess = (name, status, message) => { const proc = processes.get(name); if (!proc) return; proc.status = status; if (message) proc.message = message; const color = getServiceColor(name); const icon = getStatusIcon(status); const displayName = getDisplayName(name).padEnd(columnWidths.name); const sourceLabel = proc?.source ? ` (${proc.source})` : ""; const isRemote = proc?.source === "remote"; const isHost = name === "host"; const showPort = proc.port > 0 && (isHost || !isRemote) && status === "ready"; const statusText = status === "ready" ? isRemote && !isHost ? "loaded" : "running" : status === "starting" ? "starting" : status === "error" ? "failed" : "waiting"; const portStr = showPort ? ` :${proc.port}` : ""; write(`${colors.dim(`[${getTimestamp()}]`)} ${color(`[${displayName}]`)} ${status === "ready" ? colors.green(icon) : status === "error" ? colors.error(icon) : icon} ${statusText}${sourceLabel.padEnd(columnWidths.source)}${portStr}`); checkAllReady(); }; const addLog = (source, line, isError = false) => { const lastLine = lastLogBySource.get(source); const nextLine = `${isError ? "ERR" : "OUT"}:${line}`; if (lastLine === nextLine) return; lastLogBySource.set(source, nextLine); const color = getServiceColor(source); const logColor = isError ? colors.error : colors.dim; write(`${colors.dim(`[${getTimestamp()}]`)} ${color(`[${source.toUpperCase()}]`)} ${colors.dim("│")} ${logColor(linkify(line))}`); }; const unmount = () => onExit?.(); return { updateProcess, addLog, unmount }; } //#endregion export { renderStreamingView }; //# sourceMappingURL=streaming-view.mjs.map