everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
134 lines (132 loc) • 5.85 kB
JavaScript
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
const require_theme = require('../utils/theme.cjs');
const require_linkify = require('../utils/linkify.cjs');
let chalk = require("chalk");
chalk = require_runtime.__toESM(chalk, 1);
//#region src/components/streaming-view.ts
const orange = chalk.default.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 require_theme.colors.cyan;
if (name === "ui" || name === "ui-ssr") return require_theme.colors.magenta;
if (name === "api") return require_theme.colors.blue;
return require_theme.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 require_theme.icons.pending;
case "starting": return require_theme.icons.scan;
case "ready": return require_theme.icons.ok;
case "error": return require_theme.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 = [
"",
require_theme.colors.cyan(`${"─".repeat(52)}`),
` ${require_theme.icons.run} ${require_theme.colors.cyan(description.toUpperCase())}`,
require_theme.colors.cyan(`${"─".repeat(52)}`),
""
];
if (proxyTarget) headerLines.push(orange(` ${require_theme.icons.arrow} API PROXY → ${proxyTarget}`), "");
for (const section of sectionedProcesses) {
headerLines.push(require_theme.colors.cyan(` ${section.title}`));
for (const proc of section.processes) {
const color = getServiceColor(proc.name);
const sourceLabel = proc.source ? ` (${proc.source})` : "";
headerLines.push(`${require_theme.colors.dim(`[${getTimestamp()}]`)} ${color(`[${getDisplayName(proc.name).padEnd(columnWidths.name)}]`)} ${require_theme.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 = [
"",
require_theme.colors.dim(`${"─".repeat(52)}`),
require_theme.colors.green(`${require_theme.icons.ok} All ${processes.size} services ready`),
require_theme.colors.green(`${require_theme.icons.arrow} http://localhost:${hostPort}`),
require_theme.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(`${require_theme.colors.dim(`[${getTimestamp()}]`)} ${color(`[${displayName}]`)} ${status === "ready" ? require_theme.colors.green(icon) : status === "error" ? require_theme.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 ? require_theme.colors.error : require_theme.colors.dim;
write(`${require_theme.colors.dim(`[${getTimestamp()}]`)} ${color(`[${source.toUpperCase()}]`)} ${require_theme.colors.dim("│")} ${logColor(require_linkify.linkify(line))}`);
};
const unmount = () => onExit?.();
return {
updateProcess,
addLog,
unmount
};
}
//#endregion
exports.renderStreamingView = renderStreamingView;
//# sourceMappingURL=streaming-view.cjs.map