Merge pull request #50 from Maix0/nigel/privateMsg
This commit is contained in:
commit
ca30de7f84
6 changed files with 655 additions and 255 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -28,7 +28,13 @@
|
|||
<div id = "div-buddies">
|
||||
<!-- <p>Alice</p>
|
||||
<p>Bob</p>
|
||||
<p>Charlie</p> -->
|
||||
<p>Charlie</p> -->Marks
|
||||
</div>
|
||||
</div>
|
||||
<div id="profile-modal" class="profilPopup hidden">
|
||||
<div class="popUpBox">
|
||||
<p class="" id="modal-name"></p>
|
||||
<button id="close-modal" class="btn-style absolute bottom-32 right-12">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
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<void> {
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <string> {
|
||||
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 = `<div class="profile-info">
|
||||
<div-profil-name id="profilName"> Profil of ${allUsers.name} </div>
|
||||
<div-login-name id="loginName"> Login Name: '${allUsers?.login ?? 'Guest'}' </div>
|
||||
</br>
|
||||
<button id="popup-b-clear" class="btn-style popup-b-clear">Clear Text</button>
|
||||
<div id="profile-about">About: No description</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
"vite": "^7.2.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@redocly/cli": "^2.12.1",
|
||||
"@redocly/cli": "^2.12.3",
|
||||
"bindings": "^1.5.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
101
src/pnpm-lock.yaml
generated
101
src/pnpm-lock.yaml
generated
|
|
@ -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: {}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue