This commit is contained in:
2025-08-29 10:17:33 +05:30
11 changed files with 856 additions and 14 deletions

5
.env
View File

@@ -1,6 +1,7 @@
MONGO_URI=mongodb://192.168.0.111/
MONGO_URI=mongodb://192.168.0.113/
MONGO_USER=mydata
MONGO_PASSWORD=mongodb@hexr2002
MONGO_AUTH_DB=admin
API_PORT=9696
API_PORT=9696
SOCKET_PORT=8002

362
package-lock.json generated
View File

@@ -11,16 +11,19 @@
"dependencies": {
"body-parser": "^2.2.0",
"cors": "^2.8.5",
"dotenv": "^17.2.0",
"dotenv": "^16.4.5",
"express": "^5.1.0",
"fs": "^0.0.1-security",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.16.3",
"nodemon": "^3.1.10",
"path": "^0.12.7"
"path": "^0.12.7",
"socket.io": "^4.8.1"
},
"devDependencies": {
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.0.14"
}
},
@@ -32,6 +35,11 @@
"sparse-bitfield": "^3.0.3"
}
},
"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=="
},
"node_modules/@types/body-parser": {
"version": "1.19.6",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
@@ -55,7 +63,6 @@
"version": "2.8.19",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
@@ -89,17 +96,32 @@
"integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
"dev": true
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.10",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
"integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
"dev": true,
"dependencies": {
"@types/ms": "*",
"@types/node": "*"
}
},
"node_modules/@types/mime": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"dev": true
},
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
"dev": true
},
"node_modules/@types/node": {
"version": "24.0.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz",
"integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==",
"dev": true,
"dependencies": {
"undici-types": "~7.8.0"
}
@@ -179,6 +201,14 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"engines": {
"node": "^4.5.0 || >= 5.9"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -237,6 +267,11 @@
"node": ">=16.20.1"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -372,9 +407,9 @@
}
},
"node_modules/dotenv": {
"version": "17.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.0.tgz",
"integrity": "sha512-Q4sgBT60gzd0BB0lSyYD3xM4YxrXA9y4uBDof1JNYGzOXrQdQ6yX+7XIAqoFOGQFOTK1D3Hts5OllpxMDZFONQ==",
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"engines": {
"node": ">=12"
},
@@ -395,6 +430,14 @@
"node": ">= 0.4"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -408,6 +451,88 @@
"node": ">= 0.8"
}
},
"node_modules/engine.io": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1"
},
"engines": {
"node": ">=10.2.0"
}
},
"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==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/engine.io/node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/engine.io/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
@@ -740,6 +865,46 @@
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jwa": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kareem": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
@@ -748,6 +913,41 @@
"node": ">=12.0.0"
}
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -1280,6 +1480,131 @@
"node": ">=10"
}
},
"node_modules/socket.io": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"cors": "~2.8.5",
"debug": "~4.3.2",
"engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.2.0"
}
},
"node_modules/socket.io-adapter": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
"dependencies": {
"debug": "~4.3.4",
"ws": "~8.17.1"
}
},
"node_modules/socket.io-adapter/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"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==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io/node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/socket.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/socket.io/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/socket.io/node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
@@ -1366,8 +1691,7 @@
"node_modules/undici-types": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
"dev": true
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="
},
"node_modules/unpipe": {
"version": "1.0.0",
@@ -1422,6 +1746,26 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"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
}
}
}
}
}

View File

@@ -6,23 +6,27 @@
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start:api": "nodemon --exec tsx src/api-server/main.ts"
"start:api": "nodemon --exec tsx src/api-server/main.ts",
"start:socket": "nodemon --exec tsx src/socket-server/index.ts"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^2.2.0",
"cors": "^2.8.5",
"dotenv": "^17.2.0",
"dotenv": "^16.4.5",
"express": "^5.1.0",
"fs": "^0.0.1-security",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.16.3",
"nodemon": "^3.1.10",
"path": "^0.12.7"
"path": "^0.12.7",
"socket.io": "^4.8.1"
},
"devDependencies": {
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.0.14"
}
}

View File

@@ -0,0 +1,134 @@
import { Socket, Server } from "socket.io";
import { EVENTS } from "../events/events";
import { ErrorResponse, FinalResponse, validateFields } from "../utils/socketfunctionHelpers";
import { emitToSenderAndAdmins } from "../utils/emitEventResponse";
import { deleteEdge, edgecreation } from "../../shared/services/edgeService";
export const edgeHandleEvent = async (
event: string,
socket: Socket,
io: Server,
data: any,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.edgeConnect || !data?.organization) return;
const requiredFields = [
"from",
"to",
"projectId",
"organization",
];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.edgeConnectResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await edgecreation(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "edge Created Successfully" },
"User not found": { message: "User not found" },
"Project not found": { message: "Project not found" },
"From collection not found": {
message: "From collection not found",
},
"To collection not found": { message: "To collection not found" },
"Field already exists": { message: "Field already exists" },
};
const msg = messages[status] || { message: "Internal server error" };
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
console.log('result_Datas: ', result_Datas);
const response = FinalResponse(
status,
socket,
data.organization,
messages,
result_Datas
);
console.log('response: ', response);
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.edgeConnectResponse,
response,
connectedUsersByOrg
);
};
export const deleteEdgeHandleEvent = async (
event: string,
socket: Socket,
io: Server,
data: any,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.deleteEdgeConnect || !data?.organization) return;
const requiredFields = [
"edgeId",
"projectId",
"organization",
];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.deleteEdgeConnectResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await deleteEdge(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "edge deleted Successfully" },
"edge not found": { message: "edge not found" },
"Project not found": { message: "Project not found" },
};
const result_Datas = status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
data.organization,
messages,
result_Datas
);
console.log('response: ', response);
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.edgeConnectResponse,
response,
connectedUsersByOrg
);
};

View File

@@ -0,0 +1,70 @@
import { Socket, Server } from "socket.io";
import { EVENTS } from "../events/events";
import { ErrorResponse, FinalResponse, validateFields } from "../utils/socketfunctionHelpers";
import { emitToSenderAndAdmins } from "../utils/emitEventResponse";
import { projectCreationService } from "../../shared/services/projectService";
export const projectHandleEvent = async (
event: string,
socket: Socket,
io: Server,
data: any,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
if (event !== EVENTS.ProjectCreate || !data?.organization) return;
const requiredFields = [
"application",
"architecture",
"apiType",
"projectName",
"useableLanguage",
"organization",
];
const missingFields = validateFields(data, requiredFields);
if (missingFields.length > 0) {
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.ProjectCreateResponse,
ErrorResponse(missingFields, socket, data.organization),
connectedUsersByOrg
);
return;
}
const result = await projectCreationService(data);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
Success: { message: "Project Created Successfully" },
"Project Already Exists": { message: "Project Already Exists" },
"Already MVC architecture assigned to this projectId": { message: "Already MVC architecture assigned to this projectId" },
"Project creation unsuccessfull": {
message: "Project creation unsuccessfull",
},
"New architecture": { message: "New architecture" },
};
const result_Datas =
status === "Success" && result?.data ? result.data : undefined;
const response = FinalResponse(
status,
socket,
data.organization,
messages,
result_Datas
);
emitToSenderAndAdmins(
io,
socket,
data.organization,
EVENTS.ProjectCreateResponse,
response,
connectedUsersByOrg
);
};

View File

@@ -0,0 +1,8 @@
import { edgeHandleEvent } from "../controllers/edgeController";
import { projectHandleEvent } from "../controllers/projectController";
import { EVENTS } from "./events";
export const eventHandlerMap: Record<string, Function> = {
[EVENTS.edgeConnect]: edgeHandleEvent,
[EVENTS.ProjectCreate]: projectHandleEvent,
};

View File

@@ -0,0 +1,22 @@
export const EVENTS = {
connection: "connection",
disconnect: "disconnect",
userConnect: "userConnectResponse",
userDisConnect: "userDisConnectResponse",
joinRoom: "joinRoom",
createroom: "createRoom",
leaveRoom: "leaveRoom",
roomCreated: "roomCreated",
roomDeleted: "roomDeleted",
edgeConnect:"v1:edge:connect",
edgeConnectResponse:"v1:response:edge:connect",
deleteEdgeConnect:"v1:edge:deleteConnect",
deleteEdgeConnectResponse:"v1:response:edge:deleteConnect",
ProjectCreate:"v1:project:create",
ProjectCreateResponse:"v1:response:project:create",
}

View File

@@ -0,0 +1,32 @@
import express, { Response, Request } from "express";
import http from "http";
import dotenv from "dotenv";
import { Server } from "socket.io";
import cors from "cors";
import { SocketServer } from "./manager/manager";
dotenv.config();
const app = express();
const PORT = process.env.SOCKET_PORT;
const server = http.createServer(app);
app.use(cors());
app.use(express.json());
app.get("/", (req: Request, res: Response) => {
res.send("Hello, I am autoCode RealTime!");
});
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
SocketServer(io);
server.listen(PORT, () => {
console.log(`socket-Server is running on http://localhost:${PORT}`);
});

View File

@@ -0,0 +1,82 @@
import { Server, Socket } from "socket.io";
import jwt from "jsonwebtoken";
import { eventHandlerMap } from "../events/eventHandaler";
interface UserPayload {
userId: string;
organization: string;
[key: string]: any;
}
interface UserSocketInfo {
socketId: string;
userId: string;
organization: string;
}
const connectedUsersByOrg: { [organization: string]: UserSocketInfo[] } = {};
export const SocketServer = (io: Server) => {
// ✅ Declare all namespaces here
const namespaceNames = ["/edge", "/project", "/graph"];
const onlineUsers: { [organization: string]: Set<string> } = {};
// ✅ Attach common handler to each namespace
namespaceNames.forEach((nspName) => {
const namespace = io.of(nspName);
// namespace.use((socket: Socket, next) => {
// try {
// socket.handshake.auth
// console.log('socket.handshake.auth: ', socket.handshake.auth);
// const token = socket.handshake.auth.token as string;
// if (!token) return next(new Error("No token provided"));
// const jwt_secret = process.env.JWT_SECRET as string;
// const decoded = jwt.verify(token, jwt_secret) as UserPayload;
// (socket as any).user = decoded;
// next();
// } catch (err) {
// next(new Error("Authentication failed"));
// }
// });
namespace.on("connection", (socket: Socket) => {
console.log(`✅ Connected to namespace ${nspName}: ${socket.id}`);
// const user = (socket as any).user as UserPayload;
// const { organization, userId } = user;
// if (!onlineUsers[organization]) onlineUsers[organization] = new Set();
// onlineUsers[organization].add(socket.id);
// if (!connectedUsersByOrg[organization]) connectedUsersByOrg[organization] = [];
// connectedUsersByOrg[organization].push({ socketId: socket.id, userId, organization });
// 🎯 Common event handler
socket.onAny((event: string, data: any, callback: any) => {
const handler = eventHandlerMap[event];
if (handler) {
handler(event, socket, io, data, connectedUsersByOrg, callback);
} else {
console.warn(`⚠️ No handler found for event: ${event}`);
}
});
// socket.on("disconnect", () => {
// onlineUsers[organization]?.delete(socket.id);
// if (onlineUsers[organization]?.size === 0) {
// delete onlineUsers[organization];
// }
// connectedUsersByOrg[organization] = connectedUsersByOrg[organization]?.filter(
// (u) => u.socketId !== socket.id
// );
// });
});
});
return io;
};

View File

@@ -0,0 +1,104 @@
import { Socket, Server } from "socket.io";
interface EmitOptions {
success: boolean;
message: string;
data?: any;
error?: any;
organization: string;
socketId: string;
status?: string;
}
export const emitEventResponse = (
socket: Socket,
organization: string,
event: string,
result: EmitOptions
) => {
if (!organization) {
console.log(`Organization missing in response for event: ${event}`);
return;
}
socket.to(organization).emit(event, {
// success: result.success,
message: result.message,
data: result.data,
error: result.error,
socketId: result.socketId,
organization,
});
};
export const emitToSenderAndAdmins = (
io: Server,
socket: Socket,
organization: string,
event: string,
result: EmitOptions,
connectedUsersByOrg: {
[org: string]: { socketId: string; userId: string; role: string }[];
}
) => {
console.log('result.data: ', result.data);
socket.emit(event, {
message: result.message,
data: result.data,
error: result.error,
socketId: result.socketId,
organization,
});
socket.to(`${organization}_admins`).emit(event, {
message: result.message,
data: result.data,
error: result.error,
socketId: result.socketId,
organization,
});
};
// export const emitToRoom = (
// io: Server,
// socket: Socket,
// room: string,
// event: string,
// result: EmitOptions
// ) => {
// const payload = {
// message: result.message,
// data: result.data,
// socketId: result.socketId,
// organization: result.organization,
// };
// console.log("event: ", event);
// console.log("payload: ", payload);
// console.log("room: ", room);
// socket.emit(event, payload); // ✅ FIXED: sends to all in room including sender
// };
export const emitToRoom = (
io: Server,
socket: Socket,
room: string,
event: string,
result: EmitOptions
) => {
const payload = {
message: result.message,
data: result.data,
socketId: result.socketId,
organization: result.organization,
};
console.log("🔥 EMIT TO ROOM:");
console.log("➡️ Event: ", event);
console.log("📦 Full result input: ", result); // 👉 what you passed from observer
console.log("📤 Final payload being emitted: ", payload); // 👉 actual emitted payload
console.log("🏠 Room: ", room);
socket.to(room).emit(event, payload);
// ✅ Optional: Emit to sender too (if needed)
socket.emit(event, payload);
};

View File

@@ -0,0 +1,41 @@
import { Socket, Server } from "socket.io";
export const validateFields = (
data: any,
requiredFields: string[]
): string[] => {
return requiredFields.filter(
(field) => data[field] === undefined || data[field] === null
);
};
export const ErrorResponse = (
missingFields: string[],
socket: Socket,
organization: string
) => ({
success: false,
message: `Missing required field(s): ${missingFields.join(", ")}`,
status: "MissingFields",
socketId: socket.id,
organization: organization ?? "unknown",
});
export const FinalResponse = (
status: string,
socket: Socket,
organization: string,
messages: Record<string, { message: string }>,
data?: any
) => {
const msg = messages[status] || { message: "Internal server error" };
const includeData = (status === "Success" || status === "updated") && data;
return {
success: status === "Success" || status === "updated",
message: msg.message,
status,
socketId: socket.id,
organization,
...(includeData ? { data } : {}),
};
};