const express = require('express'); const cors = require('cors'); const path = require('path'); const app = express(); const PORT = process.env.PORT || 7860; const AWS_API_BASE = process.env.API_URL || 'https://betaprecision.com/api/v1/chain-of-custody'; app.use(cors()); app.use(express.json({ limit: '20mb' })); app.use(express.static(path.join(__dirname, 'public'))); // Default Sample Dataset Fallback const FALLBACK_DEMO = { success: true, docName: "Master_Services_Agreement_Demo.pdf", clauses: [ { id: "clause-0", index: 1, heading: "ARTICLE 1. APPOINTMENT & SCOPE", text: "Provider shall perform professional technology consulting services as set forth in statements of work executed by both parties. All services will be performed in a professional and workmanlike manner.", matrix: [[0.12,0.08,-0.04],[0.08,0.15,-0.02],[-0.04,-0.02,0.18]], topCategory: "Warranty Disclaimer", topScore: 0.78, risk: { key: "risk-match", label: "Matches baseline" }, incomingEdge: null }, { id: "clause-1", index: 2, heading: "ARTICLE 2. UNLIMITED SPECIAL LIABILITY", text: "Notwithstanding any other provision herein, Provider's liability under this Agreement is completely uncapped, and Provider expressly waives all exclusions for incidental, indirect, punitive, or consequential damages.", matrix: [[-0.22,0.14,-0.18],[0.14,-0.28,0.12],[-0.18,0.12,-0.32]], topCategory: "Limitation of Liability", topScore: 0.32, risk: { key: "risk-diverge", label: "Diverges from baseline" }, incomingEdge: { from: "clause-0", to: "clause-1", fromIndex: 1, toIndex: 2, fidelity: 0.21, bures: 1.254, tension: 0.48, gamma: 0.14, status: "broken", breakReason: "Severe Liability Fracture (T=0.48)" } }, { id: "clause-2", index: 3, heading: "ARTICLE 3. SUDDEN UNILATERAL INDEMNIFICATION", text: "Provider shall defend, indemnify, and hold harmless Customer against any and all losses, damages, and legal costs arising from any claim, whether due to market fluctuations or Customer's contributory negligence.", matrix: [[-0.18,-0.08,0.22],[-0.08,0.19,-0.11],[0.22,-0.11,-0.25]], topCategory: "Indemnification", topScore: 0.41, risk: { key: "risk-diverge", label: "Diverges from baseline" }, incomingEdge: { from: "clause-1", to: "clause-2", fromIndex: 2, toIndex: 3, fidelity: 0.35, bures: 1.140, tension: 0.39, gamma: 0.22, status: "broken", breakReason: "Hostile Indemnity Shift" } } ], cocEdges: [ { from: "clause-0", to: "clause-1", fromIndex: 1, toIndex: 2, fidelity: 0.21, bures: 1.254, tension: 0.48, gamma: 0.14, status: "broken" }, { from: "clause-1", to: "clause-2", fromIndex: 2, toIndex: 3, fidelity: 0.35, bures: 1.140, tension: 0.39, gamma: 0.22, status: "broken" } ] }; // Route: Default CoC app.get('/api/coc/default', async (req, res) => { try { const response = await fetch(AWS_API_BASE, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (!response.ok) throw new Error(`Backend returned HTTP ${response.status}`); const data = await response.json(); res.json(data); } catch (error) { console.warn('Backend unavailable, using fallback data:', error.message); res.json(FALLBACK_DEMO); } }); // Route: Analyze Contract app.post('/api/coc/analyze', async (req, res) => { try { const response = await fetch(`${AWS_API_BASE}/analyze`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(req.body) }); if (!response.ok) throw new Error(`Backend returned HTTP ${response.status}`); const data = await response.json(); res.json(data); } catch (error) { console.error('Analysis error:', error.message); res.status(500).json({ success: false, error: error.message }); } }); // Serve frontend SPA fallback app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); app.listen(PORT, '0.0.0.0', () => { console.log(`⚡ Pure Node.js Server listening on port ${PORT}`); });