Files
qipai/backend/src/config.ts
T

98 lines
4.6 KiB
TypeScript

import { z } from 'zod';
const configSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
QIPAI_API_HOST: z.string().min(1).default('0.0.0.0'),
QIPAI_API_PORT: z.coerce.number().int().min(1).max(65535).default(3001),
QIPAI_API_VERSION: z.string().min(1).default('0.1.0'),
QIPAI_API_CORS_ORIGINS: z.string().default('https://api.txyundm.cn'),
QIPAI_MYSQL_HOST: z.string().min(1).default('127.0.0.1'),
QIPAI_MYSQL_PORT: z.coerce.number().int().min(1).max(65535).default(3306),
QIPAI_MYSQL_DATABASE: z.string().min(1).default('qipai'),
QIPAI_MYSQL_USER: z.string().min(1).default('qipai_app'),
QIPAI_MYSQL_PASSWORD: z.string().default(''),
QIPAI_MYSQL_CONNECTION_LIMIT: z.coerce.number().int().min(1).max(50).default(10),
QIPAI_JWT_SECRET: z.string().min(32).default('development-only-change-this-jwt-secret'),
QIPAI_ACCESS_TOKEN_TTL_SECONDS: z.coerce.number().int().min(60).max(86400).default(900),
QIPAI_SESSION_TTL_SECONDS: z.coerce.number().int().min(300).max(2592000).default(604800),
QIPAI_WECHAT_APP_SECRETS: z.string().default('{}'),
QIPAI_TEST_PAYMENT_ENABLED: z.enum(['true', 'false']).default('false'),
QIPAI_WECHAT_PAY_CREDENTIALS: z.string().default('{}'),
QIPAI_PROFIT_SHARE_MOCK_ENABLED: z.enum(['true', 'false']).default('false'),
QIPAI_CLEANING_PAYOUT_MOCK_ENABLED: z.enum(['true', 'false']).default('false'),
QIPAI_THIRD_PARTY_CREDENTIALS: z.string().default('{}'),
QIPAI_MQTT_URL: z.string().url().default('mqtt://101.42.38.246:1883'),
QIPAI_MQTT_CLIENT_ID: z.string().min(1).max(128).default('qipai-backend'),
QIPAI_MQTT_USERNAME: z.string().default(''),
QIPAI_MQTT_PASSWORD: z.string().default(''),
QIPAI_MQTT_RECONNECT_MS: z.coerce.number().int().min(1000).max(60000).default(3000),
QIPAI_MQTT_CONNECT_TIMEOUT_MS: z.coerce.number().int().min(1000).max(60000).default(10000),
QIPAI_MQTT_MAX_MESSAGE_BYTES: z.coerce.number().int().min(1024).max(1048576).default(65536)
});
export type AppConfig = ReturnType<typeof loadConfig>;
export function loadConfig(env: NodeJS.ProcessEnv = process.env) {
const parsed = configSchema.parse(env);
if (
parsed.NODE_ENV === 'production'
&& parsed.QIPAI_JWT_SECRET === 'development-only-change-this-jwt-secret'
) {
throw new Error('QIPAI_JWT_SECRET must be explicitly configured in production.');
}
const mqttUsernameConfigured = parsed.QIPAI_MQTT_USERNAME.length > 0;
const mqttPasswordConfigured = parsed.QIPAI_MQTT_PASSWORD.length > 0;
if (mqttUsernameConfigured !== mqttPasswordConfigured) {
throw new Error('QIPAI_MQTT_USERNAME and QIPAI_MQTT_PASSWORD must be configured together.');
}
if (parsed.NODE_ENV === 'production' && !mqttUsernameConfigured) {
throw new Error('MQTT credentials must be explicitly configured in production.');
}
return {
nodeEnv: parsed.NODE_ENV,
host: parsed.QIPAI_API_HOST,
port: parsed.QIPAI_API_PORT,
version: parsed.QIPAI_API_VERSION,
corsOrigins: parsed.QIPAI_API_CORS_ORIGINS.split(',').map((item) => item.trim()).filter(Boolean),
mysql: {
host: parsed.QIPAI_MYSQL_HOST,
port: parsed.QIPAI_MYSQL_PORT,
database: parsed.QIPAI_MYSQL_DATABASE,
user: parsed.QIPAI_MYSQL_USER,
credential: parsed.QIPAI_MYSQL_PASSWORD,
passwordConfigured: parsed.QIPAI_MYSQL_PASSWORD.length > 0,
connectionLimit: parsed.QIPAI_MYSQL_CONNECTION_LIMIT
},
auth: {
jwtSecret: parsed.QIPAI_JWT_SECRET,
accessTokenTtlSeconds: parsed.QIPAI_ACCESS_TOKEN_TTL_SECONDS,
sessionTtlSeconds: parsed.QIPAI_SESSION_TTL_SECONDS,
wechatAppSecretsJson: parsed.QIPAI_WECHAT_APP_SECRETS
},
payment: {
testAdapterEnabled: parsed.NODE_ENV !== 'production'
&& parsed.QIPAI_TEST_PAYMENT_ENABLED === 'true',
wechatCredentialsJson: parsed.QIPAI_WECHAT_PAY_CREDENTIALS,
profitShareMockEnabled: parsed.NODE_ENV !== 'production'
&& parsed.QIPAI_PROFIT_SHARE_MOCK_ENABLED === 'true',
cleaningPayoutMockEnabled: parsed.NODE_ENV !== 'production'
&& parsed.QIPAI_CLEANING_PAYOUT_MOCK_ENABLED === 'true'
},
thirdParty: {
credentialsJson: parsed.QIPAI_THIRD_PARTY_CREDENTIALS
},
mqtt: {
url: parsed.QIPAI_MQTT_URL,
clientId: parsed.QIPAI_MQTT_CLIENT_ID,
username: parsed.QIPAI_MQTT_USERNAME,
credential: parsed.QIPAI_MQTT_PASSWORD,
usernameConfigured: mqttUsernameConfigured,
passwordConfigured: mqttPasswordConfigured,
reconnectPeriodMs: parsed.QIPAI_MQTT_RECONNECT_MS,
connectTimeoutMs: parsed.QIPAI_MQTT_CONNECT_TIMEOUT_MS,
maxMessageBytes: parsed.QIPAI_MQTT_MAX_MESSAGE_BYTES
}
};
}