/** * Plugin system types. * * These types define the plugin architecture and function signatures. * * @module plugin.types */ import type { Config } from '../capabilities/config'; import type { SDK } from '../sdk'; import type { Defaulter, Emitter, Exposer, Extensible, Namespaced, Requirer, } from './capability.types'; /** * Plugin interface combining all capabilities. * * Plugins receive this object as their first parameter, providing access to * all plugin capabilities through capability injection. * * This follows the JSTag3 pattern of intersection types for capabilities. * * @since 1.0.0 - Base capabilities (Namespaced, Emitter, Defaulter, Exposer, Requirer) * @since 2.0.0 - Added Extensible for plugin-to-plugin capabilities */ export interface Plugin extends Namespaced, Emitter, Defaulter, Exposer, Requirer, Extensible {} /** * Plugin function signature. * * Plugins are pure functions that receive capabilities and configure themselves. * This follows the functional plugin pattern from JSTag3. * * Plugins can: * 1. **Set namespace** - Identify themselves and scope configuration * 2. **Set defaults** - Provide default configuration values * 3. **Expose public API** - Add methods to the SDK instance for users * 4. **Hold capabilities** - Provide methods to other plugins (plugin-to-plugin API) * 5. **Listen to events** - Subscribe to SDK and plugin events * 6. **Mark as required** - Prevent SDK initialization if not properly configured * * @param plugin - Plugin capabilities (namespace, emit, defaults, expose, hold, etc.) * @param instance - SDK instance for subscribing to SDK events * @param config - Configuration object for reading plugin config * * @example Basic plugin with user-facing API * ```typescript * function analyticsPlugin( * plugin: Plugin, * instance: SDK, * config: Config * ): void { * // 1. Set namespace * plugin.ns('analytics'); * * // 2. Set defaults * plugin.defaults({ * analytics: { * enabled: true, * endpoint: '/api/track' * } * }); * * // 3. Expose public API * plugin.expose({ * track(event: string, properties?: any) { * const endpoint = config.get('analytics.endpoint'); * fetch(endpoint, { * method: 'POST', * body: JSON.stringify({ event, properties }) * }); * } * }); * * // 4. Listen to SDK events * instance.on('sdk:ready', () => { * console.log('Analytics plugin initialized'); * }); * } * * // Usage * const sdk = new SDK({ analytics: { endpoint: '/track' } }); * sdk.use(analyticsPlugin); * await sdk.init(); * sdk.track('Page Viewed'); * ``` * * @example Plugin providing capabilities to other plugins * ```typescript * // Logging plugin provides log() capability to other plugins * function loggingPlugin(plugin: Plugin, instance: SDK, config: Config): void { * plugin.ns('logging'); * * plugin.defaults({ * logging: { enabled: true, level: 'info' } * }); * * // Provide capability to other plugins via hold() * plugin.hold({ * log(level: string, message: string, data?: any) { * if (!config.get('logging.enabled')) return; * const namespace = this.namespace || 'sdk'; * console.log(`[${namespace}] [${level}] ${message}`, data); * } * }); * } * * // Usage: Load logging first, then other plugins can use plugin.log() * sdk.use(loggingPlugin).use(storagePlugin); * ``` * * @example Plugin using capabilities from other plugins * ```typescript * function storagePlugin(plugin: Plugin, instance: SDK, config: Config): void { * plugin.ns('storage'); * * // Check if logging capability is available * if (!plugin.hasCapability('log')) { * console.warn('[storage] Logging plugin not loaded - logs disabled'); * } * * // Use logging capability if available (safe with optional chaining) * plugin.log?.('info', 'Storage plugin initialized'); * * plugin.expose({ * storage: { * set(key: string, value: any) { * plugin.log?.('debug', 'Storage set', { key }); * localStorage.setItem(key, JSON.stringify(value)); * }, * get(key: string): any { * plugin.log?.('debug', 'Storage get', { key }); * const value = localStorage.getItem(key); * return value ? JSON.parse(value) : undefined; * } * } * }); * } * * // Usage: Load logging before storage to enable logging * sdk.use(loggingPlugin).use(storagePlugin); * ``` * * @example Plugin with required dependency * ```typescript * function analyticsPlugin(plugin: Plugin, instance: SDK, config: Config): void { * plugin.ns('analytics'); * * // Fail fast if required capability is missing * if (!plugin.hasCapability('log')) { * throw new Error('Analytics plugin requires logging plugin to be loaded first'); * } * * plugin.log('info', 'Analytics initialized'); * * plugin.expose({ * track(event: string, properties?: any) { * plugin.log('debug', 'Tracking event', { event, properties }); * // ... tracking logic ... * } * }); * } * * // Load order matters: logging must be loaded first * sdk.use(loggingPlugin).use(analyticsPlugin); * ``` */ export type PluginFunction = (plugin: Plugin, instance: SDK, config: Config) => void;