File size: 4,325 Bytes
1fe073f
 
 
371b64f
1fe073f
 
 
 
 
 
 
 
1fa708f
 
 
1fe073f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b125087
 
 
1fe073f
 
 
b125087
 
 
 
 
 
1fe073f
 
 
 
 
 
a6d0947
1fe073f
a6d0947
a510753
 
 
 
 
 
 
 
7f05a1c
a510753
 
67d10f0
1fe073f
 
 
 
 
a510753
1fe073f
 
 
 
 
 
 
 
 
 
 
 
 
a510753
1fe073f
 
 
 
 
 
 
 
 
a510753
1fe073f
 
 
 
 
 
 
 
 
 
 
 
 
a510753
1fe073f
 
 
 
67d10f0
a510753
67d10f0
a510753
67d10f0
 
c607f92
 
 
 
 
 
a510753
67d10f0
 
a6d0947
67d10f0
 
 
 
 
 
 
 
 
a510753
 
 
1fe073f
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
const express = require('express');
const cors = require('cors');
const dotenv = require('dotenv');
const path = require('path');

// Import models
const News = require('./models/News');
const Dataset = require('./models/Dataset');

dotenv.config();

const app = express();
// Use port 8501 for Hugging Face Spaces, or 3001 for local development
const isHuggingFaceSpaces = process.env.HF_SPACES === 'true' || process.env.HF_SPACES === true || !!process.env.HF_SPACES;
const PORT = isHuggingFaceSpaces ? 8501 : (process.env.PORT || 3001);

// Enable CORS for all origins in development, specific origins in production
if (process.env.NODE_ENV === 'development') {
  app.use(cors());
} else {
  // In production (like Hugging Face Spaces), be more specific about CORS
  app.use(cors({
    origin: function (origin, callback) {
      // Allow requests with no origin (like mobile apps or curl requests)
      if (!origin) return callback(null, true);
      
      // Allow localhost in development
      if (origin.startsWith('http://localhost') || 
          origin.startsWith('https://localhost') ||
          origin.includes('huggingface.co') ||
          origin.includes('hf.space') ||
          origin === 'http://localhost:80' ||
          origin === 'http://localhost:5173') {
        return callback(null, true);
      }
      
      // Allow same origin requests
      if (origin === `http://localhost:${PORT}`) {
        return callback(null, true);
      }
      
      callback(null, true); // Allow all in production for now
    }
  }));
}

app.use(express.json());

// Serve static files from the public directory in production
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, 'public')));
}

// Health check endpoint
app.get('/health', (req, res) => {
  res.status(200).json({ 
    status: 'OK', 
    timestamp: new Date().toISOString(),
    uptime: process.uptime()
  });
});

// API routes
app.get('/api/news', async (req, res) => {
  try {
    const news = await News.getAll();
    res.json(news);
  } catch (error) {
    console.error('Error fetching news:', error);
    res.status(500).json({ error: 'Failed to fetch news' });
  }
});

app.get('/api/news/:id', async (req, res) => {
  try {
    const { id } = req.params;
    const newsItem = await News.getById(id);
    if (!newsItem) {
      return res.status(404).json({ error: 'News item not found' });
    }
    res.json(newsItem);
  } catch (error) {
    console.error('Error fetching news item:', error);
    res.status(500).json({ error: 'Failed to fetch news item' });
  }
});

app.get('/api/datasets', async (req, res) => {
  try {
    const datasets = await Dataset.getAll();
    res.json(datasets);
  } catch (error) {
    console.error('Error fetching datasets:', error);
    res.status(500).json({ error: 'Failed to fetch datasets' });
  }
});

app.get('/api/datasets/:id', async (req, res) => {
  try {
    const { id } = req.params;
    const dataset = await Dataset.getById(id);
    if (!dataset) {
      return res.status(404).json({ error: 'Dataset not found' });
    }
    res.json(dataset);
  } catch (error) {
    console.error('Error fetching dataset:', error);
    res.status(500).json({ error: 'Failed to fetch dataset' });
  }
});

// Serve the React app for all non-API routes in production
if (process.env.NODE_ENV === 'production') {
  // For any non-API routes, serve the React app
  app.get('*', (req, res) => {
    // Don't serve the React app for API routes or health check
    if (req.path.startsWith('/api/') || req.path === '/health') {
      // For API routes that don't exist, return 404
      if (req.path.startsWith('/api/')) {
        return res.status(404).json({ error: 'API endpoint not found' });
      }
      // For health check, it's already handled above
      return res.status(404).json({ error: 'Not found' });
    }
    
    // Serve the React app for all other routes
    res.sendFile(path.resolve(__dirname, 'public', 'index.html'));
  });
} else {
  // In development, serve API info at root
  app.get('/', (req, res) => {
    res.json({ 
      message: 'BioNexus Hub API', 
      version: '1.0.0',
      timestamp: new Date().toISOString()
    });
  });
}

app.listen(PORT, '0.0.0.0', () => {
  console.log(`BioNexus Hub server running on port ${PORT}`);
});