import { loadConfig } from '@codex-team/config-loader'; import * as process from 'process'; import arg from 'arg'; import path from 'path'; import { z } from 'zod'; /** * Configuration for Hawk errors catcher */ const HawkConfig = z.object({ backendToken: z.string().optional(), // Hawk backend token frontendToken: z.string().optional(), // Hawk frontend token }); /** * Config for local uploads driver */ const LocalUploadsConfig = z.object({ driver: z.literal('local'), local: z.object({ path: z.string(), // path to the database directory }), }); /** * Config for S3 uploads driver */ const S3UploadsConfig = z.object({ driver: z.literal('s3'), s3: z.object({ bucket: z.string(), region: z.string(), baseUrl: z.string(), keyPrefix: z.string(), accessKeyId: z.string(), secretAccessKey: z.string(), }), }); export type LocalUploadsConfig = z.infer; export type S3UploadsConfig = z.infer; /** * Config for local database driver */ const LocalDatabaseConfig = z.object({ driver: z.literal('local'), local: z.object({ path: z.string(), // path to the database directory }), }); /** * Config for MongoDB database driver */ const MongoDatabaseConfig = z.object({ driver: z.literal('mongodb'), mongodb: z.object({ uri: z.string(), // MongoDB connection URI }), }); /** * Config for authentication */ const AuthConfig = z.object({ secret: z.string(), // Secret for JWT password: z.string(), // Password for admin panel }); /** * Frontend configuration */ const FrontendConfig = z.object({ title: z.string(), // Title for pages description: z.string(), // Description for pages startPage: z.string(), // Start page misprintsChatId: z.string().optional(), // Telegram chat id for misprints yandexMetrikaId: z.string().optional(), // Yandex metrika id carbon: z.object({ serve: z.string().optional(), // Carbon serve url placement: z.string().optional(), // Carbon placement }), menu: z.array(z.union([z.string(), z.object({ title: z.string(), uri: z.string() })])), // Menu for pages }); /** * Static build configuration */ const StaticBuildConfig = z.object({ outputDir: z.string(), // Output directory for static build indexPageUri: z.string(), // URI for index page to render }); export type StaticBuildConfig = z.infer; /** * Application configuration */ const AppConfig = z.object({ port: z.number(), // Port to listen on host: z.string(), // Host to listen on favicon: z.string().optional(), // Path or URL to favicon uploads: z.union([LocalUploadsConfig, S3UploadsConfig]), // Uploads configuration hawk: HawkConfig.optional().nullable(), // Hawk configuration frontend: FrontendConfig, // Frontend configuration auth: AuthConfig, // Auth configuration database: z.union([LocalDatabaseConfig, MongoDatabaseConfig]), // Database configuration staticBuild: StaticBuildConfig.optional(), // Static build configuration }); export type AppConfig = z.infer; const defaultConfig: AppConfig = { 'port': 3000, 'host': 'localhost', 'uploads': { 'driver': 'local', 'local': { 'path': './uploads', }, }, 'frontend': { 'title': 'CodeX Docs', 'description': 'Free Docs app powered by Editor.js ecosystem', 'startPage': '', 'carbon': { 'serve': '', 'placement': '', }, 'menu': [], }, 'auth': { 'secret': 'supersecret', 'password': 'secretpassword', }, 'hawk': null, 'database': { 'driver': 'local', 'local': { 'path': './db', }, }, }; const args = arg({ /* eslint-disable @typescript-eslint/naming-convention */ '--config': [ String ], '-c': '--config', }); const cwd = process.cwd(); const paths = (args['--config'] || [ './docs-config.yaml' ]).map((configPath) => { if (path.isAbsolute(configPath)) { return configPath; } return path.join(cwd, configPath); }); const loadedConfig = loadConfig(...[defaultConfig, ...paths]); const appConfig = AppConfig.parse(loadedConfig); export default appConfig;