everydaycats commited on
Commit
1b2b030
·
verified ·
1 Parent(s): 064c840

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +165 -1
app.js CHANGED
@@ -3,6 +3,169 @@ import { createServer } from 'http';
3
  import { WebSocketServer, WebSocket } from 'ws';
4
  import cors from 'cors';
5
  import jwt from 'jsonwebtoken';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  import { v4 as uuidv4 } from 'uuid';
7
  import { createClient } from '@supabase/supabase-js';
8
 
@@ -150,4 +313,5 @@ setInterval(() => {
150
  });
151
  }, 30000);
152
 
153
- server.listen(PORT, () => console.log(`🚀 Gateway on ${PORT}`));
 
 
3
  import { WebSocketServer, WebSocket } from 'ws';
4
  import cors from 'cors';
5
  import jwt from 'jsonwebtoken';
6
+ import { createClient } from '@supabase/supabase-js';
7
+
8
+ const PORT = 7860;
9
+ const SUPABASE_URL = process.env.SUPABASE_URL;
10
+ const SUPABASE_KEY = process.env.SUPABASE_SERVICE_KEY;
11
+ const CORE_URL = process.env.CORE_URL || "http://localhost:7862";
12
+
13
+ if (!SUPABASE_URL) { console.error("❌ Config Missing"); process.exit(1); }
14
+
15
+ const app = express();
16
+ const server = createServer(app);
17
+ const wss = new WebSocketServer({ noServer: true });
18
+ const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
19
+
20
+ const clients = new Map(); // UserId -> Set<WebSocket>
21
+
22
+ app.use(cors());
23
+ app.use(express.json({ limit: '50mb' }));
24
+
25
+ app.get('/', (req, res) => res.send('Gateway Active'));
26
+
27
+ // Internal Notification Webhook
28
+ app.post('/internal/notify', (req, res) => {
29
+ const { user_id, type, message } = req.body;
30
+ if (clients.has(user_id)) {
31
+ clients.get(user_id).forEach(ws => {
32
+ if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type, message }));
33
+ });
34
+ return res.json({ success: true });
35
+ }
36
+ res.json({ success: false });
37
+ });
38
+
39
+ // Verify JWT against DB Secret
40
+ async function verifyThrustToken(token) {
41
+ const decoded = jwt.decode(token);
42
+ if (!decoded || !decoded.sid) return null;
43
+
44
+ const { data: session } = await supabase
45
+ .from('user_sessions')
46
+ .select('session_secret')
47
+ .eq('id', decoded.sid)
48
+ .single();
49
+
50
+ if (!session) return null;
51
+
52
+ try {
53
+ return jwt.verify(token, session.session_secret);
54
+ } catch (e) {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ // --- NEW: FETCH PAGINATED PROJECTS VIA JWT ---
60
+ app.get('/api/projects', async (req, res) => {
61
+ const authHeader = req.headers.authorization;
62
+ if (!authHeader?.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
63
+
64
+ const token = authHeader.split(' ')[1];
65
+ const decoded = await verifyThrustToken(token);
66
+
67
+ if (!decoded || !decoded.uid) return res.status(403).json({ error: 'Invalid Token' });
68
+
69
+ // Pagination Logic (Default: 9 items per page for a 3x3 grid)
70
+ const page = parseInt(req.query.page) || 1;
71
+ const limit = parseInt(req.query.limit) || 9;
72
+ const start = (page - 1) * limit;
73
+ const end = start + limit - 1;
74
+
75
+ const { data, count, error } = await supabase
76
+ .from('leads')
77
+ .select('*', { count: 'exact' })
78
+ .eq('user_id', decoded.uid)
79
+ .order('created_at', { ascending: false })
80
+ .range(start, end);
81
+
82
+ if (error) return res.status(500).json({ error: error.message });
83
+
84
+ res.json({
85
+ projects: data,
86
+ total: count,
87
+ page: page,
88
+ totalPages: Math.ceil(count / limit) || 1
89
+ });
90
+ });
91
+
92
+ // WS Upgrade
93
+ server.on('upgrade', async (request, socket, head) => {
94
+ const url = new URL(request.url, `http://${request.headers.host}`);
95
+ const token = url.searchParams.get('token');
96
+
97
+ if (!token) { socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); socket.destroy(); return; }
98
+
99
+ const decodedData = await verifyThrustToken(token);
100
+
101
+ if (!decodedData) { socket.write('HTTP/1.1 403 Forbidden\r\n\r\n'); socket.destroy(); return; }
102
+
103
+ wss.handleUpgrade(request, socket, head, (ws) => {
104
+ wss.emit('connection', ws, request, decodedData);
105
+ });
106
+ });
107
+
108
+ // WS Logic
109
+ wss.on('connection', (ws, req, user) => {
110
+ // Note: 'uid' is what we encoded into the JWT in the Auth Proxy
111
+ const userId = user.uid;
112
+
113
+ if (!clients.has(userId)) clients.set(userId, new Set());
114
+ clients.get(userId).add(ws);
115
+
116
+ ws.isAlive = true;
117
+ ws.on('pong', () => { ws.isAlive = true; });
118
+
119
+ ws.on('message', async (message) => {
120
+ try {
121
+ const data = JSON.parse(message.toString());
122
+
123
+ if (data.type === 'prompt') {
124
+ ws.send(JSON.stringify({ type: 'status', status: 'thinking' }));
125
+
126
+ const response = await fetch(`${CORE_URL}/process`, {
127
+ method: 'POST',
128
+ headers: { 'Content-Type': 'application/json' },
129
+ body: JSON.stringify({
130
+ userId: userId,
131
+ projectId: data.projectId,
132
+ prompt: data.content,
133
+ context: data.context,
134
+ task_type: 'chat'
135
+ })
136
+ });
137
+
138
+ if (!response.ok) throw new Error("Core API Failed");
139
+ const result = await response.json();
140
+
141
+ ws.send(JSON.stringify({ type: 'response', text: result.text, should_reload: result.should_reload, usage: result.usage }));
142
+ }
143
+ } catch (e) {
144
+ console.error("WS Error", e);
145
+ ws.send(JSON.stringify({ type: 'error', message: "Processing Error" }));
146
+ }
147
+ });
148
+
149
+ ws.on('close', () => {
150
+ if (clients.has(userId)) clients.get(userId).delete(ws);
151
+ });
152
+ });
153
+
154
+ setInterval(() => {
155
+ wss.clients.forEach((ws) => {
156
+ if (ws.isAlive === false) return ws.terminate();
157
+ ws.isAlive = false;
158
+ ws.ping();
159
+ });
160
+ }, 30000);
161
+
162
+ server.listen(PORT, () => console.log(`🚀 Gateway on ${PORT}`));
163
+
164
+ /* import express from 'express';
165
+ import { createServer } from 'http';
166
+ import { WebSocketServer, WebSocket } from 'ws';
167
+ import cors from 'cors';
168
+ import jwt from 'jsonwebtoken';
169
  import { v4 as uuidv4 } from 'uuid';
170
  import { createClient } from '@supabase/supabase-js';
171
 
 
313
  });
314
  }, 30000);
315
 
316
+ server.listen(PORT, () => console.log(`🚀 Gateway on ${PORT}`));
317
+ */