UNPKG

todofordevs

Version:

CLI for TodoForDevs - A simple task management tool for developers

251 lines (250 loc) 8.83 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.endpoints = void 0; exports.get = get; exports.post = post; exports.put = put; exports.del = del; const axios_1 = __importDefault(require("axios")); const config_1 = require("../config"); const output = __importStar(require("./output")); const auth = __importStar(require("./auth")); // Store the current API URL let currentApiUrl = (0, config_1.getApiUrl)(); // Create a base axios instance for API requests let api = axios_1.default.create({ baseURL: currentApiUrl, timeout: 10000, headers: { 'Content-Type': 'application/json', }, }); // Ensure the API instance is using the correct URL function ensureCorrectApiUrl() { const apiUrl = (0, config_1.getApiUrl)(); if (apiUrl !== currentApiUrl) { // Update the stored URL currentApiUrl = apiUrl; // Create a new API instance api = axios_1.default.create({ baseURL: apiUrl, timeout: 10000, headers: { 'Content-Type': 'application/json', }, }); // Re-add the request interceptor setupRequestInterceptor(); } } // Set up the request interceptor function setupRequestInterceptor() { api.interceptors.request.use(async (config) => { // Skip token check for auth endpoints const isAuthEndpoint = config.url?.includes('/auth/'); if (!isAuthEndpoint) { // Check if token needs refresh if ((0, config_1.needsTokenRefresh)() && (0, config_1.isAuthenticated)()) { output.info('Your session is about to expire. Refreshing authentication...'); try { // Re-authenticate silently await auth.initiateLogin(); } catch (error) { output.warning('Failed to refresh authentication. Please login again.'); } } // Check if authenticated if (!(0, config_1.isAuthenticated)()) { output.error('Authentication required.'); output.info("Please run 'todo auth login' to authenticate."); // We'll let the request proceed and fail with a 401 } } // Add token to headers if available const token = (0, config_1.getAuthToken)(); if (token && config.headers) { config.headers.Authorization = `Bearer ${token}`; } return config; }); } // Set up the initial request interceptor setupRequestInterceptor(); // API endpoints and methods exports.endpoints = { // Auth endpoints auth: { login: () => '/auth/cli-login-initiate', token: (deviceCode) => `/auth/cli-token?code=${deviceCode}`, verify: () => '/auth/verify', }, // Project endpoints projects: { list: () => '/projects', get: (id) => `/projects/${id}`, }, // Task endpoints tasks: { list: (projectId, params) => { const queryParams = params ? `?${new URLSearchParams(params).toString()}` : ''; return `/projects/${projectId}/tasks${queryParams}`; }, create: (projectId) => `/projects/${projectId}/tasks`, get: (taskId) => `/tasks/${taskId}`, update: (taskId) => `/tasks/${taskId}`, delete: (taskId) => `/tasks/${taskId}`, }, }; // Generic API request methods async function get(url, config) { try { ensureCorrectApiUrl(); const response = await api.get(url, config); return response.data; } catch (error) { handleApiError(error); throw error; } } async function post(url, data, config) { try { ensureCorrectApiUrl(); const response = await api.post(url, data, config); return response.data; } catch (error) { handleApiError(error); throw error; } } async function put(url, data, config) { try { ensureCorrectApiUrl(); const response = await api.put(url, data, config); return response.data; } catch (error) { handleApiError(error); throw error; } } async function del(url, config) { try { ensureCorrectApiUrl(); const response = await api.delete(url, config); return response.data; } catch (error) { handleApiError(error); throw error; } } // Error handling function handleApiError(error) { if (axios_1.default.isAxiosError(error)) { if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx const status = error.response.status; const data = error.response.data; // Format error message based on status code switch (status) { case 400: output.error('Bad Request: The request was invalid.'); if (data?.error) { output.info(`Details: ${data.error}`); } break; case 401: output.error('Authentication required.'); output.info("Please run 'todo auth login' to authenticate."); break; case 403: output.error("Access denied. You don't have permission for this action."); break; case 404: output.error('Resource not found.'); break; case 422: output.error('Validation error:'); if (data?.errors) { Object.entries(data.errors).forEach(([field, message]) => { output.info(` - ${field}: ${message}`); }); } else if (data?.error) { output.info(` - ${data.error}`); } break; case 429: output.error('Too many requests. Please try again later.'); break; case 500: case 502: case 503: case 504: output.error('Server error. Please try again later.'); break; default: output.error(`API Error: ${status} - ${error.response.statusText}`); if (data?.error) { output.info(`Details: ${data.error}`); } } } else if (error.request) { // The request was made but no response was received output.error('Network Error: No response received from server'); output.info('Please check your internet connection.'); output.info(`Current API URL: ${(0, config_1.getApiUrl)()}`); } else { // Something happened in setting up the request that triggered an Error output.error(`Error: ${error.message}`); } } else { output.error(`Unexpected error: ${error?.message || error}`); } } exports.default = api;