Atualização automática: 2026-05-18 20:12:35

This commit is contained in:
Hermes
2026-05-18 20:12:35 +00:00
parent 37612a7b81
commit e596342950
5 changed files with 92 additions and 23 deletions
+87
View File
@@ -25,6 +25,93 @@ app.use((req, res, next) => {
app.use(cors());
app.use(express.json());
// Helper para parsear cookies
function parseCookies(cookieHeader) {
const list = {};
if (!cookieHeader) return list;
cookieHeader.split(';').forEach(cookie => {
let [name, ...rest] = cookie.split('=');
name = name?.trim();
if (!name) return;
const value = rest.join('=').trim();
if (!value) return;
list[name] = decodeURIComponent(value);
});
return list;
}
// Rota para ativar o Virtual Root Preview (define o cookie e redireciona para a raiz)
app.get('/api/preview/:folder', (req, res) => {
const folderName = req.params.folder;
res.setHeader('Set-Cookie', `clone_preview_target=${encodeURIComponent(folderName)}; Path=/; HttpOnly; SameSite=Lax`);
res.redirect('/');
});
// Rota para sair do Virtual Root Preview (limpa o cookie e volta ao dashboard)
app.get('/api/exit-preview', (req, res) => {
res.setHeader('Set-Cookie', 'clone_preview_target=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT');
res.redirect('/');
});
// Middleware de Virtual Root Proxy (serve o site clonado diretamente na raiz / quando o cookie está ativo)
app.use((req, res, next) => {
const cookies = parseCookies(req.headers.cookie);
if (cookies.clone_preview_target && !req.path.startsWith('/api') && req.path !== '/old') {
const folderName = cookies.clone_preview_target;
const folderPath = path.join(__dirname, '..', 'cloned-sites', folderName);
if (fs.existsSync(folderPath)) {
let targetFile = req.path;
if (targetFile === '/') targetFile = '/index.html';
// Se o arquivo solicitado existir dentro da pasta do clone
const fullPath = path.join(folderPath, targetFile);
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
// Se for HTML, injeta a barra de preview flutuante
if (targetFile.endsWith('.html')) {
let html = fs.readFileSync(fullPath, 'utf8');
const previewBar = `
<div id="__cloneweb_preview_bar" style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #1f2937; color: white; padding: 12px 24px; border-radius: 50px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); display: flex; align-items: center; gap: 16px; z-index: 2147483647; font-family: 'Inter', sans-serif; font-size: 14px;">
<span style="display: flex; align-items: center; gap: 8px;"><i class="fas fa-eye" style="color: #10b981;"></i> Live Preview: <strong style="color: #60a5fa;">${folderName.split('_')[0]}</strong></span>
<a href="/api/exit-preview" style="background: #ef4444; color: white; padding: 6px 16px; border-radius: 30px; text-decoration: none; font-weight: 600; transition: all 0.2s; box-shadow: 0 4px 12px rgba(239,68,68,0.3); font-size: 13px;">Sair do Preview</a>
</div>
`;
if (html.includes('</body>')) {
html = html.replace('</body>', previewBar + '</body>');
} else {
html += previewBar;
}
res.setHeader('Content-Type', 'text/html');
return res.send(html);
}
// Para outros arquivos (CSS, JS, imagens), serve diretamente com o MIME type correto
if (targetFile.endsWith('.css')) res.setHeader('Content-Type', 'text/css');
if (targetFile.endsWith('.js')) res.setHeader('Content-Type', 'application/javascript');
return res.sendFile(fullPath);
} else {
// Fallback de SPA: se a rota virtual não existir como arquivo no disco, serve o index.html do clone!!!
const indexPath = path.join(folderPath, 'index.html');
if (fs.existsSync(indexPath)) {
let html = fs.readFileSync(indexPath, 'utf8');
const previewBar = `
<div id="__cloneweb_preview_bar" style="position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #1f2937; color: white; padding: 12px 24px; border-radius: 50px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); display: flex; align-items: center; gap: 16px; z-index: 2147483647; font-family: 'Inter', sans-serif; font-size: 14px;">
<span style="display: flex; align-items: center; gap: 8px;"><i class="fas fa-eye" style="color: #10b981;"></i> Live Preview: <strong style="color: #60a5fa;">${folderName.split('_')[0]}</strong></span>
<a href="/api/exit-preview" style="background: #ef4444; color: white; padding: 6px 16px; border-radius: 30px; text-decoration: none; font-weight: 600; transition: all 0.2s; box-shadow: 0 4px 12px rgba(239,68,68,0.3); font-size: 13px;">Sair do Preview</a>
</div>
`;
if (html.includes('</body>')) html = html.replace('</body>', previewBar + '</body>');
else html += previewBar;
res.setHeader('Content-Type', 'text/html');
return res.send(html);
}
}
}
}
next();
});
// Serve static files with proper MIME types
app.use(express.static(path.join(__dirname, 'public'), {
setHeaders: (res, path) => {