/** * Color group with five container variants and an OnContainer text color. */ export interface ThemeColorGroup { container: string; containerHover: string; containerActive: string; containerLine: string; onContainer: string; } /** * Color group for interactive palette entries (Main + Container sub-groups). */ export interface ThemePaletteGroup { main: string; mainHover: string; mainActive: string; mainLine: string; onMain: string; container: string; containerHover: string; containerActive: string; containerLine: string; onContainer: string; } /** * Full color token set for a plugin theme. * Property names map directly to the folds design-token contract. */ export interface PluginThemeColors { background: ThemeColorGroup; surface: ThemeColorGroup; surfaceVariant: ThemeColorGroup; primary: ThemePaletteGroup; secondary: ThemePaletteGroup; success: ThemePaletteGroup; warning: ThemePaletteGroup; critical: ThemePaletteGroup; other: { focusRing: string; shadow: string; overlay: string; }; } /** * Theme definition supplied by a plugin. */ export interface PluginTheme { id: string; name: string; kind: 'light' | 'dark'; colors: PluginThemeColors; /** Optional extra CSS injected alongside the theme variables. */ extraCss?: string; } /** * A command argument definition. */ export interface CommandArg { name: string; type?: 'string' | 'number' | 'boolean'; required?: boolean; description?: string; } /** * A command registered by a plugin. */ export interface PluginCommand { name: string; description?: string; args?: string[] | CommandArg[]; run: (args: Record, ctx: PluginContext) => string | void | Promise; } /** Callback invoked for outgoing or incoming messages. */ export type MessageInterceptor = (msg: MessageContext) => void | Promise; /** * Message context passed to interceptors. */ export interface MessageContext { content: string; roomId: string; eventType: string; formatted?: string; metadata?: Record; } /** * Custom renderer function. * The return type is `unknown` so the package stays framework-agnostic. * Hosts using React should cast to `ReactNode` at the call-site. */ export type CustomRenderer = (data: unknown, defaultRenderer?: () => unknown) => unknown; /** * A single setting definition within a plugin's settings schema. */ export interface SettingDefinition { type: 'string' | 'number' | 'boolean' | 'select' | 'color'; label?: string; description?: string; default?: unknown; options?: Array<{ value: unknown; label: string }>; } /** The full settings schema for a plugin. */ export type SettingsSchema = Record; /** * Options for a notification emitted by a plugin. */ export interface NotificationOptions { title: string; body: string; type?: 'info' | 'success' | 'error' | 'warning'; duration?: number; actions?: Array<{ label: string; action: () => void }>; } /** * The context provided to plugins when they are initialized. * All APIs are available through this object. */ export interface PluginContext { /** Plugin ID */ pluginId: string; /** Commands API */ commands: { register: (command: PluginCommand) => void; unregister: (name: string) => void; execute: (name: string, args: Record) => Promise; }; /** Messages API */ messages: { onBeforeSend: (interceptor: MessageInterceptor) => void; onReceive: (interceptor: MessageInterceptor) => void; }; /** UI API — framework-agnostic renderer registry */ ui: { registerRenderer: (type: string, renderer: CustomRenderer) => void; unregisterRenderer: (type: string) => void; registerButton: (button: UIButtonDefinition) => void; unregisterButton: (buttonId: string) => void; }; /** Settings API */ settings: { define: (schema: SettingsSchema) => void; get: (key: string) => T | undefined; set: (key: string, value: unknown) => void; }; /** Themes API */ themes: { register: (theme: PluginTheme) => void; unregister: (themeId: string) => void; }; /** * Generic event emitter API. * Wire up any event client (Matrix, socket.io, Node EventEmitter, etc.) * via the `eventClient` option passed to `createPluginContext`. */ events: { on: (eventType: string, handler: (...args: any[]) => void) => void; off: (eventType: string, handler: (...args: any[]) => void) => void; }; /** Background tasks API */ timers: { setInterval: (callback: () => void, ms: number) => number; setTimeout: (callback: () => void, ms: number) => number; clearInterval: (id: number) => void; clearTimeout: (id: number) => void; }; /** Send a notification through the host application. */ notify: (options: NotificationOptions | string) => void | Promise; /** Logging API */ log: (...args: any[]) => void; warn: (...args: any[]) => void; error: (...args: any[]) => void; /** Require another loaded plugin's exports. */ require: (pluginId: string) => unknown; } /** * Custom settings section that a plugin can inject into the settings UI. * The `component` value is `unknown` to remain framework-agnostic. * Hosts using React should treat it as `ReactNode`. */ export interface PluginSettingsSection { id: string; name: string; icon?: string; component: unknown; } /** UI locations where plugins can inject content. */ export type UILocation = | 'room-header' | 'message-actions' | 'user-menu' | 'room-menu' | 'composer-actions' | 'channel-list' | 'direct-messages' | 'home-section' | 'search-notification-section' | 'text-composer-toolbar' | 'sidebar-actions'; /** * Button positioning configuration for plugins. * Allows buttons to be placed before or after existing elements or groups. */ export interface UIButtonPosition { /** Place button before this element/group ID */ before?: string; /** Place button after this element/group ID */ after?: string; /** * Optional group ID this button belongs to. * Buttons in the same group are rendered together. */ group?: string; /** Order within the group (lower numbers appear first) */ order?: number; } /** * Definition for a UI button registered by a plugin. * Framework-agnostic - the component/element is passed as unknown. */ export interface UIButtonDefinition { /** Unique ID for this button */ id: string; /** Location where the button should appear */ location: UILocation; /** Button label or tooltip */ label: string; /** Optional icon identifier */ icon?: string; /** Positioning configuration */ position?: UIButtonPosition; /** * The actual button component or render function. * Framework-agnostic - hosts using React should cast to ReactNode. */ component: unknown; /** Optional callback when clicked (if component doesn't handle it) */ onClick?: () => void | Promise; } /** * The main plugin interface that all plugins must implement. */ export interface Plugin { name?: string; version?: string; dependencies?: Record; /** Called when the plugin is loaded. */ onLoad: (context: PluginContext) => void | Promise; /** Called when the plugin is unloaded or disabled. */ onUnload?: () => void | Promise; /** Exposed API surface for other plugins to consume via `context.require()`. */ exports?: unknown; } /** * A single log entry produced by a plugin. */ export interface PluginLogEntry { pluginId: string; level: 'log' | 'warn' | 'error'; timestamp: number; args: unknown[]; }