import deepmerge from 'deepmerge'; import type { PartialDeep } from 'type-fest'; import { fetchConfig } from './scripts/fetchConfig'; // Config values overwrite, they don't accumulate — let the source array win. const overwriteArrays = (_destination: unknown[], source: unknown[]) => source; export interface AppConfigModule { /** * Returns the resolved config, initializing it on first access. */ getConfig: () => Promise; /** * Fetches and resolves the config, replacing any previously cached value. */ initializeConfig: () => Promise; } /** * Creates a reusable app config module. * * Each application provides its own config type `T` and a `defaultConfig` used * as the base. The fetched runtime config (see {@link fetchConfig}) is deep-merged * over the defaults. * * @example * ```ts * import { createAppConfig } from '@webitel/ui-sdk/modules/AppConfig'; * import { defaultConfig } from './defaults/defaultConfig'; * import type { AppConfig } from './types/AppConfig'; * * export const { getConfig, initializeConfig } = createAppConfig(defaultConfig); * ``` */ export function createAppConfig( defaultConfig: PartialDeep, ): AppConfigModule { let config: T; async function initializeConfig(): Promise { const fetchedConfig = await fetchConfig(); config = deepmerge>(defaultConfig as Partial, fetchedConfig, { arrayMerge: overwriteArrays, }) as T; return config; } async function getConfig(): Promise { if (!config) { config = await initializeConfig(); } return config; } return { getConfig, initializeConfig, }; } export type { PartialDeep }; export { fetchConfig };