diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index eb43dce..9c3bccd 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -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; + } \ No newline at end of file diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index 62659b4..8d380f1 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -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 { return new Promise(resolve => { @@ -141,6 +155,27 @@ function waitSocketConnected(socket: Socket): Promise { }); }; +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 { - 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); }); } } diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index 733ba7f..a798de2 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -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) 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: {}