Files
url_tracker_tool/apps/api/dist/routes/export.routes.js
Andrei 58f8093689 Rebrand from 'Redirect Intelligence v2' to 'URL Tracker Tool V2' throughout UI
- Updated all component headers and documentation
- Changed navbar and footer branding
- Updated homepage hero badge
- Modified page title in index.html
- Simplified footer text to 'Built with ❤️'
- Consistent V2 capitalization across all references
2025-08-19 19:12:23 +00:00

260 lines
10 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const zod_1 = require("zod");
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
const export_service_1 = require("../services/export.service");
const auth_middleware_1 = require("../middleware/auth.middleware");
const logger_1 = require("../lib/logger");
const router = express_1.default.Router();
const exportService = new export_service_1.ExportService();
const exportLimiter = (0, express_rate_limit_1.default)({
windowMs: 60 * 60 * 1000,
max: 20,
message: {
success: false,
error: 'Export rate limit exceeded',
message: 'Too many export requests. Please try again later.'
},
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => {
return req.user ? `user:${req.user.id}` : `ip:${req.ip}`;
},
});
const exportParamsSchema = zod_1.z.object({
checkId: zod_1.z.string().min(1, 'Check ID is required'),
});
const exportQuerySchema = zod_1.z.object({
download: zod_1.z.string().optional(),
filename: zod_1.z.string().optional(),
});
router.get('/:checkId/markdown', auth_middleware_1.optionalAuth, exportLimiter, async (req, res) => {
try {
const { checkId } = exportParamsSchema.parse(req.params);
const { download, filename } = exportQuerySchema.parse(req.query);
logger_1.logger.info(`Generating Markdown export for check: ${checkId}`, {
userId: req.user?.id,
download: !!download,
});
const markdown = await exportService.generateMarkdownReport(checkId, req.user?.id);
const fileName = filename || `redirect-report-${checkId}.md`;
if (download) {
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
}
res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
res.setHeader('Content-Length', Buffer.byteLength(markdown, 'utf8'));
res.send(markdown);
logger_1.logger.info(`Markdown export completed for check: ${checkId}`, {
userId: req.user?.id,
size: Buffer.byteLength(markdown, 'utf8'),
});
}
catch (error) {
logger_1.logger.error('Markdown export failed:', error);
if (error instanceof zod_1.z.ZodError) {
return res.status(400).json({
success: false,
error: 'Validation error',
message: error.errors[0]?.message || 'Invalid input',
details: error.errors
});
}
const statusCode = error instanceof Error && error.message.includes('not found') ? 404 : 500;
res.status(statusCode).json({
success: false,
error: 'Export failed',
message: error instanceof Error ? error.message : 'Failed to generate markdown report'
});
}
});
router.get('/:checkId/pdf', auth_middleware_1.optionalAuth, exportLimiter, async (req, res) => {
try {
const { checkId } = exportParamsSchema.parse(req.params);
const { download, filename } = exportQuerySchema.parse(req.query);
logger_1.logger.info(`Generating PDF export for check: ${checkId}`, {
userId: req.user?.id,
download: !!download,
});
const pdfBuffer = await exportService.generatePdfReport(checkId, req.user?.id);
const fileName = filename || `redirect-report-${checkId}.pdf`;
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Length', pdfBuffer.length);
if (download) {
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
}
else {
res.setHeader('Content-Disposition', `inline; filename="${fileName}"`);
}
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
res.send(pdfBuffer);
logger_1.logger.info(`PDF export completed for check: ${checkId}`, {
userId: req.user?.id,
size: pdfBuffer.length,
});
}
catch (error) {
logger_1.logger.error('PDF export failed:', error);
if (error instanceof zod_1.z.ZodError) {
return res.status(400).json({
success: false,
error: 'Validation error',
message: error.errors[0]?.message || 'Invalid input',
details: error.errors
});
}
const statusCode = error instanceof Error && error.message.includes('not found') ? 404 : 500;
res.status(statusCode).json({
success: false,
error: 'Export failed',
message: error instanceof Error ? error.message : 'Failed to generate PDF report'
});
}
});
router.post('/:checkId/save', auth_middleware_1.requireAuth, exportLimiter, async (req, res) => {
try {
const { checkId } = exportParamsSchema.parse(req.params);
const { format = 'both' } = zod_1.z.object({
format: zod_1.z.enum(['markdown', 'pdf', 'both']).default('both'),
}).parse(req.body);
logger_1.logger.info(`Saving reports for check: ${checkId}`, {
userId: req.user.id,
format,
});
const results = [];
if (format === 'markdown' || format === 'both') {
const markdown = await exportService.generateMarkdownReport(checkId, req.user.id);
const mdPath = await exportService.saveReport(markdown, checkId, 'md');
results.push({ format: 'markdown', path: mdPath });
}
if (format === 'pdf' || format === 'both') {
const pdfBuffer = await exportService.generatePdfReport(checkId, req.user.id);
const pdfPath = await exportService.saveReport(pdfBuffer, checkId, 'pdf');
results.push({ format: 'pdf', path: pdfPath });
}
logger_1.logger.info(`Reports saved for check: ${checkId}`, {
userId: req.user.id,
results: results.length,
});
res.json({
success: true,
status: 200,
data: {
checkId,
reports: results,
savedAt: new Date().toISOString(),
},
meta: {
version: 'v2',
feature: 'export-save',
}
});
}
catch (error) {
logger_1.logger.error('Report save failed:', error);
if (error instanceof zod_1.z.ZodError) {
return res.status(400).json({
success: false,
error: 'Validation error',
message: error.errors[0]?.message || 'Invalid input',
details: error.errors
});
}
res.status(500).json({
success: false,
error: 'Save failed',
message: error instanceof Error ? error.message : 'Failed to save reports'
});
}
});
router.get('/formats', (req, res) => {
res.json({
success: true,
status: 200,
data: {
formats: [
{
name: 'markdown',
extension: 'md',
mimeType: 'text/markdown',
description: 'Human-readable Markdown format with embedded Mermaid diagrams',
features: ['mermaid_diagrams', 'tables', 'links', 'formatting'],
maxSize: '1MB',
},
{
name: 'pdf',
extension: 'pdf',
mimeType: 'application/pdf',
description: 'Professional PDF report with rendered charts and formatting',
features: ['rendered_diagrams', 'professional_layout', 'print_ready', 'embedded_fonts'],
maxSize: '10MB',
}
],
limits: {
rateLimit: '20 requests per hour',
maxReportAge: '90 days',
authentication: 'Optional (higher limits for authenticated users)',
},
endpoints: {
markdown: 'GET /api/v2/export/:checkId/markdown',
pdf: 'GET /api/v2/export/:checkId/pdf',
save: 'POST /api/v2/export/:checkId/save',
}
},
meta: {
version: 'v2',
feature: 'export-formats',
}
});
});
router.delete('/cleanup', auth_middleware_1.requireAuth, async (req, res) => {
try {
const { maxAgeHours = 24 } = zod_1.z.object({
maxAgeHours: zod_1.z.number().min(1).max(168).default(24),
}).parse(req.body);
logger_1.logger.info('Starting report cleanup', {
userId: req.user.id,
maxAgeHours,
});
await exportService.cleanupOldReports(maxAgeHours);
logger_1.logger.info('Report cleanup completed', {
userId: req.user.id,
maxAgeHours,
});
res.json({
success: true,
status: 200,
data: {
message: 'Cleanup completed successfully',
maxAgeHours,
cleanupTime: new Date().toISOString(),
},
meta: {
version: 'v2',
feature: 'export-cleanup',
}
});
}
catch (error) {
logger_1.logger.error('Report cleanup failed:', error);
if (error instanceof zod_1.z.ZodError) {
return res.status(400).json({
success: false,
error: 'Validation error',
message: error.errors[0]?.message || 'Invalid input',
details: error.errors
});
}
res.status(500).json({
success: false,
error: 'Cleanup failed',
message: error instanceof Error ? error.message : 'Failed to cleanup reports'
});
}
});
exports.default = router;
//# sourceMappingURL=export.routes.js.map