Ships accumulated WIP that was sitting uncommitted: - New (home) dashboard route pages: overview, code, data/tables, hosting, infrastructure, services, domains, integrations, agents, analytics, api, automations, billing, logs, market, marketing(+seo/social), product, security, storage, users, settings(app/auth). - dashboard-sidebar, project-icon-rail, chat-panel updates; mcp + anatomy route changes; package.json/lock dependency bumps. - Coolify log tooling (scripts/fetch-app-logs.mjs + fetch-app-logs-ssh.mjs) and ai-new-thread.md "Fetching Production Logs" section. Excludes throwaway debug scripts and telemetry audit dumps (the latter contain live credentials and must not be committed).
70 lines
2.2 KiB
JavaScript
70 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Fetch a Coolify application's runtime (container stdout/stderr) logs via the
|
|
* Coolify REST API — no dashboard login needed.
|
|
*
|
|
* Usage (from the vibn-frontend/ directory):
|
|
* node scripts/fetch-app-logs.mjs <appUuid> [lines]
|
|
*
|
|
* The <appUuid> is the last path segment of the Coolify app URL, e.g.
|
|
* https://coolify.vibnai.com/project/.../application/hou4vy5mtyg5mrx3w4nl2lxv
|
|
* ^^^^^^^^^^^^^^^^^^^^^^^^ appUuid
|
|
*
|
|
* Reads COOLIFY_URL + COOLIFY_API_TOKEN from vibn-frontend/.env.local.
|
|
* Note: Coolify's /logs endpoint returns the *last N lines* of container output,
|
|
* not a date range — pull a generous N and filter by date client-side if needed.
|
|
*/
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
function loadEnv(file) {
|
|
const out = {};
|
|
try {
|
|
for (const line of fs.readFileSync(file, "utf8").split("\n")) {
|
|
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);
|
|
if (!m) continue;
|
|
let v = m[2];
|
|
if (
|
|
(v.startsWith('"') && v.endsWith('"')) ||
|
|
(v.startsWith("'") && v.endsWith("'"))
|
|
)
|
|
v = v.slice(1, -1);
|
|
out[m[1]] = v;
|
|
}
|
|
} catch {}
|
|
return out;
|
|
}
|
|
|
|
const env = { ...loadEnv(path.join(__dirname, "../.env.local")), ...process.env };
|
|
const COOLIFY_URL = env.COOLIFY_URL || "https://coolify.vibnai.com";
|
|
const TOKEN = env.COOLIFY_API_TOKEN;
|
|
const uuid = process.argv[2];
|
|
const lines = Math.max(1, Math.min(parseInt(process.argv[3] || "1000", 10), 5000));
|
|
|
|
if (!uuid) {
|
|
console.error("Usage: node scripts/fetch-app-logs.mjs <appUuid> [lines]");
|
|
process.exit(1);
|
|
}
|
|
if (!TOKEN) {
|
|
console.error("Missing COOLIFY_API_TOKEN in vibn-frontend/.env.local");
|
|
process.exit(1);
|
|
}
|
|
|
|
const url = `${COOLIFY_URL}/api/v1/applications/${uuid}/logs?lines=${lines}`;
|
|
const res = await fetch(url, {
|
|
headers: {
|
|
Authorization: `Bearer ${TOKEN}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
});
|
|
if (!res.ok) {
|
|
console.error(`Coolify API ${res.status} on ${url}:\n${await res.text()}`);
|
|
process.exit(1);
|
|
}
|
|
const data = await res.json();
|
|
process.stdout.write((data?.logs ?? "").toString());
|
|
process.stdout.write("\n");
|