import mongoose from "mongoose"; import { queryDB } from "../db/connect"; import { FeaturesResponse } from "../types/types"; import { isExpired, log } from "../utils/general"; import { allocateMaxThreads } from "../utils/executions"; import { Execution } from "../types/execution.types"; import { cache } from ".."; import { handleGetAll } from "../eventHandlers/handlers"; export const fetchExecutions = async () => { try { const url = new URL(process.env.EXECUTIONS_SERVER_URL + "/api/executions"); const response = await fetch(url.toString(), { method: "GET", headers: { 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, 'Content-Type': 'application/json' } } ); if (!response.ok) { let errorData; try { errorData = await response.text(); } catch { errorData = { message: 'Unknown error' }; } throw new Error(`${errorData || response.statusText}`); } const data = await response.json(); return data; } catch (error: any) { console.error("\n❌ Error fetching executions:", error.message || error); return { error: error.message || error || 'Unknown error' }; } }; export const fetchAllRunningExecutions = async (projectId: string) => { try { const url = new URL(`${process.env.EXECUTIONS_SERVER_URL + "/api/executions"}/running`); const response = await fetch(url.toString(), { method: "GET", headers: { 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, 'Content-Type': 'application/json' } } ); if (!response.ok) { let errorData; try { errorData = await response.text(); } catch { errorData = { message: 'Unknown error' }; } throw new Error(`${errorData || response.statusText}`); } const data = await response.json(); return data; } catch (error: any) { console.error("\n❌ Error fetching running executions:", error.message || error); return { error: error.message || error || 'Unknown error' }; } } // ! deprecated, moved the db logic to the server export async function fetchProjectMetadata() { const initProjectInfo = async (SSO_DB: mongoose.Connection) => { const projectInfo = await SSO_DB.db!.collection('projects').findOne({ _id: new mongoose.Types.ObjectId(process.env.projectId) }); if (!projectInfo) { log(`❌ Project not found for projectId: ${process.env.projectId}`); return null; } process.env.projectInfo = JSON.stringify(projectInfo); process.env.isPrivateRepo = projectInfo.privateRepo; process.env.maxExecutionThreads = projectInfo.maxExecutionThreads ?? 2; process.env.isProjectExpired = isExpired(projectInfo.expriration_date).toString(); if (process.env.isProjectExpired === 'true') { log(`⚠️ Project ${projectInfo.name} has expired.`); } else { log(`✅ Project ${projectInfo.name} is not expired.`); } } await queryDB(initProjectInfo); } export async function getFeatures(): Promise { try { const url = new URL(`${process.env.BASE_API_URL}/api/workspace/get-feature-list`); const response = await fetch(url.toString(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`, }, body: JSON.stringify({ projectId: process.env.projectId, isPrivateRepo: process.env.isPrivateRepo === 'true', }), }); if (!response.ok) { throw new Error(`Error fetching features: ${response.statusText}`); } const data: FeaturesResponse = await response.json(); log('✅ Fetched features successfully'); return data; } catch (error) { log("❌ Error fetching features:", error); throw error; } } export const createExecution = async (execution: Execution) => { const maxExecutionThreads = parseInt(process.env.maxExecutionThreads ?? "2", 10); const url = new URL(`${process.env.EXECUTIONS_SERVER_URL + "/api/executions"}/new`); const newExec = allocateMaxThreads(execution, maxExecutionThreads); const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${process.env.ACCESS_TOKEN}`, }, body: JSON.stringify(newExec), }); if (!response.ok) { let errorMessage = "Failed to create execution"; try { const errorData = await response.json(); if (response.status === 409 && errorData.message) { errorMessage = errorData.message; } } catch { } console.error(`❌ ${errorMessage}`); throw new Error(errorMessage); } console.log("\n\n✅ New execution created successfully"); return response.json(); }; export const deleteExecution = async (executionName: string) => { const executions: Execution[] = await handleGetAll(false); const execution = executions.find((exec) => exec.name === executionName.trim()); if (!execution) { throw new Error(`Execution with name "${executionName}" not found.`); } const url = new URL(`${process.env.EXECUTIONS_SERVER_URL + "/api/executions"}/${execution._id}`); const response = await fetch(url, { method: "DELETE", headers: { "Authorization": `Bearer ${process.env.ACCESS_TOKEN}`, "Content-Type": "application/json", }, }); if (!response.ok) { const errorData = await response.json(); throw new Error(`Failed to delete execution: ${errorData.message || response.statusText}`); } console.log(`\n\n✅ Execution "${executionName}" deleted successfully`); } /** * Fetch project information by token. * ! Note: When the npmrc content could have been changed, use the noCache flag * @param token The access token. * @param noCache If true, bypass the cache. * @returns The project information or null if not found. */ export async function fetchProjectByToken(token: string, noCache = true) { if (!noCache && cache.has('projectByToken', token)) { return cache.get('projectByToken', token); } const headers: Record = { 'Content-Type': 'application/json', }; try { const response = await fetch(process.env.BASE_API_URL + '/api/auth/getProjectByAccessKey', { method: 'POST', headers, body: JSON.stringify({ access_key: token, }), }); const data: { status: boolean; error?: string; project?: any; user_id?: string; } = await response.json(); if (!data.status) { throw new Error(data.error || 'Unknown error from server'); } const projectInfo = { valid: true, project: data.project, userId: data.user_id, projectId: data.project._id }; cache.set('projectByToken', token, projectInfo); return projectInfo; } catch (error) { console.error('❌ Failed to fetch project:', error); return { valid: false, error: (error as Error).message }; } } export async function fetchUserByToken(token: string) { if (cache.has('userByToken', token)) { return cache.get('userByToken', token); } const url = new URL(`${process.env.BASE_API_URL}/api/auth/get-user-info-by-token`); const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, } const getUserResponse = await fetch(url, { method: 'GET', headers }); if (!getUserResponse.ok) { throw new Error(`Failed to fetch user info: ${getUserResponse.status} ${getUserResponse.statusText}`); } const data = await getUserResponse.json(); const user = data.user; if (!data || !data.status || !user) { throw new Error('Invalid response from server'); } cache.set('userByToken', token, user); return user; } export async function fetchUserByUserId(userId: string) { if (cache.has('userById', userId)) { return cache.get('userById', userId); } const url = new URL(`${process.env.BASE_API_URL}/api/auth/get-user-info-by-userId`); url.searchParams.set("userId", userId); const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.ACCESS_TOKEN!}`, } const getUserResponse = await fetch(url, { method: 'GET', headers }); if (!getUserResponse.ok) { throw new Error(`Failed to fetch user info: ${getUserResponse.status} ${getUserResponse.statusText}`); } const data = await getUserResponse.json(); const user = data.user; if (!data || !data.status || !user) { throw new Error('Invalid response from server'); } cache.set('userById', userId, user); return user; }