From 40980bedeb15ec2abfbe01cfdd145c67dfe0e270 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Tue, 25 Nov 2025 17:49:49 +0100 Subject: [PATCH 01/22] Added Date.now ClientChat that stores user, socket id and date --- frontend/src/pages/chat/chat.html | 32 +++++++++---------- frontend/src/pages/chat/chat.ts | 46 ++++++++++++++++++++++++++- frontend/src/routing/index.ts | 1 + src/@shared/package.json | 2 +- src/auth/package.json | 2 +- src/chat/src/app.ts | 52 ++++++++++++++++++++----------- src/pnpm-lock.yaml | 18 +++++------ src/user/package.json | 2 +- 8 files changed, 107 insertions(+), 48 deletions(-) diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index 1e765fc..a0f0dde 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -1,19 +1,19 @@
- -

- Chat Box -


- - -

Welcome


-
-
-
- - -
-
-

From this Chat Box you can send messages to other players

+ +

+ Chat Box +


+ + +

Welcome


+
+
+
+ +
-
\ No newline at end of file +
+

From this Chat Box you can send messages to other players

+
+ \ No newline at end of file diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 7c30261..18bca7a 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -12,6 +12,33 @@ document.addEventListener('ft:pageChange', () => { __socket = undefined; console.log("Page changed"); }) + + +document.addEventListener("visibilitychange", async () => { + + // When user leaves tab + if (document.visibilityState === "hidden") { + console.log("User LEFT this tab"); + + // if (__socket) { + // __socket.close(); + // __socket = undefined; + // } + + return; + } + + // When user returns to tab → soft reload using imported HTML file + if (document.visibilityState === "visible") { + // location.reload(); + //console.log(location.replace(location.href)); + + + console.log('Chat Visible') + } +}); + + function getSocket(): Socket { if (__socket === undefined) __socket = io("wss://localhost:8888", { @@ -23,6 +50,10 @@ function getSocket(): Socket { } +async function isLoggedIn() { + return getUser() || null; +} + function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { @@ -43,6 +74,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }; socket.emit('message', JSON.stringify(message)); }); + // Listen for messages from the server "MsgObjectServer" socket.on("MsgObjectServer", (data: any) => { console.log("Message Obj Recieved:", data.message); @@ -109,6 +141,11 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn console.log(`Added new message: ${text}`) }; + + socket.on("welcome", (data) => { + addMessage(`${data.msg}`); + }); + // Send button sendButton?.addEventListener("click", () => { if (sendtextbox && sendtextbox.value.trim()) { @@ -141,9 +178,13 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn // Help Text button bconnected?.addEventListener("click", async () => { + + const loggedIn = await isLoggedIn(); + + if (loggedIn?.name === undefined) return ; if (chatWindow) { addMessage('@list - lists all connected users in the chat'); - await socket.emit('list'); + socket.emit('list'); } }); socket.on('listObj', (list: string) => { @@ -152,6 +193,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }); + + + // Enter key to send message sendtextbox!.addEventListener('keydown', (event) => { if (event.key === 'Enter') { diff --git a/frontend/src/routing/index.ts b/frontend/src/routing/index.ts index 0c0b9a4..9e504db 100644 --- a/frontend/src/routing/index.ts +++ b/frontend/src/routing/index.ts @@ -196,6 +196,7 @@ export async function handleRoute() { return navigateTo(`/login?returnTo=${encodeURIComponent(window.location.pathname)}`) const app = document.getElementById('app')!; document.dispatchEvent(new CustomEvent('ft:pageChange' as any, {} as any) as any); + document.dispatchEvent(new CustomEvent('ft:tabChange' as any, {} as any) as any); let ret = await executeRouteHandler(route_handler, window.location.pathname, args) app.innerHTML = ret.html; if (ret.postInsert) { diff --git a/src/@shared/package.json b/src/@shared/package.json index edcf6a8..dad8675 100644 --- a/src/@shared/package.json +++ b/src/@shared/package.json @@ -20,7 +20,7 @@ "fastify-plugin": "^5.1.0", "joi": "^18.0.2", "otp": "^1.1.2", - "typebox": "^1.0.55", + "typebox": "^1.0.56", "uuidv7": "^1.0.2" }, "devDependencies": { diff --git a/src/auth/package.json b/src/auth/package.json index 855e7f8..adb5e2e 100644 --- a/src/auth/package.json +++ b/src/auth/package.json @@ -27,7 +27,7 @@ "fastify": "^5.6.2", "fastify-cli": "^7.4.1", "fastify-plugin": "^5.1.0", - "typebox": "^1.0.55" + "typebox": "^1.0.56" }, "devDependencies": { "@types/node": "^22.19.1", diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 4749bb9..0dbac4d 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -11,7 +11,12 @@ declare const __SERVICE_NAME: string; // Global map of clients // key = socket, value = clientname -const clientChat = new Map(); +interface ClientInfo { + user: string; + lastSeen: number; +} + +const clientChat = new Map(); // @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this... const plugins = import.meta.glob('./plugins/**/*.ts', { eager: true }); @@ -79,13 +84,13 @@ async function onReady(fastify: FastifyInstance) { const seen = new Set(); // <- only log/count unique usernames - for (const [socketId, username] of clientChat) { + for (const [socketId, username,] of clientChat) { // Basic sanity checks if (typeof socketId !== 'string' || socketId.length === 0) { clientChat.delete(socketId); continue; } - if (typeof username !== 'string' || username.length === 0) { + if (typeof username.user !== 'string' || username.user.length === 0) { clientChat.delete(socketId); continue; } @@ -102,17 +107,17 @@ async function onReady(fastify: FastifyInstance) { } // Skip duplicates (DO NOT delete them — just don't count) - if (seen.has(username)) { + if (seen.has(username.user)) { continue; } // socket exists and is connected - seen.add(username); + seen.add(username.user); count++; // console.log(color.green,"count: ", count); - console.log(color.yellow, 'Client:', color.reset, username); + console.log(color.yellow, 'Client:', color.reset, username.user); const targetSocketId = target; - io.to(targetSocketId!).emit('listObj', username); + io.to(targetSocketId!).emit('listObj', username.user); console.log( color.yellow, @@ -147,8 +152,8 @@ async function onReady(fastify: FastifyInstance) { for (const s of sockets) { if (s.id !== sender) { // Send REAL JSON object - const clientName = clientChat.get(s.id) || null; - if (clientName !== null) { + const clientName = clientChat.get(s.id)?.user; + if (clientName !== undefined) { s.emit('MsgObjectServer', { message: data }); } console.log(' Target window socket ID:', s.id); @@ -159,7 +164,11 @@ async function onReady(fastify: FastifyInstance) { }); } + fastify.io.on('connection', (socket: Socket) => { + + + socket.on('message', (message: string) => { console.info( color.blue, @@ -173,9 +182,9 @@ async function onReady(fastify: FastifyInstance) { color.reset, message, ); - + const obj: ClientMessage = JSON.parse(message) as ClientMessage; - clientChat.set(socket.id, obj.user); + clientChat.set(socket.id, { user: obj.user, lastSeen: Date.now() }); console.log( color.green, 'Message from client', @@ -191,35 +200,40 @@ async function onReady(fastify: FastifyInstance) { color.reset, ); }); - + + socket.emit("welcome", { + msg: `Welcome to the chat!`, + id: socket.id + }); + socket.on('testend', (sock_id_cl: string) => { console.log('testend received from client socket id:', sock_id_cl); }); - + socket.on('list', () => { console.log(color.red, 'list activated', color.reset, socket.id); connectedUser(fastify.io, socket.id); }); - + socket.on('disconnecting', (reason) => { const clientName = clientChat.get(socket.id) || null; console.log( color.green, - `Client disconnecting: ${clientName} (${socket.id}) reason:`, + `Client disconnecting: ${clientName?.user} (${socket.id}) reason:`, reason, ); if (reason === 'transport error') return; - - if (clientName !== null) { + + if (clientName?.user !== null) { const obj = { type: 'chat', - user: clientName, + user: clientName!.user, token: '', text: 'LEFT the chat', timestamp: Date.now(), SenderWindowID: socket.id, }; - + broadcast(obj, obj.SenderWindowID); // clientChat.delete(obj.user); } diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index e77156a..bc84ef1 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -88,8 +88,8 @@ importers: specifier: ^1.1.2 version: 1.1.2 typebox: - specifier: ^1.0.55 - version: 1.0.55 + specifier: ^1.0.56 + version: 1.0.56 uuidv7: specifier: ^1.0.2 version: 1.0.2 @@ -131,8 +131,8 @@ importers: specifier: ^5.1.0 version: 5.1.0 typebox: - specifier: ^1.0.55 - version: 1.0.55 + specifier: ^1.0.56 + version: 1.0.56 devDependencies: '@types/node': specifier: ^22.19.1 @@ -266,8 +266,8 @@ importers: specifier: ^5.1.0 version: 5.1.0 typebox: - specifier: ^1.0.55 - version: 1.0.55 + specifier: ^1.0.56 + version: 1.0.56 devDependencies: '@types/node': specifier: ^22.19.1 @@ -3025,8 +3025,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typebox@1.0.55: - resolution: {integrity: sha512-TP02wN0B6tDZngprrGVu/Z9s/QUyVEmR7VIg1yEOtsqyDdXXEoQPSfWdkD2PsA2lGLxu6GgwOTtGZVS9CAoERg==} + typebox@1.0.56: + resolution: {integrity: sha512-KMd1DJnIRqLUzAicpFmGqgmt+/IePCEmT/Jtywyyyn0hK6+dupQnxm7OAIn/cL/vu22jKi1XvDjDhrpatZ46kA==} typescript-eslint@8.48.0: resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} @@ -6156,7 +6156,7 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typebox@1.0.55: {} + typebox@1.0.56: {} typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.9.3): dependencies: diff --git a/src/user/package.json b/src/user/package.json index 4f197a3..9efe221 100644 --- a/src/user/package.json +++ b/src/user/package.json @@ -26,7 +26,7 @@ "fastify": "^5.6.2", "fastify-cli": "^7.4.1", "fastify-plugin": "^5.1.0", - "typebox": "^1.0.55" + "typebox": "^1.0.56" }, "devDependencies": { "@types/node": "^22.19.1", From 422c0b26c4b1e2a37bde221311a3c908e24c978e Mon Sep 17 00:00:00 2001 From: NigeParis Date: Wed, 26 Nov 2025 14:41:21 +0100 Subject: [PATCH 02/22] added tab control to chat, When user leaves tab open on chat --- .../api/generated/.openapi-generator/FILES | 1 - .../src/api/generated/apis/OpenapiOtherApi.ts | 13 +-- frontend/src/api/generated/models/index.ts | 1 - frontend/src/pages/chat/chat.ts | 60 ++++++++---- src/chat/openapi.json | 26 ----- src/chat/src/app.ts | 95 ++++++++++++++++--- src/openapi.json | 26 ----- src/package.json | 2 +- src/pnpm-lock.yaml | 46 ++++----- 9 files changed, 151 insertions(+), 119 deletions(-) diff --git a/frontend/src/api/generated/.openapi-generator/FILES b/frontend/src/api/generated/.openapi-generator/FILES index b02736b..af12e66 100644 --- a/frontend/src/api/generated/.openapi-generator/FILES +++ b/frontend/src/api/generated/.openapi-generator/FILES @@ -2,7 +2,6 @@ apis/OpenapiOtherApi.ts apis/index.ts index.ts models/ChatTest200Response.ts -models/ChatTest500Response.ts models/DisableOtp200Response.ts models/DisableOtp401Response.ts models/DisableOtp500Response.ts diff --git a/frontend/src/api/generated/apis/OpenapiOtherApi.ts b/frontend/src/api/generated/apis/OpenapiOtherApi.ts index f03d19e..fda4f60 100644 --- a/frontend/src/api/generated/apis/OpenapiOtherApi.ts +++ b/frontend/src/api/generated/apis/OpenapiOtherApi.ts @@ -16,7 +16,6 @@ import * as runtime from '../runtime'; import type { ChatTest200Response, - ChatTest500Response, DisableOtp200Response, DisableOtp401Response, DisableOtp500Response, @@ -50,8 +49,6 @@ import type { import { ChatTest200ResponseFromJSON, ChatTest200ResponseToJSON, - ChatTest500ResponseFromJSON, - ChatTest500ResponseToJSON, DisableOtp200ResponseFromJSON, DisableOtp200ResponseToJSON, DisableOtp401ResponseFromJSON, @@ -135,7 +132,7 @@ export class OpenapiOtherApi extends runtime.BaseAPI { /** */ - async chatTestRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + async chatTestRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { const queryParameters: any = {}; const headerParameters: runtime.HTTPHeaders = {}; @@ -162,19 +159,15 @@ export class OpenapiOtherApi extends runtime.BaseAPI { // Object response for status 401 return new runtime.JSONApiResponse(response, (jsonValue) => StatusOtp401ResponseFromJSON(jsonValue)); } - if (response.status === 500) { - // Object response for status 500 - return new runtime.JSONApiResponse(response, (jsonValue) => ChatTest500ResponseFromJSON(jsonValue)); - } // CHANGED: Throw error if status code is not handled by any of the defined responses // This ensures all code paths return a value and provides clear error messages for unexpected status codes // Only throw if responses were defined but none matched the actual status code - throw new runtime.ResponseError(response, `Unexpected status code: ${response.status}. Expected one of: 200, 401, 500`); + throw new runtime.ResponseError(response, `Unexpected status code: ${response.status}. Expected one of: 200, 401`); } /** */ - async chatTest(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + async chatTest(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { const response = await this.chatTestRaw(initOverrides); return await response.value(); } diff --git a/frontend/src/api/generated/models/index.ts b/frontend/src/api/generated/models/index.ts index b4d967b..a4059b0 100644 --- a/frontend/src/api/generated/models/index.ts +++ b/frontend/src/api/generated/models/index.ts @@ -1,7 +1,6 @@ /* tslint:disable */ /* eslint-disable */ export * from './ChatTest200Response'; -export * from './ChatTest500Response'; export * from './DisableOtp200Response'; export * from './DisableOtp401Response'; export * from './DisableOtp500Response'; diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 18bca7a..1e0d53f 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -16,29 +16,49 @@ document.addEventListener('ft:pageChange', () => { document.addEventListener("visibilitychange", async () => { - // When user leaves tab + const socketId = __socket || undefined; + let oldName = localStorage.getItem("oldName") || undefined; + if (socketId == undefined) return; if (document.visibilityState === "hidden") { - console.log("User LEFT this tab"); - - // if (__socket) { - // __socket.close(); - // __socket = undefined; - // } - + let userName = await updateUser(); + oldName = userName?.name || "undefined"; + localStorage.setItem("oldName", oldName); + socketId.emit("client_left"); return; } - - // When user returns to tab → soft reload using imported HTML file if (document.visibilityState === "visible") { - // location.reload(); - //console.log(location.replace(location.href)); - - - console.log('Chat Visible') + const res = await client.guestLogin(); + let user = await updateUser(); + socketId.emit('client_entered', { + userName: oldName, + user: user?.name, + }); + setTitle('Chat Page'); + return; } }); + +async function getUserName(): Promise { + try { + const res = await client.guestLogin(); + + if (res.kind !== "success") { + console.error("Login failed:", res.msg); + return null; + } + + const user = await updateUser(); + if (!user) return null; + + return user.name; // <-- return the username + } catch (err) { + console.error("getUserName error:", err); + return null; + } +} + function getSocket(): Socket { if (__socket === undefined) __socket = io("wss://localhost:8888", { @@ -142,8 +162,8 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }; - socket.on("welcome", (data) => { - addMessage(`${data.msg}`); + socket.once('welcome', (data) => { + addMessage (`${data.msg} ` + getUser()?.name); }); // Send button @@ -161,7 +181,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn timestamp: Date.now(), SenderWindowID: socket.id, }; - socket.send(JSON.stringify(message)); + socket.emit('message', JSON.stringify(message)); } sendtextbox.value = ""; } @@ -182,6 +202,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const loggedIn = await isLoggedIn(); if (loggedIn?.name === undefined) return ; + const res = await client.guestLogin(); + let user = await updateUser(); + console.log('USER ', user?.name); if (chatWindow) { addMessage('@list - lists all connected users in the chat'); socket.emit('list'); @@ -228,3 +251,4 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } }; addRoute('/chat', handleChat, { bypass_auth: true }); +addRoute('/chat/', handleChat, { bypass_auth: true }); diff --git a/src/chat/openapi.json b/src/chat/openapi.json index 8afe3d2..bcebf94 100644 --- a/src/chat/openapi.json +++ b/src/chat/openapi.json @@ -112,32 +112,6 @@ } } } - }, - "500": { - "description": "Default Response", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "kind", - "msg" - ], - "properties": { - "kind": { - "enum": [ - "failed" - ] - }, - "msg": { - "enum": [ - "chat.failed.generic" - ] - } - } - } - } - } } } } diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 0dbac4d..abc7a53 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -163,12 +163,10 @@ async function onReady(fastify: FastifyInstance) { } }); } - + fastify.io.on('connection', (socket: Socket) => { - - - + socket.on('message', (message: string) => { console.info( color.blue, @@ -191,6 +189,10 @@ async function onReady(fastify: FastifyInstance) { color.reset, `Sender: login name: "${obj.user}" - windowID "${obj.SenderWindowID}" - text message: "${obj.text}"`, ); + socket.emit('welcome', { + msg: `Welcome to the chat! `, + }); + // Send object directly — DO NOT wrap it in a string broadcast(obj, obj.SenderWindowID); console.log( @@ -201,33 +203,35 @@ async function onReady(fastify: FastifyInstance) { ); }); - socket.emit("welcome", { - msg: `Welcome to the chat!`, - id: socket.id - }); - socket.on('testend', (sock_id_cl: string) => { console.log('testend received from client socket id:', sock_id_cl); }); + socket.on('wakeup', (message: string) => { + const obj: ClientMessage = JSON.parse(message) as ClientMessage; + clientChat.set(socket.id, { user: obj.user, lastSeen: Date.now() }); + connectedUser(fastify.io), + console.log('Wakeup: ', message); + }); + socket.on('list', () => { console.log(color.red, 'list activated', color.reset, socket.id); connectedUser(fastify.io, socket.id); }); socket.on('disconnecting', (reason) => { - const clientName = clientChat.get(socket.id) || null; + const clientName = clientChat.get(socket.id)?.user|| null; console.log( color.green, - `Client disconnecting: ${clientName?.user} (${socket.id}) reason:`, + `Client disconnecting: ${clientName} (${socket.id}) reason:`, reason, ); if (reason === 'transport error') return; - if (clientName?.user !== null) { + if (clientName !== null) { const obj = { type: 'chat', - user: clientName!.user, + user: clientName, token: '', text: 'LEFT the chat', timestamp: Date.now(), @@ -238,5 +242,70 @@ async function onReady(fastify: FastifyInstance) { // clientChat.delete(obj.user); } }); + + socket.on('client_left', (reason) => { + const clientName = clientChat.get(socket.id)?.user|| null; + console.log( + color.green, + `Client left the Chat: ${clientName} (${socket.id}) reason:`, + reason, + ); + if (reason === 'transport error') return; + + if (clientName !== null) { + const obj = { + type: 'chat', + user: clientName, + token: '', + text: 'LEFT the chat but the window is still open', + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + console.log(obj.SenderWindowID); + broadcast(obj, obj.SenderWindowID); + // clientChat.delete(obj.user); + } + }); + + + socket.on('client_entered', (data) => { + + // data may be undefined (when frontend calls emit with no payload) + const userNameFromFrontend = data?.userName || null; + const userFromFrontend = data?.user || null; + let clientName = clientChat.get(socket.id)?.user || null; + const client = clientChat.get(socket.id) || null; + let text = 'is back in the chat'; + + // connectedUser(fastify.io, socket.id); + if(clientName === null) {console.log('ERROR: clientName is NULL'); return;}; + if(client === null) {console.log('ERROR: client is NULL'); return;}; + + if (userNameFromFrontend !== userFromFrontend) { + text = `'is back in the chat, I used to be called '${userNameFromFrontend}`; + clientName = userFromFrontend; + if(clientName === null) {console.log('ERROR: clientName is NULL'); return;}; + if (client) { + client.user = clientName; + } + } + console.log( + color.green, + `Client entered the Chat: ${clientName} (${socket.id})` + ); + if (clientName !== null) { + const obj = { + type: 'chat', + user: clientName, // server-side stored name + frontendUserName: userNameFromFrontend, // from frontend + frontendUser: userFromFrontend, // from frontend + token: '', + text: text, + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + broadcast(obj, obj.SenderWindowID); + } + }); }); } diff --git a/src/openapi.json b/src/openapi.json index f370df1..4327973 100644 --- a/src/openapi.json +++ b/src/openapi.json @@ -1294,32 +1294,6 @@ } } } - }, - "500": { - "description": "Default Response", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "kind", - "msg" - ], - "properties": { - "kind": { - "enum": [ - "failed" - ] - }, - "msg": { - "enum": [ - "chat.failed.generic" - ] - } - } - } - } - } } }, "tags": [ diff --git a/src/package.json b/src/package.json index 22edb07..c833a12 100644 --- a/src/package.json +++ b/src/package.json @@ -36,7 +36,7 @@ "vite": "^7.2.4" }, "dependencies": { - "@redocly/cli": "^2.11.1", + "@redocly/cli": "^2.12.0", "bindings": "^1.5.0" } } diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index bc84ef1..c152612 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@redocly/cli': - specifier: ^2.11.1 - version: 2.11.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0) + specifier: ^2.12.0 + version: 2.12.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0) bindings: specifier: ^1.5.0 version: 1.5.0 @@ -946,27 +946,27 @@ packages: '@redocly/ajv@8.17.1': resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==} - '@redocly/cli@2.11.1': - resolution: {integrity: sha512-doNs+sdrFzzXmyf1yIeJbPh8OChacHWkvTE9N0QbuCmnYQ4k0v1IMP20qsitkwR+fK8O1hXSnFnSTVvIunMVVw==} + '@redocly/cli@2.12.0': + resolution: {integrity: sha512-/q8RnBe+Duo+XYFCG8LnaD0kroGZ8MoS6575Xq59tCgjaCL16F+pZZ75xNBU2oXfEypJClNz/6ilc2G0q1+tlw==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} hasBin: true '@redocly/config@0.22.2': resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==} - '@redocly/config@0.38.0': - resolution: {integrity: sha512-kSgMG3rRzgXIP/6gWMRuWbu9/ms0Cyuphcx19dPR9qlgc1tt9IKYPsFQ+KhJuEtqd3bcY/+Uflysf33dQkZWVQ==} + '@redocly/config@0.40.0': + resolution: {integrity: sha512-MZQZs7QEGnue3rVN9Q9QvDbcGjesxbpKXUvDeckS69R1xjtgsnT9B39VA25zmwSJtgUeA9ST+sMf9GxIqixNbw==} '@redocly/openapi-core@1.34.5': resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@redocly/openapi-core@2.11.1': - resolution: {integrity: sha512-FVCDnZxaoUJwLQxfW4inCojxUO56J3ntu7dDAE2qyWd6tJBK45CnXMQQUxpqeRTeXROr3jYQoApAw+GCEnyBeg==} + '@redocly/openapi-core@2.12.0': + resolution: {integrity: sha512-RsVwmRD0KhyJbR8acIeU98ce6N+/YCuLJf6IGN+2SOsbwnDhnI5MG0TFV9D7URK/ukEewaNA701dVYsoP1VtRQ==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} - '@redocly/respect-core@2.11.1': - resolution: {integrity: sha512-jSMJvCJeo5gmhQfg82AhuwCG0h8gbW5vqHyRITBu8KHVsBiQTgvfhXepu8SKHeJu0OexYtEc0nUnGLJlefevYw==} + '@redocly/respect-core@2.12.0': + resolution: {integrity: sha512-mrYrfE81shSRS96ygXaRiSithV4Fe4Y7XlSYLSTfM8Lo3YAz7Geirg7HZ5fNFsI+hdW05ZuQewqpKL8XLwaAeA==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} '@rollup/rollup-android-arm-eabi@4.53.3': @@ -1483,8 +1483,8 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + cookie@1.1.0: + resolution: {integrity: sha512-vXiThu1/rlos7EGu8TuNZQEg2e9TvhH9dmS4T4ZVzB7Ao1agEZ6EG3sn5n+hZRYUgduISd1HpngFzAZiDGm5vQ==} engines: {node: '>=18'} core-js@3.47.0: @@ -3436,7 +3436,7 @@ snapshots: '@fastify/cookie@11.0.2': dependencies: - cookie: 1.0.2 + cookie: 1.1.0 fastify-plugin: 5.1.0 '@fastify/deepmerge@3.1.0': {} @@ -3873,14 +3873,14 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - '@redocly/cli@2.11.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)': + '@redocly/cli@2.12.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)': dependencies: '@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.34.0 - '@redocly/openapi-core': 2.11.1(ajv@8.17.1) - '@redocly/respect-core': 2.11.1(ajv@8.17.1) + '@redocly/openapi-core': 2.12.0(ajv@8.17.1) + '@redocly/respect-core': 2.12.0(ajv@8.17.1) abort-controller: 3.0.0 chokidar: 3.6.0 colorette: 1.4.0 @@ -3913,7 +3913,7 @@ snapshots: '@redocly/config@0.22.2': {} - '@redocly/config@0.38.0': + '@redocly/config@0.40.0': dependencies: json-schema-to-ts: 2.7.2 @@ -3931,10 +3931,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@redocly/openapi-core@2.11.1(ajv@8.17.1)': + '@redocly/openapi-core@2.12.0(ajv@8.17.1)': dependencies: '@redocly/ajv': 8.17.1 - '@redocly/config': 0.38.0 + '@redocly/config': 0.40.0 ajv-formats: 2.1.1(ajv@8.17.1) colorette: 1.4.0 js-levenshtein: 1.1.6 @@ -3945,12 +3945,12 @@ snapshots: transitivePeerDependencies: - ajv - '@redocly/respect-core@2.11.1(ajv@8.17.1)': + '@redocly/respect-core@2.12.0(ajv@8.17.1)': dependencies: '@faker-js/faker': 7.6.0 '@noble/hashes': 1.8.0 '@redocly/ajv': 8.11.4 - '@redocly/openapi-core': 2.11.1(ajv@8.17.1) + '@redocly/openapi-core': 2.12.0(ajv@8.17.1) better-ajv-errors: 1.2.0(ajv@8.17.1) colorette: 2.0.20 json-pointer: 0.6.2 @@ -4448,7 +4448,7 @@ snapshots: cookie@0.7.2: {} - cookie@1.0.2: {} + cookie@1.1.0: {} core-js@3.47.0: {} @@ -5167,7 +5167,7 @@ snapshots: light-my-request@6.6.0: dependencies: - cookie: 1.0.2 + cookie: 1.1.0 process-warning: 4.0.1 set-cookie-parser: 2.7.2 From 896d9084efe5f4d616cfb0ceb7b961ce589af52f Mon Sep 17 00:00:00 2001 From: NigeParis Date: Wed, 26 Nov 2025 19:58:34 +0100 Subject: [PATCH 03/22] Added tab 'hidden' detection when chat is on, added css red text messages sent --- frontend/src/chat/chat.css | 11 ++-- frontend/src/pages/chat/chat.ts | 84 +++++++++++++------------ src/chat/src/app.ts | 107 ++++++++++++++++++++------------ 3 files changed, 115 insertions(+), 87 deletions(-) diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index d02bc50..91901a4 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -80,20 +80,17 @@ .mainboxDisplay button { @apply - cursor-pointer; + cursor-pointer } p { @apply text-black - - - } -.div-test { +div-test { @apply - italic - + text-red-800 + text-right } \ No newline at end of file diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 1e0d53f..9399b0c 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -14,6 +14,28 @@ document.addEventListener('ft:pageChange', () => { }) +function getSocket(): Socket { + if (__socket === undefined) + __socket = io("wss://localhost:8888", { + path: "/api/chat/socket.io/", + secure: false, + transports: ["websocket"], + }); + return __socket; +} + + +async function isLoggedIn() { + return getUser() || null; +} + + + +function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { + let socket = getSocket(); + + + document.addEventListener("visibilitychange", async () => { const socketId = __socket || undefined; @@ -40,44 +62,6 @@ document.addEventListener("visibilitychange", async () => { -async function getUserName(): Promise { - try { - const res = await client.guestLogin(); - - if (res.kind !== "success") { - console.error("Login failed:", res.msg); - return null; - } - - const user = await updateUser(); - if (!user) return null; - - return user.name; // <-- return the username - } catch (err) { - console.error("getUserName error:", err); - return null; - } -} - -function getSocket(): Socket { - if (__socket === undefined) - __socket = io("wss://localhost:8888", { - path: "/api/chat/socket.io/", - secure: false, - transports: ["websocket"], - }); - return __socket; -} - - -async function isLoggedIn() { - return getUser() || null; -} - - - -function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { - let socket = getSocket(); // Listen for the 'connect' event socket.on("connect", () => { console.log("I AM Connected to the server:", socket.id); @@ -154,7 +138,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const addMessage = (text: string) => { if (!chatWindow) return; - const messageElement = document.createElement("div"); + const messageElement = document.createElement("div-test"); messageElement.textContent = text; chatWindow.appendChild(messageElement); chatWindow.scrollTop = chatWindow.scrollHeight; @@ -200,14 +184,20 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn bconnected?.addEventListener("click", async () => { const loggedIn = await isLoggedIn(); - + let oldUser = localStorage.getItem("oldName") || undefined; if (loggedIn?.name === undefined) return ; + oldUser = loggedIn.name || "undefined"; const res = await client.guestLogin(); let user = await updateUser(); + localStorage.setItem("oldName", oldUser); + console.log('USER ', user?.name); if (chatWindow) { addMessage('@list - lists all connected users in the chat'); - socket.emit('list'); + socket.emit('list', { + oldUser: oldUser, + user: user?.name + }); } }); socket.on('listObj', (list: string) => { @@ -229,10 +219,22 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn // Whoami button to display user name bwhoami?.addEventListener('click', async () => { try { + const loggedIn = await isLoggedIn(); + let oldUser = localStorage.getItem("oldName") || undefined; + oldUser = loggedIn?.name || "undefined"; + localStorage.setItem("oldName", oldUser); + const res = await client.guestLogin(); switch (res.kind) { case 'success': { let user = await updateUser(); + console.log('USER ', user?.name); + if (chatWindow) { + socket.emit('updateClientName', { + oldUser: oldUser, + user: user?.name + }); + } if (user === null) return showError('Failed to get user: no user ?'); setTitle(`Welcome ${user.guest ? '[GUEST] ' : ''}${user.name}`); diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index abc7a53..7a92dc5 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -74,6 +74,9 @@ declare module 'fastify' { MsgObjectServer: (data: { message: ClientMessage }) => void; message: (msg: string) => void; testend: (sock_id_client: string) => void; + client_entered: (userName: string, user: string) => void; + list: (oldUser: string, user: string) => void; + updateClientName: (oldUser: string, user: string) => void; }>; } } @@ -84,7 +87,7 @@ async function onReady(fastify: FastifyInstance) { const seen = new Set(); // <- only log/count unique usernames - for (const [socketId, username,] of clientChat) { + for (const [socketId, username] of clientChat) { // Basic sanity checks if (typeof socketId !== 'string' || socketId.length === 0) { clientChat.delete(socketId); @@ -163,10 +166,9 @@ async function onReady(fastify: FastifyInstance) { } }); } - - + fastify.io.on('connection', (socket: Socket) => { - + socket.on('message', (message: string) => { console.info( color.blue, @@ -180,19 +182,19 @@ async function onReady(fastify: FastifyInstance) { color.reset, message, ); - + const obj: ClientMessage = JSON.parse(message) as ClientMessage; clientChat.set(socket.id, { user: obj.user, lastSeen: Date.now() }); console.log( color.green, 'Message from client', color.reset, - `Sender: login name: "${obj.user}" - windowID "${obj.SenderWindowID}" - text message: "${obj.text}"`, + `Sender: login name: ${obj.user} - windowID ${obj.SenderWindowID} - text message: ${obj.text}`, ); socket.emit('welcome', { - msg: `Welcome to the chat! `, + msg: 'Welcome to the chat!', }); - + // Send object directly — DO NOT wrap it in a string broadcast(obj, obj.SenderWindowID); console.log( @@ -202,32 +204,57 @@ async function onReady(fastify: FastifyInstance) { color.reset, ); }); - + socket.on('testend', (sock_id_cl: string) => { console.log('testend received from client socket id:', sock_id_cl); }); - - socket.on('wakeup', (message: string) => { - const obj: ClientMessage = JSON.parse(message) as ClientMessage; - clientChat.set(socket.id, { user: obj.user, lastSeen: Date.now() }); - connectedUser(fastify.io), - console.log('Wakeup: ', message); - }); - socket.on('list', () => { - console.log(color.red, 'list activated', color.reset, socket.id); + socket.on('list', (object) => { + + const userFromFrontend = object || null; + const client = clientChat.get(socket.id) || null; + + console.log(color.red, 'list activated', userFromFrontend, color.reset, socket.id); + + if (userFromFrontend.oldUser !== userFromFrontend.user) { + console.log(color.red, 'list activated', userFromFrontend.oldUser, color.reset); + if (client === null) { + console.log('ERROR: clientName is NULL'); + return; + }; + if (client) { + client.user = userFromFrontend.user; + } + } connectedUser(fastify.io, socket.id); }); - + + socket.on('updateClientName', (object) => { + const userFromFrontend = object || null; + const client = clientChat.get(socket.id) || null; + console.log(color.red, 'whoAMi activated', userFromFrontend, color.reset, socket.id); + if (userFromFrontend.oldUser !== userFromFrontend.user) { + console.log(color.red, 'whoAMi activated', userFromFrontend.oldUser, color.reset); + if (client === null) { + console.log('ERROR: clientName is NULL'); + return; + }; + if (client) { + client.user = userFromFrontend.user; + } + } + }); + + socket.on('disconnecting', (reason) => { - const clientName = clientChat.get(socket.id)?.user|| null; + const clientName = clientChat.get(socket.id)?.user || null; console.log( color.green, `Client disconnecting: ${clientName} (${socket.id}) reason:`, reason, ); if (reason === 'transport error') return; - + if (clientName !== null) { const obj = { type: 'chat', @@ -237,21 +264,20 @@ async function onReady(fastify: FastifyInstance) { timestamp: Date.now(), SenderWindowID: socket.id, }; - + broadcast(obj, obj.SenderWindowID); - // clientChat.delete(obj.user); } }); socket.on('client_left', (reason) => { - const clientName = clientChat.get(socket.id)?.user|| null; + const clientName = clientChat.get(socket.id)?.user || null; console.log( color.green, `Client left the Chat: ${clientName} (${socket.id}) reason:`, reason, ); if (reason === 'transport error') return; - + if (clientName !== null) { const obj = { type: 'chat', @@ -261,13 +287,12 @@ async function onReady(fastify: FastifyInstance) { timestamp: Date.now(), SenderWindowID: socket.id, }; - console.log(obj.SenderWindowID); + console.log(obj.SenderWindowID); broadcast(obj, obj.SenderWindowID); // clientChat.delete(obj.user); } }); - socket.on('client_entered', (data) => { // data may be undefined (when frontend calls emit with no payload) @@ -276,29 +301,33 @@ async function onReady(fastify: FastifyInstance) { let clientName = clientChat.get(socket.id)?.user || null; const client = clientChat.get(socket.id) || null; let text = 'is back in the chat'; - - // connectedUser(fastify.io, socket.id); - if(clientName === null) {console.log('ERROR: clientName is NULL'); return;}; - if(client === null) {console.log('ERROR: client is NULL'); return;}; - + + if (clientName === null) { + console.log('ERROR: clientName is NULL'); return; + }; + if (client === null) { + console.log('ERROR: client is NULL'); return; + }; if (userNameFromFrontend !== userFromFrontend) { text = `'is back in the chat, I used to be called '${userNameFromFrontend}`; clientName = userFromFrontend; - if(clientName === null) {console.log('ERROR: clientName is NULL'); return;}; + if (clientName === null) { + console.log('ERROR: clientName is NULL'); return; + }; if (client) { - client.user = clientName; - } + client.user = clientName; + } } console.log( color.green, - `Client entered the Chat: ${clientName} (${socket.id})` + `Client entered the Chat: ${clientName} (${socket.id})`, ); if (clientName !== null) { const obj = { type: 'chat', - user: clientName, // server-side stored name - frontendUserName: userNameFromFrontend, // from frontend - frontendUser: userFromFrontend, // from frontend + user: clientName, + frontendUserName: userNameFromFrontend, + frontendUser: userFromFrontend, token: '', text: text, timestamp: Date.now(), From 7b61ffe5278c84405214ce7b0b904a8caf6705cb Mon Sep 17 00:00:00 2001 From: NigeParis Date: Wed, 26 Nov 2025 20:43:08 +0100 Subject: [PATCH 04/22] minor stuff done like BG color of chat window --- frontend/src/chat/chat.css | 3 ++- frontend/src/pages/chat/chat.html | 3 +-- frontend/src/pages/chat/chat.ts | 10 +++++++--- src/chat/src/app.ts | 11 ++++++----- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index 91901a4..e2ddc60 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -62,7 +62,8 @@ flex items-center justify-center - bg-gray-100; + bg-[#43536b]; + } .mainboxDisplay { diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index a0f0dde..21005f1 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -5,8 +5,7 @@ Chat Box
- -

Welcome


+

diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 9399b0c..ba8dea1 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -43,9 +43,13 @@ document.addEventListener("visibilitychange", async () => { if (socketId == undefined) return; if (document.visibilityState === "hidden") { let userName = await updateUser(); - oldName = userName?.name || "undefined"; - localStorage.setItem("oldName", oldName); - socketId.emit("client_left"); + oldName = userName?.name || undefined; + if (oldName === undefined) return; + localStorage.setItem('oldName', oldName); + socketId.emit('client_left', { + user: userName?.name, + why: 'tab window hidden - socket not dead', + }); return; } if (document.visibilityState === "visible") { diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 7a92dc5..83876fa 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -75,6 +75,7 @@ declare module 'fastify' { message: (msg: string) => void; testend: (sock_id_client: string) => void; client_entered: (userName: string, user: string) => void; + client_left: (userName: string, why: string) => void; list: (oldUser: string, user: string) => void; updateClientName: (oldUser: string, user: string) => void; }>; @@ -192,7 +193,7 @@ async function onReady(fastify: FastifyInstance) { `Sender: login name: ${obj.user} - windowID ${obj.SenderWindowID} - text message: ${obj.text}`, ); socket.emit('welcome', { - msg: 'Welcome to the chat!', + msg: 'Welcome to the chat! : ', }); // Send object directly — DO NOT wrap it in a string @@ -269,14 +270,14 @@ async function onReady(fastify: FastifyInstance) { } }); - socket.on('client_left', (reason) => { + socket.on('client_left', (data) => { const clientName = clientChat.get(socket.id)?.user || null; + const leftChat = data || null; console.log( color.green, - `Client left the Chat: ${clientName} (${socket.id}) reason:`, - reason, + `Left the Chat User: ${clientName} id Socket: ${socket.id} reason:`, + leftChat.why, ); - if (reason === 'transport error') return; if (clientName !== null) { const obj = { From 1ec17166fcb3d61faaa10e97321f37e633571c2f Mon Sep 17 00:00:00 2001 From: NigeParis Date: Wed, 26 Nov 2025 20:44:28 +0100 Subject: [PATCH 05/22] minor stuff done like BG color of chat window --- frontend/src/pages/chat/chat.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index 21005f1..45596b5 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -1,11 +1,11 @@
- +

Chat Box


- - + +

From ef9f0af6fad8891fcb09583cbbcefb912655c153 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Wed, 26 Nov 2025 21:09:47 +0100 Subject: [PATCH 06/22] rebase with master --- src/pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index c152612..bcdb1ae 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -1483,8 +1483,8 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - cookie@1.1.0: - resolution: {integrity: sha512-vXiThu1/rlos7EGu8TuNZQEg2e9TvhH9dmS4T4ZVzB7Ao1agEZ6EG3sn5n+hZRYUgduISd1HpngFzAZiDGm5vQ==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} core-js@3.47.0: @@ -3436,7 +3436,7 @@ snapshots: '@fastify/cookie@11.0.2': dependencies: - cookie: 1.1.0 + cookie: 1.1.1 fastify-plugin: 5.1.0 '@fastify/deepmerge@3.1.0': {} @@ -4448,7 +4448,7 @@ snapshots: cookie@0.7.2: {} - cookie@1.1.0: {} + cookie@1.1.1: {} core-js@3.47.0: {} @@ -5167,7 +5167,7 @@ snapshots: light-my-request@6.6.0: dependencies: - cookie: 1.1.0 + cookie: 1.1.1 process-warning: 4.0.1 set-cookie-parser: 2.7.2 From 4ed588daa5f37988e047621fb05e8b3739ac183f Mon Sep 17 00:00:00 2001 From: NigeParis Date: Thu, 27 Nov 2025 18:20:19 +0100 Subject: [PATCH 07/22] Added machine Name to display address of connect in logs --- docker-compose.yml | 2 +- frontend/src/chat/chat.css | 9 +- frontend/src/pages/chat/chat.ts | 156 +++++++++++++++++++++++++------- src/chat/src/app.ts | 23 +++-- 4 files changed, 147 insertions(+), 43 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1b166ef..ce19a47 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -122,7 +122,7 @@ services: - JWT_SECRET=KRUGKIDROVUWG2ZAMJZG653OEBTG66BANJ2W24DTEBXXMZLSEB2GQZJANRQXU6JA - DATABASE_DIR=/volumes/database - PROVIDER_FILE=/extra/providers.toml - + - SESSION_MANAGER=${SESSION_MANAGER} ############### # USER # diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index e2ddc60..b3cb9c3 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -92,6 +92,13 @@ p { div-test { @apply text-red-800 - text-right + text-right; + +} +div-notlog { + @apply + text-red-800 + text-3xl + text-center; } \ No newline at end of file diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index ba8dea1..65b5f69 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -5,6 +5,21 @@ import client from '@app/api' import { getUser, updateUser } from "@app/auth"; import io, { Socket } from 'socket.io-client'; +const color = { + red: 'color: red; font-weight: bold;', + green: 'color: green; font-weight: bold;', + yellow: 'color: orange; font-weight: bold;', + blue: 'color: blue; font-weight: bold;', + reset: '', // not needed in browser +}; + + +// get the name of the machine useed to connect +const machineHostName = window.location.hostname; +console.log('connect to login at %chttps://' + machineHostName + ':8888/app/login',color.yellow); + + + let __socket: Socket | undefined = undefined; document.addEventListener('ft:pageChange', () => { if (__socket !== undefined) @@ -15,8 +30,10 @@ document.addEventListener('ft:pageChange', () => { function getSocket(): Socket { + let addressHost = `wss://${machineHostName}:8888`; if (__socket === undefined) - __socket = io("wss://localhost:8888", { + + __socket = io(addressHost, { path: "/api/chat/socket.io/", secure: false, transports: ["websocket"], @@ -31,38 +48,88 @@ async function isLoggedIn() { -function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { - let socket = getSocket(); - - - -document.addEventListener("visibilitychange", async () => { +async function windowStateHidden() { const socketId = __socket || undefined; let oldName = localStorage.getItem("oldName") || undefined; if (socketId == undefined) return; - if (document.visibilityState === "hidden") { - let userName = await updateUser(); - oldName = userName?.name || undefined; - if (oldName === undefined) return; - localStorage.setItem('oldName', oldName); - socketId.emit('client_left', { - user: userName?.name, - why: 'tab window hidden - socket not dead', - }); - return; - } - if (document.visibilityState === "visible") { - const res = await client.guestLogin(); - let user = await updateUser(); - socketId.emit('client_entered', { - userName: oldName, - user: user?.name, - }); - setTitle('Chat Page'); - return; - } -}); + let userName = await updateUser(); + oldName = userName?.name || undefined; + if (oldName === undefined) return; + localStorage.setItem('oldName', oldName); + socketId.emit('client_left', { + user: userName?.name, + why: 'tab window hidden - socket not dead', + }); + return; +} + + +async function windowStateVisable() { + const socketId = __socket || undefined; + let oldName = localStorage.getItem("oldName") || undefined; + if (socketId == undefined) return; + const res = await client.guestLogin(); + let user = await updateUser(); + socketId.emit('client_entered', { + userName: oldName, + user: user?.name, + }); + setTitle('Chat Page'); + return; +} + + + + + + + + + + +function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { + let socket = getSocket(); + + +// document.addEventListener("visibilitychange", async () => { + +// const socketId = __socket || undefined; +// let oldName = localStorage.getItem("oldName") || undefined; + + + +// if (socketId == undefined) return; +// if (document.visibilityState === "hidden") { +// let userName = await updateUser(); +// oldName = userName?.name || undefined; +// if (oldName === undefined) return; +// localStorage.setItem('oldName', oldName); +// socketId.emit('client_left', { +// user: userName?.name, +// why: 'tab window hidden - socket not dead', +// }); +// return; +// } + + + +// if (document.visibilityState === "visible") { +// const res = await client.guestLogin(); +// let user = await updateUser(); +// socketId.emit('client_entered', { +// userName: oldName, +// user: user?.name, +// }); +// setTitle('Chat Page'); +// return; +// } + + + + + +// }); @@ -133,11 +200,7 @@ document.addEventListener("visibilitychange", async () => { const value = await client.chatTest(); if (value.kind === "success") { console.log(value.payload); - } else if (value.kind === "notLoggedIn") { - console.log('not logged in'); - } else { - console.log('unknown response: ', value); - } + const addMessage = (text: string) => { @@ -147,8 +210,20 @@ document.addEventListener("visibilitychange", async () => { chatWindow.appendChild(messageElement); chatWindow.scrollTop = chatWindow.scrollHeight; console.log(`Added new message: ${text}`) + return ; }; + if (window.location.pathname === "/app/chat") { + window.addEventListener("focus", () => { + windowStateVisable(); + console.log("%cWindow is focused on /chat", color.green); + }); + + window.addEventListener("blur", () => { + windowStateHidden(); + console.log("%cWindow is not focused on /chat", color.red); + }); + } socket.once('welcome', (data) => { addMessage (`${data.msg} ` + getUser()?.name); @@ -253,6 +328,19 @@ document.addEventListener("visibilitychange", async () => { showError('Failed to login: Unknown error'); } }); + + } else if (value.kind === "notLoggedIn") { + + if (!chatWindow) return; + const messageElement = document.createElement('div-notlog'); + messageElement.textContent = "Not Logged in ...."; + chatWindow.appendChild(messageElement); + chatWindow.scrollTop = chatWindow.scrollHeight; + console.log('not logged in'); + + } else { + console.log('unknown response: ', value); + } } } }; diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 83876fa..d89b248 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -7,6 +7,22 @@ import * as swagger from '@shared/swagger'; import * as utils from '@shared/utils'; import { Server, Socket } from 'socket.io'; +// colors for console.log +export const color = { + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + reset: '\x1b[0m', +}; + +// shows address for connection au server transcendance +const session = process.env.SESSION_MANAGER ?? ''; +const part = session.split('/')[1]; +const machineName = part.split('.')[0]; +console.log(color.yellow, 'Connect at : https://' + machineName + ':8888/app/login'); + + declare const __SERVICE_NAME: string; // Global map of clients @@ -52,13 +68,6 @@ const app: FastifyPluginAsync = async (fastify, opts): Promise => { export default app; export { app }; -export const color = { - red: '\x1b[31m', - green: '\x1b[32m', - yellow: '\x1b[33m', - blue: '\x1b[34m', - reset: '\x1b[0m', -}; type ClientMessage = { user: string; From ede444dc26732ef8f243e9b9d0918417098351d2 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Thu, 27 Nov 2025 18:38:47 +0100 Subject: [PATCH 08/22] Added localhost for dev and connect for machine 42 option --- frontend/src/pages/chat/chat.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 65b5f69..3490985 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -30,7 +30,8 @@ document.addEventListener('ft:pageChange', () => { function getSocket(): Socket { - let addressHost = `wss://${machineHostName}:8888`; + //let addressHost = `wss://${machineHostName}:8888`; + let addressHost = `wss://localhost:8888`; if (__socket === undefined) __socket = io(addressHost, { From d54b4c7d5fc8d67be68d15bbcfd61c36478a63e1 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Thu, 27 Nov 2025 21:03:25 +0100 Subject: [PATCH 09/22] Re-orga Chat Box --- frontend/src/chat/chat.css | 62 +++++++++++++++++++++---------- frontend/src/pages/chat/chat.html | 53 +++++++++++++++++--------- frontend/src/pages/chat/chat.ts | 2 +- 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index b3cb9c3..e94c993 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -2,38 +2,52 @@ .btn-style { @apply - w-[100px] - h-[32px] - border-2 border-black + w-[100px] + h-[32px] + border-1 + border-gray-500 rounded-3xl + bg-gray-500 + text-white + cursor-pointer + shadow-[0_2px_0_0_black] + transition-all hover:bg-blue-200 - active:bg-white - text-black - cursor-pointer; + active:bg-gray-400 + active:translate-y-[1px] + active:shadow-[0_2px_0_0_black]; } .send-btn-style { @apply w-[50px] h-[50px] - border-2 border-black + border-1 + border-gray-500 rounded-3xl hover:bg-blue-200 - active:bg-white - text-black - cursor-pointer; + bg-red-100 + text-red-700 + cursor-pointer + shadow-[0_2px_0_0_black] + transition-all + active:bg-gray-400 + active:translate-y-[1px] + active:shadow-[0_2px_0_0_black];; } .chatbox-style { @apply - w-[600px] - h-[150px] /* increase height if needed */ - p-[10px] - border-1 border-black - shadow-sm + w-[650px] + h-[300px] /* increase height if needed */ + p-[8px] + border-1 + border-black + shadow-2xl text-left - text-gray-800 + text-gray-700 + bg-white rounded-3xl overflow-y-auto whitespace-pre-line @@ -49,9 +63,11 @@ p-[10px] border-1 border-black shadow-sm + flex-1 rounded-3xl - focus:bg-gray-300 - hover:bg-blue-200 + focus:bg-blue-300 + hover:bg-blue-200 + bg-white text-gray-800; } @@ -73,7 +89,7 @@ left-1/2 -translate-x-1/2 -translate-y-1/2 - bg-white w-[650px] + bg-gray-200 w-[850px] p-6 rounded-xl shadow-2xl text-center z-50; @@ -84,6 +100,14 @@ cursor-pointer } +.title { + @apply + text-6xl + font-bold + text-gray-800 +} + + p { @apply text-black diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index 45596b5..2f6c2a3 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -1,18 +1,37 @@
-
- -

- Chat Box -


- - -
-
-
- - -
-
-

From this Chat Box you can send messages to other players

-
-
\ No newline at end of file +
+ +

+ ChatterBoxes 😀😀😀 +


+ + + + +
+ +
+ +
+
+
+ + +
+
+ + +
+

Ping Buddies

+
+

Alice

+

Bob

+

Charlie

+
+
+
+
+ +

From this Chat Box you can send messages to other players

+
+
diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 3490985..54d0910 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -14,7 +14,7 @@ const color = { }; -// get the name of the machine useed to connect +// get the name of the machine used to connect const machineHostName = window.location.hostname; console.log('connect to login at %chttps://' + machineHostName + ':8888/app/login',color.yellow); From ddead83583a95f76eccdd3b833852202d896c4cb Mon Sep 17 00:00:00 2001 From: NigeParis Date: Fri, 28 Nov 2025 14:03:00 +0100 Subject: [PATCH 10/22] added PingBuddies Bar to detect connected Chatters in real time --- frontend/src/chat/chat.css | 27 +++++++++++ frontend/src/pages/chat/chat.html | 18 +++---- frontend/src/pages/chat/chat.ts | 80 +++++++++++++------------------ src/chat/src/app.ts | 7 +-- 4 files changed, 75 insertions(+), 57 deletions(-) diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index e94c993..6204f43 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -107,6 +107,33 @@ text-gray-800 } +.ping-box { + @apply + w-[150px] + ml-2 border-1 + border-gray-500 + bg-white + rounded-2xl + p-2 + shadow-md + flex flex-col + gap-1 + h-[350px]; +} + +.ping-title { + @apply + text-sm + font-semibold + text-blue-800; +} + +div-buddies-list { + @apply + text-black + whitespace-pre-wrap; + +} p { @apply diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index 2f6c2a3..7c31b84 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -2,7 +2,7 @@

- ChatterBoxes 😀😀😀 + ChatterBoxes


@@ -10,7 +10,7 @@
-
+
@@ -20,13 +20,15 @@
- -
-

Ping Buddies

+ +
+

Ping Buddies

-

Alice

-

Bob

-

Charlie

+
+ +
diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 54d0910..6e5369c 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -30,8 +30,8 @@ document.addEventListener('ft:pageChange', () => { function getSocket(): Socket { - //let addressHost = `wss://${machineHostName}:8888`; - let addressHost = `wss://localhost:8888`; + let addressHost = `wss://${machineHostName}:8888`; + // let addressHost = `wss://localhost:8888`; if (__socket === undefined) __socket = io(addressHost, { @@ -82,55 +82,23 @@ async function windowStateVisable() { +async function listBuddies(buddies: HTMLDivElement, listBuddies: string ) { + if (!buddies) return; + const messageElement = document.createElement("div-buddies-list"); + messageElement.textContent = listBuddies + '\n'; + buddies.appendChild(messageElement); + buddies.scrollTop = buddies.scrollHeight; + console.log(`Added buddies: ${listBuddies}`) + return ; - +} function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { let socket = getSocket(); - - -// document.addEventListener("visibilitychange", async () => { - -// const socketId = __socket || undefined; -// let oldName = localStorage.getItem("oldName") || undefined; - - - -// if (socketId == undefined) return; -// if (document.visibilityState === "hidden") { -// let userName = await updateUser(); -// oldName = userName?.name || undefined; -// if (oldName === undefined) return; -// localStorage.setItem('oldName', oldName); -// socketId.emit('client_left', { -// user: userName?.name, -// why: 'tab window hidden - socket not dead', -// }); -// return; -// } - - - -// if (document.visibilityState === "visible") { -// const res = await client.guestLogin(); -// let user = await updateUser(); -// socketId.emit('client_entered', { -// userName: oldName, -// user: user?.name, -// }); -// setTitle('Chat Page'); -// return; -// } - - - - - -// }); @@ -161,8 +129,14 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn console.log("Recieved data.message.timestamp: ", data.message.timestamp); // Display the message in the chat window const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement; + const bconnected = document.getElementById('b-help') as HTMLButtonElement; + if (bconnected) { + bconnected.click(); + } + if (chatWindow) { const messageElement = document.createElement("div"); + // if (getUser()?.id !== `${data.message.id}`) { console.log('==================> HERE'); messageElement.textContent = `${data.message.user}: ${data.message.text}`; @@ -197,6 +171,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const bwhoami = document.getElementById('b-whoami') as HTMLButtonElement; const bconnected = document.getElementById('b-help') as HTMLButtonElement; const username = document.getElementById('username') as HTMLDivElement; + const buddies = document.getElementById('div-buddies') as HTMLDivElement; const value = await client.chatTest(); if (value.kind === "success") { @@ -216,6 +191,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn if (window.location.pathname === "/app/chat") { window.addEventListener("focus", () => { + bconnected.click(); windowStateVisable(); console.log("%cWindow is focused on /chat", color.green); }); @@ -227,11 +203,13 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } socket.once('welcome', (data) => { + bconnected.click(); addMessage (`${data.msg} ` + getUser()?.name); }); // Send button sendButton?.addEventListener("click", () => { + bconnected.click(); if (sendtextbox && sendtextbox.value.trim()) { const msgText = sendtextbox.value.trim(); addMessage(msgText); @@ -259,6 +237,10 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } }); + + // setInterval(async () => { + // bconnected.click(); + // }, 5000); // every 1 second // Help Text button bconnected?.addEventListener("click", async () => { @@ -270,21 +252,27 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const res = await client.guestLogin(); let user = await updateUser(); localStorage.setItem("oldName", oldUser); - + buddies.textContent = ""; console.log('USER ', user?.name); if (chatWindow) { - addMessage('@list - lists all connected users in the chat'); + //addMessage('@list - lists all connected users in the chat'); socket.emit('list', { oldUser: oldUser, - user: user?.name + user: user?.name, }); } + }); socket.on('listObj', (list: string) => { console.log('List chat clients connected ', list); addMessage(list); }); + socket.on('listBud', (myBuddies: string) => { + console.log('List buddies connected ', myBuddies); + listBuddies(buddies,myBuddies); + }); + diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index d89b248..2b03457 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -82,6 +82,7 @@ declare module 'fastify' { hello: (message: string) => string; MsgObjectServer: (data: { message: ClientMessage }) => void; message: (msg: string) => void; + listBud: (msg: string) => void; testend: (sock_id_client: string) => void; client_entered: (userName: string, user: string) => void; client_left: (userName: string, why: string) => void; @@ -130,8 +131,8 @@ async function onReady(fastify: FastifyInstance) { console.log(color.yellow, 'Client:', color.reset, username.user); const targetSocketId = target; - io.to(targetSocketId!).emit('listObj', username.user); - + // io.to(targetSocketId!).emit('listObj', username.user); + io.to(targetSocketId!).emit('listBud', username.user); console.log( color.yellow, 'Chat Socket ID:', @@ -163,9 +164,9 @@ async function onReady(fastify: FastifyInstance) { function broadcast(data: ClientMessage, sender?: string) { fastify.io.fetchSockets().then((sockets) => { for (const s of sockets) { + const clientName = clientChat.get(s.id)?.user; if (s.id !== sender) { // Send REAL JSON object - const clientName = clientChat.get(s.id)?.user; if (clientName !== undefined) { s.emit('MsgObjectServer', { message: data }); } From 0eba95a4028ab1158554ebc049fae77e0ca9be65 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Fri, 28 Nov 2025 16:40:33 +0100 Subject: [PATCH 11/22] New look --- frontend/src/chat/chat.css | 4 ++ frontend/src/pages/chat/chat.html | 2 +- frontend/src/pages/chat/chat.ts | 68 +++++++++++++++---------------- src/chat/src/app.ts | 5 +-- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index 6204f43..95c2bb5 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -1,4 +1,8 @@ @import "tailwindcss"; +@font-face { + font-family: "Nimbus Mono L"; + src: url("/fonts/NimbusMonoL.woff2") format("woff2"); +} .btn-style { @apply diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index 7c31b84..dd8c5da 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -2,7 +2,7 @@

- ChatterBoxes + ChatterBox


diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 6e5369c..1636c86 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -18,8 +18,6 @@ const color = { const machineHostName = window.location.hostname; console.log('connect to login at %chttps://' + machineHostName + ':8888/app/login',color.yellow); - - let __socket: Socket | undefined = undefined; document.addEventListener('ft:pageChange', () => { if (__socket !== undefined) @@ -28,10 +26,9 @@ document.addEventListener('ft:pageChange', () => { console.log("Page changed"); }) - function getSocket(): Socket { - let addressHost = `wss://${machineHostName}:8888`; - // let addressHost = `wss://localhost:8888`; + // let addressHost = `wss://${machineHostName}:8888`; + let addressHost = `wss://localhost:8888`; if (__socket === undefined) __socket = io(addressHost, { @@ -47,9 +44,6 @@ async function isLoggedIn() { return getUser() || null; } - - - async function windowStateHidden() { const socketId = __socket || undefined; let oldName = localStorage.getItem("oldName") || undefined; @@ -81,7 +75,6 @@ async function windowStateVisable() { } - async function listBuddies(buddies: HTMLDivElement, listBuddies: string ) { if (!buddies) return; @@ -94,6 +87,16 @@ async function listBuddies(buddies: HTMLDivElement, listBuddies: string ) { } +function waitSocketConnected(socket: Socket): Promise { + return new Promise(resolve => { + if (socket.connected) return resolve(); // already connected + socket.on("connect", () => resolve()); + }); +} +const bconnected = document.getElementById('b-help') as HTMLButtonElement; +if (bconnected) { + bconnected.click(); +} @@ -103,7 +106,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn // Listen for the 'connect' event - socket.on("connect", () => { + socket.on("connect", async () => { + + await waitSocketConnected(socket); console.log("I AM Connected to the server:", socket.id); const user = getUser()?.name; // Ensure we have a user AND socket is connected @@ -157,7 +162,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn color?: { default: string, hover: string }, }; - // function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { setTitle('Chat Page'); // Listen for the 'connect' event @@ -173,10 +177,10 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const username = document.getElementById('username') as HTMLDivElement; const buddies = document.getElementById('div-buddies') as HTMLDivElement; - const value = await client.chatTest(); - if (value.kind === "success") { - console.log(value.payload); - + chatWindow.textContent = ''; + chatWindow.innerHTML = ''; + buddies.textContent = ''; + buddies.innerHTML = ''; const addMessage = (text: string) => { @@ -191,27 +195,32 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn if (window.location.pathname === "/app/chat") { window.addEventListener("focus", () => { - bconnected.click(); windowStateVisable(); + bconnected.click(); console.log("%cWindow is focused on /chat", color.green); }); window.addEventListener("blur", () => { windowStateHidden(); + bconnected.click(); console.log("%cWindow is not focused on /chat", color.red); }); } socket.once('welcome', (data) => { + chatWindow.textContent = ''; + chatWindow.innerHTML = ''; + buddies.textContent = ''; + buddies.innerHTML = ''; bconnected.click(); addMessage (`${data.msg} ` + getUser()?.name); }); // Send button sendButton?.addEventListener("click", () => { - bconnected.click(); if (sendtextbox && sendtextbox.value.trim()) { const msgText = sendtextbox.value.trim(); + bconnected.click(); addMessage(msgText); const user = getUser(); if (user && socket?.connected) { @@ -233,14 +242,16 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn // Clear Text button clearText?.addEventListener("click", () => { if (chatWindow) { + bconnected.click(); chatWindow.innerHTML = ''; } }); - // setInterval(async () => { - // bconnected.click(); - // }, 5000); // every 1 second + bconnected.click(); + setInterval(async () => { + bconnected.click(); + }, 50000); // every 1 second // Help Text button bconnected?.addEventListener("click", async () => { @@ -253,9 +264,8 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn let user = await updateUser(); localStorage.setItem("oldName", oldUser); buddies.textContent = ""; - console.log('USER ', user?.name); if (chatWindow) { - //addMessage('@list - lists all connected users in the chat'); + // addMessage('@list - lists all connected users in the chat'); socket.emit('list', { oldUser: oldUser, user: user?.name, @@ -317,21 +327,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn showError('Failed to login: Unknown error'); } }); - - } else if (value.kind === "notLoggedIn") { - - if (!chatWindow) return; - const messageElement = document.createElement('div-notlog'); - messageElement.textContent = "Not Logged in ...."; - chatWindow.appendChild(messageElement); - chatWindow.scrollTop = chatWindow.scrollHeight; - console.log('not logged in'); - - } else { - console.log('unknown response: ', value); - } } } }; addRoute('/chat', handleChat, { bypass_auth: true }); addRoute('/chat/', handleChat, { bypass_auth: true }); + diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 2b03457..c4e6677 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -157,15 +157,14 @@ async function onReady(fastify: FastifyInstance) { socketId, ); } - return count; } function broadcast(data: ClientMessage, sender?: string) { fastify.io.fetchSockets().then((sockets) => { for (const s of sockets) { - const clientName = clientChat.get(s.id)?.user; if (s.id !== sender) { + const clientName = clientChat.get(s.id)?.user; // Send REAL JSON object if (clientName !== undefined) { s.emit('MsgObjectServer', { message: data }); @@ -229,7 +228,7 @@ async function onReady(fastify: FastifyInstance) { if (userFromFrontend.oldUser !== userFromFrontend.user) { console.log(color.red, 'list activated', userFromFrontend.oldUser, color.reset); - if (client === null) { + if (client?.user === null) { console.log('ERROR: clientName is NULL'); return; }; From 91afd0ebdefeb45407fd20db1cdba1fc3a49eb8d Mon Sep 17 00:00:00 2001 From: NigeParis Date: Sat, 29 Nov 2025 14:16:20 +0100 Subject: [PATCH 12/22] Bug fixed multiple notification when user leaves by the side menu and comes back on chat without logining out --- frontend/src/pages/chat/chat.ts | 59 +++++++++++++++++++++------------ frontend/src/routing/index.ts | 1 - src/chat/src/app.ts | 16 +++++---- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 1636c86..a0c3faf 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -27,8 +27,8 @@ document.addEventListener('ft:pageChange', () => { }) function getSocket(): Socket { - // let addressHost = `wss://${machineHostName}:8888`; - let addressHost = `wss://localhost:8888`; + let addressHost = `wss://${machineHostName}:8888`; + // let addressHost = `wss://localhost:8888`; if (__socket === undefined) __socket = io(addressHost, { @@ -63,9 +63,12 @@ async function windowStateHidden() { async function windowStateVisable() { const socketId = __socket || undefined; let oldName = localStorage.getItem("oldName") || undefined; - if (socketId == undefined) return; + console.log("%coldName :'" + oldName + "'", color.green); + + if (socketId === undefined || oldName === undefined) {console.log("%SOCKET ID", color.red); return;} const res = await client.guestLogin(); let user = await updateUser(); + console.log("%cUserName :'" + user?.name + "'", color.green); socketId.emit('client_entered', { userName: oldName, user: user?.name, @@ -101,10 +104,10 @@ if (bconnected) { function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { + + let socket = getSocket(); - - - + // Listen for the 'connect' event socket.on("connect", async () => { @@ -163,6 +166,32 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }; + let toggle = false + window.addEventListener("focus", () => { + if (window.location.pathname === "/app/chat" && !toggle) { + // bconnected.click(); + console.log("%cWindow is focused on /chat:" + socket.id, color.green); + if (socket.id) + windowStateVisable(); + toggle = true; + } + }); + + window.addEventListener("blur", () => { + // if (window.location.pathname !== "/app/chat" && !toggle) { + // // bconnected.click(); + // console.log("%cWindow is not focused on /chat", color.red); + + if (socket.id) + windowStateHidden(); + // }); + toggle = false; + // } + }); + + + + setTitle('Chat Page'); // Listen for the 'connect' event return { @@ -193,20 +222,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn return ; }; - if (window.location.pathname === "/app/chat") { - window.addEventListener("focus", () => { - windowStateVisable(); - bconnected.click(); - console.log("%cWindow is focused on /chat", color.green); - }); - - window.addEventListener("blur", () => { - windowStateHidden(); - bconnected.click(); - console.log("%cWindow is not focused on /chat", color.red); - }); - } - socket.once('welcome', (data) => { chatWindow.textContent = ''; chatWindow.innerHTML = ''; @@ -214,7 +229,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn buddies.innerHTML = ''; bconnected.click(); addMessage (`${data.msg} ` + getUser()?.name); - }); + }); // Send button sendButton?.addEventListener("click", () => { @@ -331,5 +346,5 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } }; addRoute('/chat', handleChat, { bypass_auth: true }); -addRoute('/chat/', handleChat, { bypass_auth: true }); +// addRoute('/chat/', handleChat, { bypass_auth: true }); diff --git a/frontend/src/routing/index.ts b/frontend/src/routing/index.ts index 9e504db..0c0b9a4 100644 --- a/frontend/src/routing/index.ts +++ b/frontend/src/routing/index.ts @@ -196,7 +196,6 @@ export async function handleRoute() { return navigateTo(`/login?returnTo=${encodeURIComponent(window.location.pathname)}`) const app = document.getElementById('app')!; document.dispatchEvent(new CustomEvent('ft:pageChange' as any, {} as any) as any); - document.dispatchEvent(new CustomEvent('ft:tabChange' as any, {} as any) as any); let ret = await executeRouteHandler(route_handler, window.location.pathname, args) app.innerHTML = ret.html; if (ret.postInsert) { diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index c4e6677..245d2d6 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -168,6 +168,7 @@ async function onReady(fastify: FastifyInstance) { // Send REAL JSON object if (clientName !== undefined) { s.emit('MsgObjectServer', { message: data }); + console.log(color.green, 'Name Sender', clientChat); } console.log(' Target window socket ID:', s.id); console.log(' Target window ID:', [...s.rooms]); @@ -309,24 +310,24 @@ async function onReady(fastify: FastifyInstance) { const userNameFromFrontend = data?.userName || null; const userFromFrontend = data?.user || null; let clientName = clientChat.get(socket.id)?.user || null; - const client = clientChat.get(socket.id) || null; + // const client = clientChat.get(socket.id) || null; let text = 'is back in the chat'; if (clientName === null) { console.log('ERROR: clientName is NULL'); return; }; - if (client === null) { - console.log('ERROR: client is NULL'); return; - }; + // if (client === null) { + // console.log('ERROR: client is NULL'); return; + // }; if (userNameFromFrontend !== userFromFrontend) { text = `'is back in the chat, I used to be called '${userNameFromFrontend}`; clientName = userFromFrontend; if (clientName === null) { console.log('ERROR: clientName is NULL'); return; }; - if (client) { - client.user = clientName; - } + // if (client) { + // client.user = clientName; + // } } console.log( color.green, @@ -346,5 +347,6 @@ async function onReady(fastify: FastifyInstance) { broadcast(obj, obj.SenderWindowID); } }); + }); } From cd40a04e4070ddf59452a24bd3c92497e59993f7 Mon Sep 17 00:00:00 2001 From: Maieul BOYER Date: Sat, 29 Nov 2025 16:05:18 +0100 Subject: [PATCH 13/22] added blocked database --- src/@shared/src/database/index.ts | 4 +- src/@shared/src/database/init.sql | 14 ++++++ src/@shared/src/database/mixin/blocked.ts | 55 +++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/@shared/src/database/mixin/blocked.ts diff --git a/src/@shared/src/database/index.ts b/src/@shared/src/database/index.ts index 597efac..ea111db 100644 --- a/src/@shared/src/database/index.ts +++ b/src/@shared/src/database/index.ts @@ -4,11 +4,13 @@ import { FastifyInstance, FastifyPluginAsync } from 'fastify'; import { isNullish } from '@shared/utils'; import { Database as DbImpl } from './mixin/_base'; import { IUserDb, UserImpl } from './mixin/user'; +import { IBlockedDb, BlockedImpl } from './mixin/blocked'; Object.assign(DbImpl.prototype, UserImpl); +Object.assign(DbImpl.prototype, BlockedImpl); -export interface Database extends DbImpl, IUserDb { } +export interface Database extends DbImpl, IUserDb, IBlockedDb { } // When using .decorate you have to specify added properties for Typescript declare module 'fastify' { diff --git a/src/@shared/src/database/init.sql b/src/@shared/src/database/init.sql index b53675b..b4e1415 100644 --- a/src/@shared/src/database/init.sql +++ b/src/@shared/src/database/init.sql @@ -7,3 +7,17 @@ CREATE TABLE IF NOT EXISTS user ( guest INTEGER NOT NULL DEFAULT 0, oauth2 TEXT DEFAULT NULL ); + + +CREATE TABLE IF NOT EXISTS blocked ( + id INTEGER PRIMARY KEY NOT NULL, + user TEXT NOT NULL, + blocked TEXT NOT NULL, + + FOREIGN KEY(user) REFERENCES user(id); + FOREIGN KEY(blocked) REFERENCES user(id); +); + +CREATE UNIQUE INDEX IF NOT EXISTS idx_blocked_user_pair + ON blocked(user, blocked); + diff --git a/src/@shared/src/database/mixin/blocked.ts b/src/@shared/src/database/mixin/blocked.ts new file mode 100644 index 0000000..2f3c9f4 --- /dev/null +++ b/src/@shared/src/database/mixin/blocked.ts @@ -0,0 +1,55 @@ +import { isNullish } from '@shared/utils'; +import type { Database } from './_base'; +import { UserId } from './user'; + +// never use this directly + +// describe every function in the object +export interface IBlockedDb extends Database { + getBlockedUserFor(id: UserId): BlockedData[], + addBlockedUserFor(id: UserId, blocked: UserId): void, + removeBlockedUserFor(id: UserId, blocked: UserId): void, + unblockAllUserFor(id: UserId): void, +}; + +export const BlockedImpl: Omit = { + getBlockedUserFor(this: IBlockedDb, id: UserId): BlockedData[] { + const query = this.prepare('SELECT * FROM blocked WHERE user = @id'); + const data = query.all({ id }) as Partial[]; + return data.map(blockedFromRow).filter(b => !isNullish(b)); + }, + + unblockAllUserFor(this: IBlockedDb, id: UserId): void { + this.prepare('DELETE FROM blocked WHERE user = @id').run({ id }); + }, + addBlockedUserFor(this: IBlockedDb, id: UserId, blocked: UserId): void { + this.prepare('INSERT OR IGNORE INTO blocked (user, blocked) VALUES (@id, @blocked)').run({ id, blocked }); + }, + removeBlockedUserFor(this: IBlockedDb, id: UserId, blocked: UserId): void { + this.prepare('DELETE FROM blocked WHERE user = @id AND blocked = @blocked').run({ id, blocked }); + }, +}; + +export type BlockedId = number & { readonly __brand: unique symbol }; + +export type BlockedData = { + readonly id: BlockedId; + readonly user: UserId; + readonly blocked: UserId; +}; + +/** + * Get a blocked from a row + * + * @param row The data from sqlite + * + * @returns The blocked if it exists, undefined otherwise + */ +export function blockedFromRow(row?: Partial): BlockedData | undefined { + if (isNullish(row)) return undefined; + if (isNullish(row.id)) return undefined; + if (isNullish(row.user)) return undefined; + if (isNullish(row.blocked)) return undefined; + + return row as BlockedData; +} From 59a3efa6f7d81b7e7fd356e32ab6b9687a1904da Mon Sep 17 00:00:00 2001 From: NigeParis Date: Sat, 29 Nov 2025 17:47:04 +0100 Subject: [PATCH 14/22] Bug - db fixed --- frontend/src/pages/chat/chat.ts | 30 ++++++------------------------ src/@shared/src/database/init.sql | 4 ++-- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index a0c3faf..8dfeefc 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -10,7 +10,7 @@ const color = { green: 'color: green; font-weight: bold;', yellow: 'color: orange; font-weight: bold;', blue: 'color: blue; font-weight: bold;', - reset: '', // not needed in browser + reset: '', }; @@ -27,8 +27,8 @@ document.addEventListener('ft:pageChange', () => { }) function getSocket(): Socket { - let addressHost = `wss://${machineHostName}:8888`; - // let addressHost = `wss://localhost:8888`; + // let addressHost = `wss://${machineHostName}:8888`; + let addressHost = `wss://localhost:8888`; if (__socket === undefined) __socket = io(addressHost, { @@ -144,14 +144,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn if (chatWindow) { const messageElement = document.createElement("div"); - - // if (getUser()?.id !== `${data.message.id}`) { - console.log('==================> HERE'); messageElement.textContent = `${data.message.user}: ${data.message.text}`; - // } else { - // console.log('==================>AND HERE'); - // messageElement.textContent = `here`; - // } chatWindow.appendChild(messageElement); chatWindow.scrollTop = chatWindow.scrollHeight; } @@ -178,20 +171,13 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }); window.addEventListener("blur", () => { - // if (window.location.pathname !== "/app/chat" && !toggle) { - // // bconnected.click(); - // console.log("%cWindow is not focused on /chat", color.red); - + bconnected.click(); + console.log("%cWindow is not focused on /chat", color.red); if (socket.id) windowStateHidden(); - // }); - toggle = false; - // } + toggle = false; }); - - - setTitle('Chat Page'); // Listen for the 'connect' event return { @@ -299,9 +285,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }); - - - // Enter key to send message sendtextbox!.addEventListener('keydown', (event) => { if (event.key === 'Enter') { @@ -346,5 +329,4 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } }; addRoute('/chat', handleChat, { bypass_auth: true }); -// addRoute('/chat/', handleChat, { bypass_auth: true }); diff --git a/src/@shared/src/database/init.sql b/src/@shared/src/database/init.sql index b4e1415..b77edfe 100644 --- a/src/@shared/src/database/init.sql +++ b/src/@shared/src/database/init.sql @@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS blocked ( user TEXT NOT NULL, blocked TEXT NOT NULL, - FOREIGN KEY(user) REFERENCES user(id); - FOREIGN KEY(blocked) REFERENCES user(id); + FOREIGN KEY(user) REFERENCES user(id) + FOREIGN KEY(blocked) REFERENCES user(id) ); CREATE UNIQUE INDEX IF NOT EXISTS idx_blocked_user_pair From 899694a17f4ffc9e3efd64e3071a21c9745b28fb Mon Sep 17 00:00:00 2001 From: NigeParis Date: Mon, 1 Dec 2025 10:05:49 +0100 Subject: [PATCH 15/22] Bugs - review co-pilote - returned before changing code --- frontend/src/pages/chat/chat.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 8dfeefc..5706bb3 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -171,7 +171,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }); window.addEventListener("blur", () => { - bconnected.click(); + //bconnected.click(); console.log("%cWindow is not focused on /chat", color.red); if (socket.id) windowStateHidden(); @@ -252,7 +252,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn bconnected.click(); setInterval(async () => { bconnected.click(); - }, 50000); // every 1 second + }, 10000); // every 10 second // Help Text button bconnected?.addEventListener("click", async () => { From d1496e1697cd5d7aa95f20ecb46cd7bd9aede93d Mon Sep 17 00:00:00 2001 From: NigeParis Date: Mon, 1 Dec 2025 12:16:08 +0100 Subject: [PATCH 16/22] added Quit Chat Button --- frontend/src/pages/chat/chat.html | 5 ++- frontend/src/pages/chat/chat.ts | 42 +++++++++++++++++--- src/chat/src/app.ts | 66 ++++++++++++++++++++++--------- 3 files changed, 88 insertions(+), 25 deletions(-) diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index dd8c5da..e6d9e92 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -5,6 +5,7 @@ ChatterBox
+ @@ -12,9 +13,9 @@
-
+
-
+
diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 5706bb3..864608e 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -14,6 +14,9 @@ const color = { }; + + + // get the name of the machine used to connect const machineHostName = window.location.hostname; console.log('connect to login at %chttps://' + machineHostName + ':8888/app/login',color.yellow); @@ -101,6 +104,14 @@ if (bconnected) { bconnected.click(); } +function logout(socket: Socket) { + socket.emit("logout"); // notify server + socket.disconnect(); // actually close the socket + localStorage.clear(); + if (__socket !== undefined) + __socket.close(); +// window.location.href = "/login"; +} function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn { @@ -108,6 +119,8 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn let socket = getSocket(); + + // Listen for the 'connect' event socket.on("connect", async () => { @@ -151,6 +164,16 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn console.log("Getuser():", getUser()); }); + + + + socket.on('logout', () => { + const bquit = document.getElementById('b-quit') as HTMLDivElement | null; + if (bquit instanceof HTMLDivElement) { + bquit.click(); + } + }); + type Providers = { name: string, display_name: string, @@ -191,6 +214,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const bconnected = document.getElementById('b-help') as HTMLButtonElement; const username = document.getElementById('username') as HTMLDivElement; const buddies = document.getElementById('div-buddies') as HTMLDivElement; + const bquit = document.getElementById('b-quit') as HTMLDivElement; chatWindow.textContent = ''; chatWindow.innerHTML = ''; @@ -240,16 +264,28 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }); + + // Clear Text button clearText?.addEventListener("click", () => { + if (chatWindow) { bconnected.click(); chatWindow.innerHTML = ''; } }); + bquit?.addEventListener('click', () => { + if (socket) { + logout(socket); + setTitle('Chat Page'); + bconnected.click(); + } else { + getSocket(); + } + }); + - bconnected.click(); setInterval(async () => { bconnected.click(); }, 10000); // every 10 second @@ -274,10 +310,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn } }); - socket.on('listObj', (list: string) => { - console.log('List chat clients connected ', list); - addMessage(list); - }); socket.on('listBud', (myBuddies: string) => { console.log('List buddies connected ', myBuddies); diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 245d2d6..e426758 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -131,7 +131,6 @@ async function onReady(fastify: FastifyInstance) { console.log(color.yellow, 'Client:', color.reset, username.user); const targetSocketId = target; - // io.to(targetSocketId!).emit('listObj', username.user); io.to(targetSocketId!).emit('listBud', username.user); console.log( color.yellow, @@ -160,23 +159,32 @@ async function onReady(fastify: FastifyInstance) { return count; } - function broadcast(data: ClientMessage, sender?: string) { - fastify.io.fetchSockets().then((sockets) => { - for (const s of sockets) { - if (s.id !== sender) { - const clientName = clientChat.get(s.id)?.user; - // Send REAL JSON object - if (clientName !== undefined) { - s.emit('MsgObjectServer', { message: data }); - console.log(color.green, 'Name Sender', clientChat); - } - console.log(' Target window socket ID:', s.id); - console.log(' Target window ID:', [...s.rooms]); - console.log(' Sender window ID:', sender ? sender : 'none'); - } +function broadcast(data: ClientMessage, sender?: string) { + fastify.io.fetchSockets().then((sockets) => { + for (const s of sockets) { + + // Skip sender's own socket + if (s.id === sender) continue; + + // Get client name from map + const clientInfo = clientChat.get(s.id); + + if (!clientInfo?.user) { + console.log(color.yellow, `Skipping socket ${s.id} (no user found)`); + continue; } - }); - } + + // Emit structured JSON object + s.emit("MsgObjectServer", { message: data }); + + // Debug logs + console.log(color.green, "Broadcast to:", clientInfo.user); + console.log(" Target socket ID:", s.id); + console.log(" Target rooms:", [...s.rooms]); + console.log(" Sender socket ID:", sender ?? "none"); + } + }); +} fastify.io.on('connection', (socket: Socket) => { @@ -229,7 +237,7 @@ async function onReady(fastify: FastifyInstance) { if (userFromFrontend.oldUser !== userFromFrontend.user) { console.log(color.red, 'list activated', userFromFrontend.oldUser, color.reset); - if (client?.user === null) { + if (client?.user === null) { console.log('ERROR: clientName is NULL'); return; }; @@ -256,6 +264,28 @@ async function onReady(fastify: FastifyInstance) { } }); + socket.on("logout", () => { + const clientInfo = clientChat.get(socket.id); + const clientName = clientInfo?.user; + + if (!clientName) return; + console.log(color.green, `Client logging out: ${clientName} (${socket.id})`); + const obj = { + type: "chat" as const, + user: clientName, + token: "", + text: "LEFT the chat", + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + broadcast(obj, socket.id); + // Optional: remove from map + clientChat.delete(socket.id); + // Ensure socket is fully disconnected + if (socket.connected) socket.disconnect(true); + }); + + socket.on('disconnecting', (reason) => { const clientName = clientChat.get(socket.id)?.user || null; From b35c46264882248e09a17578e7d06a07c7873e94 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Mon, 1 Dec 2025 18:46:38 +0100 Subject: [PATCH 17/22] playing wiith database Blocked Users --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 22 +- frontend/src/pages/chat/chat.ts | 11 +- src/@shared/package.json | 4 +- src/@shared/src/database/mixin/blocked.ts | 21 +- src/@shared/src/database/mixin/user.ts | 11 + src/auth/package.json | 6 +- src/chat/package.json | 8 +- src/chat/src/routes/nginx-chat.ts | 94 +++++++- src/icons/package.json | 4 +- src/package.json | 4 +- src/pnpm-lock.yaml | 266 +++++++++++----------- src/user/package.json | 6 +- 13 files changed, 291 insertions(+), 168 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 9e51cb2..04bd252 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@types/js-cookie": "^3.0.6", "typescript": "~5.9.3", - "vite": "^7.2.4", + "vite": "^7.2.6", "vite-tsconfig-paths": "^5.1.4" }, "dependencies": { diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index a490db1..6addf30 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@tailwindcss/vite': specifier: ^4.1.17 - version: 4.1.17(vite@7.2.4(jiti@2.6.1)(lightningcss@1.30.2)) + version: 4.1.17(vite@7.2.6(jiti@2.6.1)(lightningcss@1.30.2)) js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -31,11 +31,11 @@ importers: specifier: ~5.9.3 version: 5.9.3 vite: - specifier: ^7.2.4 - version: 7.2.4(jiti@2.6.1)(lightningcss@1.30.2) + specifier: ^7.2.6 + version: 7.2.6(jiti@2.6.1)(lightningcss@1.30.2) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(jiti@2.6.1)(lightningcss@1.30.2)) + version: 5.1.4(typescript@5.9.3)(vite@7.2.6(jiti@2.6.1)(lightningcss@1.30.2)) packages: @@ -635,8 +635,8 @@ packages: vite: optional: true - vite@7.2.4: - resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + vite@7.2.6: + resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -919,12 +919,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 - '@tailwindcss/vite@4.1.17(vite@7.2.4(jiti@2.6.1)(lightningcss@1.30.2))': + '@tailwindcss/vite@4.1.17(vite@7.2.6(jiti@2.6.1)(lightningcss@1.30.2))': dependencies: '@tailwindcss/node': 4.1.17 '@tailwindcss/oxide': 4.1.17 tailwindcss: 4.1.17 - vite: 7.2.4(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.2.6(jiti@2.6.1)(lightningcss@1.30.2) '@types/estree@1.0.8': {} @@ -1139,18 +1139,18 @@ snapshots: typescript@5.9.3: {} - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.4(jiti@2.6.1)(lightningcss@1.30.2)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.6(jiti@2.6.1)(lightningcss@1.30.2)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 7.2.4(jiti@2.6.1)(lightningcss@1.30.2) + vite: 7.2.6(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - supports-color - typescript - vite@7.2.4(jiti@2.6.1)(lightningcss@1.30.2): + vite@7.2.6(jiti@2.6.1)(lightningcss@1.30.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 864608e..f03088e 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -184,7 +184,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn let toggle = false window.addEventListener("focus", () => { - if (window.location.pathname === "/app/chat" && !toggle) { + if (window.location.pathname === "" && !toggle) { // bconnected.click(); console.log("%cWindow is focused on /chat:" + socket.id, color.green); if (socket.id) @@ -222,6 +222,15 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn buddies.innerHTML = ''; + const value = await client.chatTest(); + if (value.kind === "success") { + console.log(value.payload); + } else if (value.kind === "notLoggedIn") { + console.log('not logged in'); + } else { + console.log('unknown response: ', value); + } + const addMessage = (text: string) => { if (!chatWindow) return; const messageElement = document.createElement("div-test"); diff --git a/src/@shared/package.json b/src/@shared/package.json index dad8675..15f2935 100644 --- a/src/@shared/package.json +++ b/src/@shared/package.json @@ -20,8 +20,8 @@ "fastify-plugin": "^5.1.0", "joi": "^18.0.2", "otp": "^1.1.2", - "typebox": "^1.0.56", - "uuidv7": "^1.0.2" + "typebox": "^1.0.59", + "uuidv7": "^1.1.0" }, "devDependencies": { "@types/better-sqlite3": "^7.6.13", diff --git a/src/@shared/src/database/mixin/blocked.ts b/src/@shared/src/database/mixin/blocked.ts index 2f3c9f4..13db21d 100644 --- a/src/@shared/src/database/mixin/blocked.ts +++ b/src/@shared/src/database/mixin/blocked.ts @@ -2,7 +2,6 @@ import { isNullish } from '@shared/utils'; import type { Database } from './_base'; import { UserId } from './user'; -// never use this directly // describe every function in the object export interface IBlockedDb extends Database { @@ -10,6 +9,8 @@ export interface IBlockedDb extends Database { addBlockedUserFor(id: UserId, blocked: UserId): void, removeBlockedUserFor(id: UserId, blocked: UserId): void, unblockAllUserFor(id: UserId): void, + getAllBlockedUsers(this: IBlockedDb): BlockedData[] | undefined, + }; export const BlockedImpl: Omit = { @@ -28,6 +29,23 @@ export const BlockedImpl: Omit = { removeBlockedUserFor(this: IBlockedDb, id: UserId, blocked: UserId): void { this.prepare('DELETE FROM blocked WHERE user = @id AND blocked = @blocked').run({ id, blocked }); }, + + + /** + * Get all blocked user + * + * @param + * + * @returns The list of users if it exists, undefined otherwise + */ + getAllBlockedUsers(this: IBlockedDb): BlockedData[] { + const rows = this.prepare('SELECT * FROM blocked').all() as Partial[]; + + return rows + .map(row => blockedFromRow(row)) + .filter((u): u is BlockedData => u !== undefined); + }, + }; export type BlockedId = number & { readonly __brand: unique symbol }; @@ -46,6 +64,7 @@ export type BlockedData = { * @returns The blocked if it exists, undefined otherwise */ export function blockedFromRow(row?: Partial): BlockedData | undefined { + console.log('HELLO ?????', row); if (isNullish(row)) return undefined; if (isNullish(row.id)) return undefined; if (isNullish(row.user)) return undefined; diff --git a/src/@shared/src/database/mixin/user.ts b/src/@shared/src/database/mixin/user.ts index 558bfee..a931aa8 100644 --- a/src/@shared/src/database/mixin/user.ts +++ b/src/@shared/src/database/mixin/user.ts @@ -18,6 +18,8 @@ export interface IUserDb extends Database { ensureUserOtpSecret(id: UserId): string | undefined, deleteUserOtpSecret(id: UserId): void, getAllUserFromProvider(provider: string): User[] | undefined, + getAllUsers(this: IUserDb): User[] | undefined, + }; export const UserImpl: Omit = { @@ -36,6 +38,15 @@ export const UserImpl: Omit = { ); }, + getAllUsers(this: IUserDb): User[] { + const rows = this.prepare('SELECT * FROM user').all() as Partial[]; + + return rows + .map(row => userFromRow(row)) + .filter((u): u is User => u !== undefined); + }, + + /** * Get a user from a raw [UserId] * diff --git a/src/auth/package.json b/src/auth/package.json index adb5e2e..9c9dd49 100644 --- a/src/auth/package.json +++ b/src/auth/package.json @@ -21,18 +21,18 @@ "@fastify/autoload": "^6.3.1", "@fastify/formbody": "^8.0.2", "@fastify/multipart": "^9.3.0", - "@fastify/sensible": "^6.0.3", + "@fastify/sensible": "^6.0.4", "@fastify/static": "^8.3.0", "confbox": "^0.2.2", "fastify": "^5.6.2", "fastify-cli": "^7.4.1", "fastify-plugin": "^5.1.0", - "typebox": "^1.0.56" + "typebox": "^1.0.59" }, "devDependencies": { "@types/node": "^22.19.1", "rollup-plugin-node-externals": "^8.1.2", - "vite": "^7.2.4", + "vite": "^7.2.6", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/src/chat/package.json b/src/chat/package.json index 7a504d7..56396ad 100644 --- a/src/chat/package.json +++ b/src/chat/package.json @@ -21,18 +21,18 @@ "@fastify/autoload": "^6.3.1", "@fastify/formbody": "^8.0.2", "@fastify/multipart": "^9.3.0", - "@fastify/sensible": "^6.0.3", + "@fastify/sensible": "^6.0.4", "@fastify/static": "^8.3.0", "@fastify/websocket": "^11.2.0", - "@sinclair/typebox": "^0.34.41", "fastify": "^5.6.2", "fastify-plugin": "^5.1.0", - "socket.io": "^4.8.1" + "socket.io": "^4.8.1", + "typebox": "^1.0.59" }, "devDependencies": { "@types/node": "^22.19.1", "rollup-plugin-node-externals": "^8.1.2", - "vite": "^7.2.4", + "vite": "^7.2.6", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/src/chat/src/routes/nginx-chat.ts b/src/chat/src/routes/nginx-chat.ts index d3aaebb..e6dd4df 100644 --- a/src/chat/src/routes/nginx-chat.ts +++ b/src/chat/src/routes/nginx-chat.ts @@ -1,6 +1,27 @@ import { FastifyPluginAsync } from 'fastify'; import { MakeStaticResponse, typeResponse } from '@shared/utils'; -import { Type } from '@sinclair/typebox'; +import { Type } from 'typebox'; +import { UserId } from '@shared/database/mixin/user'; +import { Server } from 'socket.io'; + +// colors for console.log +export const color = { + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + reset: '\x1b[0m', +}; + +// Global map of clients +// key = socket, value = clientname +interface ClientInfo { + user: string; + lastSeen: number; +} + +const clientChat = new Map(); + export const ChatRes = { 200: typeResponse('success', 'chat.success', { @@ -12,6 +33,56 @@ export const ChatRes = { export type ChatResType = MakeStaticResponse; + +function connectedUser(io: Server | undefined, targetSocketId?: string): number { + let count = 0; + + // Track unique usernames (avoid duplicates) + const seenUsers = new Set(); + + for (const [socketId, info] of clientChat) { + + // Validate entry + if (!info || typeof info.user !== "string" || info.user.trim() === "") { + clientChat.delete(socketId); + continue; + } + + const username = info.user; + + // Validate socket exists if io is passed + if (io) { + const socket = io.sockets.sockets.get(socketId); + + // Remove disconnected sockets + if (!socket || socket.disconnected) { + clientChat.delete(socketId); + continue; + } + } + + // Skip duplicates + if (seenUsers.has(username)) + continue; + + seenUsers.add(username); + count++; + + // Send to target only + if (io && targetSocketId) { + io.to(targetSocketId).emit("listBud", username); + } + + console.log(color.yellow, "Client:", color.reset, username); + console.log(color.yellow, "Socket ID:", color.reset, socketId); + } + + return count; +} + + + + const route: FastifyPluginAsync = async (fastify): Promise => { fastify.get( '/api/chat/test', @@ -23,8 +94,25 @@ const route: FastifyPluginAsync = async (fastify): Promise => { config: { requireAuth: true }, }, async (req, res) => { - // console.log('/api/chat/test called =================>'); - res.makeResponse(200, 'success', 'CCChat.success', { name: 'My_namw', 'id': req.authUser!.id, guest: false }); + + + + let users = fastify.db.getAllUsers(); + console.log("ALL USERS EVER CONNECTED:", users); + + if (!users) return; + for (const user of users) { + console.log(color.yellow, "USER:", user.name); + } + + // const usersBlocked = fastify.db.getAllBlockedUsers(); + // console.log(color.red, "ALL BLOCKED USERS:", usersBlocked); + fastify.db.addBlockedUserFor(users[0].id, users[1].id) + let usersBlocked2; + usersBlocked2 = fastify.db.getAllBlockedUsers(); + console.log(color.green, "ALL BLOCKED USERS:", usersBlocked2); + + res.makeResponse(200, 'success', 'CCChat.success', { name: 'name', 'id': req.authUser!.id, guest: false }); }, ); }; diff --git a/src/icons/package.json b/src/icons/package.json index 1952efc..3bef3d5 100644 --- a/src/icons/package.json +++ b/src/icons/package.json @@ -20,7 +20,7 @@ "@fastify/autoload": "^6.3.1", "@fastify/formbody": "^8.0.2", "@fastify/multipart": "^9.3.0", - "@fastify/sensible": "^6.0.3", + "@fastify/sensible": "^6.0.4", "@fastify/static": "^8.3.0", "fastify": "^5.6.2", "fastify-cli": "^7.4.1", @@ -31,7 +31,7 @@ "devDependencies": { "@types/node": "^22.19.1", "rollup-plugin-node-externals": "^8.1.2", - "vite": "^7.2.4", + "vite": "^7.2.6", "vite-tsconfig-paths": "^5.1.4" } } diff --git a/src/package.json b/src/package.json index c833a12..4858a48 100644 --- a/src/package.json +++ b/src/package.json @@ -33,10 +33,10 @@ "openapi-typescript": "^7.10.1", "typescript": "^5.9.3", "typescript-eslint": "^8.48.0", - "vite": "^7.2.4" + "vite": "^7.2.6" }, "dependencies": { - "@redocly/cli": "^2.12.0", + "@redocly/cli": "^2.12.1", "bindings": "^1.5.0" } } diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index bcdb1ae..a7690b6 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@redocly/cli': - specifier: ^2.12.0 - version: 2.12.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0) + specifier: ^2.12.1 + version: 2.12.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0) bindings: specifier: ^1.5.0 version: 1.5.0 @@ -49,8 +49,8 @@ importers: specifier: ^8.48.0 version: 8.48.0(eslint@9.39.1)(typescript@5.9.3) vite: - specifier: ^7.2.4 - version: 7.2.4(@types/node@24.10.1)(yaml@2.8.1) + specifier: ^7.2.6 + version: 7.2.6(@types/node@24.10.1)(yaml@2.8.2) '@shared': dependencies: @@ -88,11 +88,11 @@ importers: specifier: ^1.1.2 version: 1.1.2 typebox: - specifier: ^1.0.56 - version: 1.0.56 + specifier: ^1.0.59 + version: 1.0.59 uuidv7: - specifier: ^1.0.2 - version: 1.0.2 + specifier: ^1.1.0 + version: 1.1.0 devDependencies: '@types/better-sqlite3': specifier: ^7.6.13 @@ -113,8 +113,8 @@ importers: specifier: ^9.3.0 version: 9.3.0 '@fastify/sensible': - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^6.0.4 + version: 6.0.4 '@fastify/static': specifier: ^8.3.0 version: 8.3.0 @@ -131,8 +131,8 @@ importers: specifier: ^5.1.0 version: 5.1.0 typebox: - specifier: ^1.0.56 - version: 1.0.56 + specifier: ^1.0.59 + version: 1.0.59 devDependencies: '@types/node': specifier: ^22.19.1 @@ -141,11 +141,11 @@ importers: specifier: ^8.1.2 version: 8.1.2(rollup@4.53.3) vite: - specifier: ^7.2.4 - version: 7.2.4(@types/node@22.19.1)(yaml@2.8.1) + specifier: ^7.2.6 + version: 7.2.6(@types/node@22.19.1)(yaml@2.8.2) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.19.1)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.3)(vite@7.2.6(@types/node@22.19.1)(yaml@2.8.2)) chat: dependencies: @@ -159,17 +159,14 @@ importers: specifier: ^9.3.0 version: 9.3.0 '@fastify/sensible': - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^6.0.4 + version: 6.0.4 '@fastify/static': specifier: ^8.3.0 version: 8.3.0 '@fastify/websocket': specifier: ^11.2.0 version: 11.2.0 - '@sinclair/typebox': - specifier: ^0.34.41 - version: 0.34.41 fastify: specifier: ^5.6.2 version: 5.6.2 @@ -179,6 +176,9 @@ importers: socket.io: specifier: ^4.8.1 version: 4.8.1 + typebox: + specifier: ^1.0.59 + version: 1.0.59 devDependencies: '@types/node': specifier: ^22.19.1 @@ -187,11 +187,11 @@ importers: specifier: ^8.1.2 version: 8.1.2(rollup@4.53.3) vite: - specifier: ^7.2.4 - version: 7.2.4(@types/node@22.19.1)(yaml@2.8.1) + specifier: ^7.2.6 + version: 7.2.6(@types/node@22.19.1)(yaml@2.8.2) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.19.1)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.3)(vite@7.2.6(@types/node@22.19.1)(yaml@2.8.2)) icons: dependencies: @@ -205,8 +205,8 @@ importers: specifier: ^9.3.0 version: 9.3.0 '@fastify/sensible': - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^6.0.4 + version: 6.0.4 '@fastify/static': specifier: ^8.3.0 version: 8.3.0 @@ -233,11 +233,11 @@ importers: specifier: ^8.1.2 version: 8.1.2(rollup@4.53.3) vite: - specifier: ^7.2.4 - version: 7.2.4(@types/node@22.19.1)(yaml@2.8.1) + specifier: ^7.2.6 + version: 7.2.6(@types/node@22.19.1)(yaml@2.8.2) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.19.1)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.3)(vite@7.2.6(@types/node@22.19.1)(yaml@2.8.2)) user: dependencies: @@ -251,8 +251,8 @@ importers: specifier: ^9.3.0 version: 9.3.0 '@fastify/sensible': - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^6.0.4 + version: 6.0.4 '@fastify/static': specifier: ^8.3.0 version: 8.3.0 @@ -266,8 +266,8 @@ importers: specifier: ^5.1.0 version: 5.1.0 typebox: - specifier: ^1.0.56 - version: 1.0.56 + specifier: ^1.0.59 + version: 1.0.59 devDependencies: '@types/node': specifier: ^22.19.1 @@ -276,11 +276,11 @@ importers: specifier: ^8.1.2 version: 8.1.2(rollup@4.53.3) vite: - specifier: ^7.2.4 - version: 7.2.4(@types/node@22.19.1)(yaml@2.8.1) + specifier: ^7.2.6 + version: 7.2.6(@types/node@22.19.1)(yaml@2.8.2) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.19.1)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.3)(vite@7.2.6(@types/node@22.19.1)(yaml@2.8.2)) packages: @@ -489,8 +489,8 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@9.39.1': @@ -557,8 +557,8 @@ packages: '@fastify/send@4.1.0': resolution: {integrity: sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==} - '@fastify/sensible@6.0.3': - resolution: {integrity: sha512-Iyn8698hp/e5+v8SNBBruTa7UfrMEP52R16dc9jMpqSyEcPsvWFQo+R6WwHCUnJiLIsuci2ZoEZ7ilrSSCPIVg==} + '@fastify/sensible@6.0.4': + resolution: {integrity: sha512-1vxcCUlPMew6WroK8fq+LVOwbsLtX+lmuRuqpcp6eYqu6vmkLwbKTdBWAZwbeaSgCfW4tzUpTIHLLvTiQQ1BwQ==} '@fastify/static@8.3.0': resolution: {integrity: sha512-yKxviR5PH1OKNnisIzZKmgZSus0r2OZb8qCSbqmw34aolT4g3UlzYfeBRym+HJ1J471CR8e2ldNub4PubD1coA==} @@ -940,14 +940,11 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@redocly/ajv@8.11.4': - resolution: {integrity: sha512-77MhyFgZ1zGMwtCpqsk532SJEc3IJmSOXKTCeWoMTAvPnQOkuOgxEip1n5pG5YX1IzCTJ4kCvPKr8xYyzWFdhg==} - '@redocly/ajv@8.17.1': resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==} - '@redocly/cli@2.12.0': - resolution: {integrity: sha512-/q8RnBe+Duo+XYFCG8LnaD0kroGZ8MoS6575Xq59tCgjaCL16F+pZZ75xNBU2oXfEypJClNz/6ilc2G0q1+tlw==} + '@redocly/cli@2.12.1': + resolution: {integrity: sha512-XGD28QjjZEzN+J9WOROzw4fHNi+Fyw/gCyDZDgI4nX4j9gEBT1PcxN75wWpMoDGHKAUj8ghrhMHtfQoUuR90zg==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} hasBin: true @@ -961,12 +958,12 @@ packages: resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@redocly/openapi-core@2.12.0': - resolution: {integrity: sha512-RsVwmRD0KhyJbR8acIeU98ce6N+/YCuLJf6IGN+2SOsbwnDhnI5MG0TFV9D7URK/ukEewaNA701dVYsoP1VtRQ==} + '@redocly/openapi-core@2.12.1': + resolution: {integrity: sha512-xMlKf4dnZsxP3JYBNZFsMNBJqVxWlwLuyGLhGc36hXw50YOla1UjrVZ5psIyzLXgUPI3QJDA1XmGcJ8rcex/ow==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} - '@redocly/respect-core@2.12.0': - resolution: {integrity: sha512-mrYrfE81shSRS96ygXaRiSithV4Fe4Y7XlSYLSTfM8Lo3YAz7Geirg7HZ5fNFsI+hdW05ZuQewqpKL8XLwaAeA==} + '@redocly/respect-core@2.12.1': + resolution: {integrity: sha512-ADm+JMHWGYeOwzdGEQ8CYKjmMBLU0ycZTwJbCkQsUulXSNkNA7GzA8lrMM2+I8cPMRk25G5PmtfAR7U+a0o1ew==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} '@rollup/rollup-android-arm-eabi@4.53.3': @@ -1079,9 +1076,6 @@ packages: cpu: [x64] os: [win32] - '@sinclair/typebox@0.34.41': - resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} - '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -1209,14 +1203,6 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -1479,6 +1465,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -1726,8 +1716,8 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - fast-copy@3.0.2: - resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + fast-copy@4.0.0: + resolution: {integrity: sha512-/oA0gx1xyXE9R2YlV4FXwZJXngFdm9Du0zN8FhY38jnLkhp1u35h6bCyKgRhlsA6C9I+1vfXE4KISdt7xc6M9w==} fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} @@ -2019,8 +2009,8 @@ packages: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} - ipaddr.js@2.2.0: - resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + ipaddr.js@2.3.0: + resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} engines: {node: '>= 10'} is-binary-path@2.1.0: @@ -2187,8 +2177,8 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@11.2.2: - resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} engines: {node: 20 || >=22} lru-cache@7.18.3: @@ -2213,9 +2203,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} @@ -2225,10 +2215,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -2521,8 +2519,11 @@ packages: pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} - pino-pretty@13.1.2: - resolution: {integrity: sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-pretty@13.1.3: + resolution: {integrity: sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==} hasBin: true pino-std-serializers@7.0.0: @@ -3021,12 +3022,12 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} - typebox@1.0.56: - resolution: {integrity: sha512-KMd1DJnIRqLUzAicpFmGqgmt+/IePCEmT/Jtywyyyn0hK6+dupQnxm7OAIn/cL/vu22jKi1XvDjDhrpatZ46kA==} + typebox@1.0.59: + resolution: {integrity: sha512-D8pTcn4yPzUb34OWFyPVITP1fMZjJXV5n7tT5ss/BxHSnzfuMK4rQEFunpk1UOwq9lMCOed2BJ3GXGoIBKl7Rw==} typescript-eslint@8.48.0: resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} @@ -3071,9 +3072,6 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - uri-js-replace@1.0.1: - resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -3088,8 +3086,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuidv7@1.0.2: - resolution: {integrity: sha512-8JQkH4ooXnm1JCIhqTMbtmdnYEn6oKukBxHn1Ic9878jMkL7daTI7anTExfY18VRCX7tcdn5quzvCb6EWrR8PA==} + uuidv7@1.1.0: + resolution: {integrity: sha512-2VNnOC0+XQlwogChUDzy6pe8GQEys9QFZBGOh54l6qVfwoCUwwRvk7rDTgaIsRgsF5GFa5oiNg8LqXE3jofBBg==} hasBin: true vary@1.1.2: @@ -3104,8 +3102,8 @@ packages: vite: optional: true - vite@7.2.4: - resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + vite@7.2.6: + resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -3238,8 +3236,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.8.1: - resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} hasBin: true @@ -3395,7 +3393,7 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.1': + '@eslint/eslintrc@3.3.3': dependencies: ajv: 6.12.6 debug: 4.4.3(supports-color@10.2.2) @@ -3477,7 +3475,7 @@ snapshots: '@fastify/proxy-addr@5.1.0': dependencies: '@fastify/forwarded': 3.0.1 - ipaddr.js: 2.2.0 + ipaddr.js: 2.3.0 '@fastify/send@4.1.0': dependencies: @@ -3487,14 +3485,14 @@ snapshots: http-errors: 2.0.1 mime: 3.0.0 - '@fastify/sensible@6.0.3': + '@fastify/sensible@6.0.4': dependencies: '@lukeed/ms': 2.0.2 dequal: 2.0.3 fastify-plugin: 5.1.0 forwarded: 0.2.0 http-errors: 2.0.1 - type-is: 1.6.18 + type-is: 2.0.1 vary: 1.1.2 '@fastify/static@8.3.0': @@ -3512,7 +3510,7 @@ snapshots: fastify-plugin: 5.1.0 openapi-types: 12.1.3 rfdc: 1.4.1 - yaml: 2.8.1 + yaml: 2.8.2 '@fastify/swagger@9.6.1': dependencies: @@ -3520,7 +3518,7 @@ snapshots: json-schema-resolver: 3.0.0 openapi-types: 12.1.3 rfdc: 1.4.1 - yaml: 2.8.1 + yaml: 2.8.2 transitivePeerDependencies: - supports-color @@ -3859,13 +3857,6 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@redocly/ajv@8.11.4': - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js-replace: 1.0.1 - '@redocly/ajv@8.17.1': dependencies: fast-deep-equal: 3.1.3 @@ -3873,14 +3864,14 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - '@redocly/cli@2.12.0(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)': + '@redocly/cli@2.12.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)': dependencies: '@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.34.0 - '@redocly/openapi-core': 2.12.0(ajv@8.17.1) - '@redocly/respect-core': 2.12.0(ajv@8.17.1) + '@redocly/openapi-core': 2.12.1(ajv@8.17.1) + '@redocly/respect-core': 2.12.1(ajv@8.17.1) abort-controller: 3.0.0 chokidar: 3.6.0 colorette: 1.4.0 @@ -3931,11 +3922,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@redocly/openapi-core@2.12.0(ajv@8.17.1)': + '@redocly/openapi-core@2.12.1(ajv@8.17.1)': dependencies: '@redocly/ajv': 8.17.1 '@redocly/config': 0.40.0 - ajv-formats: 2.1.1(ajv@8.17.1) + ajv-formats: 3.0.1(ajv@8.17.1) colorette: 1.4.0 js-levenshtein: 1.1.6 js-yaml: 4.1.1 @@ -3945,12 +3936,12 @@ snapshots: transitivePeerDependencies: - ajv - '@redocly/respect-core@2.12.0(ajv@8.17.1)': + '@redocly/respect-core@2.12.1(ajv@8.17.1)': dependencies: '@faker-js/faker': 7.6.0 '@noble/hashes': 1.8.0 - '@redocly/ajv': 8.11.4 - '@redocly/openapi-core': 2.12.0(ajv@8.17.1) + '@redocly/ajv': 8.17.1 + '@redocly/openapi-core': 2.12.1(ajv@8.17.1) better-ajv-errors: 1.2.0(ajv@8.17.1) colorette: 2.0.20 json-pointer: 0.6.2 @@ -4026,8 +4017,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.53.3': optional: true - '@sinclair/typebox@0.34.41': {} - '@socket.io/component-emitter@3.1.2': {} '@standard-schema/spec@1.0.0': {} @@ -4184,10 +4173,6 @@ snapshots: agent-base@7.1.4: {} - ajv-formats@2.1.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -4446,6 +4431,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-type@1.0.5: {} + cookie@0.7.2: {} cookie@1.1.1: {} @@ -4656,7 +4643,7 @@ snapshots: '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.1 + '@eslint/eslintrc': 3.3.3 '@eslint/js': 9.39.1 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 @@ -4714,7 +4701,7 @@ snapshots: expand-template@2.0.3: {} - fast-copy@3.0.2: {} + fast-copy@4.0.0: {} fast-decode-uri-component@1.0.1: {} @@ -4769,7 +4756,7 @@ snapshots: generify: 4.2.0 help-me: 5.0.0 is-docker: 2.2.1 - pino-pretty: 13.1.2 + pino-pretty: 13.1.3 pkg-up: 3.1.0 resolve-from: 5.0.0 semver: 7.7.3 @@ -5058,7 +5045,7 @@ snapshots: ip-address@10.1.0: {} - ipaddr.js@2.2.0: {} + ipaddr.js@2.3.0: {} is-binary-path@2.1.0: dependencies: @@ -5179,7 +5166,7 @@ snapshots: nano-spawn: 2.0.0 pidtree: 0.6.0 string-argv: 0.3.2 - yaml: 2.8.1 + yaml: 2.8.2 listr2@9.0.5: dependencies: @@ -5224,7 +5211,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@11.2.2: {} + lru-cache@11.2.4: {} lru-cache@7.18.3: {} @@ -5240,7 +5227,7 @@ snapshots: math-intrinsics@1.1.0: {} - media-typer@0.3.0: {} + media-typer@1.1.0: {} micromatch@4.0.8: dependencies: @@ -5249,10 +5236,16 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@3.0.0: {} mimic-fn@2.1.0: {} @@ -5501,7 +5494,7 @@ snapshots: path-scurry@2.0.1: dependencies: - lru-cache: 11.2.2 + lru-cache: 11.2.4 minipass: 7.1.2 path-to-regexp@8.3.0: {} @@ -5520,17 +5513,21 @@ snapshots: dependencies: split2: 4.2.0 - pino-pretty@13.1.2: + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.1.3: dependencies: colorette: 2.0.20 dateformat: 4.6.3 - fast-copy: 3.0.2 + fast-copy: 4.0.0 fast-safe-stringify: 2.1.1 help-me: 5.0.0 joycon: 3.1.1 minimist: 1.2.8 on-exit-leak-free: 2.1.2 - pino-abstract-transport: 2.0.0 + pino-abstract-transport: 3.0.0 pump: 3.0.3 secure-json-parse: 4.1.0 sonic-boom: 4.2.0 @@ -6151,12 +6148,13 @@ snapshots: type-fest@4.41.0: {} - type-is@1.6.18: + type-is@2.0.1: dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 - typebox@1.0.56: {} + typebox@1.0.59: {} typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.9.3): dependencies: @@ -6190,8 +6188,6 @@ snapshots: unpipe@1.0.0: {} - uri-js-replace@1.0.1: {} - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -6204,22 +6200,22 @@ snapshots: util-deprecate@1.0.2: {} - uuidv7@1.0.2: {} + uuidv7@1.1.0: {} vary@1.1.2: {} - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@22.19.1)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.6(@types/node@22.19.1)(yaml@2.8.2)): dependencies: debug: 4.4.3(supports-color@10.2.2) globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 7.2.4(@types/node@22.19.1)(yaml@2.8.1) + vite: 7.2.6(@types/node@22.19.1)(yaml@2.8.2) transitivePeerDependencies: - supports-color - typescript - vite@7.2.4(@types/node@22.19.1)(yaml@2.8.1): + vite@7.2.6(@types/node@22.19.1)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -6230,9 +6226,9 @@ snapshots: optionalDependencies: '@types/node': 22.19.1 fsevents: 2.3.3 - yaml: 2.8.1 + yaml: 2.8.2 - vite@7.2.4(@types/node@24.10.1)(yaml@2.8.1): + vite@7.2.6(@types/node@24.10.1)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -6243,7 +6239,7 @@ snapshots: optionalDependencies: '@types/node': 24.10.1 fsevents: 2.3.3 - yaml: 2.8.1 + yaml: 2.8.2 walker@1.0.8: dependencies: @@ -6308,7 +6304,7 @@ snapshots: yaml@1.10.2: {} - yaml@2.8.1: {} + yaml@2.8.2: {} yargs-parser@20.2.9: {} diff --git a/src/user/package.json b/src/user/package.json index 9efe221..896e36c 100644 --- a/src/user/package.json +++ b/src/user/package.json @@ -21,17 +21,17 @@ "@fastify/autoload": "^6.3.1", "@fastify/formbody": "^8.0.2", "@fastify/multipart": "^9.3.0", - "@fastify/sensible": "^6.0.3", + "@fastify/sensible": "^6.0.4", "@fastify/static": "^8.3.0", "fastify": "^5.6.2", "fastify-cli": "^7.4.1", "fastify-plugin": "^5.1.0", - "typebox": "^1.0.56" + "typebox": "^1.0.59" }, "devDependencies": { "@types/node": "^22.19.1", "rollup-plugin-node-externals": "^8.1.2", - "vite": "^7.2.4", + "vite": "^7.2.6", "vite-tsconfig-paths": "^5.1.4" } } From 05130e5b8a7e994efd6f64662ed2aba442782b74 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Tue, 2 Dec 2025 12:43:57 +0100 Subject: [PATCH 18/22] Trying to fix BUG with / when guest changes name without closing the window --- frontend/src/pages/chat/chat.ts | 49 +++++++++++++++++---------------- src/chat/src/app.ts | 20 ++++++++------ 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index f03088e..cff6c80 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -49,11 +49,12 @@ async function isLoggedIn() { async function windowStateHidden() { const socketId = __socket || undefined; - let oldName = localStorage.getItem("oldName") || undefined; - if (socketId == undefined) return; + // let oldName = localStorage.getItem("oldName") ?? undefined; + let oldName: string; + if (socketId === undefined) return; let userName = await updateUser(); - oldName = userName?.name || undefined; - if (oldName === undefined) return; + oldName = userName?.name ?? ""; + if (oldName === "") return; localStorage.setItem('oldName', oldName); socketId.emit('client_left', { user: userName?.name, @@ -66,11 +67,12 @@ async function windowStateHidden() { async function windowStateVisable() { const socketId = __socket || undefined; let oldName = localStorage.getItem("oldName") || undefined; - console.log("%coldName :'" + oldName + "'", color.green); + console.log("%c WINDOW VISIBLE - oldName :'" + oldName + "'", color.green); if (socketId === undefined || oldName === undefined) {console.log("%SOCKET ID", color.red); return;} - const res = await client.guestLogin(); + // const res = await client.guestLogin(); let user = await updateUser(); + if(user === null) return; console.log("%cUserName :'" + user?.name + "'", color.green); socketId.emit('client_entered', { userName: oldName, @@ -184,21 +186,21 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn let toggle = false window.addEventListener("focus", () => { - if (window.location.pathname === "" && !toggle) { - // bconnected.click(); - console.log("%cWindow is focused on /chat:" + socket.id, color.green); - if (socket.id) - windowStateVisable(); - toggle = true; + const bwhoami = document.getElementById('b-whoami') as HTMLButtonElement; + if (window.location.pathname === '/app/chat') { + console.log("%cWindow is focused on /chat:" + socket.id, color.green); + if (socket.id) + windowStateVisable(); + bwhoami.click(); + toggle = true; } }); window.addEventListener("blur", () => { - //bconnected.click(); console.log("%cWindow is not focused on /chat", color.red); if (socket.id) windowStateHidden(); - toggle = false; + toggle = false; }); setTitle('Chat Page'); @@ -303,20 +305,23 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn bconnected?.addEventListener("click", async () => { const loggedIn = await isLoggedIn(); - let oldUser = localStorage.getItem("oldName") || undefined; - if (loggedIn?.name === undefined) return ; + console.log('%cloggedIn:',color.blue, loggedIn?.name); + let oldUser = localStorage.getItem("oldName") ?? ""; + console.log('%coldUser:',color.yellow, oldUser); + if (loggedIn?.name === undefined) {console.log('');return ;} oldUser = loggedIn.name || "undefined"; const res = await client.guestLogin(); let user = await updateUser(); + console.log('%User?name:',color.yellow, user?.name); localStorage.setItem("oldName", oldUser); buddies.textContent = ""; - if (chatWindow) { + // if (chatWindow) { // addMessage('@list - lists all connected users in the chat'); socket.emit('list', { oldUser: oldUser, user: user?.name, }); - } + // } }); @@ -337,18 +342,16 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn bwhoami?.addEventListener('click', async () => { try { const loggedIn = await isLoggedIn(); - let oldUser = localStorage.getItem("oldName") || undefined; - oldUser = loggedIn?.name || "undefined"; - localStorage.setItem("oldName", oldUser); const res = await client.guestLogin(); switch (res.kind) { case 'success': { let user = await updateUser(); - console.log('USER ', user?.name); + console.log('%cUSER_NAME ',color.yellow, user?.name); + console.log('%cGET_user ',color.yellow, getUser()?.name || null); if (chatWindow) { socket.emit('updateClientName', { - oldUser: oldUser, + oldUser: '', user: user?.name }); } diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index e426758..f5082b4 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -237,10 +237,10 @@ function broadcast(data: ClientMessage, sender?: string) { if (userFromFrontend.oldUser !== userFromFrontend.user) { console.log(color.red, 'list activated', userFromFrontend.oldUser, color.reset); - if (client?.user === null) { - console.log('ERROR: clientName is NULL'); - return; - }; + // if (client?.user === null) { + // console.log('ERROR: clientName is NULL'); + // return; + // }; if (client) { client.user = userFromFrontend.user; } @@ -254,12 +254,14 @@ function broadcast(data: ClientMessage, sender?: string) { console.log(color.red, 'whoAMi activated', userFromFrontend, color.reset, socket.id); if (userFromFrontend.oldUser !== userFromFrontend.user) { console.log(color.red, 'whoAMi activated', userFromFrontend.oldUser, color.reset); - if (client === null) { - console.log('ERROR: clientName is NULL'); - return; - }; + // if (client === null) { + // console.log('ERROR: clientName is NULL'); + // return; + // }; if (client) { client.user = userFromFrontend.user; + console.log(color.green, 'client.user is: ', client.user); + } } }); @@ -328,7 +330,7 @@ function broadcast(data: ClientMessage, sender?: string) { timestamp: Date.now(), SenderWindowID: socket.id, }; - console.log(obj.SenderWindowID); + console.log(color.blue, 'BROADCASTS OUT :',obj.SenderWindowID); broadcast(obj, obj.SenderWindowID); // clientChat.delete(obj.user); } From c086c27c4af3c7e344679c45ee494b10b4c25f98 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Tue, 2 Dec 2025 16:52:41 +0100 Subject: [PATCH 19/22] chat general broadcast done with now notifications system separated in different space on the chat windo --- frontend/src/@types/dom.d.ts | 2 ++ frontend/src/chat/chat.css | 28 ++++++++++++++-- frontend/src/pages/chat/chat.html | 10 +++--- frontend/src/pages/chat/chat.ts | 53 ++++++++++++++++++++----------- src/chat/src/app.ts | 18 +++++++---- src/chat/src/routes/nginx-chat.ts | 48 ---------------------------- 6 files changed, 81 insertions(+), 78 deletions(-) diff --git a/frontend/src/@types/dom.d.ts b/frontend/src/@types/dom.d.ts index 5cbf23c..1c35dd9 100644 --- a/frontend/src/@types/dom.d.ts +++ b/frontend/src/@types/dom.d.ts @@ -9,4 +9,6 @@ declare global { dispatchEvent(ev: CustomEventMap[K]): void; } } + + export { }; //keep that for TS compiler. diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index 95c2bb5..eb43dce 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -40,7 +40,6 @@ active:shadow-[0_2px_0_0_black];; } - .chatbox-style { @apply w-[650px] @@ -60,12 +59,37 @@ mx-auto; } +.system-info { + @apply + h-[40px] + bg-gray-200 + text-gray-700 + p-3 + rounded-3xl + mb-2 border + border-gray-200 + text-center + shadow + overflow-y-auto + justify-end /* 👈 forces text to bottom */ + relative; /* needed for overlay */ +} + + +.text-info { + @apply + text-blue-800 + +} + + .chat-window-style { @apply w-[400px] h-[50px] p-[10px] - border-1 border-black + border-1 + border-black shadow-sm flex-1 rounded-3xl diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html index e6d9e92..2882ae5 100644 --- a/frontend/src/pages/chat/chat.html +++ b/frontend/src/pages/chat/chat.html @@ -7,9 +7,10 @@ - - + +
System: connecting ...
+
@@ -20,7 +21,6 @@
-

Ping Buddies

@@ -34,7 +34,9 @@
-

From this Chat Box you can send messages to other players

+ + + diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index cff6c80..26dd177 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -4,17 +4,22 @@ import authHtml from './chat.html?raw'; import client from '@app/api' import { getUser, updateUser } from "@app/auth"; import io, { Socket } from 'socket.io-client'; +// import type { ClientMessage } from "@app/@types/dom"; const color = { - red: 'color: red; font-weight: bold;', - green: 'color: green; font-weight: bold;', - yellow: 'color: orange; font-weight: bold;', - blue: 'color: blue; font-weight: bold;', + red: 'color: red;', + green: 'color: green;', + yellow: 'color: orange;', + blue: 'color: blue;', reset: '', }; - - +export type ClientMessage = { + destination: string; + user: string; + text: string; + SenderWindowID: string; +}; // get the name of the machine used to connect @@ -143,26 +148,39 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn }); // Listen for messages from the server "MsgObjectServer" - socket.on("MsgObjectServer", (data: any) => { - console.log("Message Obj Recieved:", data.message); - console.log("Recieved data.message.text: ", data.message.text); - console.log("Recieved data.message.user: ", data.message.user); - console.log("Recieved data.message.type: ", data.message.type); - console.log("Recieved data.message.token: ", data.message.token); - console.log("Recieved data.message.timestamp: ", data.message.timestamp); + socket.on("MsgObjectServer", (data: { message: ClientMessage}) => { + console.log("Message Obj Recieved:", data); + console.log("%cRecieved data.message.text: ", color.blue, data.message.text); + console.log("%cRecieved data.message.user: ", color.blue, data.message.user); // Display the message in the chat window + const systemWindow = document.getElementById('system-box') as HTMLDivElement; const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement; const bconnected = document.getElementById('b-help') as HTMLButtonElement; if (bconnected) { bconnected.click(); } - if (chatWindow) { + if (chatWindow && data.message.destination === "") { const messageElement = document.createElement("div"); messageElement.textContent = `${data.message.user}: ${data.message.text}`; chatWindow.appendChild(messageElement); chatWindow.scrollTop = chatWindow.scrollHeight; } + const MAX_SYSTEM_MESSAGES = 10; + + if (systemWindow && data.message.destination === "system-info") { + const messageElement = document.createElement("div"); + messageElement.textContent = `${data.message.user}: ${data.message.text}`; + systemWindow.appendChild(messageElement); + + // keep only last 10 + while (systemWindow.children.length > MAX_SYSTEM_MESSAGES) { + systemWindow.removeChild(systemWindow.firstChild!); + } + + systemWindow.scrollTop = systemWindow.scrollHeight; + } + console.log("Getuser():", getUser()); }); @@ -261,6 +279,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn const user = getUser(); if (user && socket?.connected) { const message = { + destination: "", type: "chat", user: user.name, token: document.cookie, @@ -298,7 +317,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn setInterval(async () => { - bconnected.click(); + //bconnected.click(); }, 10000); // every 10 second // Help Text button @@ -312,7 +331,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn oldUser = loggedIn.name || "undefined"; const res = await client.guestLogin(); let user = await updateUser(); - console.log('%User?name:',color.yellow, user?.name); + console.log('%cUser?name:',color.yellow, user?.name); localStorage.setItem("oldName", oldUser); buddies.textContent = ""; // if (chatWindow) { @@ -347,8 +366,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn switch (res.kind) { case 'success': { let user = await updateUser(); - console.log('%cUSER_NAME ',color.yellow, user?.name); - console.log('%cGET_user ',color.yellow, getUser()?.name || null); if (chatWindow) { socket.emit('updateClientName', { oldUser: '', diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index f5082b4..933048b 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -32,6 +32,13 @@ interface ClientInfo { lastSeen: number; } +export type ClientMessage = { + destination: string; + user: string; + text: string; + SenderWindowID: string; +}; + const clientChat = new Map(); // @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this... @@ -69,18 +76,13 @@ export default app; export { app }; -type ClientMessage = { - user: string; - text: string; - SenderWindowID: string; -}; // When using .decorate you have to specify added properties for Typescript declare module 'fastify' { interface FastifyInstance { io: Server<{ hello: (message: string) => string; - MsgObjectServer: (data: { message: ClientMessage }) => void; + MsgObjectServer: (data: { message: ClientMessage } ) => void; message: (msg: string) => void; listBud: (msg: string) => void; testend: (sock_id_client: string) => void; @@ -273,6 +275,7 @@ function broadcast(data: ClientMessage, sender?: string) { if (!clientName) return; console.log(color.green, `Client logging out: ${clientName} (${socket.id})`); const obj = { + destination: "system-info", type: "chat" as const, user: clientName, token: "", @@ -300,6 +303,7 @@ function broadcast(data: ClientMessage, sender?: string) { if (clientName !== null) { const obj = { + destination: "system-info", type: 'chat', user: clientName, token: '', @@ -323,6 +327,7 @@ function broadcast(data: ClientMessage, sender?: string) { if (clientName !== null) { const obj = { + destination: "system-info", type: 'chat', user: clientName, token: '', @@ -367,6 +372,7 @@ function broadcast(data: ClientMessage, sender?: string) { ); if (clientName !== null) { const obj = { + destination: "system-info", type: 'chat', user: clientName, frontendUserName: userNameFromFrontend, diff --git a/src/chat/src/routes/nginx-chat.ts b/src/chat/src/routes/nginx-chat.ts index e6dd4df..99dc7a6 100644 --- a/src/chat/src/routes/nginx-chat.ts +++ b/src/chat/src/routes/nginx-chat.ts @@ -34,54 +34,6 @@ export const ChatRes = { export type ChatResType = MakeStaticResponse; -function connectedUser(io: Server | undefined, targetSocketId?: string): number { - let count = 0; - - // Track unique usernames (avoid duplicates) - const seenUsers = new Set(); - - for (const [socketId, info] of clientChat) { - - // Validate entry - if (!info || typeof info.user !== "string" || info.user.trim() === "") { - clientChat.delete(socketId); - continue; - } - - const username = info.user; - - // Validate socket exists if io is passed - if (io) { - const socket = io.sockets.sockets.get(socketId); - - // Remove disconnected sockets - if (!socket || socket.disconnected) { - clientChat.delete(socketId); - continue; - } - } - - // Skip duplicates - if (seenUsers.has(username)) - continue; - - seenUsers.add(username); - count++; - - // Send to target only - if (io && targetSocketId) { - io.to(targetSocketId).emit("listBud", username); - } - - console.log(color.yellow, "Client:", color.reset, username); - console.log(color.yellow, "Socket ID:", color.reset, socketId); - } - - return count; -} - - - const route: FastifyPluginAsync = async (fastify): Promise => { fastify.get( From ace8367f7758ed57dba6707d7ee76e572521f17f Mon Sep 17 00:00:00 2001 From: NigeParis Date: Tue, 2 Dec 2025 17:11:50 +0100 Subject: [PATCH 20/22] added eslint norme to code --- src/@shared/package.json | 2 +- src/@shared/src/database/mixin/blocked.ts | 4 +- src/auth/package.json | 2 +- src/chat/package.json | 2 +- src/chat/src/app.ts | 75 +++++----- src/chat/src/routes/nginx-chat.ts | 34 ++--- src/package.json | 6 +- src/pnpm-lock.yaml | 158 +++++++++++----------- src/user/package.json | 2 +- 9 files changed, 128 insertions(+), 157 deletions(-) diff --git a/src/@shared/package.json b/src/@shared/package.json index 15f2935..d563f63 100644 --- a/src/@shared/package.json +++ b/src/@shared/package.json @@ -20,7 +20,7 @@ "fastify-plugin": "^5.1.0", "joi": "^18.0.2", "otp": "^1.1.2", - "typebox": "^1.0.59", + "typebox": "^1.0.61", "uuidv7": "^1.1.0" }, "devDependencies": { diff --git a/src/@shared/src/database/mixin/blocked.ts b/src/@shared/src/database/mixin/blocked.ts index 13db21d..a6b0a28 100644 --- a/src/@shared/src/database/mixin/blocked.ts +++ b/src/@shared/src/database/mixin/blocked.ts @@ -30,11 +30,10 @@ export const BlockedImpl: Omit = { this.prepare('DELETE FROM blocked WHERE user = @id AND blocked = @blocked').run({ id, blocked }); }, - /** * Get all blocked user * - * @param + * @param * * @returns The list of users if it exists, undefined otherwise */ @@ -64,7 +63,6 @@ export type BlockedData = { * @returns The blocked if it exists, undefined otherwise */ export function blockedFromRow(row?: Partial): BlockedData | undefined { - console.log('HELLO ?????', row); if (isNullish(row)) return undefined; if (isNullish(row.id)) return undefined; if (isNullish(row.user)) return undefined; diff --git a/src/auth/package.json b/src/auth/package.json index 9c9dd49..81d3afe 100644 --- a/src/auth/package.json +++ b/src/auth/package.json @@ -27,7 +27,7 @@ "fastify": "^5.6.2", "fastify-cli": "^7.4.1", "fastify-plugin": "^5.1.0", - "typebox": "^1.0.59" + "typebox": "^1.0.61" }, "devDependencies": { "@types/node": "^22.19.1", diff --git a/src/chat/package.json b/src/chat/package.json index 56396ad..1e61398 100644 --- a/src/chat/package.json +++ b/src/chat/package.json @@ -27,7 +27,7 @@ "fastify": "^5.6.2", "fastify-plugin": "^5.1.0", "socket.io": "^4.8.1", - "typebox": "^1.0.59" + "typebox": "^1.0.61" }, "devDependencies": { "@types/node": "^22.19.1", diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 933048b..5d30955 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -75,14 +75,12 @@ const app: FastifyPluginAsync = async (fastify, opts): Promise => { export default app; export { app }; - - // When using .decorate you have to specify added properties for Typescript declare module 'fastify' { interface FastifyInstance { io: Server<{ hello: (message: string) => string; - MsgObjectServer: (data: { message: ClientMessage } ) => void; + MsgObjectServer: (data: { message: ClientMessage }) => void; message: (msg: string) => void; listBud: (msg: string) => void; testend: (sock_id_client: string) => void; @@ -161,32 +159,27 @@ async function onReady(fastify: FastifyInstance) { return count; } -function broadcast(data: ClientMessage, sender?: string) { - fastify.io.fetchSockets().then((sockets) => { - for (const s of sockets) { - - // Skip sender's own socket - if (s.id === sender) continue; - - // Get client name from map - const clientInfo = clientChat.get(s.id); - - if (!clientInfo?.user) { - console.log(color.yellow, `Skipping socket ${s.id} (no user found)`); - continue; + function broadcast(data: ClientMessage, sender?: string) { + fastify.io.fetchSockets().then((sockets) => { + for (const s of sockets) { + // Skip sender's own socket + if (s.id === sender) continue; + // Get client name from map + const clientInfo = clientChat.get(s.id); + if (!clientInfo?.user) { + console.log(color.yellow, `Skipping socket ${s.id} (no user found)`); + continue; + } + // Emit structured JSON object + s.emit('MsgObjectServer', { message: data }); + // Debug logs + console.log(color.green, 'Broadcast to:', clientInfo.user); + console.log(' Target socket ID:', s.id); + console.log(' Target rooms:', [...s.rooms]); + console.log(' Sender socket ID:', sender ?? 'none'); } - - // Emit structured JSON object - s.emit("MsgObjectServer", { message: data }); - - // Debug logs - console.log(color.green, "Broadcast to:", clientInfo.user); - console.log(" Target socket ID:", s.id); - console.log(" Target rooms:", [...s.rooms]); - console.log(" Sender socket ID:", sender ?? "none"); - } - }); -} + }); + } fastify.io.on('connection', (socket: Socket) => { @@ -239,7 +232,7 @@ function broadcast(data: ClientMessage, sender?: string) { if (userFromFrontend.oldUser !== userFromFrontend.user) { console.log(color.red, 'list activated', userFromFrontend.oldUser, color.reset); - // if (client?.user === null) { + // if (client?.user === null) { // console.log('ERROR: clientName is NULL'); // return; // }; @@ -268,18 +261,18 @@ function broadcast(data: ClientMessage, sender?: string) { } }); - socket.on("logout", () => { + socket.on('logout', () => { const clientInfo = clientChat.get(socket.id); const clientName = clientInfo?.user; - + if (!clientName) return; console.log(color.green, `Client logging out: ${clientName} (${socket.id})`); const obj = { - destination: "system-info", - type: "chat" as const, + destination: 'system-info', + type: 'chat' as const, user: clientName, - token: "", - text: "LEFT the chat", + token: '', + text: 'LEFT the chat', timestamp: Date.now(), SenderWindowID: socket.id, }; @@ -287,11 +280,9 @@ function broadcast(data: ClientMessage, sender?: string) { // Optional: remove from map clientChat.delete(socket.id); // Ensure socket is fully disconnected - if (socket.connected) socket.disconnect(true); + if (socket.connected) socket.disconnect(true); }); - - socket.on('disconnecting', (reason) => { const clientName = clientChat.get(socket.id)?.user || null; console.log( @@ -303,7 +294,7 @@ function broadcast(data: ClientMessage, sender?: string) { if (clientName !== null) { const obj = { - destination: "system-info", + destination: 'system-info', type: 'chat', user: clientName, token: '', @@ -327,7 +318,7 @@ function broadcast(data: ClientMessage, sender?: string) { if (clientName !== null) { const obj = { - destination: "system-info", + destination: 'system-info', type: 'chat', user: clientName, token: '', @@ -335,7 +326,7 @@ function broadcast(data: ClientMessage, sender?: string) { timestamp: Date.now(), SenderWindowID: socket.id, }; - console.log(color.blue, 'BROADCASTS OUT :',obj.SenderWindowID); + console.log(color.blue, 'BROADCASTS OUT :', obj.SenderWindowID); broadcast(obj, obj.SenderWindowID); // clientChat.delete(obj.user); } @@ -372,7 +363,7 @@ function broadcast(data: ClientMessage, sender?: string) { ); if (clientName !== null) { const obj = { - destination: "system-info", + destination: 'system-info', type: 'chat', user: clientName, frontendUserName: userNameFromFrontend, diff --git a/src/chat/src/routes/nginx-chat.ts b/src/chat/src/routes/nginx-chat.ts index 99dc7a6..1ba77c2 100644 --- a/src/chat/src/routes/nginx-chat.ts +++ b/src/chat/src/routes/nginx-chat.ts @@ -1,8 +1,8 @@ import { FastifyPluginAsync } from 'fastify'; import { MakeStaticResponse, typeResponse } from '@shared/utils'; import { Type } from 'typebox'; -import { UserId } from '@shared/database/mixin/user'; -import { Server } from 'socket.io'; +// import { UserId } from '@shared/database/mixin/user'; +// import { Server } from 'socket.io'; // colors for console.log export const color = { @@ -13,16 +13,6 @@ export const color = { reset: '\x1b[0m', }; -// Global map of clients -// key = socket, value = clientname -interface ClientInfo { - user: string; - lastSeen: number; -} - -const clientChat = new Map(); - - export const ChatRes = { 200: typeResponse('success', 'chat.success', { name: Type.String(), @@ -33,8 +23,6 @@ export const ChatRes = { export type ChatResType = MakeStaticResponse; - - const route: FastifyPluginAsync = async (fastify): Promise => { fastify.get( '/api/chat/test', @@ -47,23 +35,17 @@ const route: FastifyPluginAsync = async (fastify): Promise => { }, async (req, res) => { - - - let users = fastify.db.getAllUsers(); - console.log("ALL USERS EVER CONNECTED:", users); - + const users = fastify.db.getAllUsers(); + console.log('ALL USERS EVER CONNECTED:', users); if (!users) return; for (const user of users) { - console.log(color.yellow, "USER:", user.name); + console.log(color.yellow, 'USER:', user.name); } - // const usersBlocked = fastify.db.getAllBlockedUsers(); // console.log(color.red, "ALL BLOCKED USERS:", usersBlocked); - fastify.db.addBlockedUserFor(users[0].id, users[1].id) - let usersBlocked2; - usersBlocked2 = fastify.db.getAllBlockedUsers(); - console.log(color.green, "ALL BLOCKED USERS:", usersBlocked2); - + fastify.db.addBlockedUserFor(users[0].id, users[1].id); + const usersBlocked2 = fastify.db.getAllBlockedUsers(); + console.log(color.green, 'ALL BLOCKED USERS:', usersBlocked2); res.makeResponse(200, 'success', 'CCChat.success', { name: 'name', 'id': req.authUser!.id, guest: false }); }, ); diff --git a/src/package.json b/src/package.json index 4858a48..9fa1e9c 100644 --- a/src/package.json +++ b/src/package.json @@ -24,15 +24,15 @@ "devDependencies": { "@eslint/js": "^9.39.1", "@openapitools/openapi-generator-cli": "^2.25.2", - "@typescript-eslint/eslint-plugin": "^8.48.0", - "@typescript-eslint/parser": "^8.48.0", + "@typescript-eslint/eslint-plugin": "^8.48.1", + "@typescript-eslint/parser": "^8.48.1", "eslint": "^9.39.1", "husky": "^9.1.7", "lint-staged": "^16.2.7", "openapi-generator-cli": "^1.0.0", "openapi-typescript": "^7.10.1", "typescript": "^5.9.3", - "typescript-eslint": "^8.48.0", + "typescript-eslint": "^8.48.1", "vite": "^7.2.6" }, "dependencies": { diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index a7690b6..ad74292 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -22,11 +22,11 @@ importers: specifier: ^2.25.2 version: 2.25.2(@types/node@24.10.1) '@typescript-eslint/eslint-plugin': - specifier: ^8.48.0 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + specifier: ^8.48.1 + version: 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) '@typescript-eslint/parser': - specifier: ^8.48.0 - version: 8.48.0(eslint@9.39.1)(typescript@5.9.3) + specifier: ^8.48.1 + version: 8.48.1(eslint@9.39.1)(typescript@5.9.3) eslint: specifier: ^9.39.1 version: 9.39.1 @@ -46,8 +46,8 @@ importers: specifier: ^5.9.3 version: 5.9.3 typescript-eslint: - specifier: ^8.48.0 - version: 8.48.0(eslint@9.39.1)(typescript@5.9.3) + specifier: ^8.48.1 + version: 8.48.1(eslint@9.39.1)(typescript@5.9.3) vite: specifier: ^7.2.6 version: 7.2.6(@types/node@24.10.1)(yaml@2.8.2) @@ -88,8 +88,8 @@ importers: specifier: ^1.1.2 version: 1.1.2 typebox: - specifier: ^1.0.59 - version: 1.0.59 + specifier: ^1.0.61 + version: 1.0.61 uuidv7: specifier: ^1.1.0 version: 1.1.0 @@ -131,8 +131,8 @@ importers: specifier: ^5.1.0 version: 5.1.0 typebox: - specifier: ^1.0.59 - version: 1.0.59 + specifier: ^1.0.61 + version: 1.0.61 devDependencies: '@types/node': specifier: ^22.19.1 @@ -177,8 +177,8 @@ importers: specifier: ^4.8.1 version: 4.8.1 typebox: - specifier: ^1.0.59 - version: 1.0.59 + specifier: ^1.0.61 + version: 1.0.61 devDependencies: '@types/node': specifier: ^22.19.1 @@ -266,8 +266,8 @@ importers: specifier: ^5.1.0 version: 5.1.0 typebox: - specifier: ^1.0.59 - version: 1.0.59 + specifier: ^1.0.61 + version: 1.0.61 devDependencies: '@types/node': specifier: ^22.19.1 @@ -1119,63 +1119,63 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.48.0': - resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} + '@typescript-eslint/eslint-plugin@8.48.1': + resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.48.0 + '@typescript-eslint/parser': ^8.48.1 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.48.0': - resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} + '@typescript-eslint/parser@8.48.1': + resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.48.0': - resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} + '@typescript-eslint/project-service@8.48.1': + resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.48.0': - resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} + '@typescript-eslint/scope-manager@8.48.1': + resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.48.0': - resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} + '@typescript-eslint/tsconfig-utils@8.48.1': + resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.48.0': - resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} + '@typescript-eslint/type-utils@8.48.1': + resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.48.0': - resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} + '@typescript-eslint/types@8.48.1': + resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.48.0': - resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} + '@typescript-eslint/typescript-estree@8.48.1': + resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.48.0': - resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} + '@typescript-eslint/utils@8.48.1': + resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.48.0': - resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} + '@typescript-eslint/visitor-keys@8.48.1': + resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} abort-controller@3.0.0: @@ -3026,11 +3026,11 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} - typebox@1.0.59: - resolution: {integrity: sha512-D8pTcn4yPzUb34OWFyPVITP1fMZjJXV5n7tT5ss/BxHSnzfuMK4rQEFunpk1UOwq9lMCOed2BJ3GXGoIBKl7Rw==} + typebox@1.0.61: + resolution: {integrity: sha512-5KeeL5QoPBoYm8Z7tGR1Pw9FjWA75MLhVuiSMCRgtgTg/d2+kTvolFddhOUua9FxpIaqXznFPZcc3sl6cEpafw==} - typescript-eslint@8.48.0: - resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} + typescript-eslint@8.48.1: + resolution: {integrity: sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -4062,14 +4062,14 @@ snapshots: '@types/trusted-types@2.0.7': optional: true - '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.1 + '@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.1 eslint: 9.39.1 graphemer: 1.4.0 ignore: 7.0.5 @@ -4079,41 +4079,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/scope-manager': 8.48.1 + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.1 debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) + '@typescript-eslint/types': 8.48.1 debug: 4.4.3(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.48.0': + '@typescript-eslint/scope-manager@8.48.1': dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/visitor-keys': 8.48.1 - '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.1 ts-api-utils: 2.1.0(typescript@5.9.3) @@ -4121,14 +4121,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.48.0': {} + '@typescript-eslint/types@8.48.1': {} - '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/visitor-keys': 8.48.1 debug: 4.4.3(supports-color@10.2.2) minimatch: 9.0.5 semver: 7.7.3 @@ -4138,20 +4138,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.1 + '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.48.0': + '@typescript-eslint/visitor-keys@8.48.1': dependencies: - '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/types': 8.48.1 eslint-visitor-keys: 4.2.1 abort-controller@3.0.0: @@ -6154,14 +6154,14 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.2 - typebox@1.0.59: {} + typebox@1.0.61: {} - typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.9.3): + typescript-eslint@8.48.1(eslint@9.39.1)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: diff --git a/src/user/package.json b/src/user/package.json index 896e36c..6dfb965 100644 --- a/src/user/package.json +++ b/src/user/package.json @@ -26,7 +26,7 @@ "fastify": "^5.6.2", "fastify-cli": "^7.4.1", "fastify-plugin": "^5.1.0", - "typebox": "^1.0.59" + "typebox": "^1.0.61" }, "devDependencies": { "@types/node": "^22.19.1", From 566d4ccd8e975f4d59b23e4f41c9b70c988a0e93 Mon Sep 17 00:00:00 2001 From: NigeParis Date: Wed, 3 Dec 2025 21:52:45 +0100 Subject: [PATCH 21/22] minor bug fixed SESSION_MANAGER when not in env --- src/chat/src/app.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 5d30955..4ac2c96 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -18,10 +18,11 @@ export const color = { // shows address for connection au server transcendance const session = process.env.SESSION_MANAGER ?? ''; -const part = session.split('/')[1]; -const machineName = part.split('.')[0]; -console.log(color.yellow, 'Connect at : https://' + machineName + ':8888/app/login'); - +if (session) { + const part = session.split('/')[1]; + const machineName = part.split('.')[0]; + console.log(color.yellow, 'Connect at : https://' + machineName + ':8888/app/login'); +} declare const __SERVICE_NAME: string; From 8959331b3765785dfdfaa47ed61244e17a60265e Mon Sep 17 00:00:00 2001 From: NigeParis Date: Thu, 4 Dec 2025 10:01:28 +0100 Subject: [PATCH 22/22] commented out experience with database can block the chat at the moment --- src/chat/src/routes/nginx-chat.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/chat/src/routes/nginx-chat.ts b/src/chat/src/routes/nginx-chat.ts index 1ba77c2..02162cc 100644 --- a/src/chat/src/routes/nginx-chat.ts +++ b/src/chat/src/routes/nginx-chat.ts @@ -35,17 +35,17 @@ const route: FastifyPluginAsync = async (fastify): Promise => { }, async (req, res) => { - const users = fastify.db.getAllUsers(); - console.log('ALL USERS EVER CONNECTED:', users); - if (!users) return; - for (const user of users) { - console.log(color.yellow, 'USER:', user.name); - } - // const usersBlocked = fastify.db.getAllBlockedUsers(); - // console.log(color.red, "ALL BLOCKED USERS:", usersBlocked); - fastify.db.addBlockedUserFor(users[0].id, users[1].id); - const usersBlocked2 = fastify.db.getAllBlockedUsers(); - console.log(color.green, 'ALL BLOCKED USERS:', usersBlocked2); + // const users = fastify.db.getAllUsers(); + // console.log('ALL USERS EVER CONNECTED:', users); + // if (!users) return; + // for (const user of users) { + // console.log(color.yellow, 'USER:', user.name); + // } + // // const usersBlocked = fastify.db.getAllBlockedUsers(); + // // console.log(color.red, "ALL BLOCKED USERS:", usersBlocked); + // fastify.db.addBlockedUserFor(users[0].id, users[1].id); + // const usersBlocked2 = fastify.db.getAllBlockedUsers(); + // console.log(color.green, 'ALL BLOCKED USERS:', usersBlocked2); res.makeResponse(200, 'success', 'CCChat.success', { name: 'name', 'id': req.authUser!.id, guest: false }); }, );