First private messages working

This commit is contained in:
NigeParis 2025-12-05 16:37:26 +01:00 committed by apetitco
parent bf66c11356
commit eb613c10f4
5 changed files with 303 additions and 172 deletions

View file

@ -159,8 +159,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 +183,10 @@ div-notlog {
text-red-800
text-3xl
text-center;
}
div-private {
@apply
text-blue-800;
}

View file

@ -47,7 +47,6 @@ function getSocket(): Socket {
return __socket;
};
function addMessage(text: string) {
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
if (!chatWindow) return;
@ -59,7 +58,6 @@ function addMessage(text: string) {
return ;
};
async function isLoggedIn() {
return getUser() || null;
};
@ -80,14 +78,12 @@ async function windowStateHidden() {
return;
};
async function windowStateVisable() {
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);
@ -100,39 +96,57 @@ async function windowStateVisable() {
};
function parseCmdMsg(msgText: string): string[] | undefined {
if (!msgText?.trim()) {
console.log('%c DEBUG - in FN parseCmdMsg : msgText = ""', color.red);
return;
}
msgText = msgText.trim();
// Find the first space
const firstSpaceIndex = msgText.indexOf(' ');
const cmd = firstSpaceIndex === -1 ? msgText : msgText.slice(0, firstSpaceIndex);
const rest = firstSpaceIndex === -1 ? "" : msgText.slice(firstSpaceIndex + 1).trim();
const command: string[] = ["", ""];
if (!msgText.startsWith('@')) {
command[0] = "@msg";
command[1] = msgText;
} else {
command[0] = cmd;
command[1] = rest;
}
console.log('%c DEBUG - split msgText[0]:', color.red, command[0]);
console.log('%c DEBUG - split msgText[1]:', color.red, command[1]);
return command;
};
async function listBuddies(buddies: HTMLDivElement, listBuddies: string ) {
if (!msgText?.trim()) return;
msgText = msgText.trim();
const command: string[] = ['', ''];
if (!msgText.startsWith('@')) {
command[0] = '@msg';
command[1] = msgText;
return command;
}
const noArgCommands = ['@quit', '@cls', '@profile'];
if (noArgCommands.includes(msgText)) {
command[0] = msgText;
command[1] = '';
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) {
if (!buddies) return;
const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement;
const messageElement = document.createElement("div-buddies-list");
messageElement.textContent = listBuddies + '\n';
// ✔ Add click-to-copy
messageElement.style.cursor = "pointer"; // optional visual hint
messageElement.addEventListener("click", () => {
navigator.clipboard.writeText(listBuddies);
sendtextbox.value = `@${listBuddies}: `;
console.log("Copied to clipboard:", listBuddies);
sendtextbox.focus(); // move cursor into the box
});
buddies.appendChild(messageElement);
buddies.scrollTop = buddies.scrollHeight;
console.log(`Added buddies: ${listBuddies}`)
return ;
console.log(`Added buddies: ${listBuddies}`);
}
};
function waitSocketConnected(socket: Socket): Promise<void> {
return new Promise(resolve => {
@ -141,6 +155,27 @@ function waitSocketConnected(socket: Socket): Promise<void> {
});
};
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();
@ -163,7 +198,7 @@ function broadcastMsg (socket: Socket, msgCommand: string[]): void {
if (user && socket?.connected) {
const message = {
command: msgCommand,
destination: "",
destination: '',
type: "chat",
user: user.name,
token: document.cookie,
@ -178,28 +213,61 @@ function broadcastMsg (socket: Socket, msgCommand: string[]): void {
async function connected(socket: Socket): Promise<void> {
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 = "";
// if (chatWindow) {
// addMessage('@list - lists all connected users in the chat');
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 = 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');
}
};
function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn {
@ -227,19 +295,17 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
SenderWindowID: socket.id,
};
socket.emit('message', JSON.stringify(message));
// if (systemWindow) {
const messageElement = document.createElement("div");
messageElement.textContent = `${user}: is connected au server`;
systemWindow.appendChild(messageElement);
systemWindow.scrollTop = systemWindow.scrollHeight;
// }
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;
@ -255,6 +321,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") {
@ -272,13 +346,14 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
});
socket.on('logout', () => {
const bquit = document.getElementById('b-quit') as HTMLDivElement | null;
if (bquit instanceof HTMLDivElement) {
bquit.click();
}
socket.on('logout', () => {
quitChat(socket);
});
socket.on('privMessageCopy', (message) => {
addMessage(message);
})
type Providers = {
name: string,
display_name: string,
@ -288,7 +363,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
let toggle = false
window.addEventListener("focus", () => {
const bwhoami = document.getElementById('b-whoami') as HTMLButtonElement;
//nst 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) {
@ -298,6 +373,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
toggle = true;
}
});
window.addEventListener("blur", () => {
console.log("%cWindow is not focused on /chat", color.red);
if (socket.id)
@ -305,6 +381,28 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
toggle = false;
});
// setInterval(async () => {
// //connected(socket);
// },10000); // every 10 seco
socket.on('listBud', (myBuddies: string) => {
const buddies = document.getElementById('div-buddies') as HTMLDivElement;
console.log('List buddies connected ', myBuddies);
listBuddies(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);
});
setTitle('Chat Page');
// Listen for the 'connect' event
return {
@ -336,16 +434,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
console.log('unknown response: ', value);
}
socket.once('welcome', (data) => {
chatWindow.textContent = '';
chatWindow.innerHTML = '';
buddies.textContent = '';
buddies.innerHTML = '';
connected(socket);
addMessage (`${data.msg} ` + getUser()?.name);
});
// Send button
sendButton?.addEventListener("click", () => {
if (sendtextbox && sendtextbox.value.trim()) {
@ -358,16 +446,32 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
broadcastMsg(socket, msgCommand);
break;
case '@who':
bwhoami.click();
break;
whoami(socket);
break;
case '@cls':
chatWindow.innerHTML = '';
break;
case '@quit':
bquit.click();
quitChat(socket);
break;
default:
addMessage('Command not known');
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,
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
@ -378,35 +482,15 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
// Clear Text button
clearText?.addEventListener("click", () => {
if (chatWindow) {
chatWindow.innerHTML = '';
}
});
bquit?.addEventListener('click', () => {
if (socket) {
logout(socket);
setTitle('Chat Page');
systemWindow.innerHTML = "";
chatWindow.textContent = "";
connected(socket);
} else {
getSocket();
}
quitChat(socket);
});
setInterval(async () => {
//connected(socket);
},10000); // every 10 second
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') {
@ -416,32 +500,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
// Whoami button to display user name
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);
});
}
}

View file

@ -83,6 +83,8 @@ declare module 'fastify' {
io: Server<{
hello: (message: string) => string;
MsgObjectServer: (data: { message: ClientMessage }) => void;
privMessage: (data: string) => void;
privMessageCopy: (msg: string) => void;
message: (msg: string) => void;
listBud: (msg: string) => void;
testend: (sock_id_client: string) => void;
@ -183,6 +185,33 @@ async function onReady(fastify: FastifyInstance) {
});
}
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;
}
let user: string = clientChat.get(s.id)?.user ?? "";
const atUser = `@${user}`;
if (atUser !== data.command || atUser === "") {
console.log(color.yellow, `User: '${atUser}' (No user the same is found): '${data.command}' `);
continue;
}
s.emit('MsgObjectServer', { message: data });
if (senderSocket)
senderSocket.emit('privMessageCopy',`${data.command}: ${data.text}🔒`);
// Debug logs
console.log(color.green, 'Priv to:', clientInfo.user);
}
});
}
fastify.io.on('connection', (socket: Socket) => {
socket.on('message', (message: string) => {
@ -337,6 +366,33 @@ async function onReady(fastify: FastifyInstance) {
}
});
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, 'PRIV MESSAGE OUT :', obj.SenderWindowID);
sendPrivMessage(obj, obj.SenderWindowID);
// clientChat.delete(obj.user);
}
});
socket.on('client_entered', (data) => {
// data may be undefined (when frontend calls emit with no payload)

View file

@ -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
View file

@ -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: {}