Socket Setup

This commit is contained in:
BhagwanSingh 2025-11-12 12:03:23 +05:30
parent d42a26ad8e
commit aa00c75edf
9 changed files with 574 additions and 38 deletions

340
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^2.10.1", "@reduxjs/toolkit": "^2.10.1",
"@tailwindcss/vite": "^4.1.16", "@tailwindcss/vite": "^4.1.16",
"active-win": "^7.2.0",
"axios": "^1.13.2", "axios": "^1.13.2",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"electron-store": "^11.0.2", "electron-store": "^11.0.2",
@ -22,11 +23,13 @@
"react-router-dom": "^7.9.5", "react-router-dom": "^7.9.5",
"recharts": "^2.12.7", "recharts": "^2.12.7",
"sharp": "^0.34.4", "sharp": "^0.34.4",
"tailwindcss": "^4.1.16" "socket.io-client": "^4.8.1",
"tailwindcss": "^4.1.16",
"windowmanager": "^0.14.8"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.47.2", "@playwright/test": "^1.47.2",
"@types/node": "^22.5.5", "@types/node": "^22.19.0",
"@types/os-utils": "^0.0.4", "@types/os-utils": "^0.0.4",
"@types/react": "^18.3.8", "@types/react": "^18.3.8",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
@ -2300,6 +2303,12 @@
"url": "https://github.com/sindresorhus/is?sponsor=1" "url": "https://github.com/sindresorhus/is?sponsor=1"
} }
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@standard-schema/spec": { "node_modules/@standard-schema/spec": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
@ -2758,14 +2767,22 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.5.5", "version": "22.19.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.0.tgz",
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "integrity": "sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==",
"devOptional": true, "devOptional": true,
"license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.19.2" "undici-types": "~6.21.0"
} }
}, },
"node_modules/@types/node/node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"devOptional": true,
"license": "MIT"
},
"node_modules/@types/os-utils": { "node_modules/@types/os-utils": {
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/@types/os-utils/-/os-utils-0.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/os-utils/-/os-utils-0.0.4.tgz",
@ -2987,6 +3004,24 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"devOptional": true "devOptional": true
}, },
"node_modules/active-win": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/active-win/-/active-win-7.2.0.tgz",
"integrity": "sha512-36fAH3MZinQ4dHQVa607P2woABkhgVxvSLBVGI7eK/M4Tx8LS+Gc+5fyx78MkAlM+RGV7wV9YnIx0lEuHERVZA==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
},
"optionalDependencies": {
"ffi-napi": "^4.0.3",
"ref-napi": "^3.0.2",
"ref-struct-napi": "^1.1.1",
"ref-wchar-napi": "^1.0.3"
}
},
"node_modules/agent-base": { "node_modules/agent-base": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@ -4526,7 +4561,6 @@
"version": "4.3.6", "version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
"devOptional": true,
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -5257,6 +5291,28 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"node_modules/engine.io-client": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.1.1"
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.18.3", "version": "5.18.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
@ -5572,6 +5628,32 @@
"pend": "~1.2.0" "pend": "~1.2.0"
} }
}, },
"node_modules/ffi-napi": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/ffi-napi/-/ffi-napi-4.0.3.tgz",
"integrity": "sha512-PMdLCIvDY9mS32RxZ0XGb95sonPRal8aqRhLbeEtWKZTe2A87qRFG9HjOhvG8EX2UmQw5XNRMIOT+1MYlWmdeg==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"debug": "^4.1.1",
"get-uv-event-loop-napi-h": "^1.0.5",
"node-addon-api": "^3.0.0",
"node-gyp-build": "^4.2.1",
"ref-napi": "^2.0.1 || ^3.0.2",
"ref-struct-di": "^1.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/ffi-napi/node_modules/node-addon-api": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
"license": "MIT",
"optional": true
},
"node_modules/filelist": { "node_modules/filelist": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
@ -5869,6 +5951,23 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/get-symbol-from-current-process-h": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/get-symbol-from-current-process-h/-/get-symbol-from-current-process-h-1.0.2.tgz",
"integrity": "sha512-syloC6fsCt62ELLrr1VKBM1ggOpMdetX9hTrdW77UQdcApPHLmf7CI7OKcN1c9kYuNxKcDe4iJ4FY9sX3aw2xw==",
"license": "MIT",
"optional": true
},
"node_modules/get-uv-event-loop-napi-h": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/get-uv-event-loop-napi-h/-/get-uv-event-loop-napi-h-1.0.6.tgz",
"integrity": "sha512-t5c9VNR84nRoF+eLiz6wFrEp1SE2Acg0wS+Ysa2zF0eROes+LzOfuTaVHxGy8AbS8rq7FHEJzjnCZo1BupwdJg==",
"license": "MIT",
"optional": true,
"dependencies": {
"get-symbol-from-current-process-h": "^1.0.1"
}
},
"node_modules/get-windows": { "node_modules/get-windows": {
"version": "9.2.3", "version": "9.2.3",
"resolved": "https://registry.npmjs.org/get-windows/-/get-windows-9.2.3.tgz", "resolved": "https://registry.npmjs.org/get-windows/-/get-windows-9.2.3.tgz",
@ -6528,6 +6627,21 @@
"ms": "^2.0.0" "ms": "^2.0.0"
} }
}, },
"node_modules/iconv": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/iconv/-/iconv-2.3.5.tgz",
"integrity": "sha512-U5ajDbtDfadp7pvUMC0F2XbkP5vQn9Xrwa6UptePl+cK8EILxapAt3sXers9B3Gxagk+zVjL2ELKuzQvyqOwug==",
"hasInstallScript": true,
"license": "ISC",
"optional": true,
"dependencies": {
"nan": "^2.14.0",
"safer-buffer": "^2.1.2"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/iconv-corefoundation": { "node_modules/iconv-corefoundation": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
@ -7981,8 +8095,14 @@
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
"devOptional": true },
"node_modules/nan": {
"version": "2.23.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.23.1.tgz",
"integrity": "sha512-r7bBUGKzlqk8oPBDYxt6Z0aEdF1G1rwlMcLk8LCOMbOzf0mG+JUfUzG4fIMWwHWP0iyaLWEQZJmtB7nOHEm/qw==",
"license": "MIT",
"optional": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.7",
@ -8114,6 +8234,18 @@
"node": "^12.13 || ^14.13 || >=16" "node": "^12.13 || ^14.13 || >=16"
} }
}, },
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"license": "MIT",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/node-gyp/node_modules/semver": { "node_modules/node-gyp/node_modules/semver": {
"version": "7.6.3", "version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@ -9134,6 +9266,129 @@
"redux": "^5.0.0" "redux": "^5.0.0"
} }
}, },
"node_modules/ref-napi": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/ref-napi/-/ref-napi-3.0.3.tgz",
"integrity": "sha512-LiMq/XDGcgodTYOMppikEtJelWsKQERbLQsYm0IOOnzhwE9xYZC7x8txNnFC9wJNOkPferQI4vD4ZkC0mDyrOA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"debug": "^4.1.1",
"get-symbol-from-current-process-h": "^1.0.2",
"node-addon-api": "^3.0.0",
"node-gyp-build": "^4.2.1"
},
"engines": {
"node": ">= 10.0"
}
},
"node_modules/ref-napi/node_modules/node-addon-api": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
"license": "MIT",
"optional": true
},
"node_modules/ref-struct-di": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ref-struct-di/-/ref-struct-di-1.1.1.tgz",
"integrity": "sha512-2Xyn/0Qgz89VT+++WP0sTosdm9oeowLP23wRJYhG4BFdMUrLj3jhwHZNEytYNYgtPKLNTP3KJX4HEgBvM1/Y2g==",
"license": "MIT",
"optional": true,
"dependencies": {
"debug": "^3.1.0"
}
},
"node_modules/ref-struct-di/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/ref-struct-napi": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ref-struct-napi/-/ref-struct-napi-1.1.1.tgz",
"integrity": "sha512-YgS5/d7+kT5zgtySYI5ieH0hREdv+DabgDvoczxsui0f9VLm0rrDcWEj4DHKehsH+tJnVMsLwuyctWgvdEcVRw==",
"license": "MIT",
"optional": true,
"dependencies": {
"debug": "2",
"ref-napi": "^1.4.2"
}
},
"node_modules/ref-struct-napi/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"optional": true,
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/ref-struct-napi/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT",
"optional": true
},
"node_modules/ref-struct-napi/node_modules/node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
"license": "MIT",
"optional": true
},
"node_modules/ref-struct-napi/node_modules/ref-napi": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/ref-napi/-/ref-napi-1.5.2.tgz",
"integrity": "sha512-hwyNmWpUkt1bDWDW4aiwCoC+SJfJO69UIdjqssNqdaS0sYJpgqzosGg/rLtk69UoQ8drZdI9yyQefM7eEMM3Gw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"debug": "^3.1.0",
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.1"
},
"engines": {
"node": ">= 6.0"
}
},
"node_modules/ref-struct-napi/node_modules/ref-napi/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/ref-struct-napi/node_modules/ref-napi/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT",
"optional": true
},
"node_modules/ref-wchar-napi": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/ref-wchar-napi/-/ref-wchar-napi-1.0.3.tgz",
"integrity": "sha512-rx8b0pVfz/jShQPS288Rox/A0DQkcw6La+4YC3FgV4F9KUQ/VTxFrVpKOKGuj5yBvVoHdejbX6/BlHSkKHj9Lg==",
"license": "MIT",
"optional": true,
"dependencies": {
"iconv": "2",
"ref-napi": "^3.0.1"
}
},
"node_modules/regenerator-runtime": { "node_modules/regenerator-runtime": {
"version": "0.14.1", "version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
@ -9388,7 +9643,7 @@
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true "devOptional": true
}, },
"node_modules/sanitize-filename": { "node_modules/sanitize-filename": {
"version": "1.6.3", "version": "1.6.3",
@ -9688,6 +9943,34 @@
"npm": ">= 3.0.0" "npm": ">= 3.0.0"
} }
}, },
"node_modules/socket.io-client": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.6.1",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socks": { "node_modules/socks": {
"version": "2.8.3", "version": "2.8.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
@ -10354,7 +10637,7 @@
"version": "6.19.8", "version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"devOptional": true "dev": true
}, },
"node_modules/unique-filename": { "node_modules/unique-filename": {
"version": "2.0.1", "version": "2.0.1",
@ -10746,6 +11029,12 @@
"string-width": "^1.0.2 || 2 || 3 || 4" "string-width": "^1.0.2 || 2 || 3 || 4"
} }
}, },
"node_modules/windowmanager": {
"version": "0.14.8",
"resolved": "https://registry.npmjs.org/windowmanager/-/windowmanager-0.14.8.tgz",
"integrity": "sha512-USYABhvy9hce52h9p6h+8LSGhA0ypm/wuydnUm0nAaukPnWyfGByZs+eJAzfE4udVLDykIdZX3YzMk/lTHkgKw==",
"license": "MIT"
},
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@ -10853,6 +11142,27 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"devOptional": true "devOptional": true
}, },
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlbuilder": { "node_modules/xmlbuilder": {
"version": "15.1.1", "version": "15.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
@ -10862,6 +11172,14 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/xmlhttprequest-ssl": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@ -20,6 +20,7 @@
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^2.10.1", "@reduxjs/toolkit": "^2.10.1",
"@tailwindcss/vite": "^4.1.16", "@tailwindcss/vite": "^4.1.16",
"active-win": "^7.2.0",
"axios": "^1.13.2", "axios": "^1.13.2",
"chalk": "^5.6.2", "chalk": "^5.6.2",
"electron-store": "^11.0.2", "electron-store": "^11.0.2",
@ -32,11 +33,13 @@
"react-router-dom": "^7.9.5", "react-router-dom": "^7.9.5",
"recharts": "^2.12.7", "recharts": "^2.12.7",
"sharp": "^0.34.4", "sharp": "^0.34.4",
"tailwindcss": "^4.1.16" "socket.io-client": "^4.8.1",
"tailwindcss": "^4.1.16",
"windowmanager": "^0.14.8"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.47.2", "@playwright/test": "^1.47.2",
"@types/node": "^22.5.5", "@types/node": "^22.19.0",
"@types/os-utils": "^0.0.4", "@types/os-utils": "^0.0.4",
"@types/react": "^18.3.8", "@types/react": "^18.3.8",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",

View File

@ -1,10 +1,8 @@
import { ipcMain, BrowserWindow } from "electron"; import { ipcMain, BrowserWindow } from "electron";
import { getToken, saveToken, clearToken } from "../utils/tokenHelper.js"; import { getToken, saveToken, clearToken } from "../utils/tokenHelper.js";
import { getActiveApp, handleLogin, takeScreenshot, startWindowPolling } from "../utils/utilityFunctions.js"; import { getActiveApp, handleLogin, takeScreenshot, startWindowPolling, getRunningAppsList, captureSpecificApp } from "../utils/utilityFunctions.js";
import api from "../api/axiosClient.js"; import api from "../api/axiosClient.js";
import { getMainWindow } from '../main.js'; import { getMainWindow } from '../main.js';
import { exec } from 'child_process';
export const registerIPCHandlers = (mainWindow: BrowserWindow) => { export const registerIPCHandlers = (mainWindow: BrowserWindow) => {
console.log("⚙️ Registering IPC Handlers..."); console.log("⚙️ Registering IPC Handlers...");
@ -53,18 +51,25 @@ export const registerIPCHandlers = (mainWindow: BrowserWindow) => {
const mainWindow = getMainWindow() const mainWindow = getMainWindow()
console.log("toggle-close-btn Called", mainWindow) console.log("toggle-close-btn Called", mainWindow)
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.setClosable(shouldEnable); mainWindow.setClosable(shouldEnable);
} }
}); });
ipcMain.handle('resize-window', (event, width: number, height: number) => { ipcMain.handle('resize-window', (event, width: number, height: number) => {
const mainWindow = getMainWindow() const mainWindow = getMainWindow()
console.log("toggle-close-btn Called", mainWindow) console.log("toggle-close-btn Called", mainWindow)
// if (mainWindow && !mainWindow.isDestroyed()) { // if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.setSize(width, height); mainWindow.setSize(width, height);
// } // }
}) })
// ✅ Start background polling when main window is ready
}; };
// startWindowPolling(mainWindow);
ipcMain.handle('get-running-apps', async () => {
return await getRunningAppsList()
});
ipcMain.handle('capture-specific-window', async (event, appTitle: string) => {
console.log(appTitle, "IPC HANDLE")
return await captureSpecificApp(appTitle)
});

View File

@ -8,6 +8,13 @@ import { registerIPCHandlers } from './ipc/ipcHandler.js';
let mainWindow:any = null; let mainWindow:any = null;
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
// Prevent the default behavior of showing a certificate error dialog
event.preventDefault();
// Allow the certificate, effectively ignoring the error
callback(true);
});
app.on('ready', async () => { app.on('ready', async () => {
console.log("ready"); console.log("ready");

View File

@ -10,6 +10,8 @@ contextBridge.exposeInMainWorld('electron', {
getActiveAppDetails: () => ipcRenderer.invoke('get-active-app'), getActiveAppDetails: () => ipcRenderer.invoke('get-active-app'),
toggleCloseBtn: (shouldEnable: boolean) => ipcRenderer.invoke('toggle-close-btn', shouldEnable), toggleCloseBtn: (shouldEnable: boolean) => ipcRenderer.invoke('toggle-close-btn', shouldEnable),
resizeWindow: (width: number, height: number) => ipcRenderer.invoke('resize-window', width, height), resizeWindow: (width: number, height: number) => ipcRenderer.invoke('resize-window', width, height),
getRunningApps: () => ipcRenderer.invoke('get-running-apps'),
captureAppScreenShot: (appTitle: string) : Promise<string> => ipcRenderer.invoke('capture-specific-window', appTitle),
onWindowUpdate: (callback) => onWindowUpdate: (callback) =>
ipcRenderer.on("window:updated", (_, data) => callback(data)), ipcRenderer.on("window:updated", (_, data) => callback(data)),
} satisfies Window['electron']); } satisfies Window['electron']);

View File

@ -5,6 +5,7 @@ import axios from 'axios';
import sharp from 'sharp'; import sharp from 'sharp';
import { saveToken } from "./tokenHelper.js"; import { saveToken } from "./tokenHelper.js";
import { activeWindow } from "get-windows"; import { activeWindow } from "get-windows";
import { exec } from "child_process";
// Blur using an offscreen canvas // Blur using an offscreen canvas
async function blurAndCompressBase64Image(base64: string): Promise<Buffer> { async function blurAndCompressBase64Image(base64: string): Promise<Buffer> {
@ -97,21 +98,81 @@ export const handleLogin = async (credentials: { email: string, password: string
// Get active window info with timestamp // Get active window info with timestamp
export const getActiveApp = async () => { export const getActiveApp = async () => {
const result = await activeWindow(); const result = await activeWindow();
const dataWithTime = { ...result, timestamp: new Date().toISOString() }; const dataWithTime = { ...result, timestamp: new Date().toISOString() };
// console.log("🪟 Active Window with Time:", dataWithTime); // console.log("🪟 Active Window with Time:", dataWithTime);
return dataWithTime; return dataWithTime;
}; };
// Periodically send active window updates // Periodically send active window updates
export const startWindowPolling = (win: BrowserWindow) => { export const startWindowPolling = (win: BrowserWindow) => {
console.log("⏱️ Started active window polling (every 5s)"); console.log("⏱️ Started active window polling (every 5s)");
setInterval(async () => { setInterval(async () => {
try { try {
const app = await getActiveApp(); const app = await getActiveApp();
if (app) win.webContents.send("window:updated", app); if (app) win.webContents.send("window:updated", app);
} catch (err) { } catch (err) {
console.error("❌ Polling error:", err); console.error("❌ Polling error:", err);
} }
}, 5000); }, 5000);
}; };
export const getRunningAppsList = async () => {
try {
// PowerShell command: Get only apps with visible windows (non-background)
const sources = await desktopCapturer.getSources({
types: ['window', 'screen'],
thumbnailSize: { width: 150, height: 150 } // Optional: set thumbnail size
});
const app = sources.map(source => ({
name: source.name,
pid: source.id,
// thumbnail: source.thumbnail // Can be used as screenshot
}));
return app
} catch (error) {
return []
}
}
export const captureSpecificApp = async (windowTitle: string) : Promise<string> => {
try {
const sources = await desktopCapturer.getSources({
types: ['window', 'screen'],
thumbnailSize: { width: 650, height: 430 }
});
const targetSource = sources.find(source => source.name === windowTitle);
if (targetSource) {
let image = targetSource.thumbnail.toDataURL();
const blurredBuffer = await blurAndCompressBase64Image(image);
// Convert buffer → base64 string
const base64String = `data:image/png;base64,${blurredBuffer.toString('base64')}`;
// ✅ Return the processed base64 instead of saving
return base64String;
// const folderPath = "C:\\Users\\Public\\vatracker\\screenshots";
// // Ensure directory exists
// if (!fs.existsSync(folderPath)) {
// fs.mkdirSync(folderPath, { recursive: true });
// }
// const filePath = path.join(folderPath, `screenshot-${Date.now()}.png`);
// fs.writeFileSync(filePath, blurredBuffer);
// console.log(`Screenshot saved to ${filePath}`);
} else {
console.log(`Window with title "${windowTitle}" not found.`);
return "Not Found"
}
} catch (error) {
console.error('Error capturing screenshot:', error);
return 'Failed to capture screenshot.';
}
}

View File

@ -1,4 +1,6 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
import io, { Socket } from 'socket.io-client';
import { import {
Outlet, Outlet,
NavLink, NavLink,
@ -93,6 +95,11 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
useActiveAppTracker(isTracking, selectedProject?.id, selectedProject?.projectName); useActiveAppTracker(isTracking, selectedProject?.id, selectedProject?.projectName);
const socketRef = useRef<Socket | null>(null);
const intervalRef = useRef<number | null>(null);
const [isConnected, setIsConnected] = useState(false);
// const [seclectedScreen, setSelectedScreen] = useState<string | null>(null)
const [projectsData, setProjectsData] = useState<Project[]>([ const [projectsData, setProjectsData] = useState<Project[]>([
{ id: 1, projectName: "CRM Redesign", clientName: "Salesforce" }, { id: 1, projectName: "CRM Redesign", clientName: "Salesforce" },
{ id: 2, projectName: "AI Assistant", clientName: "OpenAI" }, { id: 2, projectName: "AI Assistant", clientName: "OpenAI" },
@ -116,6 +123,77 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
} }
}; };
// Connect and start sending
const handleConnect = () => {
if (socketRef.current) {
console.warn("Already connected");
return;
}
if(!selectedProject?.id) return
console.log(selectedProject?.id, "SelectedProject ID")
socketRef.current = io("http://localhost:3000", {
transports: ["websocket"],
auth: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY5MGIzMjhkMDkxMDFmNzRjZjUyNGMwNyIsImVtYWlsIjoiYmhhZ3dhbi5yQGhpY2dsb2JhbHNvbHV0aW9ucy5jb20iLCJuYW1lIjoiUm9oaXQiLCJpYXQiOjE3NjI4NTgxOTMsImV4cCI6MTc2Mjk0NDU5M30.UlHy3RU9W5LOid7smG7WzyNT7dnqhQT4qqzRrN1axmU",
projectId: selectedProject?.id,
userType: "va"
},
});
socketRef.current.on("connect", () => {
console.log("🟢 Connected:", socketRef.current?.id);
setIsConnected(true);
// Start sending every 5 seconds
intervalRef.current = setInterval(async () => {
const apps = await window.electron.getRunningApps()
socketRef.current?.emit("getVisibleApps", { token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY5MGIzMjhkMDkxMDFmNzRjZjUyNGMwNyIsImVtYWlsIjoiYmhhZ3dhbi5yQGhpY2dsb2JhbHNvbHV0aW9ucy5jb20iLCJuYW1lIjoiUm9oaXQiLCJpYXQiOjE3NjI4NTgxOTMsImV4cCI6MTc2Mjk0NDU5M30.UlHy3RU9W5LOid7smG7WzyNT7dnqhQT4qqzRrN1axmU", apps });
// const base64String = await window.electron.captureAppScreenShot("Screen 1");
// if (base64String) {
// socketRef.current?.emit("sendImage", {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY5MGIzMjhkMDkxMDFmNzRjZjUyNGMwNyIsImVtYWlsIjoiYmhhZ3dhbi5yQGhpY2dsb2JhbHNvbHV0aW9ucy5jb20iLCJuYW1lIjoiUm9oaXQiLCJpYXQiOjE3NjI4NTgxOTMsImV4cCI6MTc2Mjk0NDU5M30.UlHy3RU9W5LOid7smG7WzyNT7dnqhQT4qqzRrN1axmU", image: base64String, title: "Screen 1"});
// }
}, 5000);
});
socketRef.current.on("appToCapture", async ({ appTitle }) => {
console.log("📸 Capture requested for:", appTitle);
const base64String = await window.electron.captureAppScreenShot(appTitle);
if (base64String && socketRef.current) {
socketRef.current.emit("sendImage", {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY5MGIzMjhkMDkxMDFmNzRjZjUyNGMwNyIsImVtYWlsIjoiYmhhZ3dhbi5yQGhpY2dsb2JhbHNvbHV0aW9ucy5jb20iLCJuYW1lIjoiUm9oaXQiLCJpYXQiOjE3NjI4NTgxOTMsImV4cCI6MTc2Mjk0NDU5M30.UlHy3RU9W5LOid7smG7WzyNT7dnqhQT4qqzRrN1axmU",
image: base64String,
title: appTitle
});
}
});
socketRef.current.on("disconnect", () => {
console.log("🔴 Disconnected");
setIsConnected(false);
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
});
};
const handleDisconnect = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
if (socketRef.current) {
socketRef.current.disconnect();
socketRef.current = null;
setIsConnected(false);
console.log("🔌 Disconnected manually");
}
};
const menuItems = [ const menuItems = [
{ label: "Dashboard", path: "/dashboard", icon: <Home size={18} />, exact: true }, { label: "Dashboard", path: "/dashboard", icon: <Home size={18} />, exact: true },
@ -154,7 +232,6 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
const currentSessionTime = Math.floor((now - startTimestamp) / 1000); const currentSessionTime = Math.floor((now - startTimestamp) / 1000);
const totalPausedTime = current.totalPausedTime || 0; const totalPausedTime = current.totalPausedTime || 0;
// FIX: Add accumulated time from previous sessions
const calculatedElapsed = const calculatedElapsed =
(current.accumulatedTime || 0) + currentSessionTime - totalPausedTime; (current.accumulatedTime || 0) + currentSessionTime - totalPausedTime;
@ -276,7 +353,6 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
const current = updated.get(selectedProject.id); const current = updated.get(selectedProject.id);
if (!current) return updated; if (!current) return updated;
// FIX: Store current elapsed time as accumulated time
current.accumulatedTime = current.elapsedTime; current.accumulatedTime = current.elapsedTime;
current.isTracking = false; current.isTracking = false;
current.isPaused = false; current.isPaused = false;
@ -359,6 +435,21 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
{/* Header */} {/* Header */}
<header className="w-full flex justify-between items-center h-12 px-6 bg-base-100 border-b border-base-300 sticky top-0 z-30"> <header className="w-full flex justify-between items-center h-12 px-6 bg-base-100 border-b border-base-300 sticky top-0 z-30">
{/* Left Section */} {/* Left Section */}
{!isConnected ? (
<button
onClick={handleConnect}
className="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded"
>
Connect
</button>
) : (
<button
onClick={handleDisconnect}
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded"
>
Disconnect
</button>
)}
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
{selectedProject ? ( {selectedProject ? (
isTracking ? ( isTracking ? (

View File

@ -1,4 +1,4 @@
import React, { useRef } from "react"; import React, { useEffect, useRef, useState } from "react";
import { Clock, TrendingUp, Play, Square, ProjectorIcon, Pause } from "lucide-react"; import { Clock, TrendingUp, Play, Square, ProjectorIcon, Pause } from "lucide-react";
import { useOutletContext } from "react-router-dom"; import { useOutletContext } from "react-router-dom";
@ -87,11 +87,32 @@ const Dashboard: React.FC = () => {
projectsData, projectsData,
} = useOutletContext<TrackingState>(); } = useOutletContext<TrackingState>();
// interface AppsListInt {
// name: string;
// pid: string;
// title: string;
// }
// const [runningApps, setRunningApps] = useState<AppsListInt[]>([]);
const selectedData = selectedProject const selectedData = selectedProject
? projectTrackingMap.get(selectedProject.id) ? projectTrackingMap.get(selectedProject.id)
: null; : null;
// const getRunningApps = async () => {
// const res = await window.electron.getRunningApps()
// const appsList: AppsListInt[] = Array.isArray(res) ? res : [];
// setRunningApps(appsList)
// }
// useEffect(() => {
// setInterval(() => {
// getRunningApps();
// }, 5000)
// }, [])
return ( return (
@ -107,6 +128,32 @@ const Dashboard: React.FC = () => {
> >
Screenshot Test Screenshot Test
</button> </button>
{/* {
runningApps && runningApps.map((obj) => {
return (
<div
key={obj.pid}
onClick={async () => {
console.log("Call ", obj.name)
await window.electron.captureAppScreenShot(obj.name)
}}
>
{obj.name}
</div>
)
})
} */}
</div> </div>
{/* Widgets */} {/* Widgets */}

2
types.d.ts vendored
View File

@ -32,6 +32,8 @@ interface Window {
getActiveAppDetails: () => {}; getActiveAppDetails: () => {};
toggleCloseBtn: (shouldEnable: boolean) => {}, toggleCloseBtn: (shouldEnable: boolean) => {},
resizeWindow: (width: number, height: number) => {}, resizeWindow: (width: number, height: number) => {},
getRunningApps: () => {},
captureAppScreenShot: (appTitle: string) => Promise<string>,
onWindowUpdate: (callback: (data: any) => void) => void; onWindowUpdate: (callback: (data: any) => void) => void;
}; };
} }