77 lines
2.2 KiB
JavaScript
77 lines
2.2 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const appInstaller = require('../services/appInstaller');
|
|
|
|
/**
|
|
* GET /api/v1/apps
|
|
* Lists all recipes merged with installed status.
|
|
*/
|
|
router.get('/', (req, res) => {
|
|
try {
|
|
const recipes = appInstaller.loadRecipes();
|
|
const installed = appInstaller.getInstalledApps();
|
|
|
|
const merged = recipes.map(recipe => ({
|
|
...recipe,
|
|
installed: !!installed[recipe.id],
|
|
installedInfo: installed[recipe.id] || null
|
|
}));
|
|
|
|
res.json({ success: true, apps: merged });
|
|
} catch (err) {
|
|
res.status(500).json({ success: false, error: err.message });
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/v1/apps/:id/install
|
|
* SSE endpoint for app installation streaming log.
|
|
*/
|
|
router.post('/:id/install', async (req, res) => {
|
|
const { id } = req.params;
|
|
const { domain, dbPassword, port } = req.body;
|
|
|
|
// Only domain is strictly required at this layer.
|
|
// appInstaller.js handles dbPassword validation if the recipe needs it.
|
|
if (!domain) {
|
|
return res.status(400).json({ success: false, error: 'Domain is required' });
|
|
}
|
|
|
|
// Set headers for SSE
|
|
res.setHeader('Content-Type', 'text/event-stream');
|
|
res.setHeader('Cache-Control', 'no-cache');
|
|
res.setHeader('Connection', 'keep-alive');
|
|
res.flushHeaders();
|
|
|
|
const onLog = (line) => {
|
|
res.write(`data: ${JSON.stringify({ log: line })}\n\n`);
|
|
};
|
|
|
|
try {
|
|
const result = await appInstaller.streamInstall(id, { domain, dbPassword, port }, onLog);
|
|
res.write(`data: ${JSON.stringify({ success: result.success, completed: true })}\n\n`);
|
|
} catch (err) {
|
|
res.write(`data: ${JSON.stringify({ error: err.message, completed: true })}\n\n`);
|
|
} finally {
|
|
res.end();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/v1/apps/:id/status
|
|
*/
|
|
router.get('/:id/status', (req, res) => {
|
|
try {
|
|
const installed = appInstaller.getInstalledApps();
|
|
const info = installed[req.params.id];
|
|
res.json({
|
|
success: true,
|
|
installed: !!info,
|
|
info: info || null
|
|
});
|
|
} catch (err) {
|
|
res.status(500).json({ success: false, error: err.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|