|
| 1 | +"use strict"; |
| 2 | +var __importDefault = (this && this.__importDefault) || function (mod) { |
| 3 | + return (mod && mod.__esModule) ? mod : { "default": mod }; |
| 4 | +}; |
| 5 | +Object.defineProperty(exports, "__esModule", { value: true }); |
| 6 | +const express_1 = __importDefault(require("express")); |
| 7 | +const cors_1 = __importDefault(require("cors")); |
| 8 | +const helmet_1 = __importDefault(require("helmet")); |
| 9 | +const morgan_1 = __importDefault(require("morgan")); |
| 10 | +const express_rate_limit_1 = __importDefault(require("express-rate-limit")); |
| 11 | +const dotenv_1 = __importDefault(require("dotenv")); |
| 12 | +const auth_1 = require("./routes/auth"); |
| 13 | +const transfer_1 = require("./routes/transfer"); |
| 14 | +const webhook_1 = require("./routes/webhook"); |
| 15 | +const admin_1 = require("./routes/admin"); |
| 16 | +const usecases_1 = require("./routes/usecases"); |
| 17 | +const billing_1 = require("./routes/billing"); |
| 18 | +const apiKey_1 = require("./middleware/apiKey"); |
| 19 | +const hmac_1 = require("./middleware/hmac"); |
| 20 | +const errorHandler_1 = require("./middleware/errorHandler"); |
| 21 | +dotenv_1.default.config(); |
| 22 | +const app = (0, express_1.default)(); |
| 23 | +const PORT = process.env.PORT || 3000; |
| 24 | +// Security middleware |
| 25 | +app.use((0, helmet_1.default)({ |
| 26 | + contentSecurityPolicy: { |
| 27 | + directives: { |
| 28 | + defaultSrc: ["'self'"], |
| 29 | + scriptSrc: ["'self'"], |
| 30 | + styleSrc: ["'self'", "'unsafe-inline'"], |
| 31 | + connectSrc: ["'self'"], |
| 32 | + frameAncestors: ["'none'"] |
| 33 | + } |
| 34 | + }, |
| 35 | + hsts: { maxAge: 31536000, includeSubDomains: true, preload: true }, |
| 36 | + referrerPolicy: { policy: 'strict-origin-when-cross-origin' } |
| 37 | +})); |
| 38 | +const allowedOrigins = (process.env.ALLOWED_ORIGINS || '').split(',').filter(o => o && o !== '*'); |
| 39 | +app.use((0, cors_1.default)({ |
| 40 | + origin: allowedOrigins.length > 0 ? allowedOrigins : (process.env.NODE_ENV === 'production' ? false : true), |
| 41 | + credentials: true, |
| 42 | + methods: ['GET', 'POST', 'PUT', 'DELETE'], |
| 43 | + allowedHeaders: ['Content-Type', 'Authorization', 'x-reverso-signature', 'x-reverso-timestamp', 'x-reverso-nonce'] |
| 44 | +})); |
| 45 | +app.use((0, morgan_1.default)('combined')); |
| 46 | +// Raw body for Stripe webhook signature verification |
| 47 | +app.use('/api/v1/billing/webhook', express_1.default.raw({ type: 'application/json', limit: '1mb' }), (req, _res, next) => { |
| 48 | + req.rawBody = req.body; |
| 49 | + req.body = JSON.parse(req.body.toString()); |
| 50 | + next(); |
| 51 | +}); |
| 52 | +app.use(express_1.default.json({ limit: '10mb' })); |
| 53 | +// Global rate limit |
| 54 | +const globalLimiter = (0, express_rate_limit_1.default)({ |
| 55 | + windowMs: 15 * 60 * 1000, // 15 minutes |
| 56 | + max: 1000, // max 1000 requests per 15 min |
| 57 | + message: { error: 'Too many requests, please try again later' } |
| 58 | +}); |
| 59 | +app.use(globalLimiter); |
| 60 | +// Health check (no auth) |
| 61 | +app.get('/health', (req, res) => { |
| 62 | + res.json({ |
| 63 | + status: 'ok', |
| 64 | + version: '1.0.0', |
| 65 | + timestamp: new Date().toISOString() |
| 66 | + }); |
| 67 | +}); |
| 68 | +// API Documentation |
| 69 | +app.get('/', (req, res) => { |
| 70 | + res.json({ |
| 71 | + name: 'REVERSO Enterprise API', |
| 72 | + version: '1.0.0', |
| 73 | + documentation: 'https://reverso.one/api', |
| 74 | + endpoints: { |
| 75 | + auth: '/api/v1/auth', |
| 76 | + transfers: '/api/v1/transfers', |
| 77 | + webhooks: '/api/v1/webhooks', |
| 78 | + admin: '/api/v1/admin' |
| 79 | + }, |
| 80 | + plans: { |
| 81 | + starter: { price: '$99/month', txLimit: 100, features: ['API Access', 'Email Support'] }, |
| 82 | + business: { price: '$499/month', txLimit: -1, features: ['Unlimited TX', 'Dashboard', 'Priority Support'] }, |
| 83 | + enterprise: { price: '$2000/month', txLimit: -1, features: ['White-label', 'SLA', '24/7 Support', 'Custom Integration', 'Usecase APIs'] } |
| 84 | + } |
| 85 | + }); |
| 86 | +}); |
| 87 | +// Public routes |
| 88 | +app.use('/api/v1/auth', auth_1.authRouter); |
| 89 | +app.use('/api/v1/billing', billing_1.billingRouter); |
| 90 | +// Protected routes (require API key + HMAC) |
| 91 | +app.use('/api/v1/transfers', apiKey_1.apiKeyMiddleware, hmac_1.hmacMiddleware, transfer_1.transferRouter); |
| 92 | +app.use('/api/v1/webhooks', apiKey_1.apiKeyMiddleware, hmac_1.hmacMiddleware, webhook_1.webhookRouter); |
| 93 | +app.use('/api/v1/admin', apiKey_1.apiKeyMiddleware, hmac_1.hmacMiddleware, admin_1.adminRouter); |
| 94 | +app.use('/api/v1/usecases', apiKey_1.apiKeyMiddleware, hmac_1.hmacMiddleware, usecases_1.usecaseRouter); |
| 95 | +// Error handling |
| 96 | +app.use(errorHandler_1.errorHandler); |
| 97 | +// 404 handler |
| 98 | +app.use((req, res) => { |
| 99 | + res.status(404).json({ error: 'Endpoint not found' }); |
| 100 | +}); |
| 101 | +app.listen(PORT, () => { |
| 102 | + console.log(` |
| 103 | +╔═══════════════════════════════════════════════════════════╗ |
| 104 | +║ ║ |
| 105 | +║ 🔄 REVERSO Enterprise API v1.0.0 ║ |
| 106 | +║ ║ |
| 107 | +║ Server running on port ${PORT} ║ |
| 108 | +║ Documentation: https://reverso.one/api ║ |
| 109 | +║ ║ |
| 110 | +║ Plans: ║ |
| 111 | +║ • Starter: $99/mo - 100 tx/month ║ |
| 112 | +║ • Business: $499/mo - Unlimited tx ║ |
| 113 | +║ • Enterprise: $2000/mo - White-label + SLA ║ |
| 114 | +║ ║ |
| 115 | +╚═══════════════════════════════════════════════════════════╝ |
| 116 | + `); |
| 117 | + // Self-ping every 14 minutes to keep Render free tier awake |
| 118 | + const SELF_URL = process.env.RENDER_EXTERNAL_URL || `http://localhost:${PORT}`; |
| 119 | + setInterval(() => { |
| 120 | + fetch(`${SELF_URL}/health`).catch(() => { }); |
| 121 | + }, 14 * 60 * 1000); |
| 122 | +}); |
| 123 | +exports.default = app; |
0 commit comments