diff --git a/integration/landing.html b/integration/landing.html index 1fa8204..06cb867 100644 --- a/integration/landing.html +++ b/integration/landing.html @@ -9,7 +9,16 @@ diff --git a/package-lock.json b/package-lock.json index 935f41f..64871b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "call-me", - "version": "1.2.75", + "version": "1.2.76", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "call-me", - "version": "1.2.75", + "version": "1.2.76", "license": "AGPLv3", "dependencies": { "@ngrok/ngrok": "1.6.0", @@ -14,7 +14,7 @@ "colors": "^1.4.0", "cors": "^2.8.5", "dotenv": "^17.2.3", - "express": "^5.1.0", + "express": "^5.2.1", "helmet": "^8.1.0", "httpolyglot": "0.1.2", "js-yaml": "4.1.1", @@ -23,7 +23,7 @@ }, "devDependencies": { "nodemon": "^3.1.11", - "prettier": "3.6.2" + "prettier": "3.7.4" } }, "node_modules/@ngrok/ngrok": { @@ -359,29 +359,33 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/body-parser/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -741,18 +745,19 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -1095,19 +1100,23 @@ } }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/httpolyglot": { @@ -1119,15 +1128,19 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ignore-by-default": { @@ -1396,9 +1409,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "license": "MIT", "bin": { @@ -1460,18 +1473,18 @@ } }, "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/readdirp": { @@ -1758,9 +1771,9 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -1851,15 +1864,19 @@ } }, "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/undefsafe": { diff --git a/package.json b/package.json index 04687d1..bbc0c94 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "call-me", - "version": "1.2.75", + "version": "1.2.76", "description": "Your Go-To for Instant Video Calls", "author": "Miroslav Pejic - miroslav.pejic.85@gmail.com", "license": "AGPLv3", @@ -24,7 +24,7 @@ "colors": "^1.4.0", "cors": "^2.8.5", "dotenv": "^17.2.3", - "express": "^5.1.0", + "express": "^5.2.1", "helmet": "^8.1.0", "httpolyglot": "0.1.2", "js-yaml": "4.1.1", @@ -33,6 +33,6 @@ }, "devDependencies": { "nodemon": "^3.1.11", - "prettier": "3.6.2" + "prettier": "3.7.4" } } diff --git a/public/client.js b/public/client.js index 7e3e2d0..cdd8618 100755 --- a/public/client.js +++ b/public/client.js @@ -767,7 +767,7 @@ async function startScreenSharing() { stopScreenSharing(); }; - toast('Screen sharing started', 'success', 'top-end', 2000); + toast('Screen sharing started', 'success', 'top', 2000); console.log('Screen sharing started'); } catch (error) { if (error.name === 'NotAllowedError') { @@ -848,7 +848,7 @@ async function stopScreenSharing() { // Ensure UI button state matches actual video state checkVideoAudioStatus(); - toast('Screen sharing stopped', 'success', 'top-end', 2000); + toast('Screen sharing stopped', 'success', 'top', 2000); console.log('Screen sharing stopped'); } catch (error) { handleError('Failed to stop screen sharing', error.message); @@ -1805,10 +1805,12 @@ if (chatForm && chatInput) { chatForm.addEventListener('submit', (e) => { e.preventDefault(); const text = chatInput.value.trim(); - if (text.length > 0) { + if (text.length > 0 && allConnectedUsers.length > 0) { socket.emit('message', { type: 'chat', text }); addChatMessage({ from: userName || 'Me', text, timestamp: Date.now() }, true); chatInput.value = ''; + } else { + toast('Cannot send empty message or no user connected', 'warning', 'top', 2000); } }); } @@ -1845,7 +1847,7 @@ function addChatMessage(msg, isSelf = false) { // Show toast notification for new messages only if sidebar is not opened if (!userSidebar.classList.contains('active')) { - toast(`New message from ${msg.from}`, 'info', 'top-end', 2000); + toast(`New message from ${msg.from}`, 'info', 'top', 2000); } } } @@ -1971,7 +1973,7 @@ function handleSaveChatClick() { const chatText = generateChatExportText(); if (!chatText) { - toast('No chat messages to save', 'info', 'top-end', 2000); + toast('No chat messages to save', 'info', 'top', 2000); return; } @@ -1980,13 +1982,13 @@ function handleSaveChatClick() { downloadTextAsFile(chatText, fileName); - toast(`Chat messages saved as ${fileName}`, 'success', 'top-end', 3000); + toast(`Chat messages saved as ${fileName}`, 'success', 'top', 3000); } // Handle clear chat button click function handleClearChatClick() { if (!thereAreChatMessages()) { - toast('No chat messages to clear', 'info', 'top-end', 2000); + toast('No chat messages to clear', 'info', 'top', 2000); return; } @@ -2010,7 +2012,7 @@ function handleClearChatClick() { updateChatNotification(); // Show success message - toast('Chat messages cleared successfully', 'success', 'top-end', 2000); + toast('Chat messages cleared successfully', 'success', 'top', 2000); } }); } @@ -2201,7 +2203,7 @@ async function refreshDevices(showToast = true) { await enumerateDevices(); updateUIForAvailableDevices(); if (showToast) { - toast('Devices refreshed successfully', 'success', 'top-end', 2000); + toast('Devices refreshed successfully', 'success', 'top', 2000); } } catch (error) { console.error('Error refreshing devices:', error); @@ -2220,7 +2222,7 @@ async function handleVideoDeviceChange() { selectedDevices.videoInput = newDeviceId; await updateVideoStream(); updateUIForAvailableDevices(); - toast('Camera changed successfully', 'success', 'top-end', 2000); + toast('Camera changed successfully', 'success', 'top', 2000); } } @@ -2230,7 +2232,7 @@ async function handleAudioDeviceChange() { selectedDevices.audioInput = newDeviceId; await updateAudioStream(); updateUIForAvailableDevices(); - toast('Microphone changed successfully', 'success', 'top-end', 2000); + toast('Microphone changed successfully', 'success', 'top', 2000); } } @@ -2239,7 +2241,7 @@ async function handleAudioOutputDeviceChange() { if (newDeviceId && newDeviceId !== selectedDevices.audioOutput) { selectedDevices.audioOutput = newDeviceId; await setAudioOutputDevice(newDeviceId); - toast('Speaker changed successfully', 'success', 'top-end', 2000); + toast('Speaker changed successfully', 'success', 'top', 2000); } } @@ -2364,7 +2366,7 @@ async function setAudioOutputDevice(deviceId) { selectedDevices.audioOutput = deviceId; } else { console.warn('Browser does not support audio output device selection'); - toast('Audio output selection not supported in this browser', 'warning', 'top-end', 3000); + toast('Audio output selection not supported in this browser', 'warning', 'top', 3000); } } catch (error) { console.error('Error setting audio output device:', error); @@ -2384,7 +2386,7 @@ async function testDevices() { const hasMic = availableDevices.audioInputs.length > 0; if (!hasCamera && !hasMic) { - toast('No devices available to test', 'warning', 'top-end', 2000); + toast('No devices available to test', 'warning', 'top', 2000); return; } @@ -2414,7 +2416,7 @@ async function testDevices() { // Test for 2 seconds then stop setTimeout(() => { testStream.getTracks().forEach((track) => track.stop()); - toast('Device test completed successfully', 'success', 'top-end', 2000); + toast('Device test completed successfully', 'success', 'top', 2000); }, 2000); } catch (error) { console.error('Error testing devices:', error);