import { readFile } from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; const merchantProfileSchema = z.object({ alias: z.string().min(1), merchantAccount: z.string().min(1), secretKey: z.string().min(1), merchantPassword: z.string().min(1).optional(), domainName: z.string().min(1).optional(), defaultCurrency: z.string().min(1).default("UAH"), serviceUrl: z.string().url().optional(), }); const merchantsSchema = z.array(merchantProfileSchema).min(1); export type MerchantProfile = z.infer; export interface AppConfig { defaultMerchantAlias: string | null; enableWriteTools: boolean; requestTimeoutMs: number; merchants: MerchantProfile[]; } function parseBoolean(rawValue: string | undefined, defaultValue: boolean): boolean { if (rawValue === undefined) { return defaultValue; } return ["1", "true", "yes", "on"].includes(rawValue.trim().toLowerCase()); } function parsePositiveInt(rawValue: string | undefined, defaultValue: number): number { if (rawValue === undefined) { return defaultValue; } const parsed = Number.parseInt(rawValue, 10); if (!Number.isFinite(parsed) || parsed <= 0) { throw new Error(`Expected a positive integer, got "${rawValue}"`); } return parsed; } async function loadMerchants(): Promise { const merchantsJson = process.env.WFP_MERCHANTS_JSON; if (merchantsJson) { const parsed = JSON.parse(merchantsJson); return merchantsSchema.parse(parsed); } const merchantsFile = process.env.WFP_MERCHANTS_FILE; if (!merchantsFile) { throw new Error("WayForPay MCP requires WFP_MERCHANTS_JSON or WFP_MERCHANTS_FILE"); } const resolvedPath = path.isAbsolute(merchantsFile) ? merchantsFile : path.resolve(process.cwd(), merchantsFile); const fileContents = await readFile(resolvedPath, "utf8"); const parsed = JSON.parse(fileContents); return merchantsSchema.parse(parsed); } export async function loadConfig(): Promise { const merchants = await loadMerchants(); const defaultMerchantAlias = process.env.WFP_DEFAULT_MERCHANT ?? (merchants.length === 1 ? merchants[0]!.alias : null); if (defaultMerchantAlias && !merchants.some((merchant) => merchant.alias === defaultMerchantAlias)) { throw new Error(`WFP_DEFAULT_MERCHANT points to unknown alias "${defaultMerchantAlias}"`); } return { defaultMerchantAlias, enableWriteTools: parseBoolean(process.env.WFP_ENABLE_WRITE_TOOLS, false), requestTimeoutMs: parsePositiveInt(process.env.WFP_REQUEST_TIMEOUT_MS, 15_000), merchants, }; }