Files
Paperless-Contracts/src/config.ts

101 lines
3.9 KiB
TypeScript

import { z } from "zod";
const supportedLocales = ["de", "en"] as const;
const configSchema = z.object({
port: z.coerce.number().min(1).max(65535).default(8000),
logLevel: z.enum(["debug", "info", "warn", "error"]).default("info"),
databasePath: z.string().default("./data/contracts.db"),
paperlessBaseUrl: z.string().url().optional(),
paperlessToken: z.string().min(1).optional(),
paperlessExternalUrl: z.string().url().optional(),
paperlessWebhookUrl: z.string().url().optional(),
appExternalUrl: z.string().url().optional(),
appLocale: z.enum(supportedLocales).default("de"),
schedulerIntervalMinutes: z.coerce.number().min(5).default(60),
alertDaysBefore: z.coerce.number().min(1).default(30),
mailServer: z.string().optional(),
mailPort: z.coerce.number().min(1).max(65535).default(587),
mailUsername: z.string().optional(),
mailPassword: z.string().optional(),
mailUseTls: z.coerce.boolean().default(true),
mailFrom: z.string().email().optional(),
mailTo: z.string().email().optional(),
authUsername: z.string().optional(),
authPassword: z.string().optional(),
authJwtSecret: z.string().optional(),
authTokenExpiresInHours: z.coerce.number().min(1).max(168).default(12),
ntfyServerUrl: z.string().url().optional(),
ntfyTopic: z.string().min(1).optional(),
ntfyToken: z.string().optional(),
ntfyPriority: z.string().optional(),
icalSecret: z.string().optional(),
aiEnabled: z.coerce.boolean().default(false),
aiProvider: z.enum(["openai", "openai-compatible", "gemini"]).optional(),
aiBaseUrl: z.string().url().optional(),
aiModel: z.string().min(1).optional(),
aiApiKey: z.string().min(1).optional(),
aiSystemPrompt: z.string().optional(),
aiTimeoutSeconds: z.coerce.number().min(5).max(300).default(60),
aiMaxTokens: z.coerce.number().min(256).max(16000).default(2000),
paperlessWebhookSecret: z.string().min(10).optional()
});
function parseBoolean(value: string | undefined, fallback: boolean): boolean {
if (value === undefined) {
return fallback;
}
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
}
function readEnv(name: string): string | undefined {
const value = process.env[name];
if (value === undefined) {
return undefined;
}
return value.trim().length > 0 ? value : undefined;
}
const rawConfig = {
port: readEnv("PORT"),
logLevel: readEnv("LOG_LEVEL"),
databasePath: readEnv("DATABASE_PATH"),
paperlessBaseUrl: readEnv("PAPERLESS_BASE_URL"),
paperlessToken: readEnv("PAPERLESS_TOKEN"),
paperlessExternalUrl: readEnv("PAPERLESS_EXTERNAL_URL"),
paperlessWebhookUrl: readEnv("PAPERLESS_WEBHOOK_URL"),
appExternalUrl: readEnv("APP_EXTERNAL_URL"),
appLocale: readEnv("APP_LOCALE"),
schedulerIntervalMinutes: readEnv("SCHEDULER_INTERVAL_MINUTES"),
alertDaysBefore: readEnv("ALERT_DAYS_BEFORE"),
mailServer: readEnv("MAIL_SERVER"),
mailPort: readEnv("MAIL_PORT"),
mailUsername: readEnv("MAIL_USERNAME"),
mailPassword: readEnv("MAIL_PASSWORD"),
mailUseTls: parseBoolean(readEnv("MAIL_USE_TLS"), true),
mailFrom: readEnv("MAIL_FROM"),
mailTo: readEnv("MAIL_TO"),
authUsername: readEnv("AUTH_USERNAME"),
authPassword: readEnv("AUTH_PASSWORD"),
authJwtSecret: readEnv("AUTH_JWT_SECRET"),
authTokenExpiresInHours: readEnv("AUTH_TOKEN_EXPIRES_IN_HOURS"),
ntfyServerUrl: readEnv("NTFY_SERVER_URL"),
ntfyTopic: readEnv("NTFY_TOPIC"),
ntfyToken: readEnv("NTFY_TOKEN"),
ntfyPriority: readEnv("NTFY_PRIORITY"),
icalSecret: readEnv("ICAL_SECRET"),
aiEnabled: parseBoolean(readEnv("AI_ENABLED"), false),
aiProvider: readEnv("AI_PROVIDER"),
aiBaseUrl: readEnv("AI_BASE_URL"),
aiModel: readEnv("AI_MODEL"),
aiApiKey: readEnv("AI_API_KEY"),
aiSystemPrompt: readEnv("AI_SYSTEM_PROMPT"),
aiTimeoutSeconds: readEnv("AI_TIMEOUT_SECONDS"),
aiMaxTokens: readEnv("AI_MAX_TOKENS"),
paperlessWebhookSecret: readEnv("PAPERLESS_WEBHOOK_SECRET")
};
export type AppConfig = z.infer<typeof configSchema>;
export const config: AppConfig = configSchema.parse(rawConfig);