diff --git a/app.js b/app.js index 1cee79f..b27f280 100644 --- a/app.js +++ b/app.js @@ -16,6 +16,7 @@ app.use(express.json()); // Routes app.use('/auth', authRoutes); app.use('/users', userRoutes); +app.use('/products', productRoutes); app.use('/rates', rateRoutes); app.use('/cart', cartRoutes); app.use('/', orderRoutes); diff --git a/package-lock.json b/package-lock.json index 17d52ee..335405f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@prisma/client": "^6.19.3", "@prisma/config": "^7.7.0", + "axios": "^1.18.0", "bcrypt": "^6.0.0", "bcryptjs": "^3.0.3", "cloudinary": "^2.9.0", @@ -1684,6 +1685,18 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1790,6 +1803,18 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/axios": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, "node_modules/babel-jest": { "version": "30.3.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", @@ -3177,6 +3202,26 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", "license": "MIT" }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -3571,6 +3616,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5578,6 +5636,15 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", diff --git a/package.json b/package.json index dfebd9e..f1a4f16 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "dependencies": { "@prisma/client": "^6.19.3", "@prisma/config": "^7.7.0", + "axios": "^1.18.0", "bcrypt": "^6.0.0", "bcryptjs": "^3.0.3", "cloudinary": "^2.9.0", diff --git a/server.js b/server.js index 0e6a23f..0c3e2bc 100644 --- a/server.js +++ b/server.js @@ -19,6 +19,23 @@ app.use(express.urlencoded({ extended: true })); app.use(corsConfig()); app.use(helmet()); + // --- HEALTH CHECK ENDPOINT --- +app.get('/health', (req, res) => { + const healthcheck = { + status: 'UP', + uptime: process.uptime(), // Returns the number of seconds the server has been running + timestamp: new Date().toISOString(), + memoryUsage: process.memoryUsage() // For monitoring memory leaks + }; + + try { + res.status(200).json(healthcheck); + } catch (error) { + healthcheck.status = 'DOWN'; + res.status(503).json(healthcheck); + } +}); + app.use('/auth', require('./routes/authRouter')); app.use('/users', require('./routes/userRouter')); app.use('/products', require('./routes/productRouter')); diff --git a/test/product.test.js b/test/product.test.js index 5471c23..9798fe8 100644 --- a/test/product.test.js +++ b/test/product.test.js @@ -1,6 +1,5 @@ const request = require('supertest'); -const express = require('express'); -const productRoutes = require('../routes/productRouter'); +const app = require('../app') // --- Mocks --- jest.mock('../config/prisma', () => ({ @@ -30,11 +29,6 @@ jest.mock('../middleware/jwt', () => ({ } })); -// Initialize App -const app = express(); -app.use(express.json()); -app.use('/products', productRoutes); - const prisma = require('../config/prisma'); describe('Product Security & Isolation Requirements', () => { diff --git a/utils/keepServer.js b/utils/keepServer.js new file mode 100644 index 0000000..040dbce --- /dev/null +++ b/utils/keepServer.js @@ -0,0 +1,17 @@ +const logger = require('./logger'); +const axios = require('axios'); +const HEALTH_CHECK_URL = process.env.HEALTH_CHECK_URL + + +const keepServer = async () => { + try { + const health = await axios.get(`${HEALTH_CHECK_URL}`) + logger.info(health.data) + } catch (error) { + logger.error('Server is down') + } +} + +setTimeout(() =>{ + keepServer() +}, 1000 * 60 * 45) \ No newline at end of file