| | |
| |
|
| | import axios, { AxiosResponse } from 'axios'; |
| | import fs from 'fs'; |
| | import path from 'path'; |
| | import simpleGit, { SimpleGit } from 'simple-git'; |
| | import { Request, Response, Application } from 'express'; |
| | import { WebSocketServer } from 'ws'; |
| | import { Server as HttpServer } from 'http'; |
| |
|
| | const TEMPLATE_URL = 'https://raw.githubusercontent.com/ChoruOfficial/global-exocore/main/template.json'; |
| | const configPath = path.resolve(__dirname, '../config.json'); |
| | const git: SimpleGit = simpleGit(); |
| |
|
| | interface Template { |
| | id: string; |
| | name: string; |
| | description: string; |
| | image: string; |
| | git: string; |
| | } |
| |
|
| | interface ConfigData { |
| | project?: string; |
| | [key: string]: any; |
| | } |
| |
|
| | interface CreateProjectOptions { |
| | templateId?: string; |
| | gitUrl?: string; |
| | } |
| |
|
| | async function pathExists(p: string): Promise<boolean> { |
| | try { |
| | await fs.promises.access(p); |
| | return true; |
| | } catch { |
| | return false; |
| | } |
| | } |
| |
|
| | const api = { |
| | async getTemplates(): Promise<Template[]> { |
| | try { |
| | const res: AxiosResponse<Template[]> = await axios.get(TEMPLATE_URL); |
| | if (Array.isArray(res.data)) return res.data; |
| | console.warn('Fetched template.json is not an array.'); |
| | return []; |
| | } catch (err: unknown) { |
| | console.error('Failed to fetch templates:', err); |
| | return []; |
| | } |
| | }, |
| |
|
| | async updateConfig(projectName: string): Promise<void> { |
| | let config: ConfigData = {}; |
| | try { |
| | if (await pathExists(configPath)) { |
| | const file = await fs.promises.readFile(configPath, 'utf-8'); |
| | config = file.trim() ? JSON.parse(file) : {}; |
| | } |
| | } catch (err) { |
| | console.error('Error reading config:', err); |
| | } |
| |
|
| | config.project = `../${projectName}`; |
| | try { |
| | await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2)); |
| | console.log(`Config updated: ${configPath}`); |
| | } catch (err) { |
| | console.error('Error writing config:', err); |
| | } |
| | }, |
| |
|
| | async cloneTemplate(gitUrl: string, targetPath: string): Promise<void> { |
| | try { |
| | await git.clone(gitUrl, targetPath); |
| | console.log('Cloned template successfully.'); |
| | } catch (err) { |
| | console.error('Git clone failed:', err); |
| | throw new Error('Git clone failed'); |
| | } |
| | }, |
| |
|
| | async checkProjectStatus(): Promise<{ exists: boolean }> { |
| | if (!await pathExists(configPath)) return { exists: false }; |
| | try { |
| | const raw = await fs.promises.readFile(configPath, 'utf-8'); |
| | const config: ConfigData = JSON.parse(raw); |
| | if (!config.project) return { exists: false }; |
| |
|
| | const folder = path.resolve(path.dirname(configPath), config.project); |
| | return { exists: await pathExists(folder) }; |
| | } catch (err) { |
| | console.error('Error checking project status:', err); |
| | return { exists: false }; |
| | } |
| | }, |
| |
|
| | async createProject(projectName: string, { templateId, gitUrl }: CreateProjectOptions): Promise<string> { |
| | if (!projectName.trim()) throw new Error('Project name is required.'); |
| |
|
| | let cloneUrl: string; |
| |
|
| | if (gitUrl && templateId) throw new Error('Provide either a template ID or a Git URL, not both.'); |
| | if (gitUrl) { |
| | cloneUrl = gitUrl; |
| | } else if (templateId) { |
| | const templates = await api.getTemplates(); |
| | const template = templates.find(t => t.id === templateId); |
| | if (!template) throw new Error(`Template "${templateId}" not found.`); |
| | cloneUrl = template.git; |
| | } else { |
| | throw new Error('You must provide a template ID or Git URL.'); |
| | } |
| |
|
| | const base = path.resolve(__dirname, '../..'); |
| | const target = path.join(base, projectName); |
| |
|
| | if (await pathExists(target)) { |
| | throw new Error(`Project "${projectName}" already exists.`); |
| | } |
| |
|
| | await api.cloneTemplate(cloneUrl, target); |
| | await api.updateConfig(projectName); |
| | return `Project "${projectName}" created at ${target}`; |
| | }, |
| | }; |
| |
|
| | interface ProjectRouteParams { |
| | req: Request; |
| | res: Response; |
| | app?: Application; |
| | wss?: WebSocketServer; |
| | wssConsole?: WebSocketServer; |
| | Shellwss?: WebSocketServer; |
| | server?: HttpServer; |
| | } |
| |
|
| | interface ProjectExpressRouteModule { |
| | method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head' | 'all'; |
| | path: string; |
| | install: (params: any) => Promise<void> | void; |
| | } |
| |
|
| | interface CreateProjectRequestBody { |
| | name: string; |
| | template?: string; |
| | gitUrl?: string; |
| | } |
| |
|
| | export const modules: ProjectExpressRouteModule[] = [ |
| | { |
| | method: 'post', |
| | path: '/templates', |
| | install: async ({ res }: Pick<ProjectRouteParams, 'res'>) => { |
| | try { |
| | const templates = await api.getTemplates(); |
| | res.json(templates); |
| | } catch (err) { |
| | console.error('Error in /templates:', err); |
| | res.status(500).json({ error: 'Failed to load templates.' }); |
| | } |
| | } |
| | }, |
| | { |
| | method: 'post', |
| | path: '/project', |
| | install: async ({ req, res }: Pick<ProjectRouteParams, 'req' | 'res'>) => { |
| | const { name, template, gitUrl } = req.body as CreateProjectRequestBody; |
| | try { |
| | const msg = await api.createProject(name, { templateId: template, gitUrl }); |
| | res.status(201).json({ success: true, message: msg, projectPath: name }); |
| | } catch (err) { |
| | console.error('Project creation failed:', err); |
| | res.status(400).json({ success: false, error: (err as Error).message }); |
| | } |
| | } |
| | }, |
| | { |
| | method: 'post', |
| | path: '/project/status', |
| | install: async ({ res }: Pick<ProjectRouteParams, 'res'>) => { |
| | try { |
| | const status = await api.checkProjectStatus(); |
| | res.json(status); |
| | } catch (err) { |
| | console.error('Error checking status:', err); |
| | res.status(500).json({ error: 'Unable to check project status.' }); |
| | } |
| | } |
| | } |
| | ]; |
| |
|