UNPKG

hackages

Version:

CLI tool for learning software development concepts through test-driven development

119 lines (118 loc) 4.02 kB
import open from "open"; import fs from "fs"; import path from "path"; import { printInfo, printSuccess, printError } from "../utils/console.js"; import { apiClient } from "./api.js"; import prompts from "prompts"; function getConfigDir() { const homeDir = process.env.HOME || process.env.USERPROFILE || ""; const configDir = path.join(homeDir, ".hackages"); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); } return configDir; } function getLearningGoalPath() { const learningPath = path.join(getConfigDir(), "learning.json"); if (!fs.existsSync(learningPath)) { fs.writeFileSync(learningPath, JSON.stringify({})); } return learningPath; } export function checkIfLearningJSONIsEmpty() { const learningGoalPath = getLearningGoalPath(); const learningGoal = JSON.parse(fs.readFileSync(learningGoalPath, "utf8")); return Object.keys(learningGoal).length === 0; } export function writeLearningGoal(learningGoal) { const learningJsonPath = getLearningGoalPath(); let learningData = {}; if (fs.existsSync(learningJsonPath)) { try { const fileContent = fs.readFileSync(learningJsonPath, "utf8"); learningData = JSON.parse(fileContent); } catch (err) { // If file is corrupted or unreadable, start fresh learningData = {}; } } // Add or update the new learning goal and set as current learningData.current = learningGoal.id; learningData[learningGoal.id] = learningGoal; fs.writeFileSync(learningJsonPath, JSON.stringify(learningData, null, 2)); } function getTokenPath() { return path.join(getConfigDir(), "auth.json"); } export function getStoredAuth() { try { const tokenPath = getTokenPath(); if (fs.existsSync(tokenPath)) { const data = fs.readFileSync(tokenPath, "utf8"); return JSON.parse(data); } } catch (error) { // If there's an error reading the token, treat as not authenticated } return null; } function storeAuth(auth) { try { const tokenPath = getTokenPath(); fs.writeFileSync(tokenPath, JSON.stringify(auth, null, 2)); } catch (error) { printError(`Failed to store authentication: ${error}`); } } export function clearAuth() { try { const tokenPath = getTokenPath(); if (fs.existsSync(tokenPath)) { fs.unlinkSync(tokenPath); } } catch (error) { printError(`Failed to clear authentication: ${error}`); } } export async function loginWithGitHub() { try { // Open GitHub OAuth page const { authUrl } = await apiClient.auth.getAuthUrl(); printInfo("Opening GitHub login page..."); await open(authUrl); // Wait for user to complete OAuth flow printInfo("Please complete the GitHub login in your browser."); printInfo("After logging in, you'll be redirected to a page with a code."); printInfo("Copy that code and paste it here:"); // Get code from user input using prompts for better UX const { code } = await prompts({ type: "text", name: "code", message: "Enter the code from GitHub:", validate: (value) => (value.length > 0 ? true : "Please enter the code"), }); if (!code) { throw new Error("No code provided"); } // Exchange code for token const { authToken: token, user, expiresAt } = await apiClient.auth.login(code); // Store auth data storeAuth({ access_token: token, user }); printSuccess(`Successfully logged in as ${user?.name || user?.login}!`); } catch (error) { printError(`Login failed: ${error}`); throw error; } } export function isLoggedIn() { return !!getStoredAuth(); } export function getCurrentUser() { const auth = getStoredAuth(); return auth?.user || null; }