todofordevs
Version:
CLI for TodoForDevs - A simple task management tool for developers
251 lines (250 loc) • 8.83 kB
JavaScript
;
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;