65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
|
|
import type { Server } from "socket.io";
|
|||
|
|
import type {
|
|||
|
|
ServerToClientEvents,
|
|||
|
|
ClientToServerEvents,
|
|||
|
|
InterServerEvents,
|
|||
|
|
SocketData,
|
|||
|
|
} from "@storybid/shared";
|
|||
|
|
|
|||
|
|
import { registerLiveAuctionHandlers } from "./live-auction.js";
|
|||
|
|
import { registerSilentAuctionHandlers } from "./silent-auction.js";
|
|||
|
|
import { verifyToken } from "../lib/jwt.js";
|
|||
|
|
|
|||
|
|
type IO = Server<ClientToServerEvents, ServerToClientEvents, InterServerEvents, SocketData>;
|
|||
|
|
|
|||
|
|
export function registerSocketHandlers(io: IO): void {
|
|||
|
|
// Auth middleware – validate JWT on handshake
|
|||
|
|
io.use((socket, next) => {
|
|||
|
|
const token =
|
|||
|
|
(socket.handshake.auth["token"] as string | undefined) ??
|
|||
|
|
(socket.handshake.headers["authorization"] as string | undefined)?.replace("Bearer ", "");
|
|||
|
|
|
|||
|
|
if (!token) {
|
|||
|
|
// Allow unauthenticated connections for display board / public catalog
|
|||
|
|
return next();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const payload = verifyToken(token);
|
|||
|
|
socket.data.bidderId = payload.role === "bidder" ? payload.sub : undefined;
|
|||
|
|
socket.data.staffId = payload.role !== "bidder" ? payload.sub : undefined;
|
|||
|
|
socket.data.role = payload.role;
|
|||
|
|
socket.data.deviceId = payload.deviceId;
|
|||
|
|
} catch {
|
|||
|
|
return next(new Error("Invalid token"));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
next();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
io.on("connection", (socket) => {
|
|||
|
|
console.log(`[socket] connected ${socket.id} role=${socket.data.role ?? "guest"}`);
|
|||
|
|
|
|||
|
|
// Auto-join personal room for outbid / checkout notifications
|
|||
|
|
if (socket.data.bidderId) {
|
|||
|
|
void socket.join(`bidder:${socket.data.bidderId}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Room join/leave for event-scoped broadcasts
|
|||
|
|
socket.on("join_event", (eventId) => {
|
|||
|
|
void socket.join(`event:${eventId}`);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
socket.on("leave_event", (eventId) => {
|
|||
|
|
void socket.leave(`event:${eventId}`);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
registerLiveAuctionHandlers(io, socket);
|
|||
|
|
registerSilentAuctionHandlers(io, socket);
|
|||
|
|
|
|||
|
|
socket.on("disconnect", (reason) => {
|
|||
|
|
console.log(`[socket] disconnected ${socket.id} reason=${reason}`);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|