84398de390
Destructive removal per user confirmation ("حذف نهائي ما يرجع").
Removed:
- API: routes/conversations.ts, schema/conversations.ts, all chat
socket handlers in src/index.ts, /admin/users/:id/dependents/
conversations+messages endpoints, conversation/message dependency
counts in users/stats routes.
- Web: pages/chat.tsx, /chat route, dock chat filter, MessageSquare
icon and messages StatCard on home, all chat-related UI in
notifications + admin (dependency badges, delete-dialog rows,
UserDependentConversations/Messages sections, count map keys).
- Locales: nav.chat, home.stats.messages, full chat.* block,
admin.deleteUser conv/msgCount, admin.users.counts.conv/msg,
admin.audit.unit.conversation_*/message_*, admin.dependents.user*.
- OpenAPI spec: tags, all /conversations/* paths, conv/msg dependent
paths, related schemas (ConversationWithDetails, MessageWithSender,
UserDependentConversation/MessageItem+Page, etc.), UserProfile and
UserDeletionConflict conv/msg fields, HomeStats.unreadMessages.
Regenerated client via orval.
- Database: dropped message_reads, messages,
conversation_participants, conversations (CASCADE); deleted
notifications with related_type='conversation' or type='chat';
deleted apps row with slug='chat'; ran drizzle push-force.
- Seed: removed chat:access permission + user-role assignment +
seeded chat app entry from scripts/src/seed.ts.
- Tests: deleted conversations-leave.test.mjs; cleaned chat refs from
list-dependency-counts, delete-force-warnings, audit-log-coverage,
and admin-inline-dependency-counts (e2e) — replaced chat dependents
with note dependents where needed for force-delete coverage.
Notes preserved: notes.tsx noConversationsYet/conversationWith refer
to NOTE THREADS (not chat) and were intentionally NOT touched.
executive-meetings.ts not modified per replit.md restriction.
Pre-existing flaky test failures in executive-meetings/group/etc
suites remain unrelated to this task.
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
import { createServer } from "http";
|
|
import { Server as SocketIOServer } from "socket.io";
|
|
import type { IncomingMessage, ServerResponse } from "http";
|
|
import app, { sessionMiddleware } from "./app";
|
|
import { logger } from "./lib/logger";
|
|
|
|
const rawPort = process.env["PORT"];
|
|
|
|
if (!rawPort) {
|
|
throw new Error(
|
|
"PORT environment variable is required but was not provided.",
|
|
);
|
|
}
|
|
|
|
const port = Number(rawPort);
|
|
|
|
if (Number.isNaN(port) || port <= 0) {
|
|
throw new Error(`Invalid PORT value: "${rawPort}"`);
|
|
}
|
|
|
|
const httpServer = createServer(app);
|
|
|
|
export const io = new SocketIOServer(httpServer, {
|
|
path: "/api/socket.io",
|
|
cors: {
|
|
origin: process.env.ALLOWED_ORIGINS
|
|
? process.env.ALLOWED_ORIGINS.split(",").map((o) => o.trim())
|
|
: true,
|
|
methods: ["GET", "POST"],
|
|
credentials: true,
|
|
},
|
|
});
|
|
|
|
io.engine.use(
|
|
(req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => {
|
|
sessionMiddleware(req as Parameters<typeof sessionMiddleware>[0], res as Parameters<typeof sessionMiddleware>[1], next);
|
|
},
|
|
);
|
|
|
|
io.use((socket, next) => {
|
|
const req = socket.request as IncomingMessage & { session?: { userId?: number } };
|
|
const userId = req.session?.userId;
|
|
if (!userId) {
|
|
return next(new Error("Unauthorized: no session"));
|
|
}
|
|
socket.data.userId = userId;
|
|
next();
|
|
});
|
|
|
|
io.on("connection", (socket) => {
|
|
const userId = socket.data.userId as number;
|
|
logger.info({ socketId: socket.id, userId }, "Socket connected");
|
|
|
|
socket.join(`user:${userId}`);
|
|
|
|
socket.on("disconnect", () => {
|
|
logger.info({ socketId: socket.id }, "Socket disconnected");
|
|
});
|
|
});
|
|
|
|
httpServer.listen(port, () => {
|
|
logger.info({ port }, "Server listening");
|
|
});
|