decocms
Version:
CLI for managing deco.chat apps & projects
125 lines • 5.34 kB
JavaScript
import { createServer } from "http";
import { URL } from "url";
import { spawn } from "child_process";
import { AUTH_PORT_CLI, DECO_CHAT_LOGIN } from "../../lib/constants.js";
import { saveSession } from "../../lib/session.js";
import { createClient } from "../../lib/supabase.js";
import process from "node:process";
export const loginCommand = () => {
return new Promise((resolve, reject) => {
let timeout;
const server = createServer(async (req, res) => {
const url = new URL(req.url, `http://localhost:${AUTH_PORT_CLI}`);
// Convert IncomingMessage headers to Headers object
const headers = new Headers();
for (const [key, value] of Object.entries(req.headers)) {
if (value) {
headers.set(key, Array.isArray(value) ? value.join(", ") : value);
}
}
const { client, responseHeaders } = createClient(headers);
if (url.pathname === "/login/oauth") {
const credentials = {
provider: (url.searchParams.get("provider") ??
"google"),
options: { redirectTo: new URL("/auth/callback/oauth", url).href },
};
const { data } = await client.auth.signInWithOAuth(credentials);
if (data.url) {
// Convert Headers to plain object
const responseHeadersObj = {};
responseHeaders.forEach((value, key) => {
responseHeadersObj[key] = value;
});
res.writeHead(302, {
Location: data.url,
...responseHeadersObj,
});
res.end();
return;
}
res.writeHead(500);
res.end("Error redirecting to OAuth provider");
return;
}
if (url.pathname === "/auth/callback/oauth") {
const code = url.searchParams.get("code");
if (!code) {
res.writeHead(400);
res.end("No code found");
return;
}
const { data, error } = await client.auth.exchangeCodeForSession(code);
if (error || !data?.session) {
res.writeHead(400);
res.end(error?.message ?? "Unknown error");
return;
}
// Save session data securely
try {
await saveSession(data);
}
catch (e) {
console.error("Failed to save session data:", e);
}
// Clear the timeout since login was successful
if (timeout) {
clearTimeout(timeout);
}
res.writeHead(200, { "Content-Type": "text/html" });
res.end(`<!DOCTYPE html>
<html>
<head>
<title>Authentication Complete</title>
</head>
<body>
<h1>Authentication Complete</h1>
<p>You can close this window now.</p>
<script>
window.close();
</script>
</body>
</html>`);
// Close server after successful authentication
server.close(() => resolve());
return;
}
res.writeHead(404);
res.end("Not found");
});
server.listen(AUTH_PORT_CLI, () => {
// Try to open browser with OS-appropriate command
const browserCommands = {
linux: "xdg-open",
darwin: "open",
win32: "start",
freebsd: "xdg-open",
openbsd: "xdg-open",
sunos: "xdg-open",
aix: "open",
};
const browser = process.env.BROWSER ?? browserCommands[process.platform] ?? "open";
console.log("🔐 Starting authentication process...");
console.log("Opening browser for login...\n");
// Windows requires using cmd.exe because 'start' is a built-in command
const command = process.platform === "win32" && browser === "start"
? spawn("cmd", ["/c", "start", DECO_CHAT_LOGIN], { detached: true })
: spawn(browser, [DECO_CHAT_LOGIN], { detached: true });
command.unref(); // Don't keep process alive
// Handle potential browser opening failures
command.on("error", () => {
console.log("⚠️ Could not automatically open browser");
});
// Always show the fallback URL
timeout = setTimeout(() => {
console.log("📋 If your browser didn't open automatically, please click the following link:");
console.log(`\n ${DECO_CHAT_LOGIN}\n`);
console.log("Waiting for authentication to complete...\n");
}, 1000); // Small delay to let browser opening attempt complete
});
server.on("error", (err) => {
reject(err);
});
});
};
//# sourceMappingURL=login.js.map