// apps/web/server.js import express from 'express'; import http from 'http'; import next from 'next'; import { WebSocketServer } from 'ws'; import { applyWSSHandler } from '@trpc/server/adapters/ws'; import { appRouter } from '@lifetracker/trpc/routers/_app'; import { createWSContext } from '@/server/api/ws'; import { parse } from 'url'; import { NextRequestHint } from 'next/dist/server/web/adapter'; const dev = process.env.NODE_ENV !== 'production'; // Create an Express app and HTTP server. const app = express(); const server = http.createServer(app); const nextApp = next({ dev, customServer: true, hostname: process.env.HOSTNAME || "localhost", port: Number(process.env.PORT) || 3000, }); const handle = nextApp.getRequestHandler(); nextApp.prepare().then(() => { // Fallback to NextJS request handling for everything else. app.all('*', (req: express.Request, res: express.Response) => { return handle(req, res); }); // Create a WebSocket server that shares the same HTTP server. const wss = new WebSocketServer({ noServer: true, path: '/api/ws', }); // Attach the TRPC WebSocket handler. const handler = applyWSSHandler({ wss, router: appRouter, createContext: createWSContext, }); wss.on('connection', (ws) => { console.log(`➕➕ Got new websocket connection (now ${wss.clients.size})`); ws.once('close', () => { console.log(`➖➖ Closed websocket connection (now ${wss.clients.size})`); }); }); wss.on('error', function (error) { console.log(error); }); const port = process.env.PORT || 3000; server.listen(port, () => { console.log(`> Server listening on http://localhost:${port}`); console.log(`> TRPC WebSocket server listening at ws://localhost:${port}/api/ws`); }); app.all('*', (req: express.Request, res: express.Response) => { return handle(req, res); }); server.on('upgrade', (request, socket, head) => { const { pathname } = parse(request.url!); // Only handle WebSocket upgrades of the specific path(s) your application // needs to handle if (pathname === "/api/ws") { wss.handleUpgrade(request, socket, head, function done(ws) { console.log("Socket connected"); // At this point, you have the WebSocket in `ws` // and the original HTTP request in `request` available ws.send("Hello from Lifetracker!"); }); } }); // Handle graceful shutdown. process.on('SIGTERM', () => { console.log('SIGTERM received, shutting down gracefully.'); handler.broadcastReconnectNotification(); server.close(); }); });