import express from 'express'; import { createServer } from 'http'; import { WebSocketServer } from 'ws'; import { createClient } from '@supabase/supabase-js'; import crypto from 'crypto'; import path from 'path'; import { fileURLToPath } from 'url'; import { handleWsMessage } from './wsHandler.js'; import { sessionStore, initStoreConfig } from './sessionStore.js'; import { SUPABASE_URL, SUPABASE_ANON_KEY } from './config.js'; import { safeSend } from './helpers.js'; export { SUPABASE_URL, SUPABASE_ANON_KEY }; export { LIGHTNING_BASE, PUBLIC_URL } from './config.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); initStoreConfig(SUPABASE_URL, SUPABASE_ANON_KEY); export const supabaseAnon = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); const PORT = process.env.PORT || 7860; const app = express(); app.use(express.static(path.join(__dirname, '..', 'public'))); app.use(express.json({ limit: '10mb' })); app.get('/health', (_req, res) => res.json({ ok: true })); app.get('/api/share/:token', async (req, res) => { try { const shared = await sessionStore.resolveShareToken(req.params.token); if (!shared) return res.status(404).json({ error: 'Not found' }); const snap = shared.session_snapshot; res.json({ name: snap.name, preview: (snap.history || []).slice(0, 6).map(m => ({ role: m.role, content: (typeof m.content === 'string' ? m.content : JSON.stringify(m.content)).slice(0, 400), })), }); } catch { res.status(500).json({ error: 'Server error' }); } }); app.get('*', (req, res) => { if (!req.path.startsWith('/api/')) res.sendFile(path.join(__dirname, '..', 'public', 'index.html')); }); const httpServer = createServer(app); const wss = new WebSocketServer({ server: httpServer, path: '/ws' }); export const wsClients = new Map(); wss.on('connection', (ws, req) => { const ip = (req.headers['x-forwarded-for'] || '').split(',')[0].trim() || req.socket.remoteAddress || 'unknown'; const userAgent = req.headers['user-agent'] || 'unknown'; wsClients.set(ws, { tempId: crypto.randomUUID(), ip, userAgent, userId: null, authenticated: false }); ws.on('message', async raw => { try { await handleWsMessage(ws, JSON.parse(raw.toString()), wsClients); } catch (ex) { safeSend(ws, { type: 'error', message: 'Invalid message' }); console.log("Invalid message: " + ex); } }); ws.on('close', () => { const c = wsClients.get(ws); if (c?.userId) sessionStore.markOffline(c.userId, ws); wsClients.delete(ws); }); ws.on('error', () => wsClients.delete(ws)); safeSend(ws, { type: 'connected', tempId: wsClients.get(ws)?.tempId }); }); httpServer.listen(PORT, '0.0.0.0', () => console.log(`InferencePort Web on port ${PORT}`));