diff --git a/.env.example b/.env.example index 71df3e8..60a9048 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ -SERVER_PORT=3000 -JWT_SECRET=secret -#DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" \ No newline at end of file +# Server configuration +ENV=development +PORT=4000 +DATABASE_URL="mysql://root@localhost:3306/nq" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8fa0495..0ab9320 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,25 +10,23 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", - "jsonwebtoken": "^9.0.2", - "prisma": "^5.13.0" + "prisma": "^5.13.0", + "socket.io": "^4.7.5", + "ts-node": "^10.9.2", + "typescript": "^5.4.5" }, "devDependencies": { "@types/bcryptjs": "^2.4.6", "@types/express": "^4.17.21", - "@types/jsonwebtoken": "^9.0.6", - "@types/node": "^20.12.8", + "@types/node": "^20.12.11", "@types/socket.io": "^3.0.2", - "nodemon": "^3.1.0", - "ts-node": "^10.9.2", - "typescript": "^5.4.5" + "nodemon": "^3.1.0" } }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -40,7 +38,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -48,14 +45,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -121,32 +116,27 @@ "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==", - "dev": true + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" }, "node_modules/@types/bcryptjs": { "version": "2.4.6", @@ -176,14 +166,12 @@ "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, "dependencies": { "@types/node": "*" } @@ -218,15 +206,6 @@ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", - "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -234,10 +213,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.10.tgz", - "integrity": "sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==", - "dev": true, + "version": "20.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", + "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", "dependencies": { "undici-types": "~5.26.4" } @@ -307,7 +285,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -319,7 +296,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -340,8 +316,7 @@ "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -358,7 +333,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, "engines": { "node": "^4.5.0 || >= 5.9" } @@ -425,11 +399,6 @@ "node": ">=8" } }, - "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", @@ -533,8 +502,7 @@ "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "node_modules/debug": { "version": "2.6.9", @@ -581,7 +549,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, "engines": { "node": ">=0.3.1" } @@ -597,14 +564,6 @@ "url": "https://dotenvx.com" } }, - "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", @@ -622,7 +581,6 @@ "version": "6.5.4", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", - "dev": true, "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -643,7 +601,6 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", - "dev": true, "engines": { "node": ">=10.0.0" } @@ -652,7 +609,6 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -661,7 +617,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -677,8 +632,7 @@ "node_modules/engine.io/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/es-define-property": { "version": "1.0.0", @@ -1001,91 +955,10 @@ "node": ">=0.12.0" } }, - "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/jsonwebtoken/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==" - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "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/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/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "node_modules/media-typer": { "version": "0.3.0", @@ -1399,6 +1272,7 @@ "version": "7.6.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.1.tgz", "integrity": "sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -1502,7 +1376,6 @@ "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "dev": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -1520,7 +1393,6 @@ "version": "2.5.4", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", - "dev": true, "dependencies": { "debug": "~4.3.4", "ws": "~8.11.0" @@ -1530,7 +1402,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1546,14 +1417,12 @@ "node_modules/socket.io-adapter/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "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==", - "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -1566,7 +1435,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1582,14 +1450,12 @@ "node_modules/socket.io-parser/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/socket.io/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1605,8 +1471,7 @@ "node_modules/socket.io/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/statuses": { "version": "2.0.1", @@ -1664,7 +1529,6 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -1719,7 +1583,6 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1737,8 +1600,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unpipe": { "version": "1.0.0", @@ -1759,8 +1621,7 @@ "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "node_modules/vary": { "version": "1.1.2", @@ -1774,7 +1635,6 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, "engines": { "node": ">=10.0.0" }, @@ -1795,7 +1655,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, "engines": { "node": ">=6" } diff --git a/package.json b/package.json index a751dd9..1d8be14 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "scripts": { - "build": "tsc", "start": "node dist/index.js", - "dev": "nodemon src/server.ts --exec ts-node" + "dev": "nodemon --exec ts-node src/application.ts", + "build": "tsc" }, "dependencies": { "@prisma/client": "^5.13.0", @@ -10,17 +10,16 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", - "jsonwebtoken": "^9.0.2", - "prisma": "^5.13.0" + "prisma": "^5.13.0", + "socket.io": "^4.7.5", + "ts-node": "^10.9.2", + "typescript": "^5.4.5" }, "devDependencies": { "@types/bcryptjs": "^2.4.6", "@types/express": "^4.17.21", - "@types/jsonwebtoken": "^9.0.6", - "@types/node": "^20.12.8", + "@types/node": "^20.12.11", "@types/socket.io": "^3.0.2", - "nodemon": "^3.1.0", - "ts-node": "^10.9.2", - "typescript": "^5.4.5" + "nodemon": "^3.1.0" } } diff --git a/prisma/migrations/20240504233128_init/migration.sql b/prisma/migrations/20240504233128_init/migration.sql deleted file mode 100644 index 5a1de25..0000000 --- a/prisma/migrations/20240504233128_init/migration.sql +++ /dev/null @@ -1,42 +0,0 @@ --- CreateTable -CREATE TABLE `User` ( - `id` INTEGER NOT NULL AUTO_INCREMENT, - `username` VARCHAR(191) NOT NULL, - `password` VARCHAR(191) NOT NULL, - `position_x` INTEGER NOT NULL, - `position_y` INTEGER NOT NULL, - `rotation` INTEGER NOT NULL, - `mapId` INTEGER NULL, - - UNIQUE INDEX `User_username_key`(`username`), - UNIQUE INDEX `User_mapId_key`(`mapId`), - PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- CreateTable -CREATE TABLE `Map` ( - `id` INTEGER NOT NULL AUTO_INCREMENT, - `name` VARCHAR(191) NOT NULL, - `tiles` VARCHAR(191) NOT NULL, - - PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- CreateTable -CREATE TABLE `Chatlogs` ( - `id` INTEGER NOT NULL AUTO_INCREMENT, - `userId` INTEGER NOT NULL, - `message` VARCHAR(191) NOT NULL, - `mapId` INTEGER NOT NULL, - - PRIMARY KEY (`id`) -) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- AddForeignKey -ALTER TABLE `User` ADD CONSTRAINT `User_mapId_fkey` FOREIGN KEY (`mapId`) REFERENCES `Map`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `Chatlogs` ADD CONSTRAINT `Chatlogs_mapId_fkey` FOREIGN KEY (`mapId`) REFERENCES `Map`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `Chatlogs` ADD CONSTRAINT `Chatlogs_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20240504233249_init/migration.sql b/prisma/migrations/20240504233249_init/migration.sql deleted file mode 100644 index c8e0b46..0000000 --- a/prisma/migrations/20240504233249_init/migration.sql +++ /dev/null @@ -1,4 +0,0 @@ --- AlterTable -ALTER TABLE `User` MODIFY `position_x` INTEGER NULL, - MODIFY `position_y` INTEGER NULL, - MODIFY `rotation` INTEGER NULL; diff --git a/prisma/migrations/20240504233358_init/migration.sql b/prisma/migrations/20240504233358_init/migration.sql deleted file mode 100644 index 7bf27c6..0000000 --- a/prisma/migrations/20240504233358_init/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -/* - Warnings: - - - You are about to alter the column `tiles` on the `Map` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Json`. - - Added the required column `height` to the `Map` table without a default value. This is not possible if the table is not empty. - - Added the required column `width` to the `Map` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE `Map` ADD COLUMN `height` INTEGER NOT NULL, - ADD COLUMN `width` INTEGER NOT NULL, - MODIFY `tiles` JSON NOT NULL; diff --git a/prisma/migrations/20240509002250_init/migration.sql b/prisma/migrations/20240509002250_init/migration.sql new file mode 100644 index 0000000..b828a76 --- /dev/null +++ b/prisma/migrations/20240509002250_init/migration.sql @@ -0,0 +1,9 @@ +-- CreateTable +CREATE TABLE `User` ( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `email` VARCHAR(191) NOT NULL, + `name` VARCHAR(191) NULL, + + UNIQUE INDEX `User_email_key`(`email`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/migrations/20240509011349_init/migration.sql b/prisma/migrations/20240509011349_init/migration.sql new file mode 100644 index 0000000..bb2ff49 --- /dev/null +++ b/prisma/migrations/20240509011349_init/migration.sql @@ -0,0 +1,59 @@ +/* + Warnings: + + - You are about to drop the column `email` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `name` on the `User` table. All the data in the column will be lost. + - A unique constraint covering the columns `[username]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[mapId]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `password` to the `User` table without a default value. This is not possible if the table is not empty. + - Added the required column `username` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropIndex +DROP INDEX `User_email_key` ON `User`; + +-- AlterTable +ALTER TABLE `User` DROP COLUMN `email`, + DROP COLUMN `name`, + ADD COLUMN `mapId` INTEGER NULL, + ADD COLUMN `password` VARCHAR(191) NOT NULL, + ADD COLUMN `position_x` INTEGER NULL, + ADD COLUMN `position_y` INTEGER NULL, + ADD COLUMN `rotation` INTEGER NULL, + ADD COLUMN `username` VARCHAR(191) NOT NULL; + +-- CreateTable +CREATE TABLE `Map` ( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(191) NOT NULL, + `width` INTEGER NOT NULL, + `height` INTEGER NOT NULL, + `tiles` JSON NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Chatlogs` ( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `userId` INTEGER NOT NULL, + `message` VARCHAR(191) NOT NULL, + `mapId` INTEGER NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateIndex +CREATE UNIQUE INDEX `User_username_key` ON `User`(`username`); + +-- CreateIndex +CREATE UNIQUE INDEX `User_mapId_key` ON `User`(`mapId`); + +-- AddForeignKey +ALTER TABLE `User` ADD CONSTRAINT `User_mapId_fkey` FOREIGN KEY (`mapId`) REFERENCES `Map`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Chatlogs` ADD CONSTRAINT `Chatlogs_mapId_fkey` FOREIGN KEY (`mapId`) REFERENCES `Map`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Chatlogs` ADD CONSTRAINT `Chatlogs_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7de53ba..098bc47 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,8 +1,14 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? -// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init +// CHEAT SHEET +// 1. Create a new Prisma project +// npx prisma init +// 2. Create a new database schema +// npx prisma db push +// 3. Generate Prisma Client +// npx prisma generate +// 4. Create a new migration +// npx prisma migrate dev --name init +// 5. Apply the migration +// npx prisma migrate deploy generator client { provider = "prisma-client-js" diff --git a/src/app/events/disconnect.ts b/src/app/events/disconnect.ts new file mode 100644 index 0000000..7c68868 --- /dev/null +++ b/src/app/events/disconnect.ts @@ -0,0 +1,7 @@ +import { Socket, Server } from "socket.io"; + +export default function user_connect(socket: Socket, io: Server) { + socket.on('disconnect', (data) => { + console.log(`---User ${socket.id} has disconnected.`); + }); +} \ No newline at end of file diff --git a/src/app/events/player_connect.ts b/src/app/events/player_connect.ts new file mode 100644 index 0000000..7287ea6 --- /dev/null +++ b/src/app/events/player_connect.ts @@ -0,0 +1,7 @@ +import { Socket, Server } from "socket.io"; + +export default function player_connect(socket: Socket, io: Server) { + socket.on('player:connect', (data) => { + console.log(`---User ${socket.id} has joined.`); + }); +} \ No newline at end of file diff --git a/src/app/events/player_map_load.ts b/src/app/events/player_map_load.ts new file mode 100644 index 0000000..c657c6f --- /dev/null +++ b/src/app/events/player_map_load.ts @@ -0,0 +1,7 @@ +import { Socket, Server } from "socket.io"; + +export default function player_map_load(socket: Socket, io: Server) { + socket.on('player:map:load', (data) => { + console.log(`---User ${socket.id} has requested map.`); + }); +} diff --git a/src/app/logo.txt b/src/app/logo.txt new file mode 100644 index 0000000..666f554 --- /dev/null +++ b/src/app/logo.txt @@ -0,0 +1,6 @@ +███╗░░██╗███████╗░██╗░░░░░░░██╗  ░██████╗░██╗░░░██╗███████╗░██████╗████████╗ +████╗░██║██╔════╝░██║░░██╗░░██║  ██╔═══██╗██║░░░██║██╔════╝██╔════╝╚══██╔══╝ +██╔██╗██║█████╗░░░╚██╗████╗██╔╝  ██║██╗██║██║░░░██║█████╗░░╚█████╗░░░░██║░░░ +██║╚████║██╔══╝░░░░████╔═████║░  ╚██████╔╝██║░░░██║██╔══╝░░░╚═══██╗░░░██║░░░ +██║░╚███║███████╗░░╚██╔╝░╚██╔╝░  ░╚═██╔═╝░╚██████╔╝███████╗██████╔╝░░░██║░░░ +╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚═╝░░  ░░░╚═╝░░░░╚═════╝░╚══════╝╚═════╝░░░░╚═╝░░░ \ No newline at end of file diff --git a/src/repositories/Map.ts b/src/app/repositories/map.ts similarity index 67% rename from src/repositories/Map.ts rename to src/app/repositories/map.ts index c204b6f..33f419a 100644 --- a/src/repositories/Map.ts +++ b/src/app/repositories/map.ts @@ -1,15 +1,15 @@ import { Map } from '@prisma/client'; -import prisma from '../helpers/prisma'; // Import the global Prisma instance +import prisma from '../utilities/prisma'; // Import the global Prisma instance class MapRepository { async getFirst(): Promise { try { return await prisma.map.findFirst(); - } catch (error) { + } catch (error: any) { // Handle error throw new Error(`Failed to get first map: ${error.message}`); } } } -export default new MapRepository; \ No newline at end of file +export default MapRepository; \ No newline at end of file diff --git a/src/app/repositories/user.ts b/src/app/repositories/user.ts new file mode 100644 index 0000000..df42a37 --- /dev/null +++ b/src/app/repositories/user.ts @@ -0,0 +1,33 @@ +import prisma from '../utilities/prisma'; // Import the global Prisma instance +import { User } from '@prisma/client'; + +class UserRepository { + async getByUsername(username: string): Promise { + try { + return await prisma.user.findUnique({ + where: { + username, + }, + }); + } catch (error: any) { + // Handle error + throw new Error(`Failed to get user by username: ${error.message}`); + } + } + + async create(username: string, password: string): Promise { + try { + return await prisma.user.create({ + data: { + username, + password, + }, + }); + } catch (error: any) { + // Handle error + throw new Error(`Failed to create user: ${error.message}`); + } + } +} + +export default new UserRepository; \ No newline at end of file diff --git a/src/app/server.ts b/src/app/server.ts new file mode 100644 index 0000000..b19f393 --- /dev/null +++ b/src/app/server.ts @@ -0,0 +1,81 @@ +import fs from "fs"; +import path from "path"; +import express from 'express'; +import http from 'http'; +import cors from 'cors'; +import {Server as HttpServer, Socket} from 'socket.io'; +import config from './utilities/config'; +import prisma from './utilities/prisma'; +import api from "./utilities/api"; + +export class Server +{ + private readonly app: express.Application; + private readonly server: any; + private readonly io: HttpServer; + + /** + * Creates an instance of GameServer. + */ + constructor() { + this.app = express(); + this.app.use(cors()); + this.app.use(express.json()); + this.app.use(express.urlencoded({ extended: true })); + this.server = http.createServer(this.app) + this.io = new HttpServer(this.server); + } + + /** + * Start the server + */ + public async start() { + // Print logo + const art = fs.readFileSync(path.join(__dirname, 'logo.txt'), 'utf8'); + console.log('\x1b[31m%s\x1b[0m', art + '\n'); + + // Check prisma connection + try { + await prisma.$connect(); + console.log('[✅] Database connected'); + } catch (error: any) { + throw new Error(`[❌] Database connection failed: ${error.message}`); + } + + // Start the server + try { + await this.server.listen(config.PORT); + console.log('[✅] Socket.IO running on port', config.PORT); + } catch (error: any) { + throw new Error(`[❌] Socket.IO failed to start: ${error.message}`); + } + + // Add API routes + await api.addAuthRoutes(this.app); + + // Add socket events + this.io.on('connection', this.handleConnection.bind(this)); + } + + /** + * Handle socket connection + * @param socket + * @private + */ + private async handleConnection(socket: Socket) { + const eventsPath = path.join(__dirname, 'events'); + try { + const files = await fs.promises.readdir(eventsPath); + for (const file of files) { + if (!file.endsWith('.ts')) { + continue; + } + + const module = await import(path.join(eventsPath, file)); + module.default(socket, this.io); + } + } catch (error: any) { + throw new Error('[❌] Failed to load event handlers: ' + error.message); + } + } +} diff --git a/src/app/services/user.ts b/src/app/services/user.ts new file mode 100644 index 0000000..5230363 --- /dev/null +++ b/src/app/services/user.ts @@ -0,0 +1,30 @@ +import bcrypt from "bcryptjs"; +import UserRepository from "../repositories/user"; + +class UserService { + async login(username: string, password: string): Promise { + const user = await UserRepository.getByUsername(username); + if (!user) { + return false; + } + + const passwordMatch = await bcrypt.compare(password, user.password); + if (!passwordMatch) { + return false; + } + + return user; + } + + async register(username: string, password: string): Promise { + const user = await UserRepository.getByUsername(username); + if (user) { + return false; + } + + const hashedPassword = await bcrypt.hash(password, 10); + return await UserRepository.create(username, hashedPassword); + } +} + +export default UserService; \ No newline at end of file diff --git a/src/app/utilities/api.ts b/src/app/utilities/api.ts new file mode 100644 index 0000000..16c5304 --- /dev/null +++ b/src/app/utilities/api.ts @@ -0,0 +1,32 @@ +import { Request, Response } from 'express'; +import UserService from '../services/user'; + +async function addAuthRoutes(app: any) { + app.post('/login', async (req: Request, res: Response) => { + const { username, password } = req.body; + + const userService = new UserService(); + const user = await userService.login(username, password); + + if (user) { + return res.status(200).json(user); + } + return res.status(401).json({ message: 'Invalid credentials' }); + }); + + app.post('/register', async (req: Request, res: Response) => { + const { username, password } = req.body; + + const userService = new UserService(); + const user = await userService.register(username, password); + + if (user) { + return res.status(201).json(user); + } + return res.status(400).json({ message: 'Failed to register user' }); + }); + + console.log('[🌎] Auth routes added'); +} + +export default { addAuthRoutes }; \ No newline at end of file diff --git a/src/app/utilities/config.ts b/src/app/utilities/config.ts new file mode 100644 index 0000000..b69e9fb --- /dev/null +++ b/src/app/utilities/config.ts @@ -0,0 +1,10 @@ +import dotenv from "dotenv"; + +dotenv.config(); + +class config { + static ENV: string = process.env.ENV || "prod"; + static PORT: number = process.env.PORT ? parseInt(process.env.PORT) : 5000; +} + +export default config; \ No newline at end of file diff --git a/src/helpers/prisma.ts b/src/app/utilities/prisma.ts similarity index 100% rename from src/helpers/prisma.ts rename to src/app/utilities/prisma.ts diff --git a/src/application.ts b/src/application.ts new file mode 100644 index 0000000..0efe091 --- /dev/null +++ b/src/application.ts @@ -0,0 +1,9 @@ +/** + * Entry point of the application + * Made by Dennis Postma + * for New Quest + */ + +import { Server } from './app/server'; + +new Server().start(); \ No newline at end of file diff --git a/src/helpers/http.ts b/src/helpers/http.ts deleted file mode 100644 index 08bdebb..0000000 --- a/src/helpers/http.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Request, Response } from 'express'; -import UserService from '../services/User'; - -export async function registerUser(req: Request, res: Response): Promise { - const { username, password } = req.body; - try { - await UserService.createUser(username, password); - res.status(201).send('User registered'); - } catch (error) { - console.error('Error registering user:', error); - res.status(500).send('Error registering user'); - } -} - -export async function loginUser(req: Request, res: Response): Promise { - const { username, password } = req.body; - try { - const isValid = await UserService.validateUserCredentials(username, password); - if (isValid) { - res.send('Login successful'); - } else { - res.status(401).send('Invalid credentials'); - } - } catch (error) { - console.error('Error validating credentials:', error); - res.status(500).send('Error validating credentials'); - } -} diff --git a/src/helpers/interfaces.ts b/src/helpers/interfaces.ts deleted file mode 100644 index 340c40b..0000000 --- a/src/helpers/interfaces.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface IUser { - id?: number; - username: string; - password: string; -} - -export interface IMap { - name: string; - tiles: any; - width: number; - height: number; - players: { - id: number; - x: number; - y: number; - }[]; -} \ No newline at end of file diff --git a/src/repositories/User.ts b/src/repositories/User.ts deleted file mode 100644 index 0ee9967..0000000 --- a/src/repositories/User.ts +++ /dev/null @@ -1,20 +0,0 @@ -import prisma from '../helpers/prisma'; // Import the global Prisma instance -import { User } from '@prisma/client'; -import bcrypt from 'bcryptjs'; - -class UserRepository { - async getByUsername(username: string): Promise { - try { - return await prisma.user.findUnique({ - where: { - username, - }, - }); - } catch (error) { - // Handle error - throw new Error(`Failed to get user by username: ${error.message}`); - } - } -} - -export default new UserRepository; \ No newline at end of file diff --git a/src/server.ts b/src/server.ts deleted file mode 100644 index 73e81da..0000000 --- a/src/server.ts +++ /dev/null @@ -1,122 +0,0 @@ -import express from 'express'; -import {Server} from 'socket.io'; -import http from 'http'; -import cors from 'cors'; -import UserRepository from "./repositories/User"; -import UserService from "./services/User"; -import MapRepository from "./repositories/Map"; -import {loginUser, registerUser} from './helpers/http'; -import {IUser, IMap} from "./helpers/interfaces"; - -const app = express(); -const server = http.createServer(app); -const io = new Server(server, { cors: { origin: '*' } }); - -app.use(cors()); -app.use(express.json()); - -app.post('/login', loginUser); -app.post('/register', registerUser); - -let world_players: any = {}; - -async function handleSocketConnection(socket: any) { - const { username, password } = socket.handshake.query; - - try { - await authenticateUser(socket, username, password); - await initializeUser(socket, username); - await setupMap(socket); - await startTickEmitter(socket); - listenForMoveEvents(socket); - listenForDisconnect(socket, username); - } catch (error) { - console.error('Error handling socket connection:', error.message); - socket.disconnect(true); - } -} - -async function authenticateUser(socket: any, username: string, password: string) { - if (!username || !password) { - throw new Error('Username or password missing.'); - } - - const user = await UserRepository.getByUsername(username); - if (!user || !(await UserService.validateUserCredentials(username, password))) { - throw new Error('Invalid username or password.'); - } - - console.log('User connected:', username); - - socket.user = user; - - world_players[user.id] = { - id: user.id, - username: user.username, - coords: { - x: 0, - y: 0 - } - }; -} - -async function initializeUser(socket: any, username: string) { - socket.emit('message', 'Welcome to the server!'); -} - -async function setupMap(socket: any) { - const map = await MapRepository.getFirst(); - socket.join(map.name); - socket.emit('map', { - name: map.name, - tiles: map.tiles, - width: map.width, - height: map.height, - players: world_players - }); - socket.emit('message', 'You have joined the room: ' + map.name); - // list world players - socket.emit('message', 'World players: ' + JSON.stringify(world_players)); - - // let the room know a new player has joined - io.to(map.name).emit('player_join', world_players[socket.user.id]); - return map; -} - -async function startTickEmitter(socket: any) { - setInterval(async () => { - const users = await listConnectedUsers(); - socket.emit('ping', users); - }, 3000); -} - -function listenForMoveEvents(socket: any) { - socket.on('move', (coords: any) => { - console.log('Player moved:', socket.user.id, coords) - const user = socket.user as IUser; - world_players[user.id].coords = coords; - io.in('Test Map').emit('player_moved', { - id: user.id, - coords - }); - }); -} -//r -function listenForDisconnect(socket: any, username: string) { - socket.on('disconnect', () => { - console.log('User disconnected:', username); - }); -} - -// function list all connected users -// function list all connected users -async function listConnectedUsers() { - const sockets = await io.in('Test Map').fetchSockets(); - // @ts-ignore - return sockets.map(socket => socket.user); -} - -io.on('connection', handleSocketConnection); - -const PORT = process.env.PORT || 3000; -server.listen(PORT, () => console.log(`Server running on port ${PORT}`)); \ No newline at end of file diff --git a/src/services/Map.ts b/src/services/Map.ts deleted file mode 100644 index a6853c8..0000000 --- a/src/services/Map.ts +++ /dev/null @@ -1,6 +0,0 @@ - -class MapService { - -} - -export default MapService; \ No newline at end of file diff --git a/src/services/User.ts b/src/services/User.ts deleted file mode 100644 index 50a50ed..0000000 --- a/src/services/User.ts +++ /dev/null @@ -1,35 +0,0 @@ -import bcrypt from "bcryptjs"; -import prisma from "../helpers/prisma"; -import UserRepository from "../repositories/User"; - -class UserService { - async createUser(username: string, password: string): Promise { - try { - const hashedPassword = await bcrypt.hash(password, 10); - await prisma.user.create({ - data: { - username, - password: hashedPassword, - }, - }); - } catch (error) { - // Handle error - throw new Error(`Failed to create user: ${error.message}`); - } - } - - async validateUserCredentials(username: string, password: string): Promise { - try { - const user = await UserRepository.getByUsername(username); - - if (!user) return false; - - return bcrypt.compareSync(password, user.password); - } catch (error) { - // Handle error - throw new Error(`Failed to validate user credentials: ${error.message}`); - } - } -} - -export default new UserService; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index ffde79c..805c534 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,109 @@ { "compilerOptions": { - "target": "ESNext", - "module": "commonjs", - "strict": false, - "esModuleInterop": true, - "outDir": "./dist", - "rootDir": "./src", - "resolveJsonModule": true, - "sourceMap": true, - "declaration": true, - "baseUrl": "./", - "paths": { - "*": ["node_modules/*", "src/types/*"] - } - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "**/*.spec.ts"], - "allowJs": true, - "checkJs": true -} \ No newline at end of file + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}