From 1ce0a13a56cbc2b29acaaa213dd0d0a3e5736f14 Mon Sep 17 00:00:00 2001 From: samad13 Date: Mon, 29 Jun 2026 20:54:23 +0100 Subject: [PATCH 1/2] fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ba6041..9e554e0 100644 --- a/README.md +++ b/README.md @@ -269,7 +269,7 @@ pnpm test --- -linked PR 5 +linked PR 5,4 ## 📄 License From 39118ca182585bcba7c68fede274ab61b57db728 Mon Sep 17 00:00:00 2001 From: samad13 Date: Wed, 1 Jul 2026 11:34:03 +0100 Subject: [PATCH 2/2] env --- package.json | 3 ++- pnpm-lock.yaml | 11 +++++++++++ src/app.ts | 7 ++++--- src/config/database.ts | 3 ++- src/config/env.ts | 36 ++++++++++++++++++++++++++++++++++++ src/server.ts | 5 +++-- 6 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/config/env.ts diff --git a/package.json b/package.json index eeeb8c4..9bdca00 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "jsonwebtoken": "9.0.2", "mongoose": "7.6.3", "uuid": "9.0.1", - "winston": "3.11.0" + "winston": "3.11.0", + "zod": "^4.4.3" }, "devDependencies": { "@types/bcryptjs": "2.4.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 633d702..9a3049e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,6 +43,9 @@ importers: winston: specifier: 3.11.0 version: 3.11.0 + zod: + specifier: ^4.4.3 + version: 4.4.3 devDependencies: '@types/bcryptjs': specifier: 2.4.6 @@ -4911,6 +4914,12 @@ packages: } engines: { node: '>=10' } + zod@4.4.3: + resolution: + { + integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==, + } + snapshots: '@babel/code-frame@7.29.7': dependencies: @@ -8063,3 +8072,5 @@ snapshots: yn@3.1.1: {} yocto-queue@0.1.0: {} + + zod@4.4.3: {} diff --git a/src/app.ts b/src/app.ts index ac1ab58..90c854d 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,6 +7,7 @@ import { connectDatabase } from './config/database'; import logger from './config/logger'; import errorHandler from './middleware/errorHandler'; import routes from './routes'; +import env from './config/env'; const app = express(); @@ -16,15 +17,15 @@ app.use(helmet()); // CORS configuration app.use( cors({ - origin: process.env.CORS_ORIGIN || '*', + origin: env.CORS_ORIGIN, credentials: true, }), ); // Rate limiting const limiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: 100, // Limit each IP to 100 requests per windowMs + windowMs: env.RATE_LIMIT_WINDOW_MS, + max: env.RATE_LIMIT_MAX_REQUESTS, standardHeaders: true, legacyHeaders: false, }); diff --git a/src/config/database.ts b/src/config/database.ts index 65bb270..caf1b2e 100644 --- a/src/config/database.ts +++ b/src/config/database.ts @@ -1,9 +1,10 @@ import mongoose from 'mongoose'; import logger from './logger'; +import env from './env'; export const connectDatabase = async (): Promise => { try { - const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/swiftchain'; + const mongoUri = env.MONGODB_URI; await mongoose.connect(mongoUri); diff --git a/src/config/env.ts b/src/config/env.ts new file mode 100644 index 0000000..c9e13fe --- /dev/null +++ b/src/config/env.ts @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import dotenv from 'dotenv'; +import logger from './logger'; + +dotenv.config(); + +const envSchema = z.object({ + NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), + PORT: z.coerce.number().int().min(1).max(65535).default(3000), + MONGODB_URI: z.string().url(), + JWT_SECRET: z.string().min(16), + JWT_EXPIRES_IN: z.string().default('7d'), + BCRYPT_ROUNDS: z.coerce.number().int().min(8).max(31).default(10), + LOG_LEVEL: z.enum(['error', 'warn', 'info', 'http', 'verbose', 'debug', 'silly']).default('info'), + CORS_ORIGIN: z.string().url(), + RATE_LIMIT_WINDOW_MS: z.coerce.number().int().min(1000).default(900000), + RATE_LIMIT_MAX_REQUESTS: z.coerce.number().int().min(1).default(100), +}); + +let env: z.infer; + +try { + env = envSchema.parse(process.env); +} catch (error) { + if (error instanceof z.ZodError) { + logger.error('❌ Invalid environment variables:'); + error.issues.forEach((err) => { + logger.error(` - ${err.path.join('.')}: ${err.message}`); + }); + } else { + logger.error('❌ Failed to parse environment variables:', error); + } + process.exit(1); +} + +export default env; diff --git a/src/server.ts b/src/server.ts index 4f34316..ec2c7ad 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,10 +1,11 @@ import app from './app'; import logger from './config/logger'; +import env from './config/env'; -const PORT = process.env.PORT || 3000; +const PORT = env.PORT; const server = app.listen(PORT, () => { - logger.info(`🚀 Server running on port ${PORT} in ${process.env.NODE_ENV} mode`); + logger.info(`🚀 Server running on port ${PORT} in ${env.NODE_ENV} mode`); logger.info(`📝 Health check: http://localhost:${PORT}/health`); });