diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css
index eb43dce..5e9b65e 100644
--- a/frontend/src/chat/chat.css
+++ b/frontend/src/chat/chat.css
@@ -1,8 +1,10 @@
@import "tailwindcss";
-@font-face {
+/* @font-face {
font-family: "Nimbus Mono L";
src: url("/fonts/NimbusMonoL.woff2") format("woff2");
-}
+} */
+
+@tailwind utilities;
.btn-style {
@apply
@@ -159,8 +161,11 @@
div-buddies-list {
@apply
text-black
- whitespace-pre-wrap;
-
+ whitespace-pre-wrap
+ cursor-pointer
+ hover:text-blue-500
+ transition-colors
+ duration-150;
}
p {
@@ -180,4 +185,44 @@ div-notlog {
text-red-800
text-3xl
text-center;
+}
+
+div-private {
+ @apply
+ text-blue-800;
+
+}
+
+.popUpBox {
+ @apply
+ bg-white
+ p-6 rounded-xl
+ shadow-xl
+ w-[800px]
+ h-[350px]
+ p-[10px]
+ border-1
+ border-black
+
+}
+
+.profilPopup {
+ @apply
+ fixed
+ inset-0
+ bg-black/50
+ flex
+ justify-center
+ items-center;
+}
+
+.popup-b-clear {
+ @apply
+ absolute
+ bottom-42
+ right-12
+}
+
+.hidden{
+ display: none;
}
\ No newline at end of file
diff --git a/frontend/src/pages/chat/chat.html b/frontend/src/pages/chat/chat.html
index 2882ae5..bf06259 100644
--- a/frontend/src/pages/chat/chat.html
+++ b/frontend/src/pages/chat/chat.html
@@ -28,7 +28,13 @@
+
+
diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts
index 26dd177..4b8bd2f 100644
--- a/frontend/src/pages/chat/chat.ts
+++ b/frontend/src/pages/chat/chat.ts
@@ -4,7 +4,6 @@ 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;',
@@ -15,6 +14,7 @@ const color = {
};
export type ClientMessage = {
+ command: string
destination: string;
user: string;
text: string;
@@ -32,11 +32,11 @@ document.addEventListener('ft:pageChange', () => {
__socket.close();
__socket = undefined;
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, {
@@ -45,12 +45,54 @@ function getSocket(): Socket {
transports: ["websocket"],
});
return __socket;
+};
+
+function addMessage(text: string) {
+ const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
+ if (!chatWindow) return;
+ const messageElement = document.createElement("div-test");
+ messageElement.textContent = text;
+ chatWindow.appendChild(messageElement);
+ chatWindow.scrollTop = chatWindow.scrollHeight;
+ console.log(`Added new message: ${text}`)
+ return ;
+};
+
+function clearText() {
+ const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
+ if (!chatWindow) return;
+ chatWindow.innerHTML = "";
}
-
-async function isLoggedIn() {
+function isLoggedIn() {
return getUser() || null;
-}
+};
+
+function actionBtnPopUp() {
+ setTimeout(() => {
+ const clearTextBtn = document.querySelector("#popup-b-clear");
+ clearTextBtn?.addEventListener("click", () => {
+ clearText();
+ });
+ }, 0)
+}
+
+// getProfil get the profil of user
+function getProfil(socket: Socket, user: string) {
+ if (!socket.connected) return;
+ const profil = {
+ command: '@profil',
+ destination: 'profilMessage',
+ type: "chat",
+ user: user,
+ token: document.cookie ?? "",
+ text: user,
+ timestamp: Date.now(),
+ SenderWindowID: socket.id,
+ };
+ // addMessage(JSON.stringify(profil));
+ socket.emit('profilMessage', JSON.stringify(profil));
+}
async function windowStateHidden() {
const socketId = __socket || undefined;
@@ -64,18 +106,18 @@ async function windowStateHidden() {
socketId.emit('client_left', {
user: userName?.name,
why: 'tab window hidden - socket not dead',
- });
+ });
return;
-}
+};
-
-async function windowStateVisable() {
+async function windowStateVisable() {
+
+ const buddies = document.getElementById('div-buddies') as HTMLDivElement;
const socketId = __socket || undefined;
let oldName = localStorage.getItem("oldName") || undefined;
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();
let user = await updateUser();
if(user === null) return;
console.log("%cUserName :'" + user?.name + "'", color.green);
@@ -83,33 +125,121 @@ async function windowStateVisable() {
userName: oldName,
user: user?.name,
});
+ buddies.innerHTML = '';
+ buddies.textContent = '';
+ //connected(socketId);
setTitle('Chat Page');
return;
+};
+
+function parseCmdMsg(msgText: string): string[] | undefined {
+
+ if (!msgText?.trim()) return;
+ msgText = msgText.trim();
+ const command: string[] = ['', ''];
+ if (!msgText.startsWith('@')) {
+ command[0] = '@msg';
+ command[1] = msgText;
+ return command;
+ }
+ const noArgCommands = ['@quit', '@who', '@cls'];
+ if (noArgCommands.includes(msgText)) {
+ command[0] = msgText;
+ command[1] = '';
+ return command;
+ }
+
+ const ArgCommands = ['@profil', '@block'];
+ const userName = msgText.indexOf(" ");
+ const cmd2 = msgText.slice(0, userName).trim() ?? "";
+ const user = msgText.slice(userName + 1).trim();
+ if (ArgCommands.includes(cmd2)) {
+ command[0] = cmd2;
+ command[1] = user;
+ return command;
+ }
+ const colonIndex = msgText.indexOf(":");
+ if (colonIndex === -1) {
+ command[0] = msgText;
+ command[1] = '';
+ return command;
+ }
+ const cmd = msgText.slice(0, colonIndex).trim();
+ const rest = msgText.slice(colonIndex + 1).trim();
+ command[0] = cmd;
+ command[1] = rest;
+ return command;
}
-
-async function listBuddies(buddies: HTMLDivElement, listBuddies: string ) {
+async function listBuddies(socket: Socket, 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 ;
+ const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement;
+ const buddiesElement = document.createElement("div-buddies-list");
+ buddiesElement.textContent = listBuddies + '\n';
+ const user = getUser()?.name ?? "";
+ buddiesElement.style.cursor = "pointer";
+ buddiesElement.addEventListener("click", () => {
+ navigator.clipboard.writeText(listBuddies);
+ if (listBuddies !== user && user !== "") {
+ sendtextbox.value = `@${listBuddies}: `;
+ console.log("Copied to clipboard:", listBuddies);
+ sendtextbox.focus();
+ }
+ });
+
+ buddiesElement.addEventListener("dblclick", () => {
+ console.log("Open profile:", listBuddies);
+ getProfil(socket, listBuddies);
+ // openProfilePopup(`${profile}`);
+ // setTimeout(() => {
+ // const clearTextBtn = document.querySelector("#popup-b-clear");
+ // clearTextBtn?.addEventListener("click", () => {
+ // clearText();
+ // });
+ // }, 0)
+ // actionBtnPopUp();
+ });
+
+ buddies.appendChild(buddiesElement);
+ buddies.scrollTop = buddies.scrollHeight;
+ console.log(`Added buddies: ${listBuddies}`);
}
+
function waitSocketConnected(socket: Socket): Promise {
return new Promise(resolve => {
- if (socket.connected) return resolve(); // already connected
+ if (socket.connected) return resolve();
socket.on("connect", () => resolve());
});
-}
-const bconnected = document.getElementById('b-help') as HTMLButtonElement;
-if (bconnected) {
- bconnected.click();
-}
+};
+
+function quitChat (socket: Socket) {
+
+ try {
+ const systemWindow = document.getElementById('system-box') as HTMLDivElement;
+ const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
+ if (socket) {
+ logout(socket);
+ setTitle('Chat Page');
+ systemWindow.innerHTML = "";
+ chatWindow.textContent = "";
+ connected(socket);
+ } else {
+ getSocket();
+ }
+ } catch (e) {
+ console.error("Quit Chat error:", e);
+ showError('Failed to Quit Chat: Unknown error');
+ }
+
+};
+
+// const bconnected = document.getElementById('b-help') as HTMLButtonElement;
+// if (bconnected) {
+// bconnected.click();
+// }
function logout(socket: Socket) {
socket.emit("logout"); // notify server
@@ -118,6 +248,94 @@ function logout(socket: Socket) {
if (__socket !== undefined)
__socket.close();
// window.location.href = "/login";
+};
+
+function broadcastMsg (socket: Socket, msgCommand: string[]): void {
+ let msgText = msgCommand[1] ?? "";
+ console.log('%cmsgText:', color.red, msgText);
+ addMessage(msgText);
+ const user = getUser();
+ if (user && socket?.connected) {
+ const message = {
+ command: msgCommand,
+ destination: '',
+ type: "chat",
+ user: user.name,
+ token: document.cookie,
+ text: msgText,
+ timestamp: Date.now(),
+ SenderWindowID: socket.id,
+ };
+ socket.emit('message', JSON.stringify(message));
+ }
+};
+
+
+async function connected(socket: Socket): Promise {
+
+ try {
+ const buddies = document.getElementById('div-buddies') as HTMLDivElement;
+ const loggedIn = await isLoggedIn();
+ 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 ?? "";
+ // const res = await client.guestLogin();
+ let user = await updateUser();
+ console.log('%cUser?name:',color.yellow, user?.name);
+ localStorage.setItem("oldName", oldUser);
+ buddies.textContent = "";
+ socket.emit('list', {
+ oldUser: oldUser,
+ user: user?.name,
+ });
+ } catch (e) {
+ console.error("Login error:", e);
+ showError('Failed to login: Unknown error');
+ }
+};
+
+async function whoami(socket: Socket) {
+ try {
+ const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
+ const loggedIn = isLoggedIn();
+
+ const res = await client.guestLogin();
+ switch (res.kind) {
+ case 'success': {
+ let user = await updateUser();
+ if (chatWindow) {
+ socket.emit('updateClientName', {
+ oldUser: '',
+ user: user?.name
+ });
+ }
+ if (user === null)
+ return showError('Failed to get user: no user ?');
+ setTitle(`Welcome ${user.guest ? '[GUEST] ' : ''}${user.name}`);
+ break;
+ }
+ case 'failed': {
+ showError(`Failed to login: ${res.msg}`);
+ }
+ }
+ } catch (e) {
+ console.error("Login error:", e);
+ showError('Failed to login: Unknown error');
+ }
+};
+
+async function openProfilePopup(profil: string) {
+
+
+ const modalname = document.getElementById("modal-name") ?? null;
+ if (modalname)
+ modalname.innerHTML = `${profil}`;
+ const profilList = document.getElementById("profile-modal") ?? null;
+ if (profilList)
+ profilList.classList.remove("hidden");
+ // The popup now exists → attach the event
}
@@ -130,13 +348,16 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
// Listen for the 'connect' event
socket.on("connect", async () => {
-
+
+ const systemWindow = document.getElementById('system-box') as HTMLDivElement;
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
if (!user || !socket.connected) return;
const message = {
+ command: "",
+ destination: 'system-info',
type: "chat",
user,
token: document.cookie ?? "",
@@ -145,19 +366,24 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
SenderWindowID: socket.id,
};
socket.emit('message', JSON.stringify(message));
+ const messageElement = document.createElement("div");
+ messageElement.textContent = `${user}: is connected au server`;
+ systemWindow.appendChild(messageElement);
+ systemWindow.scrollTop = systemWindow.scrollHeight;
});
// Listen for messages from the server "MsgObjectServer"
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);
+ console.log("%cDEBUG LOGS - Message Obj Recieved:", color.green, data);
+ console.log("%cDEBUG LOGS - Recieved data.message.text: ", color.green, data.message.text);
+ console.log("%cDEBUG LOGS - Recieved data.message.user: ", color.green, 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();
+ connected(socket);
}
if (chatWindow && data.message.destination === "") {
@@ -166,6 +392,14 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
chatWindow.appendChild(messageElement);
chatWindow.scrollTop = chatWindow.scrollHeight;
}
+ if (chatWindow && data.message.destination === "privateMsg") {
+ const messageElement = document.createElement("div-private");
+ 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") {
@@ -177,23 +411,25 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
while (systemWindow.children.length > MAX_SYSTEM_MESSAGES) {
systemWindow.removeChild(systemWindow.firstChild!);
}
-
systemWindow.scrollTop = systemWindow.scrollHeight;
}
-
console.log("Getuser():", getUser());
});
-
-
-
- socket.on('logout', () => {
- const bquit = document.getElementById('b-quit') as HTMLDivElement | null;
- if (bquit instanceof HTMLDivElement) {
- bquit.click();
- }
+ socket.on('profilMessage', (profil) => {
+ openProfilePopup(profil);
+ actionBtnPopUp();
});
+
+ socket.on('logout', () => {
+ quitChat(socket);
+ });
+
+ socket.on('privMessageCopy', (message) => {
+ addMessage(message);
+ })
+
type Providers = {
name: string,
display_name: string,
@@ -201,25 +437,46 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
color?: { default: string, hover: string },
};
-
- let toggle = false
- window.addEventListener("focus", () => {
- 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;
+ let toggle = false
+ window.addEventListener("focus", () => {
+ //nst bwhoami = document.getElementById('b-whoami') as HTMLButtonElement;
+ if (window.location.pathname === '/app/chat') {
+ connected(socket);
+ console.log("%cWindow is focused on /chat:" + socket.id, color.green);
+ if (socket.id) {
+ windowStateVisable();
}
- });
+ toggle = true;
+ }
+ });
+
+ window.addEventListener("blur", () => {
+ console.log("%cWindow is not focused on /chat", color.red);
+ if (socket.id)
+ windowStateHidden();
+ toggle = false;
+ });
+
+
+ // setInterval(async () => {
+ // //connected(socket);
+ // },10000); // every 10 seco
+ socket.on('listBud', async (myBuddies: string) => {
+ const buddies = document.getElementById('div-buddies') as HTMLDivElement;
+ console.log('List buddies connected ', myBuddies);
+ listBuddies(socket, buddies, myBuddies);
+ });
+
+ socket.once('welcome', (data) => {
+ const buddies = document.getElementById('div-buddies') as HTMLDivElement;
+ const chatWindow = document.getElementById('t-chatbox') as HTMLDivElement;
+ chatWindow.innerHTML = '';
+ buddies.textContent = '';
+ buddies.innerHTML = '';
+ connected(socket);
+ addMessage (`${data.msg} ` + getUser()?.name);
+ });
- window.addEventListener("blur", () => {
- console.log("%cWindow is not focused on /chat", color.red);
- if (socket.id)
- windowStateHidden();
- toggle = false;
- });
setTitle('Chat Page');
// Listen for the 'connect' event
@@ -235,6 +492,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
const username = document.getElementById('username') as HTMLDivElement;
const buddies = document.getElementById('div-buddies') as HTMLDivElement;
const bquit = document.getElementById('b-quit') as HTMLDivElement;
+ const systemWindow = document.getElementById('system-box') as HTMLDivElement;
chatWindow.textContent = '';
chatWindow.innerHTML = '';
@@ -251,105 +509,90 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
console.log('unknown response: ', value);
}
- const addMessage = (text: string) => {
- if (!chatWindow) return;
- const messageElement = document.createElement("div-test");
- messageElement.textContent = text;
- chatWindow.appendChild(messageElement);
- chatWindow.scrollTop = chatWindow.scrollHeight;
- console.log(`Added new message: ${text}`)
- return ;
- };
- socket.once('welcome', (data) => {
- chatWindow.textContent = '';
- chatWindow.innerHTML = '';
- buddies.textContent = '';
- buddies.innerHTML = '';
- bconnected.click();
- addMessage (`${data.msg} ` + getUser()?.name);
- });
+
+ const buttonPro = document.getElementById("close-modal") ?? null;
+
+ if (buttonPro)
+ buttonPro.addEventListener("click", () => {
+ const profilList = document.getElementById("profile-modal") ?? null;
+ if (profilList) profilList.classList.add("hidden");
+ });
// Send button
sendButton?.addEventListener("click", () => {
if (sendtextbox && sendtextbox.value.trim()) {
- const msgText = sendtextbox.value.trim();
- bconnected.click();
- addMessage(msgText);
- const user = getUser();
- if (user && socket?.connected) {
- const message = {
- destination: "",
- type: "chat",
- user: user.name,
- token: document.cookie,
- text: msgText,
- timestamp: Date.now(),
- SenderWindowID: socket.id,
- };
- socket.emit('message', JSON.stringify(message));
+ let msgText: string = sendtextbox.value.trim();
+ const msgCommand = parseCmdMsg(msgText) ?? "";
+ connected(socket);
+ if (msgCommand !== "") {
+ switch (msgCommand[0]) {
+ case '@msg':
+ broadcastMsg(socket, msgCommand);
+ break;
+ case '@who':
+ whoami(socket);
+ break;
+ case '@profil':
+ getProfil(socket, msgCommand[1]);
+ // Ensure we have a user AND socket is connected
+ // if (!socket.connected) return;
+ // const profil = {
+ // command: msgCommand[0],
+ // destination: 'profil',
+ // type: "chat",
+ // user: msgCommand[1],
+ // token: document.cookie ?? "",
+ // text: msgCommand[1],
+ // timestamp: Date.now(),
+ // SenderWindowID: socket.id,
+ // };
+ // //socket.emit('MsgObjectServer', message);
+ // addMessage(JSON.stringify(profil));
+ // socket.emit('profilMessage', JSON.stringify(profil));
+ break;
+ case '@cls':
+ chatWindow.innerHTML = '';
+ break;
+ case '@quit':
+ quitChat(socket);
+ break;
+ default:
+ const user = getUser()?.name;
+ // Ensure we have a user AND socket is connected
+ if (!user || !socket.connected) return;
+ const message = {
+ command: msgCommand[0],
+ destination: '',
+ type: "chat",
+ user: user,
+ token: document.cookie ?? "",
+ text: msgCommand[1],
+ timestamp: Date.now(),
+ SenderWindowID: socket.id,
+ };
+ //socket.emit('MsgObjectServer', message);
+ socket.emit('privMessage', JSON.stringify(message));
+ // addMessage(JSON.stringify(message));
+ break;
+ }
+ // Clear the input in all cases
+ sendtextbox.value = "";
}
- sendtextbox.value = "";
}
});
-
-
-
// 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();
- }
+ quitChat(socket);
});
-
- setInterval(async () => {
- //bconnected.click();
- }, 10000); // every 10 second
-
- // Help Text button
- bconnected?.addEventListener("click", async () => {
-
- const loggedIn = await isLoggedIn();
- 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('%cUser?name:',color.yellow, user?.name);
- localStorage.setItem("oldName", oldUser);
- buddies.textContent = "";
- // if (chatWindow) {
- // addMessage('@list - lists all connected users in the chat');
- socket.emit('list', {
- oldUser: oldUser,
- user: user?.name,
- });
- // }
-
- });
-
- socket.on('listBud', (myBuddies: string) => {
- console.log('List buddies connected ', myBuddies);
- listBuddies(buddies,myBuddies);
- });
-
-
// Enter key to send message
sendtextbox!.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
@@ -357,34 +600,10 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
}
});
- // Whoami button to display user name
+ // Whoami button to display user name addMessage(msgCommand[0]);
+
bwhoami?.addEventListener('click', async () => {
- try {
- const loggedIn = await isLoggedIn();
-
- const res = await client.guestLogin();
- switch (res.kind) {
- case 'success': {
- let user = await updateUser();
- if (chatWindow) {
- socket.emit('updateClientName', {
- oldUser: '',
- user: user?.name
- });
- }
- if (user === null)
- return showError('Failed to get user: no user ?');
- setTitle(`Welcome ${user.guest ? '[GUEST] ' : ''}${user.name}`);
- break;
- }
- case 'failed': {
- showError(`Failed to login: ${res.msg}`);
- }
- }
- } catch (e) {
- console.error("Login error:", e);
- showError('Failed to login: Unknown error');
- }
+ whoami(socket);
});
}
}
diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts
index 4ac2c96..033e17c 100644
--- a/src/chat/src/app.ts
+++ b/src/chat/src/app.ts
@@ -6,6 +6,7 @@ import * as auth from '@shared/auth';
import * as swagger from '@shared/swagger';
import * as utils from '@shared/utils';
import { Server, Socket } from 'socket.io';
+import type { User } from '@shared/database/mixin/user';
// colors for console.log
export const color = {
@@ -34,6 +35,7 @@ interface ClientInfo {
}
export type ClientMessage = {
+ command: string
destination: string;
user: string;
text: string;
@@ -82,6 +84,9 @@ declare module 'fastify' {
io: Server<{
hello: (message: string) => string;
MsgObjectServer: (data: { message: ClientMessage }) => void;
+ privMessage: (data: string) => void;
+ profilMessage: (data: string) => void;
+ privMessageCopy: (msg: string) => void;
message: (msg: string) => void;
listBud: (msg: string) => void;
testend: (sock_id_client: string) => void;
@@ -129,55 +134,117 @@ async function onReady(fastify: FastifyInstance) {
seen.add(username.user);
count++;
// console.log(color.green,"count: ", count);
- console.log(color.yellow, 'Client:', color.reset, username.user);
+ // console.log(color.yellow, 'Client:', color.reset, username.user);
const targetSocketId = target;
io.to(targetSocketId!).emit('listBud', username.user);
- console.log(
- color.yellow,
- 'Chat Socket ID:',
- color.reset,
- socketId,
- );
+ // console.log(
+ // color.yellow,
+ // 'Chat Socket ID:',
+ // color.reset,
+ // socketId,
+ // );
continue;
}
-
// If no io provided, assume entries in the map are valid and count them.
count++;
- console.log(
- color.red,
- 'Client (unverified):',
- color.reset,
- username,
- );
- console.log(
- color.red,
- 'Chat Socket ID (unverified):',
- color.reset,
- socketId,
- );
+ console.log(color.red, 'DEBUG LOG: - Client (unverified):', color.reset, username);
+ console.log(color.red, 'DEBUG LOG: - Chat Socket ID (unverified):', color.reset, socketId);
}
return count;
}
function broadcast(data: ClientMessage, sender?: string) {
fastify.io.fetchSockets().then((sockets) => {
- for (const s of sockets) {
+ for (const socket of sockets) {
// Skip sender's own socket
- if (s.id === sender) continue;
+ if (socket.id === sender) continue;
// Get client name from map
+ const clientInfo = clientChat.get(socket.id);
+ if (!clientInfo?.user) {
+ console.log(color.yellow, `Skipping socket ${socket.id} (no user found)`);
+ continue;
+ }
+ // Emit structured JSON object
+ socket.emit('MsgObjectServer', { message: data });
+ // Debug logs
+ console.log(color.green, `'Broadcast to:', ${data.command} message: ${data.text}`);
+ // console.log('DEBUG - Target socket ID:', s.id);
+ // console.log('DEBUG - Target rooms:', [...s.rooms]);
+ // console.log('DEBUG - Sender socket ID:', sender ?? 'none');
+ }
+ });
+ }
+
+ // function formatTimestamp(ms: number) {
+ // const d = new Date(ms);
+ // return d.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' });
+ // }
+
+ function getUserByName(users: User[], name: string) {
+ return users.find(u => u.name === name) || null;
+ }
+
+
+ // this function returns html the profil pop up in CHAT of a user 'nickname unique' TODO ....
+ async function getProfil(user: string): Promise {
+ let profilHtmlPopup = '404: Error: Profil not found';
+ const users: User[] = fastify.db.getAllUsers() ?? [];
+ const allUsers: User | null = getUserByName(users, user);
+ console.log(color.yellow, `'userFound is:'${allUsers?.name}`);
+ if (user === allUsers?.name) {
+ console.log(color.yellow, `'login Name: '${allUsers.login}' user: '${user}'`);
+ profilHtmlPopup = `
+
Profil of ${allUsers.name}
+ Login Name: '${allUsers?.login ?? 'Guest'}'
+
+
+ About: No description
+ `;
+ }
+
+ return profilHtmlPopup;
+ };
+
+ function sendProfil(data: ClientMessage, clientProfil?: string) {
+
+ fastify.io.fetchSockets().then((sockets) => {
+ const senderSocket = sockets.find(socket => socket.id === clientProfil);
+ for (const socket of sockets) {
+ const clientInfo = clientChat.get(socket.id);
+ if (clientInfo?.user === data.user) {
+ if (senderSocket) {
+ socket.emit('profilMessage', `${data.text}`);
+ }
+ }
+ }
+ });
+ }
+
+ function sendPrivMessage(data: ClientMessage, sender?: string) {
+ fastify.io.fetchSockets().then((sockets) => {
+ const senderSocket = sockets.find(s => s.id === sender);
+ for (const s of sockets) {
+ if (s.id === sender) continue;
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');
+ const user: string = clientChat.get(s.id)?.user ?? '';
+ const atUser = `@${user}`;
+ if (atUser !== data.command || atUser === '') {
+ console.log(color.yellow, `DEBUG LOG: User: '${atUser}' command NOT FOUND: '${data.command[0]}' `);
+ continue;
+ }
+ if (data.text !== '') {
+ s.emit('MsgObjectServer', { message: data });
+ console.log(color.yellow, `DEBUG LOG: User: '${atUser}' command FOUND: '${data.command}' `);
+ if (senderSocket) {
+ senderSocket.emit('privMessageCopy', `${data.command}: ${data.text}🔒`);
+ }
+ }
+ console.log(color.green, `DEBUG LOG: 'Priv to:', ${data.command} message: ${data.text}`);
}
});
}
@@ -212,12 +279,7 @@ async function onReady(fastify: FastifyInstance) {
// Send object directly — DO NOT wrap it in a string
broadcast(obj, obj.SenderWindowID);
- console.log(
- color.red,
- 'connected in the Chat :',
- connectedUser(fastify.io),
- color.reset,
- );
+ console.log(color.red, 'DEBUG LOG: connected in the Chat :', connectedUser(fastify.io), color.reset);
});
socket.on('testend', (sock_id_cl: string) => {
@@ -256,8 +318,7 @@ async function onReady(fastify: FastifyInstance) {
// };
if (client) {
client.user = userFromFrontend.user;
- console.log(color.green, 'client.user is: ', client.user);
-
+ console.log(color.green, `'DEBUG LOG: client.user is, '${client.user}'`);
}
}
});
@@ -269,6 +330,7 @@ async function onReady(fastify: FastifyInstance) {
if (!clientName) return;
console.log(color.green, `Client logging out: ${clientName} (${socket.id})`);
const obj = {
+ command: '',
destination: 'system-info',
type: 'chat' as const,
user: clientName,
@@ -295,6 +357,7 @@ async function onReady(fastify: FastifyInstance) {
if (clientName !== null) {
const obj = {
+ command: '',
destination: 'system-info',
type: 'chat',
user: clientName,
@@ -319,6 +382,7 @@ async function onReady(fastify: FastifyInstance) {
if (clientName !== null) {
const obj = {
+ command: '',
destination: 'system-info',
type: 'chat',
user: clientName,
@@ -328,11 +392,69 @@ async function onReady(fastify: FastifyInstance) {
SenderWindowID: socket.id,
};
console.log(color.blue, 'BROADCASTS OUT :', obj.SenderWindowID);
+
broadcast(obj, obj.SenderWindowID);
// clientChat.delete(obj.user);
}
});
+
+ socket.on('privMessage', (data) => {
+ const clientName: string = clientChat.get(socket.id)?.user || '';
+ const prvMessage: ClientMessage = JSON.parse(data) || '';
+ console.log(
+ color.blue,
+ `DEBUG LOG: ClientName: '${clientName}' id Socket: '${socket.id}' target Name:`,
+ prvMessage.command,
+ );
+
+ if (clientName !== null) {
+ const obj = {
+ command: prvMessage.command,
+ destination: 'privateMsg',
+ type: 'chat',
+ user: clientName,
+ token: '',
+ text: prvMessage.text,
+ timestamp: Date.now(),
+ SenderWindowID: socket.id,
+ };
+ console.log(color.blue, 'DEBUG LOG: PRIV MESSAGE OUT :', obj.SenderWindowID);
+ sendPrivMessage(obj, obj.SenderWindowID);
+ // clientChat.delete(obj.user);
+ }
+ });
+
+ socket.on('profilMessage', async (data) => {
+ const clientName: string = clientChat.get(socket.id)?.user || '';
+ const profilMessage: ClientMessage = JSON.parse(data) || '';
+ const users: User[] = fastify.db.getAllUsers() ?? [];
+ console.log(color.yellow, 'DEBUG LOG: ALL USERS EVER CONNECTED:', users);
+ console.log(
+ color.blue,
+ `DEBUG LOG: ClientName: '${clientName}' id Socket: '${socket.id}' target profil:`,
+ profilMessage.user,
+ );
+ const profileHtml: string = await getProfil(profilMessage.user);
+ if (clientName !== null) {
+ const testuser: User | null = getUserByName(users, profilMessage.user);
+ console.log(color.yellow, 'user:', testuser?.login ?? 'Guest');
+ const obj = {
+ command: profilMessage.command,
+ destination: 'profilMsg',
+ type: 'chat',
+ user: clientName,
+ token: '',
+ text: profileHtml,
+ timestamp: Date.now(),
+ SenderWindowID: socket.id,
+ };
+ console.log(color.blue, 'DEBUG - profil message MESSAGE OUT :', obj.SenderWindowID);
+ sendProfil(obj, obj.SenderWindowID);
+ // clientChat.delete(obj.user);
+ }
+ });
+
socket.on('client_entered', (data) => {
// data may be undefined (when frontend calls emit with no payload)
@@ -364,6 +486,7 @@ async function onReady(fastify: FastifyInstance) {
);
if (clientName !== null) {
const obj = {
+ command: '',
destination: 'system-info',
type: 'chat',
user: clientName,
diff --git a/src/package.json b/src/package.json
index 9fa1e9c..45b7a6d 100644
--- a/src/package.json
+++ b/src/package.json
@@ -36,7 +36,7 @@
"vite": "^7.2.6"
},
"dependencies": {
- "@redocly/cli": "^2.12.1",
+ "@redocly/cli": "^2.12.3",
"bindings": "^1.5.0"
}
}
diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml
index ad74292..a50dc94 100644
--- a/src/pnpm-lock.yaml
+++ b/src/pnpm-lock.yaml
@@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@redocly/cli':
- specifier: ^2.12.1
- version: 2.12.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)
+ specifier: ^2.12.3
+ version: 2.12.3(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)
bindings:
specifier: ^1.5.0
version: 1.5.0
@@ -943,8 +943,8 @@ packages:
'@redocly/ajv@8.17.1':
resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==}
- '@redocly/cli@2.12.1':
- resolution: {integrity: sha512-XGD28QjjZEzN+J9WOROzw4fHNi+Fyw/gCyDZDgI4nX4j9gEBT1PcxN75wWpMoDGHKAUj8ghrhMHtfQoUuR90zg==}
+ '@redocly/cli@2.12.3':
+ resolution: {integrity: sha512-1SDW551scNdb4HmNpzyUf4gjsK89KkRUeXF91VVMRkQ5+lFEq1Nj259jN1M25uOd/cg1QjKE3kIbnN1dxPa3ng==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
hasBin: true
@@ -958,12 +958,12 @@ packages:
resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==}
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
- '@redocly/openapi-core@2.12.1':
- resolution: {integrity: sha512-xMlKf4dnZsxP3JYBNZFsMNBJqVxWlwLuyGLhGc36hXw50YOla1UjrVZ5psIyzLXgUPI3QJDA1XmGcJ8rcex/ow==}
+ '@redocly/openapi-core@2.12.3':
+ resolution: {integrity: sha512-3gdSRftIeUbzXvwDi/tBjO0uj9PzR0XzbWjNwuu3HlVXJ1ElB+K31AnzQ2iA6mjIHq9uvmLRXAs9MsP/0Hbzug==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
- '@redocly/respect-core@2.12.1':
- resolution: {integrity: sha512-ADm+JMHWGYeOwzdGEQ8CYKjmMBLU0ycZTwJbCkQsUulXSNkNA7GzA8lrMM2+I8cPMRk25G5PmtfAR7U+a0o1ew==}
+ '@redocly/respect-core@2.12.3':
+ resolution: {integrity: sha512-ZYqrLBlRVVHwgPawOjo94sKmeuuien77xtkXluTa6+y/wkQ8c5oYY7OqWbasMv0IoxSPehwVMa0AL0OCQP3uCQ==}
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
'@rollup/rollup-android-arm-eabi@4.53.3':
@@ -2613,10 +2613,10 @@ packages:
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
hasBin: true
- react-dom@19.2.0:
- resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==}
+ react-dom@19.2.1:
+ resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==}
peerDependencies:
- react: ^19.2.0
+ react: ^19.2.1
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@@ -2626,8 +2626,8 @@ packages:
peerDependencies:
react: ^18.0.0 || ^19.0.0
- react@19.2.0:
- resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==}
+ react@19.2.1:
+ resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==}
engines: {node: '>=0.10.0'}
readable-stream@3.6.2:
@@ -3054,6 +3054,10 @@ packages:
resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==}
engines: {node: '>=18'}
+ ulid@3.0.2:
+ resolution: {integrity: sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w==}
+ hasBin: true
+
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -3864,14 +3868,14 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
- '@redocly/cli@2.12.1(@opentelemetry/api@1.9.0)(ajv@8.17.1)(core-js@3.47.0)':
+ '@redocly/cli@2.12.3(@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.1(ajv@8.17.1)
- '@redocly/respect-core': 2.12.1(ajv@8.17.1)
+ '@redocly/openapi-core': 2.12.3(ajv@8.17.1)
+ '@redocly/respect-core': 2.12.3(ajv@8.17.1)
abort-controller: 3.0.0
chokidar: 3.6.0
colorette: 1.4.0
@@ -3883,13 +3887,14 @@ snapshots:
https-proxy-agent: 7.0.6(supports-color@10.2.2)
mobx: 6.15.0
pluralize: 8.0.0
- react: 19.2.0
- react-dom: 19.2.0(react@19.2.0)
- redoc: 2.5.1(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(styled-components@6.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0))
+ react: 19.2.1
+ react-dom: 19.2.1(react@19.2.1)
+ redoc: 2.5.1(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(styled-components@6.1.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1))
semver: 7.7.3
set-cookie-parser: 2.7.2
simple-websocket: 9.1.0
- styled-components: 6.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ styled-components: 6.1.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
+ ulid: 3.0.2
undici: 6.22.0
yargs: 17.0.1
transitivePeerDependencies:
@@ -3922,7 +3927,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@redocly/openapi-core@2.12.1(ajv@8.17.1)':
+ '@redocly/openapi-core@2.12.3(ajv@8.17.1)':
dependencies:
'@redocly/ajv': 8.17.1
'@redocly/config': 0.40.0
@@ -3936,12 +3941,12 @@ snapshots:
transitivePeerDependencies:
- ajv
- '@redocly/respect-core@2.12.1(ajv@8.17.1)':
+ '@redocly/respect-core@2.12.3(ajv@8.17.1)':
dependencies:
'@faker-js/faker': 7.6.0
'@noble/hashes': 1.8.0
'@redocly/ajv': 8.17.1
- '@redocly/openapi-core': 2.12.1(ajv@8.17.1)
+ '@redocly/openapi-core': 2.12.3(ajv@8.17.1)
better-ajv-errors: 1.2.0(ajv@8.17.1)
colorette: 2.0.20
json-pointer: 0.6.2
@@ -5282,21 +5287,21 @@ snapshots:
dependencies:
obliterator: 2.0.5
- mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+ mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
dependencies:
mobx: 6.15.0
- react: 19.2.0
- use-sync-external-store: 1.6.0(react@19.2.0)
+ react: 19.2.1
+ use-sync-external-store: 1.6.0(react@19.2.1)
optionalDependencies:
- react-dom: 19.2.0(react@19.2.0)
+ react-dom: 19.2.1(react@19.2.1)
- mobx-react@9.2.0(mobx@6.15.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+ mobx-react@9.2.0(mobx@6.15.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
dependencies:
mobx: 6.15.0
- mobx-react-lite: 4.1.1(mobx@6.15.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
- react: 19.2.0
+ mobx-react-lite: 4.1.1(mobx@6.15.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
+ react: 19.2.1
optionalDependencies:
- react-dom: 19.2.0(react@19.2.0)
+ react-dom: 19.2.1(react@19.2.1)
mobx@6.15.0: {}
@@ -5661,20 +5666,20 @@ snapshots:
minimist: 1.2.8
strip-json-comments: 2.0.1
- react-dom@19.2.0(react@19.2.0):
+ react-dom@19.2.1(react@19.2.1):
dependencies:
- react: 19.2.0
+ react: 19.2.1
scheduler: 0.27.0
react-is@16.13.1: {}
- react-tabs@6.1.0(react@19.2.0):
+ react-tabs@6.1.0(react@19.2.1):
dependencies:
clsx: 2.1.1
prop-types: 15.8.1
- react: 19.2.0
+ react: 19.2.1
- react@19.2.0: {}
+ react@19.2.1: {}
readable-stream@3.6.2:
dependencies:
@@ -5690,7 +5695,7 @@ snapshots:
real-require@0.2.0: {}
- redoc@2.5.1(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(styled-components@6.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)):
+ redoc@2.5.1(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(styled-components@6.1.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1)):
dependencies:
'@redocly/openapi-core': 1.34.5(supports-color@10.2.2)
classnames: 2.5.1
@@ -5703,19 +5708,19 @@ snapshots:
mark.js: 8.11.1
marked: 4.3.0
mobx: 6.15.0
- mobx-react: 9.2.0(mobx@6.15.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ mobx-react: 9.2.0(mobx@6.15.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
openapi-sampler: 1.6.2
path-browserify: 1.0.1
perfect-scrollbar: 1.5.6
polished: 4.3.1
prismjs: 1.30.0
prop-types: 15.8.1
- react: 19.2.0
- react-dom: 19.2.0(react@19.2.0)
- react-tabs: 6.1.0(react@19.2.0)
+ react: 19.2.1
+ react-dom: 19.2.1(react@19.2.1)
+ react-tabs: 6.1.0(react@19.2.1)
slugify: 1.4.7
stickyfill: 1.1.1
- styled-components: 6.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+ styled-components: 6.1.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
swagger2openapi: 7.0.8
url-template: 2.0.8
transitivePeerDependencies:
@@ -6034,7 +6039,7 @@ snapshots:
dependencies:
'@tokenizer/token': 0.3.0
- styled-components@6.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+ styled-components@6.1.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
dependencies:
'@emotion/is-prop-valid': 1.2.2
'@emotion/unitless': 0.8.1
@@ -6042,8 +6047,8 @@ snapshots:
css-to-react-native: 3.2.0
csstype: 3.1.3
postcss: 8.4.49
- react: 19.2.0
- react-dom: 19.2.0(react@19.2.0)
+ react: 19.2.1
+ react-dom: 19.2.1(react@19.2.1)
shallowequal: 1.1.0
stylis: 4.3.2
tslib: 2.6.2
@@ -6178,6 +6183,8 @@ snapshots:
uint8array-extras@1.5.0: {}
+ ulid@3.0.2: {}
+
undici-types@6.21.0: {}
undici-types@7.16.0: {}
@@ -6194,9 +6201,9 @@ snapshots:
url-template@2.0.8: {}
- use-sync-external-store@1.6.0(react@19.2.0):
+ use-sync-external-store@1.6.0(react@19.2.1):
dependencies:
- react: 19.2.0
+ react: 19.2.1
util-deprecate@1.0.2: {}