import express from 'express'; import { createServer as createHttpServer } from 'node:http'; import path from 'path'; import { fileURLToPath } from 'url'; import { createServer as createViteServer } from 'vite'; import healthRouter from './routes/health'; import llmRouter from './routes/llm'; import previewRouter from './routes/preview'; import artifactsRouter from './routes/artifacts'; import tenantRouter from './routes/tenant'; import bucketsRouter from './routes/buckets'; import gitRouter from './routes/git'; import codingSessionsRouter from './routes/codingSessions'; import codexAccountRouter from './routes/codexAccount'; import { requireRokcetAuth } from './auth'; import { developerMcpClientMetadata } from './services/bucketsMcpOAuth'; import { attachRokcetNodeGateway } from './services/rokcetNodeConnection'; import { attachWorkspaceHostGateway } from './services/workspaceHostConnection'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); export function createApp() { const app = express(); app.set('trust proxy', 1); app.use(express.json({ limit: '25mb' })); // Public OAuth Client ID Metadata Document for Buckets Developer MCP. In // production this HTTPS URL is itself Rokcet's public OAuth client_id. app.get('/.well-known/buckets-developer-mcp-client', (_req, res) => { res.setHeader('Content-Type', 'application/client-metadata+json'); res.setHeader('Cache-Control', 'public, max-age=300'); res.json(developerMcpClientMetadata()); }); // Public health and authentication/session establishment. tenantRouter applies // authentication internally to its workspace/deployment routes. app.use('/api', healthRouter); app.use('/api', tenantRouter); // Rokcet workspace capabilities are product-session protected. A Buckets central // SSO session is exchanged for a local Rokcet session before reaching these. app.use('/api', requireRokcetAuth, llmRouter); app.use('/api', requireRokcetAuth, artifactsRouter); app.use('/api', requireRokcetAuth, bucketsRouter); app.use('/api', requireRokcetAuth, gitRouter); app.use('/api', requireRokcetAuth, codingSessionsRouter); app.use('/api', requireRokcetAuth, codexAccountRouter); // Preview compilation accepts generated source and therefore stays behind the // Rokcet product session. Rendering is request-scoped and serverless-safe. app.use('/api/preview', requireRokcetAuth); app.use(previewRouter); return app; } export async function startServer() { const app = createApp(); const PORT = Number(process.env.PORT || 3000); if (process.env.NODE_ENV !== 'production') { const vite = await createViteServer({ server: { middlewareMode: true }, appType: 'spa', }); app.use(vite.middlewares); } else { const distPath = path.join(process.cwd(), 'dist'); app.use(express.static(distPath)); app.get('*', (req, res) => { res.sendFile(path.join(distPath, 'index.html')); }); } const server = createHttpServer(app); attachRokcetNodeGateway(server); attachWorkspaceHostGateway(server); server.listen(PORT, '0.0.0.0', () => { console.log(`[Open WebUI Workspace Monorepo] Server listening at http://0.0.0.0:${PORT}`); }); return server; }