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