import { createContext, useContext } from 'react'; export type HashRouterConfig = { enabled?: boolean; basename?: string; }; export type PushConfig = { vapidPublicKey: string; gatewayUrl: string; webAppId?: string; fcmAppId?: string; }; export type BotConfig = { id?: string; mxid?: string; name?: string; /** Optional operator override of the localized description. Falls back * to i18n key `Bots.description.` when absent. */ description?: string; experience?: { type?: string; url?: string; commandPrefix?: string; /** Declarative opt-in to elevated host verbs (e.g. `vojo.add_to_chat`). * Validated against an allowlist at load (catalog.ts `normalizeBotCaps`); * unknown entries are dropped, absent ⇒ `[]`. config.json is a trusted, * operator-controlled root — the widget cannot grant itself a capability. */ capabilities?: string[]; }; }; export type ChannelsConfig = { /** Default true. When false, M4 per-thread unread machinery (badges, * thread-aware receipt handler, drawer markAsRead) falls back to * pre-M4 blind-DELETE semantics. `threadSupport: true` stays on * unconditionally — drawer (M2) reads `room.getThread()` and * ThreadEvent emitters which silently NO-OP without it. */ unreadThreading?: boolean; }; export type ClientConfig = { defaultHomeserver?: number; homeserverList?: string[]; allowCustomHomeservers?: boolean; featuredCommunities?: { openAsDefault?: boolean; spaces?: string[]; rooms?: string[]; servers?: string[]; }; hashRouter?: HashRouterConfig; push?: PushConfig; bots?: BotConfig[]; channels?: ChannelsConfig; }; export const isUnreadThreadingEnabled = (clientConfig: ClientConfig): boolean => clientConfig.channels?.unreadThreading !== false; const ClientConfigContext = createContext(null); export const ClientConfigProvider = ClientConfigContext.Provider; export function useClientConfig(): ClientConfig { const config = useContext(ClientConfigContext); if (!config) throw new Error('Client config are not provided!'); return config; } // Single source of truth for the M4 kill switch. Default true (absent // config = enabled). Consumers should call this hook instead of reading // `useClientConfig()` + `isUnreadThreadingEnabled(...)` separately — // keeps the predicate in one place and lets future telemetry / runtime // flips slot in transparently. export function useUnreadThreadingEnabled(): boolean { return isUnreadThreadingEnabled(useClientConfig()); } export const clientDefaultServer = (clientConfig: ClientConfig): string => clientConfig.homeserverList?.[clientConfig.defaultHomeserver ?? 0] ?? 'matrix.org'; export const clientAllowedServer = (clientConfig: ClientConfig, server: string): boolean => { const { homeserverList, allowCustomHomeservers } = clientConfig; if (allowCustomHomeservers) return true; return homeserverList?.includes(server) === true; };