feat: add environment variables validation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
77032538e8
commit
f9c0bc0768
+32
@@ -0,0 +1,32 @@
|
|||||||
|
import logger from './utils/logger.js';
|
||||||
|
|
||||||
|
const requiredEnv = {
|
||||||
|
BOT_TOKEN: process.env.BOT_TOKEN,
|
||||||
|
STORAGE_CHANNEL_ID: process.env.STORAGE_CHANNEL_ID,
|
||||||
|
BASE_URL: process.env.BASE_URL,
|
||||||
|
DATABASE_URL: process.env.DATABASE_URL,
|
||||||
|
PORT: process.env.PORT
|
||||||
|
};
|
||||||
|
|
||||||
|
const missing = Object.entries(requiredEnv)
|
||||||
|
.filter(([_, value]) => value === undefined || value === '')
|
||||||
|
.map(([key]) => key);
|
||||||
|
|
||||||
|
if (missing.length > 0) {
|
||||||
|
logger.error('Missing required environment variables:', missing);
|
||||||
|
throw new Error(`Missing environment variables: ${missing.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
botToken: process.env.BOT_TOKEN,
|
||||||
|
storageChatId: parseInt(process.env.STORAGE_CHANNEL_ID, 10),
|
||||||
|
baseUrl: process.env.BASE_URL,
|
||||||
|
databaseUrl: process.env.DATABASE_URL,
|
||||||
|
port: parseInt(process.env.PORT, 10) || 3000,
|
||||||
|
nodeEnv: process.env.NODE_ENV || 'development',
|
||||||
|
logLevel: process.env.LOG_LEVEL || 'info',
|
||||||
|
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS, 10) || 60000,
|
||||||
|
rateLimitMaxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS, 10) || 30
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.info('Environment variables loaded', { config: { ...config, botToken: config.botToken?.substring(0, 10) + '...' } });
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { describe, it, expect, beforeAll } from "bun:test";
|
||||||
|
import { config } from "../src/env.js";
|
||||||
|
|
||||||
|
describe("Environment Variables Validation", () => {
|
||||||
|
it("config should have all required fields", () => {
|
||||||
|
expect(config).toHaveProperty("botToken");
|
||||||
|
expect(config).toHaveProperty("storageChatId");
|
||||||
|
expect(config).toHaveProperty("baseUrl");
|
||||||
|
expect(config).toHaveProperty("databaseUrl");
|
||||||
|
expect(config).toHaveProperty("port");
|
||||||
|
expect(config).toHaveProperty("nodeEnv");
|
||||||
|
expect(config).toHaveProperty("logLevel");
|
||||||
|
expect(config).toHaveProperty("rateLimitWindowMs");
|
||||||
|
expect(config).toHaveProperty("rateLimitMaxRequests");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("config.botToken should return BOT_TOKEN from process.env", () => {
|
||||||
|
expect(config.botToken).toBe(process.env.BOT_TOKEN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("config.storageChatId should be parsed as integer from STORAGE_CHANNEL_ID", () => {
|
||||||
|
expect(typeof config.storageChatId).toBe("number");
|
||||||
|
expect(config.storageChatId).toBe(parseInt(process.env.STORAGE_CHANNEL_ID, 10));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("config.port should default to 3000 when not specified", () => {
|
||||||
|
expect(typeof config.port).toBe("number");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("nodeEnv should be 'test' or 'development'", () => {
|
||||||
|
expect(["test", "development"]).toContain(config.nodeEnv);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("logLevel should default to 'info'", () => {
|
||||||
|
expect(config.logLevel).toBe("info");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rateLimitWindowMs should default to 60000 when not specified", () => {
|
||||||
|
expect(config.rateLimitWindowMs).toBe(60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rateLimitMaxRequests should default to 30 when not specified", () => {
|
||||||
|
expect(config.rateLimitMaxRequests).toBe(30);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user