somratpro Claude Haiku 4.5 commited on
Commit
c65d941
·
1 Parent(s): 2d464ab

Add WebSocket proxy and suppress events/ws log noise

Browse files

- Proxy WebSocket upgrades (events/ws) through to Paperclip using raw
net.connect — fixes persistent 403 reconnect spam in logs
- Skip morgan logging for /events/ws paths
- Switch from app.listen to http.createServer so upgrade events attach

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

Files changed (1) hide show
  1. health-server.js +29 -4
health-server.js CHANGED
@@ -5,6 +5,7 @@ const fs = require("fs");
5
  const path = require("path");
6
  const { promisify } = require("util");
7
  const http = require("http");
 
8
 
9
  const app = express();
10
  const PORT = 7861; // always public-facing port, never read from PORT (that's for Paperclip)
@@ -13,10 +14,11 @@ const PAPERCLIP_PORT = 3100;
13
 
14
  // Middleware
15
  app.use(cors());
16
- // Skip logging for health polling and static assets too noisy
17
  app.use(morgan("tiny", {
18
  skip: (req) => req.path === "/health" || req.path === "/sw.js" ||
19
- req.path.startsWith("/assets/") || req.path === "/favicon.ico"
 
20
  }));
21
  app.use(express.json());
22
  app.use(express.urlencoded({ extended: true }));
@@ -788,9 +790,32 @@ function getDashboardHTML() {
788
  }
789
 
790
  // ============================================================================
791
- // Start Server
792
  // ============================================================================
793
- app.listen(PORT, "0.0.0.0", () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794
  console.log(`✓ Health server listening on port ${PORT}`);
795
  console.log(`✓ Dashboard: http://localhost:${PORT}/`);
796
  console.log(`✓ API proxy: http://localhost:${PORT}/api/*`);
 
5
  const path = require("path");
6
  const { promisify } = require("util");
7
  const http = require("http");
8
+ const net = require("net");
9
 
10
  const app = express();
11
  const PORT = 7861; // always public-facing port, never read from PORT (that's for Paperclip)
 
14
 
15
  // Middleware
16
  app.use(cors());
17
+ // Skip logging for health polling, static assets, and WebSocket upgrade attempts
18
  app.use(morgan("tiny", {
19
  skip: (req) => req.path === "/health" || req.path === "/sw.js" ||
20
+ req.path.startsWith("/assets/") || req.path === "/favicon.ico" ||
21
+ req.path.endsWith("/events/ws")
22
  }));
23
  app.use(express.json());
24
  app.use(express.urlencoded({ extended: true }));
 
790
  }
791
 
792
  // ============================================================================
793
+ // Start Server + WebSocket Proxy
794
  // ============================================================================
795
+ const server = http.createServer(app);
796
+
797
+ // Proxy WebSocket upgrades (e.g. /api/companies/:id/events/ws) directly to Paperclip.
798
+ // Without this, the browser gets 403 and spams reconnect attempts.
799
+ server.on("upgrade", (req, socket, head) => {
800
+ const targetSocket = net.connect(PAPERCLIP_PORT, "127.0.0.1", () => {
801
+ let upgradeReq = `${req.method} ${req.url} HTTP/1.1\r\n`;
802
+ for (const [key, val] of Object.entries(req.headers)) {
803
+ upgradeReq += `${key}: ${val}\r\n`;
804
+ }
805
+ upgradeReq += "\r\n";
806
+ targetSocket.write(upgradeReq);
807
+ if (head && head.length > 0) targetSocket.write(head);
808
+ socket.pipe(targetSocket);
809
+ targetSocket.pipe(socket);
810
+ });
811
+ targetSocket.on("error", () => {
812
+ socket.write("HTTP/1.1 503 Service Unavailable\r\n\r\n");
813
+ socket.destroy();
814
+ });
815
+ socket.on("error", () => targetSocket.destroy());
816
+ });
817
+
818
+ server.listen(PORT, "0.0.0.0", () => {
819
  console.log(`✓ Health server listening on port ${PORT}`);
820
  console.log(`✓ Dashboard: http://localhost:${PORT}/`);
821
  console.log(`✓ API proxy: http://localhost:${PORT}/api/*`);