@scarlett-player/core 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -11
- package/dist/index.js.map +1 -1
- package/dist/scarlett-player.d.ts.map +1 -1
- package/dist/scarlett-player.js +5 -14
- package/dist/scarlett-player.js.map +1 -1
- package/package.json +12 -12
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/state/effect.ts","../src/state/signal.ts","../src/state/computed.ts","../src/state/state-manager.ts","../src/events/event-bus.ts","../src/logger.ts","../src/error-handler.ts","../src/plugin-api.ts","../src/plugin-manager.ts","../src/scarlett-player.ts"],"sourcesContent":["/**\n * Effect tracking for automatic dependency management in signals.\n *\n * When a signal is accessed within an effect, it automatically\n * subscribes the effect to that signal's updates.\n */\n\n/**\n * Effect context that can be modified\n * @internal\n */\nconst effectContext = {\n current: null as (() => void) | null,\n};\n\n/**\n * Currently executing effect (for dependency tracking)\n * @internal\n */\nexport let currentEffect: (() => void) | null = null;\n\n/**\n * Set the current effect context (used internally by computed)\n * @internal\n */\nexport function setCurrentEffect(effect: (() => void) | null): void {\n effectContext.current = effect;\n currentEffect = effect;\n}\n\n/**\n * Get the current effect context\n * @internal\n */\nexport function getCurrentEffect(): (() => void) | null {\n return effectContext.current;\n}\n\n/**\n * Unsubscribe function returned by effect()\n */\nexport type UnsubscribeFn = () => void;\n\n/**\n * Create a reactive effect that runs when its dependencies change.\n *\n * The effect runs immediately and tracks any signals accessed during execution.\n * When those signals change, the effect re-runs automatically.\n *\n * @param fn - Function to run as an effect\n * @returns Unsubscribe function to stop the effect\n *\n * @example\n * ```ts\n * const count = signal(0);\n *\n * effect(() => {\n * console.log('Count:', count.get());\n * });\n *\n * count.set(1); // Logs: \"Count: 1\"\n * ```\n */\nexport function effect(fn: () => void): UnsubscribeFn {\n const execute = () => {\n // Set as current effect for dependency tracking\n setCurrentEffect(execute);\n try {\n fn();\n } catch (error) {\n console.error('[Scarlett Player] Error in effect:', error);\n throw error;\n } finally {\n // Clear current effect\n setCurrentEffect(null);\n }\n };\n\n // Run immediately to establish dependencies\n execute();\n\n // Return cleanup function (can be extended for unsubscribing)\n return () => {\n // Future: Add unsubscribe logic if needed\n };\n}\n","/**\n * Signal - Core reactive primitive for Scarlett Player.\n *\n * Signals are observable values that automatically track dependencies\n * and notify subscribers when the value changes.\n *\n * Target size: ~500 bytes minified\n */\n\nimport { currentEffect, type UnsubscribeFn } from './effect';\n\n/**\n * A reactive signal that holds a value and notifies subscribers on changes.\n *\n * @template T - The type of value held by this signal\n *\n * @example\n * ```ts\n * const count = new Signal(0);\n *\n * // Subscribe to changes\n * const unsub = count.subscribe(() => {\n * console.log('Count changed:', count.get());\n * });\n *\n * count.set(1); // Logs: \"Count changed: 1\"\n * unsub(); // Stop listening\n * ```\n */\nexport class Signal<T> {\n private value: T;\n private subscribers = new Set<() => void>();\n\n constructor(initialValue: T) {\n this.value = initialValue;\n }\n\n /**\n * Get the current value and track dependency if called within an effect.\n *\n * @returns Current value\n */\n get(): T {\n // Track dependency if in effect context\n if (currentEffect) {\n this.subscribers.add(currentEffect);\n }\n return this.value;\n }\n\n /**\n * Set a new value and notify subscribers if changed.\n *\n * @param newValue - New value to set\n */\n set(newValue: T): void {\n // Skip if value hasn't changed\n if (Object.is(this.value, newValue)) {\n return;\n }\n\n this.value = newValue;\n this.notify();\n }\n\n /**\n * Update the value using a function.\n *\n * @param updater - Function that receives current value and returns new value\n *\n * @example\n * ```ts\n * const count = new Signal(0);\n * count.update(n => n + 1); // Increments by 1\n * ```\n */\n update(updater: (current: T) => T): void {\n this.set(updater(this.value));\n }\n\n /**\n * Subscribe to changes without automatic dependency tracking.\n *\n * @param callback - Function to call when value changes\n * @returns Unsubscribe function\n */\n subscribe(callback: () => void): UnsubscribeFn {\n this.subscribers.add(callback);\n return () => this.subscribers.delete(callback);\n }\n\n /**\n * Notify all subscribers of a change.\n * @internal\n */\n private notify(): void {\n this.subscribers.forEach(subscriber => {\n try {\n subscriber();\n } catch (error) {\n console.error('[Scarlett Player] Error in signal subscriber:', error);\n }\n });\n }\n\n /**\n * Clean up all subscriptions.\n * Call this when destroying the signal.\n */\n destroy(): void {\n this.subscribers.clear();\n }\n\n /**\n * Get the current number of subscribers (for debugging).\n * @internal\n */\n getSubscriberCount(): number {\n return this.subscribers.size;\n }\n}\n\n/**\n * Helper function to create a signal.\n *\n * @param initialValue - Initial value for the signal\n * @returns New signal instance\n *\n * @example\n * ```ts\n * const playing = signal(false);\n * playing.set(true);\n * ```\n */\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n","/**\n * Computed - Derived reactive values for Scarlett Player.\n *\n * Computed values are lazy-evaluated and cached until dependencies change.\n *\n * Target size: ~400 bytes minified\n */\n\nimport { currentEffect, setCurrentEffect, getCurrentEffect, type UnsubscribeFn } from './effect';\n\n/**\n * A computed signal that derives its value from other signals.\n *\n * The computation is lazy (only runs when accessed) and cached\n * until dependencies change.\n *\n * @template T - The type of computed value\n *\n * @example\n * ```ts\n * const count = signal(0);\n * const doubled = new Computed(() => count.get() * 2);\n *\n * doubled.get(); // 0\n * count.set(5);\n * doubled.get(); // 10\n * ```\n */\nexport class Computed<T> {\n private value: T | undefined;\n private dirty = true;\n private subscribers = new Set<() => void>();\n private computation: () => T;\n private dependencies = new Set<UnsubscribeFn>();\n private invalidateCallback: () => void;\n\n constructor(computation: () => T) {\n this.computation = computation;\n // Create invalidate callback once to avoid creating new functions\n this.invalidateCallback = () => this.invalidate();\n }\n\n /**\n * Get the computed value, tracking dependency if in effect context.\n *\n * Recomputes if dirty, otherwise returns cached value.\n *\n * @returns Computed value\n */\n get(): T {\n if (this.dirty) {\n // Run computation with this computed as the current effect\n const prevEffect = getCurrentEffect();\n setCurrentEffect(this.invalidateCallback);\n\n try {\n this.value = this.computation();\n this.dirty = false;\n } finally {\n setCurrentEffect(prevEffect);\n }\n }\n\n // Track dependency if in effect context\n if (currentEffect) {\n this.subscribers.add(currentEffect);\n }\n\n return this.value!;\n }\n\n /**\n * Mark the computed value as dirty (needs recomputation).\n *\n * Called when a dependency changes.\n * @internal\n */\n invalidate(): void {\n const wasDirty = this.dirty;\n this.dirty = true;\n\n // Always notify subscribers when invalidated, even if already dirty\n // This ensures subscribers know when dependencies have changed\n if (!wasDirty || this.subscribers.size > 0) {\n this.notifySubscribers();\n }\n }\n\n /**\n * Subscribe to computed value changes.\n *\n * @param callback - Function to call when computed value may have changed\n * @returns Unsubscribe function\n */\n subscribe(callback: () => void): UnsubscribeFn {\n this.subscribers.add(callback);\n return () => this.subscribers.delete(callback);\n }\n\n /**\n * Notify subscribers that this computed value needs recomputation.\n * @internal\n */\n private notifySubscribers(): void {\n this.subscribers.forEach(subscriber => {\n try {\n subscriber();\n } catch (error) {\n console.error('[Scarlett Player] Error in computed subscriber:', error);\n }\n });\n }\n\n /**\n * Clean up all subscriptions.\n */\n destroy(): void {\n this.dependencies.forEach(unsub => unsub());\n this.dependencies.clear();\n this.subscribers.clear();\n this.value = undefined;\n this.dirty = true;\n }\n\n /**\n * Get the current number of subscribers (for debugging).\n * @internal\n */\n getSubscriberCount(): number {\n return this.subscribers.size;\n }\n}\n\n/**\n * Helper function to create a computed signal.\n *\n * @param computation - Function that computes the derived value\n * @returns New computed instance\n *\n * @example\n * ```ts\n * const playing = signal(false);\n * const paused = computed(() => !playing.get());\n * ```\n */\nexport function computed<T>(computation: () => T): Computed<T> {\n return new Computed(computation);\n}\n","/**\n * StateManager - Centralized reactive state management for Scarlett Player.\n *\n * Manages all player state using reactive signals. Each state property\n * is a Signal that can be observed for changes.\n *\n * Target size: ~1-2KB (excluding type definitions)\n */\n\nimport { signal, type Signal } from './signal';\nimport type {\n StateStore,\n StateKey,\n StateValue,\n StateUpdate,\n StateChangeEvent,\n} from '../types/state';\n\n/**\n * Default initial values for all state properties.\n */\nconst DEFAULT_STATE: StateStore = {\n // Core Playback State\n playbackState: 'idle',\n playing: false,\n paused: true,\n ended: false,\n buffering: false,\n waiting: false,\n seeking: false,\n\n // Time & Duration\n currentTime: 0,\n duration: NaN,\n buffered: null,\n bufferedAmount: 0,\n\n // Media Info\n mediaType: 'unknown',\n source: null,\n title: '',\n poster: '',\n\n // Volume & Audio\n volume: 1.0,\n muted: false,\n\n // Playback Controls\n playbackRate: 1.0,\n fullscreen: false,\n pip: false,\n controlsVisible: true,\n\n // Quality & Tracks\n qualities: [],\n currentQuality: null,\n audioTracks: [],\n currentAudioTrack: null,\n textTracks: [],\n currentTextTrack: null,\n\n // Live/DVR State (TSP features)\n live: false,\n liveEdge: true,\n seekableRange: null,\n liveLatency: 0,\n lowLatencyMode: false,\n\n // Chapters (TSP features)\n chapters: [],\n currentChapter: null,\n\n // Error State\n error: null,\n\n // Network & Performance\n bandwidth: 0,\n autoplay: false,\n loop: false,\n\n // Casting State\n airplayAvailable: false,\n airplayActive: false,\n chromecastAvailable: false,\n chromecastActive: false,\n\n // UI State\n interacting: false,\n hovering: false,\n focused: false,\n};\n\n/**\n * StateManager manages all player state using reactive signals.\n *\n * Each state property is a Signal that automatically tracks dependencies\n * and notifies subscribers when changed.\n *\n * @example\n * ```ts\n * const state = new StateManager();\n *\n * // Get a signal\n * const playingSignal = state.get('playing');\n * playingSignal.get(); // false\n *\n * // Set a value\n * state.set('playing', true);\n *\n * // Subscribe to changes\n * state.subscribe((event) => {\n * console.log(`${event.key} changed to`, event.value);\n * });\n *\n * // Batch updates\n * state.update({\n * playing: true,\n * currentTime: 10,\n * volume: 0.8,\n * });\n * ```\n */\nexport class StateManager {\n /** Internal map of state signals */\n private signals = new Map<StateKey, Signal<any>>();\n\n /** Global state change subscribers */\n private changeSubscribers = new Set<(event: StateChangeEvent) => void>();\n\n /**\n * Create a new StateManager with default initial state.\n *\n * @param initialState - Optional partial initial state (merged with defaults)\n */\n constructor(initialState?: Partial<StateStore>) {\n this.initializeSignals(initialState);\n }\n\n /**\n * Initialize all state signals with default or provided values.\n * @private\n */\n private initializeSignals(overrides?: Partial<StateStore>): void {\n const initialState = { ...DEFAULT_STATE, ...overrides };\n\n // Create signals for all state properties\n for (const [key, value] of Object.entries(initialState)) {\n const stateKey = key as StateKey;\n const stateSignal = signal(value);\n\n // Subscribe to each signal to emit global change events\n stateSignal.subscribe(() => {\n this.notifyChangeSubscribers(stateKey);\n });\n\n this.signals.set(stateKey, stateSignal);\n }\n }\n\n /**\n * Get the signal for a state property.\n *\n * @param key - State property key\n * @returns Signal for the property\n *\n * @example\n * ```ts\n * const playingSignal = state.get('playing');\n * playingSignal.get(); // false\n * playingSignal.set(true);\n * ```\n */\n get<K extends StateKey>(key: K): Signal<StateValue<K>> {\n const stateSignal = this.signals.get(key);\n if (!stateSignal) {\n throw new Error(`[StateManager] Unknown state key: ${key}`);\n }\n return stateSignal as Signal<StateValue<K>>;\n }\n\n /**\n * Get the current value of a state property (convenience method).\n *\n * @param key - State property key\n * @returns Current value\n *\n * @example\n * ```ts\n * state.getValue('playing'); // false\n * ```\n */\n getValue<K extends StateKey>(key: K): StateValue<K> {\n return this.get(key).get();\n }\n\n /**\n * Set the value of a state property.\n *\n * @param key - State property key\n * @param value - New value\n *\n * @example\n * ```ts\n * state.set('playing', true);\n * state.set('currentTime', 10.5);\n * ```\n */\n set<K extends StateKey>(key: K, value: StateValue<K>): void {\n this.get(key).set(value);\n }\n\n /**\n * Update multiple state properties at once (batch update).\n *\n * More efficient than calling set() multiple times.\n *\n * @param updates - Partial state object with updates\n *\n * @example\n * ```ts\n * state.update({\n * playing: true,\n * currentTime: 0,\n * volume: 1.0,\n * });\n * ```\n */\n update(updates: StateUpdate): void {\n for (const [key, value] of Object.entries(updates)) {\n const stateKey = key as StateKey;\n if (this.signals.has(stateKey)) {\n this.set(stateKey, value);\n }\n }\n }\n\n /**\n * Subscribe to changes on a specific state property.\n *\n * @param key - State property key\n * @param callback - Callback function receiving new value\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = state.subscribe('playing', (value) => {\n * console.log('Playing:', value);\n * });\n * ```\n */\n subscribeToKey<K extends StateKey>(\n key: K,\n callback: (value: StateValue<K>) => void\n ): () => void {\n const stateSignal = this.get(key);\n return stateSignal.subscribe(() => {\n callback(stateSignal.get());\n });\n }\n\n /**\n * Subscribe to all state changes.\n *\n * Receives a StateChangeEvent for every state property change.\n *\n * @param callback - Callback function receiving change events\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = state.subscribe((event) => {\n * console.log(`${event.key} changed:`, event.value);\n * });\n * ```\n */\n subscribe(callback: (event: StateChangeEvent) => void): () => void {\n this.changeSubscribers.add(callback);\n return () => this.changeSubscribers.delete(callback);\n }\n\n /**\n * Notify all global change subscribers.\n * @private\n */\n private notifyChangeSubscribers<K extends StateKey>(key: K): void {\n const stateSignal = this.get(key);\n const value = stateSignal.get();\n\n const event: StateChangeEvent<K> = {\n key,\n value,\n previousValue: value, // Note: We don't track previous values in this simple impl\n };\n\n this.changeSubscribers.forEach(subscriber => {\n try {\n subscriber(event);\n } catch (error) {\n console.error('[StateManager] Error in change subscriber:', error);\n }\n });\n }\n\n /**\n * Reset all state to default values.\n *\n * @example\n * ```ts\n * state.reset();\n * ```\n */\n reset(): void {\n this.update(DEFAULT_STATE);\n }\n\n /**\n * Reset a specific state property to its default value.\n *\n * @param key - State property key\n *\n * @example\n * ```ts\n * state.resetKey('playing');\n * ```\n */\n resetKey<K extends StateKey>(key: K): void {\n const defaultValue = DEFAULT_STATE[key] as StateValue<K>;\n this.set(key, defaultValue);\n }\n\n /**\n * Get a snapshot of all current state values.\n *\n * @returns Frozen snapshot of current state\n *\n * @example\n * ```ts\n * const snapshot = state.snapshot();\n * console.log(snapshot.playing, snapshot.currentTime);\n * ```\n */\n snapshot(): Readonly<StateStore> {\n const snapshot: Partial<StateStore> = {};\n\n for (const [key, stateSignal] of this.signals) {\n (snapshot as any)[key] = stateSignal.get();\n }\n\n return Object.freeze(snapshot as StateStore);\n }\n\n /**\n * Get the number of subscribers for a state property (for debugging).\n *\n * @param key - State property key\n * @returns Number of subscribers\n * @internal\n */\n getSubscriberCount(key: StateKey): number {\n return this.signals.get(key)?.getSubscriberCount() ?? 0;\n }\n\n /**\n * Destroy the state manager and cleanup all signals.\n *\n * @example\n * ```ts\n * state.destroy();\n * ```\n */\n destroy(): void {\n // Destroy all signals\n this.signals.forEach(stateSignal => stateSignal.destroy());\n this.signals.clear();\n\n // Clear change subscribers\n this.changeSubscribers.clear();\n }\n}\n","/**\n * EventBus - Type-safe event system for Scarlett Player.\n *\n * Provides pub/sub event communication between player components and plugins\n * with optional interceptors for event modification/cancellation.\n *\n * Target size: ~1KB\n */\n\nimport type {\n EventName,\n EventPayload,\n EventHandler,\n EventInterceptor,\n EventEmitterOptions,\n} from '../types/events';\n\n/**\n * Default options for EventBus.\n */\nconst DEFAULT_OPTIONS: Required<EventEmitterOptions> = {\n maxListeners: 100,\n async: false,\n interceptors: true,\n};\n\n/**\n * EventBus provides type-safe event emission and subscription.\n *\n * Features:\n * - Type-safe events based on PlayerEventMap\n * - Event interceptors for modification/cancellation\n * - One-time subscriptions with once()\n * - Async event emission\n * - Error handling for handlers\n *\n * @example\n * ```ts\n * const events = new EventBus();\n *\n * // Subscribe to event\n * events.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Emit event\n * events.emit('playback:play', undefined);\n *\n * // Intercept events\n * events.intercept('playback:timeupdate', (payload) => {\n * // Modify payload or return null to cancel\n * return { currentTime: Math.floor(payload.currentTime) };\n * });\n * ```\n */\nexport class EventBus {\n /** Event listeners map */\n private listeners = new Map<EventName, Set<EventHandler<any>>>();\n\n /** One-time listeners (removed after first call) */\n private onceListeners = new Map<EventName, Set<EventHandler<any>>>();\n\n /** Event interceptors map */\n private interceptors = new Map<EventName, Set<EventInterceptor<any>>>();\n\n /** Configuration options */\n private options: Required<EventEmitterOptions>;\n\n /**\n * Create a new EventBus.\n *\n * @param options - Optional configuration\n */\n constructor(options?: EventEmitterOptions) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n /**\n * Subscribe to an event.\n *\n * @param event - Event name\n * @param handler - Event handler function\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = events.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Later: unsubscribe\n * unsub();\n * ```\n */\n on<T extends EventName>(event: T, handler: EventHandler<T>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n const handlers = this.listeners.get(event)!;\n handlers.add(handler);\n\n // Warn if max listeners exceeded\n this.checkMaxListeners(event);\n\n return () => this.off(event, handler);\n }\n\n /**\n * Subscribe to an event once (auto-unsubscribe after first call).\n *\n * @param event - Event name\n * @param handler - Event handler function\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * events.once('player:ready', () => {\n * console.log('Player ready!');\n * });\n * ```\n */\n once<T extends EventName>(event: T, handler: EventHandler<T>): () => void {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n\n const handlers = this.onceListeners.get(event)!;\n handlers.add(handler);\n\n // Also track in regular listeners for counting\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n return () => {\n handlers.delete(handler);\n };\n }\n\n /**\n * Unsubscribe from an event.\n *\n * @param event - Event name\n * @param handler - Event handler function to remove\n *\n * @example\n * ```ts\n * const handler = () => console.log('Playing!');\n * events.on('playback:play', handler);\n * events.off('playback:play', handler);\n * ```\n */\n off<T extends EventName>(event: T, handler: EventHandler<T>): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n const onceHandlers = this.onceListeners.get(event);\n if (onceHandlers) {\n onceHandlers.delete(handler);\n if (onceHandlers.size === 0) {\n this.onceListeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event synchronously.\n *\n * Runs interceptors first, then calls all handlers.\n *\n * @param event - Event name\n * @param payload - Event payload\n *\n * @example\n * ```ts\n * events.emit('playback:play', undefined);\n * events.emit('playback:timeupdate', { currentTime: 10.5 });\n * ```\n */\n emit<T extends EventName>(event: T, payload: EventPayload<T>): void {\n // Run interceptors\n const interceptedPayload = this.runInterceptors(event, payload);\n if (interceptedPayload === null) {\n // Event cancelled by interceptor\n return;\n }\n\n // Call regular handlers\n const handlers = this.listeners.get(event);\n if (handlers) {\n // Create array to avoid calling handlers added during iteration\n const handlersArray = Array.from(handlers);\n handlersArray.forEach(handler => {\n this.safeCallHandler(handler, interceptedPayload);\n });\n }\n\n // Call once handlers\n const onceHandlers = this.onceListeners.get(event);\n if (onceHandlers) {\n // Create array to avoid modification during iteration\n const handlersArray = Array.from(onceHandlers);\n handlersArray.forEach(handler => {\n this.safeCallHandler(handler, interceptedPayload);\n });\n // Clear once handlers after calling\n this.onceListeners.delete(event);\n }\n }\n\n /**\n * Emit an event asynchronously (next tick).\n *\n * @param event - Event name\n * @param payload - Event payload\n * @returns Promise that resolves when all handlers complete\n *\n * @example\n * ```ts\n * await events.emitAsync('media:loaded', { src: 'video.mp4', type: 'video/mp4' });\n * ```\n */\n async emitAsync<T extends EventName>(\n event: T,\n payload: EventPayload<T>\n ): Promise<void> {\n // Run interceptors\n const interceptedPayload = await this.runInterceptorsAsync(event, payload);\n if (interceptedPayload === null) {\n // Event cancelled by interceptor\n return;\n }\n\n // Call regular handlers\n const handlers = this.listeners.get(event);\n if (handlers) {\n const promises = Array.from(handlers).map(handler =>\n this.safeCallHandlerAsync(handler, interceptedPayload)\n );\n await Promise.all(promises);\n }\n\n // Call once handlers\n const onceHandlers = this.onceListeners.get(event);\n if (onceHandlers) {\n const handlersArray = Array.from(onceHandlers);\n const promises = handlersArray.map(handler =>\n this.safeCallHandlerAsync(handler, interceptedPayload)\n );\n await Promise.all(promises);\n // Clear once handlers after calling\n this.onceListeners.delete(event);\n }\n }\n\n /**\n * Add an event interceptor.\n *\n * Interceptors run before handlers and can modify or cancel events.\n *\n * @param event - Event name\n * @param interceptor - Interceptor function\n * @returns Remove interceptor function\n *\n * @example\n * ```ts\n * events.intercept('playback:timeupdate', (payload) => {\n * // Round time to 2 decimals\n * return { currentTime: Math.round(payload.currentTime * 100) / 100 };\n * });\n *\n * // Cancel events\n * events.intercept('playback:play', (payload) => {\n * if (notReady) return null; // Cancel event\n * return payload;\n * });\n * ```\n */\n intercept<T extends EventName>(\n event: T,\n interceptor: EventInterceptor<T>\n ): () => void {\n if (!this.options.interceptors) {\n return () => {}; // No-op if interceptors disabled\n }\n\n if (!this.interceptors.has(event)) {\n this.interceptors.set(event, new Set());\n }\n\n const interceptorsSet = this.interceptors.get(event)!;\n interceptorsSet.add(interceptor);\n\n return () => {\n interceptorsSet.delete(interceptor);\n if (interceptorsSet.size === 0) {\n this.interceptors.delete(event);\n }\n };\n }\n\n /**\n * Remove all listeners for an event (or all events if no event specified).\n *\n * @param event - Optional event name\n *\n * @example\n * ```ts\n * events.removeAllListeners('playback:play'); // Remove all playback:play listeners\n * events.removeAllListeners(); // Remove ALL listeners\n * ```\n */\n removeAllListeners(event?: EventName): void {\n if (event) {\n this.listeners.delete(event);\n this.onceListeners.delete(event);\n } else {\n this.listeners.clear();\n this.onceListeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event.\n *\n * @param event - Event name\n * @returns Number of listeners\n *\n * @example\n * ```ts\n * events.listenerCount('playback:play'); // 3\n * ```\n */\n listenerCount(event: EventName): number {\n const regularCount = this.listeners.get(event)?.size ?? 0;\n const onceCount = this.onceListeners.get(event)?.size ?? 0;\n return regularCount + onceCount;\n }\n\n /**\n * Destroy event bus and cleanup all listeners/interceptors.\n *\n * @example\n * ```ts\n * events.destroy();\n * ```\n */\n destroy(): void {\n this.listeners.clear();\n this.onceListeners.clear();\n this.interceptors.clear();\n }\n\n /**\n * Run interceptors synchronously.\n * @private\n */\n private runInterceptors<T extends EventName>(\n event: T,\n payload: EventPayload<T>\n ): EventPayload<T> | null {\n if (!this.options.interceptors) {\n return payload;\n }\n\n const interceptorsSet = this.interceptors.get(event);\n if (!interceptorsSet || interceptorsSet.size === 0) {\n return payload;\n }\n\n let currentPayload: EventPayload<T> | null = payload;\n\n for (const interceptor of interceptorsSet) {\n try {\n currentPayload = interceptor(currentPayload as any) as EventPayload<T> | null;\n if (currentPayload === null) {\n // Event cancelled\n return null;\n }\n } catch (error) {\n console.error('[EventBus] Error in interceptor:', error);\n // Continue with other interceptors\n }\n }\n\n return currentPayload;\n }\n\n /**\n * Run interceptors asynchronously.\n * @private\n */\n private async runInterceptorsAsync<T extends EventName>(\n event: T,\n payload: EventPayload<T>\n ): Promise<EventPayload<T> | null> {\n if (!this.options.interceptors) {\n return payload;\n }\n\n const interceptorsSet = this.interceptors.get(event);\n if (!interceptorsSet || interceptorsSet.size === 0) {\n return payload;\n }\n\n let currentPayload: EventPayload<T> | null = payload;\n\n for (const interceptor of interceptorsSet) {\n try {\n const result = interceptor(currentPayload as any);\n currentPayload = (result instanceof Promise ? await result : result) as EventPayload<T> | null;\n if (currentPayload === null) {\n // Event cancelled\n return null;\n }\n } catch (error) {\n console.error('[EventBus] Error in interceptor:', error);\n // Continue with other interceptors\n }\n }\n\n return currentPayload;\n }\n\n /**\n * Safely call a handler with error handling.\n * @private\n */\n private safeCallHandler<T extends EventName>(\n handler: EventHandler<T>,\n payload: EventPayload<T>\n ): void {\n try {\n handler(payload);\n } catch (error) {\n console.error('[EventBus] Error in event handler:', error);\n }\n }\n\n /**\n * Safely call a handler asynchronously with error handling.\n * @private\n */\n private async safeCallHandlerAsync<T extends EventName>(\n handler: EventHandler<T>,\n payload: EventPayload<T>\n ): Promise<void> {\n try {\n const result = handler(payload);\n if (result instanceof Promise) {\n await result;\n }\n } catch (error) {\n console.error('[EventBus] Error in event handler:', error);\n }\n }\n\n /**\n * Check if max listeners exceeded and warn.\n * @private\n */\n private checkMaxListeners(event: EventName): void {\n const count = this.listenerCount(event);\n if (count > this.options.maxListeners) {\n console.warn(\n `[EventBus] Max listeners (${this.options.maxListeners}) exceeded for event: ${event}. ` +\n `Current count: ${count}. This may indicate a memory leak.`\n );\n }\n }\n}\n","/**\n * Logger - Structured logging system for Scarlett Player.\n *\n * Provides leveled logging with plugin-scoped child loggers,\n * structured metadata, and custom log handlers.\n *\n * Target size: ~0.3-0.5KB\n */\n\n/**\n * Log severity levels.\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Structured log entry.\n */\nexport interface LogEntry {\n /** Severity level */\n level: LogLevel;\n /** Log message */\n message: string;\n /** Timestamp (milliseconds since epoch) */\n timestamp: number;\n /** Optional scope (e.g., plugin name) */\n scope?: string;\n /** Optional structured metadata */\n metadata?: Record<string, any>;\n}\n\n/**\n * Custom log handler function.\n */\nexport type LogHandler = (entry: LogEntry) => void;\n\n/**\n * Logger options.\n */\nexport interface LoggerOptions {\n /** Minimum log level to output (default: 'warn') */\n level?: LogLevel;\n /** Logger scope (e.g., plugin name) */\n scope?: string;\n /** Enable/disable logging (default: true) */\n enabled?: boolean;\n /** Custom log handlers (default: console handler) */\n handlers?: LogHandler[];\n}\n\n/**\n * Log level ordering for threshold comparison.\n */\nconst LOG_LEVELS: LogLevel[] = ['debug', 'info', 'warn', 'error'];\n\n/**\n * Default console handler for log entries.\n * @private\n */\nconst defaultConsoleHandler: LogHandler = (entry) => {\n const prefix = entry.scope ? `[${entry.scope}]` : '[ScarlettPlayer]';\n const message = `${prefix} ${entry.message}`;\n const metadata = entry.metadata ?? '';\n\n switch (entry.level) {\n case 'debug':\n console.debug(message, metadata);\n break;\n case 'info':\n console.info(message, metadata);\n break;\n case 'warn':\n console.warn(message, metadata);\n break;\n case 'error':\n console.error(message, metadata);\n break;\n }\n};\n\n/**\n * Logger provides structured, leveled logging with plugin scoping.\n *\n * Features:\n * - Log levels: debug, info, warn, error\n * - Plugin-scoped child loggers\n * - Structured metadata support\n * - Custom log handlers\n * - Dynamic level and enable/disable\n *\n * @example\n * ```ts\n * // Main player logger\n * const logger = new Logger({ level: 'warn' });\n * logger.info('Player initialized');\n *\n * // Plugin logger (scoped)\n * const pluginLogger = logger.child('hls-plugin');\n * pluginLogger.debug('Manifest loaded', { url: 'video.m3u8' });\n * // Output: [ScarlettPlayer:hls-plugin] Manifest loaded\n *\n * // Custom handler for analytics\n * logger.addHandler((entry) => {\n * if (entry.level === 'error') {\n * sendToAnalytics(entry);\n * }\n * });\n *\n * // Change level dynamically\n * if (import.meta.env.DEV) {\n * logger.setLevel('debug');\n * }\n * ```\n */\nexport class Logger {\n /** Minimum log level threshold */\n private level: LogLevel;\n\n /** Logger scope (e.g., plugin name) */\n private scope?: string;\n\n /** Log handlers */\n private handlers: LogHandler[];\n\n /** Enable/disable logging */\n private enabled: boolean;\n\n /**\n * Create a new Logger.\n *\n * @param options - Logger configuration\n */\n constructor(options?: LoggerOptions) {\n this.level = options?.level ?? 'warn';\n this.scope = options?.scope;\n this.enabled = options?.enabled ?? true;\n this.handlers = options?.handlers ?? [defaultConsoleHandler];\n }\n\n /**\n * Create a child logger with a scope.\n *\n * Child loggers inherit parent settings and chain scopes.\n *\n * @param scope - Child logger scope\n * @returns New child logger\n *\n * @example\n * ```ts\n * const logger = new Logger();\n * const hlsLogger = logger.child('hls-plugin');\n * hlsLogger.info('Loading manifest');\n * // Output: [ScarlettPlayer:hls-plugin] Loading manifest\n * ```\n */\n child(scope: string): Logger {\n return new Logger({\n level: this.level,\n scope: this.scope ? `${this.scope}:${scope}` : scope,\n enabled: this.enabled,\n handlers: this.handlers,\n });\n }\n\n /**\n * Log a debug message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.debug('Request sent', { url: '/api/video' });\n * ```\n */\n debug(message: string, metadata?: Record<string, any>): void {\n this.log('debug', message, metadata);\n }\n\n /**\n * Log an info message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.info('Player ready');\n * ```\n */\n info(message: string, metadata?: Record<string, any>): void {\n this.log('info', message, metadata);\n }\n\n /**\n * Log a warning message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.warn('Low buffer', { buffered: 2.5 });\n * ```\n */\n warn(message: string, metadata?: Record<string, any>): void {\n this.log('warn', message, metadata);\n }\n\n /**\n * Log an error message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.error('Playback failed', { code: 'MEDIA_ERR_DECODE' });\n * ```\n */\n error(message: string, metadata?: Record<string, any>): void {\n this.log('error', message, metadata);\n }\n\n /**\n * Set the minimum log level threshold.\n *\n * @param level - New log level\n *\n * @example\n * ```ts\n * logger.setLevel('debug'); // Show all logs\n * logger.setLevel('error'); // Show only errors\n * ```\n */\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n /**\n * Enable or disable logging.\n *\n * @param enabled - Enable flag\n *\n * @example\n * ```ts\n * logger.setEnabled(false); // Disable all logging\n * ```\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /**\n * Add a custom log handler.\n *\n * @param handler - Log handler function\n *\n * @example\n * ```ts\n * logger.addHandler((entry) => {\n * if (entry.level === 'error') {\n * sendToAnalytics(entry);\n * }\n * });\n * ```\n */\n addHandler(handler: LogHandler): void {\n this.handlers.push(handler);\n }\n\n /**\n * Remove a custom log handler.\n *\n * @param handler - Log handler function to remove\n *\n * @example\n * ```ts\n * logger.removeHandler(myHandler);\n * ```\n */\n removeHandler(handler: LogHandler): void {\n const index = this.handlers.indexOf(handler);\n if (index !== -1) {\n this.handlers.splice(index, 1);\n }\n }\n\n /**\n * Core logging implementation.\n * @private\n */\n private log(\n level: LogLevel,\n message: string,\n metadata?: Record<string, any>\n ): void {\n if (!this.enabled || !this.shouldLog(level)) {\n return;\n }\n\n const entry: LogEntry = {\n level,\n message,\n timestamp: Date.now(),\n scope: this.scope,\n metadata,\n };\n\n for (const handler of this.handlers) {\n try {\n handler(entry);\n } catch (error) {\n // Don't let handler errors break logging\n console.error('[Logger] Handler error:', error);\n }\n }\n }\n\n /**\n * Check if a log level should be output.\n * @private\n */\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.level);\n }\n}\n\n/**\n * Create a new logger instance.\n *\n * Convenience factory function.\n *\n * @param scope - Optional logger scope\n * @returns New Logger instance\n *\n * @example\n * ```ts\n * const logger = createLogger('my-plugin');\n * logger.info('Plugin initialized');\n * ```\n */\nexport function createLogger(scope?: string): Logger {\n return new Logger({ scope });\n}\n","/**\n * ErrorHandler - Centralized error handling for Scarlett Player.\n *\n * Provides error classification, logging, history tracking, and event emission\n * for all player errors.\n *\n * Target size: ~0.4-0.6KB\n */\n\nimport type { EventBus } from './events/event-bus';\nimport type { Logger } from './logger';\n\n/**\n * Player error codes.\n */\nexport enum ErrorCode {\n // Source loading errors\n SOURCE_NOT_SUPPORTED = 'SOURCE_NOT_SUPPORTED',\n SOURCE_LOAD_FAILED = 'SOURCE_LOAD_FAILED',\n\n // Provider errors\n PROVIDER_NOT_FOUND = 'PROVIDER_NOT_FOUND',\n PROVIDER_SETUP_FAILED = 'PROVIDER_SETUP_FAILED',\n\n // Plugin errors\n PLUGIN_SETUP_FAILED = 'PLUGIN_SETUP_FAILED',\n PLUGIN_NOT_FOUND = 'PLUGIN_NOT_FOUND',\n\n // Playback errors\n PLAYBACK_FAILED = 'PLAYBACK_FAILED',\n MEDIA_DECODE_ERROR = 'MEDIA_DECODE_ERROR',\n MEDIA_NETWORK_ERROR = 'MEDIA_NETWORK_ERROR',\n\n // General errors\n UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n}\n\n/**\n * Structured player error.\n */\nexport interface PlayerError {\n /** Error code */\n code: ErrorCode;\n /** Error message */\n message: string;\n /** Whether error is fatal (unrecoverable) */\n fatal: boolean;\n /** Timestamp (milliseconds since epoch) */\n timestamp: number;\n /** Optional context (what was happening) */\n context?: Record<string, any>;\n /** Original error if wrapped */\n originalError?: Error;\n}\n\n/**\n * ErrorHandler options.\n */\nexport interface ErrorHandlerOptions {\n /** Maximum error history to keep (default: 10) */\n maxHistory?: number;\n}\n\n/**\n * ErrorHandler manages all player errors with classification and history.\n *\n * Features:\n * - Error classification (fatal vs recoverable)\n * - Error code mapping\n * - Error event emission\n * - Error history tracking\n * - Context capture\n * - Logger integration\n *\n * @example\n * ```ts\n * const errorHandler = new ErrorHandler(eventBus, logger);\n *\n * // Handle native error\n * try {\n * // Some operation\n * } catch (error) {\n * errorHandler.handle(error as Error, {\n * operation: 'loadSource',\n * src: 'video.mp4'\n * });\n * }\n *\n * // Throw specific error\n * errorHandler.throw(\n * ErrorCode.SOURCE_NOT_SUPPORTED,\n * 'MP4 files are not supported',\n * { fatal: true, context: { src: 'video.mp4' } }\n * );\n *\n * // Check error history\n * const lastError = errorHandler.getLastError();\n * const hasFatal = errorHandler.hasFatalError();\n * ```\n */\nexport class ErrorHandler {\n /** Event bus for error emission */\n private eventBus: EventBus;\n\n /** Logger for error logging */\n private logger: Logger;\n\n /** Error history */\n private errors: PlayerError[] = [];\n\n /** Maximum history size */\n private maxHistory: number;\n\n /**\n * Create a new ErrorHandler.\n *\n * @param eventBus - Event bus for error emission\n * @param logger - Logger for error logging\n * @param options - Optional configuration\n */\n constructor(eventBus: EventBus, logger: Logger, options?: ErrorHandlerOptions) {\n this.eventBus = eventBus;\n this.logger = logger;\n this.maxHistory = options?.maxHistory ?? 10;\n }\n\n /**\n * Handle an error.\n *\n * Normalizes, logs, emits, and tracks the error.\n *\n * @param error - Error to handle (native or PlayerError)\n * @param context - Optional context (what was happening)\n * @returns Normalized PlayerError\n *\n * @example\n * ```ts\n * try {\n * loadVideo();\n * } catch (error) {\n * errorHandler.handle(error as Error, { src: 'video.mp4' });\n * }\n * ```\n */\n handle(error: Error | PlayerError, context?: Record<string, any>): PlayerError {\n const playerError = this.normalizeError(error, context);\n\n // Add to history\n this.addToHistory(playerError);\n\n // Log the error\n this.logError(playerError);\n\n // Emit error event\n this.eventBus.emit('error', playerError);\n\n return playerError;\n }\n\n /**\n * Create and handle an error from code.\n *\n * @param code - Error code\n * @param message - Error message\n * @param options - Optional error options\n * @returns Created PlayerError\n *\n * @example\n * ```ts\n * errorHandler.throw(\n * ErrorCode.SOURCE_NOT_SUPPORTED,\n * 'MP4 not supported',\n * { fatal: true, context: { type: 'video/mp4' } }\n * );\n * ```\n */\n throw(\n code: ErrorCode,\n message: string,\n options?: {\n fatal?: boolean;\n context?: Record<string, any>;\n originalError?: Error;\n }\n ): PlayerError {\n const error: PlayerError = {\n code,\n message,\n fatal: options?.fatal ?? this.isFatalCode(code),\n timestamp: Date.now(),\n context: options?.context,\n originalError: options?.originalError,\n };\n\n return this.handle(error, options?.context);\n }\n\n /**\n * Get error history.\n *\n * @returns Readonly copy of error history\n *\n * @example\n * ```ts\n * const history = errorHandler.getHistory();\n * console.log(`${history.length} errors occurred`);\n * ```\n */\n getHistory(): readonly PlayerError[] {\n return [...this.errors];\n }\n\n /**\n * Get last error that occurred.\n *\n * @returns Last error or null if none\n *\n * @example\n * ```ts\n * const lastError = errorHandler.getLastError();\n * if (lastError?.fatal) {\n * showErrorMessage(lastError.message);\n * }\n * ```\n */\n getLastError(): PlayerError | null {\n return this.errors[this.errors.length - 1] ?? null;\n }\n\n /**\n * Clear error history.\n *\n * @example\n * ```ts\n * errorHandler.clearHistory();\n * ```\n */\n clearHistory(): void {\n this.errors = [];\n }\n\n /**\n * Check if any fatal errors occurred.\n *\n * @returns True if any fatal error in history\n *\n * @example\n * ```ts\n * if (errorHandler.hasFatalError()) {\n * player.reset();\n * }\n * ```\n */\n hasFatalError(): boolean {\n return this.errors.some((e) => e.fatal);\n }\n\n /**\n * Normalize error to PlayerError.\n * @private\n */\n private normalizeError(\n error: Error | PlayerError,\n context?: Record<string, any>\n ): PlayerError {\n if (this.isPlayerError(error)) {\n return {\n ...error,\n context: { ...error.context, ...context },\n };\n }\n\n // Convert native Error to PlayerError\n return {\n code: this.getErrorCode(error),\n message: error.message,\n fatal: this.isFatal(error),\n timestamp: Date.now(),\n context,\n originalError: error,\n };\n }\n\n /**\n * Determine error code from native Error.\n * @private\n */\n private getErrorCode(error: Error): ErrorCode {\n const message = error.message.toLowerCase();\n\n if (message.includes('network')) {\n return ErrorCode.MEDIA_NETWORK_ERROR;\n }\n if (message.includes('decode')) {\n return ErrorCode.MEDIA_DECODE_ERROR;\n }\n if (message.includes('source')) {\n return ErrorCode.SOURCE_LOAD_FAILED;\n }\n if (message.includes('plugin')) {\n return ErrorCode.PLUGIN_SETUP_FAILED;\n }\n if (message.includes('provider')) {\n return ErrorCode.PROVIDER_SETUP_FAILED;\n }\n\n return ErrorCode.UNKNOWN_ERROR;\n }\n\n /**\n * Determine if error is fatal.\n * @private\n */\n private isFatal(error: Error): boolean {\n return this.isFatalCode(this.getErrorCode(error));\n }\n\n /**\n * Determine if error code is fatal.\n * @private\n */\n private isFatalCode(code: ErrorCode): boolean {\n const fatalCodes = [\n ErrorCode.SOURCE_NOT_SUPPORTED,\n ErrorCode.PROVIDER_NOT_FOUND,\n ErrorCode.MEDIA_DECODE_ERROR,\n ];\n return fatalCodes.includes(code);\n }\n\n /**\n * Type guard for PlayerError.\n * @private\n */\n private isPlayerError(error: any): error is PlayerError {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n 'message' in error &&\n 'fatal' in error &&\n 'timestamp' in error\n );\n }\n\n /**\n * Add error to history.\n * @private\n */\n private addToHistory(error: PlayerError): void {\n this.errors.push(error);\n\n // Keep only max history\n if (this.errors.length > this.maxHistory) {\n this.errors.shift();\n }\n }\n\n /**\n * Log error with appropriate level.\n * @private\n */\n private logError(error: PlayerError): void {\n const logMessage = `[${error.code}] ${error.message}`;\n\n if (error.fatal) {\n this.logger.error(logMessage, {\n code: error.code,\n context: error.context,\n });\n } else {\n this.logger.warn(logMessage, {\n code: error.code,\n context: error.context,\n });\n }\n }\n}\n","/**\n * PluginAPI - Scoped API surface for plugins.\n *\n * Wraps StateManager and EventBus to provide a controlled interface\n * for plugins to interact with player state and events.\n *\n * Target size: ~0.5KB\n */\n\nimport type { StateManager } from './state/state-manager';\nimport type { EventBus } from './events/event-bus';\nimport type { Logger } from './logger';\nimport type { StateKey, StateValue, StateChangeEvent } from './types/state';\nimport type { EventName, EventPayload, EventHandler } from './types/events';\nimport type { IPluginAPI } from './types/plugin';\n\n/**\n * PluginAPI dependencies.\n */\nexport interface PluginAPIDeps {\n stateManager: StateManager;\n eventBus: EventBus;\n logger: Logger;\n container: HTMLElement;\n getPlugin: <T = unknown>(id: string) => T | null;\n}\n\n/**\n * PluginAPI provides a scoped interface for plugins to interact with the player.\n *\n * Instead of giving plugins direct access to StateManager and EventBus,\n * PluginAPI provides controlled methods that can be scoped, logged, and monitored.\n *\n * @example\n * ```ts\n * // Inside a plugin's init() method:\n * init(api: IPluginAPI) {\n * // Get state\n * const isPlaying = api.getState('playing');\n *\n * // Set state\n * api.setState('volume', 0.8);\n *\n * // Subscribe to events\n * const unsub = api.on('playback:play', () => {\n * console.log('Playback started');\n * });\n *\n * // Emit events\n * api.emit('plugin:ready', { name: this.id });\n *\n * // Register cleanup\n * api.onDestroy(unsub);\n * }\n * ```\n */\nexport class PluginAPI implements IPluginAPI {\n /** Plugin ID this API belongs to */\n readonly pluginId: string;\n\n /** Player container element */\n readonly container: HTMLElement;\n\n /** Scoped logger for this plugin */\n readonly logger: IPluginAPI['logger'];\n\n /** State manager reference */\n private stateManager: StateManager;\n\n /** Event bus reference */\n private eventBus: EventBus;\n\n /** Function to get other plugins */\n private getPluginFn: <T = unknown>(id: string) => T | null;\n\n /** Cleanup functions registered by this plugin */\n private cleanupFns: Array<() => void> = [];\n\n /**\n * Create a new PluginAPI.\n *\n * @param pluginId - ID of the plugin this API belongs to\n * @param deps - Dependencies (stateManager, eventBus, logger, container, getPlugin)\n */\n constructor(pluginId: string, deps: PluginAPIDeps) {\n this.pluginId = pluginId;\n this.stateManager = deps.stateManager;\n this.eventBus = deps.eventBus;\n this.container = deps.container;\n this.getPluginFn = deps.getPlugin;\n\n // Create scoped logger for this plugin\n this.logger = {\n debug: (msg: string, metadata?: Record<string, any>) => deps.logger.debug(`[${pluginId}] ${msg}`, metadata),\n info: (msg: string, metadata?: Record<string, any>) => deps.logger.info(`[${pluginId}] ${msg}`, metadata),\n warn: (msg: string, metadata?: Record<string, any>) => deps.logger.warn(`[${pluginId}] ${msg}`, metadata),\n error: (msg: string, metadata?: Record<string, any>) => deps.logger.error(`[${pluginId}] ${msg}`, metadata),\n };\n }\n\n /**\n * Get a state value.\n *\n * @param key - State property key\n * @returns Current state value\n */\n getState<K extends StateKey>(key: K): StateValue<K> {\n return this.stateManager.getValue(key);\n }\n\n /**\n * Set a state value.\n *\n * @param key - State property key\n * @param value - New state value\n */\n setState<K extends StateKey>(key: K, value: StateValue<K>): void {\n this.stateManager.set(key, value);\n }\n\n /**\n * Subscribe to an event.\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n on<T extends EventName>(event: T, handler: EventHandler<T>): () => void {\n return this.eventBus.on(event, handler);\n }\n\n /**\n * Unsubscribe from an event.\n *\n * @param event - Event name\n * @param handler - Event handler to remove\n */\n off<T extends EventName>(event: T, handler: EventHandler<T>): void {\n this.eventBus.off(event, handler);\n }\n\n /**\n * Emit an event.\n *\n * @param event - Event name\n * @param payload - Event payload\n */\n emit<T extends EventName>(event: T, payload: EventPayload<T>): void {\n this.eventBus.emit(event, payload);\n }\n\n /**\n * Get another plugin by ID (if ready).\n *\n * @param id - Plugin ID\n * @returns Plugin instance or null if not found/ready\n */\n getPlugin<T = unknown>(id: string): T | null {\n return this.getPluginFn<T>(id);\n }\n\n /**\n * Register a cleanup function to run when plugin is destroyed.\n *\n * @param cleanup - Cleanup function\n */\n onDestroy(cleanup: () => void): void {\n this.cleanupFns.push(cleanup);\n }\n\n /**\n * Subscribe to state changes.\n *\n * @param callback - Callback function called on any state change\n * @returns Unsubscribe function\n */\n subscribeToState(callback: (event: StateChangeEvent) => void): () => void {\n return this.stateManager.subscribe(callback);\n }\n\n /**\n * Run all registered cleanup functions.\n * Called by PluginManager when destroying the plugin.\n *\n * @internal\n */\n runCleanups(): void {\n for (const cleanup of this.cleanupFns) {\n try {\n cleanup();\n } catch (error) {\n this.logger.error('Cleanup function failed', { error });\n }\n }\n this.cleanupFns = [];\n }\n\n /**\n * Get all registered cleanup functions.\n *\n * @returns Array of cleanup functions\n * @internal\n */\n getCleanupFns(): Array<() => void> {\n return this.cleanupFns;\n }\n}\n","/**\n * PluginManager - Plugin lifecycle and dependency management with\n * topological dependency resolution and circular dependency detection.\n */\n\nimport type { EventBus } from './events/event-bus';\nimport type { StateManager } from './state/state-manager';\nimport type { Logger } from './logger';\nimport type { Plugin, PluginState, PluginConfig, PluginDescriptor } from './types/plugin';\nimport { PluginAPI } from './plugin-api';\n\nexport interface PluginManagerOptions {\n container: HTMLElement;\n}\n\n/** @internal */\ninterface PluginRecord extends PluginDescriptor {\n api: PluginAPI;\n}\n\nexport class PluginManager {\n private plugins = new Map<string, PluginRecord>();\n private eventBus: EventBus;\n private stateManager: StateManager;\n private logger: Logger;\n private container: HTMLElement;\n\n constructor(\n eventBus: EventBus,\n stateManager: StateManager,\n logger: Logger,\n options: PluginManagerOptions\n ) {\n this.eventBus = eventBus;\n this.stateManager = stateManager;\n this.logger = logger;\n this.container = options.container;\n }\n\n /** Register a plugin with optional configuration. */\n register<T extends PluginConfig>(plugin: Plugin<T>, config?: T): void {\n if (this.plugins.has(plugin.id)) {\n throw new Error(`Plugin \"${plugin.id}\" is already registered`);\n }\n\n this.validatePlugin(plugin);\n\n const api = new PluginAPI(plugin.id, {\n stateManager: this.stateManager,\n eventBus: this.eventBus,\n logger: this.logger,\n container: this.container,\n getPlugin: <T = unknown>(id: string): T | null => this.getReadyPlugin(id) as T | null,\n });\n\n this.plugins.set(plugin.id, {\n plugin,\n state: 'registered',\n config,\n cleanupFns: [],\n api,\n });\n\n this.logger.info(`Plugin registered: ${plugin.id}`);\n this.eventBus.emit('plugin:registered', { name: plugin.id, type: plugin.type });\n }\n\n /** Unregister a plugin. Destroys it first if active. */\n async unregister(id: string): Promise<void> {\n const record = this.plugins.get(id);\n if (!record) return;\n\n if (record.state === 'ready') {\n await this.destroyPlugin(id);\n }\n\n this.plugins.delete(id);\n this.logger.info(`Plugin unregistered: ${id}`);\n }\n\n /** Initialize all registered plugins in dependency order. */\n async initAll(): Promise<void> {\n const order = this.resolveDependencyOrder();\n\n for (const id of order) {\n await this.initPlugin(id);\n }\n }\n\n /** Initialize a specific plugin. */\n async initPlugin(id: string): Promise<void> {\n const record = this.plugins.get(id);\n if (!record) {\n throw new Error(`Plugin \"${id}\" not found`);\n }\n\n if (record.state === 'ready') return;\n if (record.state === 'initializing') {\n throw new Error(`Plugin \"${id}\" is already initializing (possible circular dependency)`);\n }\n\n // Ensure dependencies are ready\n for (const depId of record.plugin.dependencies || []) {\n const dep = this.plugins.get(depId);\n if (!dep) {\n throw new Error(`Plugin \"${id}\" depends on missing plugin \"${depId}\"`);\n }\n if (dep.state !== 'ready') {\n await this.initPlugin(depId);\n }\n }\n\n try {\n record.state = 'initializing';\n\n if (record.plugin.onStateChange) {\n const unsub = this.stateManager.subscribe(record.plugin.onStateChange.bind(record.plugin));\n record.api.onDestroy(unsub);\n }\n\n if (record.plugin.onError) {\n const unsub = this.eventBus.on('error', (err) => {\n record.plugin.onError?.(err.originalError || new Error(err.message));\n });\n record.api.onDestroy(unsub);\n }\n\n await record.plugin.init(record.api, record.config);\n\n record.state = 'ready';\n this.logger.info(`Plugin ready: ${id}`);\n this.eventBus.emit('plugin:active', { name: id });\n } catch (error) {\n record.state = 'error';\n record.error = error as Error;\n this.logger.error(`Plugin init failed: ${id}`, { error });\n this.eventBus.emit('plugin:error', { name: id, error: error as Error });\n throw error;\n }\n }\n\n /** Destroy all plugins in reverse dependency order. */\n async destroyAll(): Promise<void> {\n const order = this.resolveDependencyOrder().reverse();\n\n for (const id of order) {\n await this.destroyPlugin(id);\n }\n }\n\n /** Destroy a specific plugin. */\n async destroyPlugin(id: string): Promise<void> {\n const record = this.plugins.get(id);\n if (!record || record.state !== 'ready') return;\n\n try {\n await record.plugin.destroy();\n record.api.runCleanups();\n // Reset to 'registered' so it can be re-initialized later\n record.state = 'registered';\n this.logger.info(`Plugin destroyed: ${id}`);\n this.eventBus.emit('plugin:destroyed', { name: id });\n } catch (error) {\n this.logger.error(`Plugin destroy failed: ${id}`, { error });\n // Even on error, reset state so plugin can be retried\n record.state = 'registered';\n }\n }\n\n /** Get a plugin by ID (returns any registered plugin). */\n getPlugin<T extends Plugin = Plugin>(id: string): T | null {\n const record = this.plugins.get(id);\n return record ? (record.plugin as T) : null;\n }\n\n /** Get a plugin by ID only if ready (used by PluginAPI). */\n getReadyPlugin<T extends Plugin = Plugin>(id: string): T | null {\n const record = this.plugins.get(id);\n return record?.state === 'ready' ? (record.plugin as T) : null;\n }\n\n /** Check if a plugin is registered. */\n hasPlugin(id: string): boolean {\n return this.plugins.has(id);\n }\n\n /** Get plugin state. */\n getPluginState(id: string): PluginState | null {\n return this.plugins.get(id)?.state ?? null;\n }\n\n /** Get all registered plugin IDs. */\n getPluginIds(): string[] {\n return Array.from(this.plugins.keys());\n }\n\n /** Get all ready plugins. */\n getReadyPlugins(): Plugin[] {\n return Array.from(this.plugins.values())\n .filter((r) => r.state === 'ready')\n .map((r) => r.plugin);\n }\n\n /** Get plugins by type. */\n getPluginsByType(type: string): Plugin[] {\n return Array.from(this.plugins.values())\n .filter((r) => r.plugin.type === type)\n .map((r) => r.plugin);\n }\n\n /** Select a provider plugin that can play a source. */\n selectProvider(source: string): Plugin | null {\n const providers = this.getPluginsByType('provider');\n for (const provider of providers) {\n const canPlay = (provider as any).canPlay;\n if (typeof canPlay === 'function' && canPlay(source)) {\n return provider;\n }\n }\n return null;\n }\n\n /** Resolve plugin initialization order using topological sort. */\n private resolveDependencyOrder(): string[] {\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const sorted: string[] = [];\n\n const visit = (id: string, path: string[] = []) => {\n if (visited.has(id)) return;\n\n if (visiting.has(id)) {\n const cycle = [...path, id].join(' -> ');\n throw new Error(`Circular dependency detected: ${cycle}`);\n }\n\n const record = this.plugins.get(id);\n if (!record) return;\n\n visiting.add(id);\n\n for (const depId of record.plugin.dependencies || []) {\n if (this.plugins.has(depId)) {\n visit(depId, [...path, id]);\n }\n }\n\n visiting.delete(id);\n visited.add(id);\n sorted.push(id);\n };\n\n for (const id of this.plugins.keys()) {\n visit(id);\n }\n\n return sorted;\n }\n\n /** Validate plugin has required properties. */\n private validatePlugin(plugin: Plugin): void {\n if (!plugin.id || typeof plugin.id !== 'string') {\n throw new Error('Plugin must have a valid id');\n }\n if (!plugin.name || typeof plugin.name !== 'string') {\n throw new Error(`Plugin \"${plugin.id}\" must have a valid name`);\n }\n if (!plugin.version || typeof plugin.version !== 'string') {\n throw new Error(`Plugin \"${plugin.id}\" must have a valid version`);\n }\n if (!plugin.type || typeof plugin.type !== 'string') {\n throw new Error(`Plugin \"${plugin.id}\" must have a valid type`);\n }\n if (typeof plugin.init !== 'function') {\n throw new Error(`Plugin \"${plugin.id}\" must have an init() method`);\n }\n if (typeof plugin.destroy !== 'function') {\n throw new Error(`Plugin \"${plugin.id}\" must have a destroy() method`);\n }\n }\n}\n","/**\n * ScarlettPlayer - Main player class integrating all core systems.\n *\n * Provides the public API for video playback, plugin management,\n * state access, and event handling.\n *\n * Target size: ~1-1.5KB\n */\n\nimport { EventBus } from './events/event-bus';\nimport { StateManager } from './state/state-manager';\nimport { Logger } from './logger';\nimport { ErrorHandler, ErrorCode } from './error-handler';\nimport { PluginManager } from './plugin-manager';\nimport type { Plugin } from './types/plugin';\nimport type { EventName, EventHandler as EventHandlerFn } from './types/events';\nimport type { StateStore } from './types/state';\n\n/**\n * Player configuration options.\n */\nexport interface PlayerOptions {\n /** HTML container element or CSS selector */\n container: HTMLElement | string;\n /** Initial source URL */\n src?: string;\n /** Poster image URL */\n poster?: string;\n /** Initial log level (default: 'warn') */\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Autoplay (default: false) */\n autoplay?: boolean;\n /** Loop playback (default: false) */\n loop?: boolean;\n /** Initial volume 0-1 (default: 1.0) */\n volume?: number;\n /** Start muted (default: false) */\n muted?: boolean;\n /** Plugins to register on initialization */\n plugins?: Plugin[];\n}\n\n/**\n * Quality level interface for proxy methods.\n */\nexport interface QualityLevel {\n id: string;\n label: string;\n width: number;\n height: number;\n bitrate: number;\n active: boolean;\n}\n\n/**\n * ScarlettPlayer - Lightweight, plugin-based video player.\n *\n * Features:\n * - Plugin-based architecture\n * - Reactive state management\n * - Type-safe event system\n * - Automatic provider selection\n * - Live/DVR support (TSP)\n * - Chapter/marker support (TSP)\n *\n * @example\n * ```ts\n * const player = new ScarlettPlayer({\n * container: document.getElementById('player'),\n * plugins: [hlsPlugin, controlsPlugin],\n * });\n *\n * // Load and play\n * await player.load('video.m3u8');\n * player.play();\n *\n * // Listen to events\n * player.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Access state\n * console.log(player.playing, player.currentTime);\n *\n * // Cleanup\n * player.destroy();\n * ```\n */\nexport class ScarlettPlayer {\n /** Player container element */\n readonly container: HTMLElement;\n\n /** Event bus */\n private eventBus: EventBus;\n\n /** State manager */\n private stateManager: StateManager;\n\n /** Logger */\n private logger: Logger;\n\n /** Error handler */\n private errorHandler: ErrorHandler;\n\n /** Plugin manager */\n private pluginManager: PluginManager;\n\n /** Current media provider plugin */\n private _currentProvider: Plugin | null = null;\n\n /** Player destroyed flag */\n private destroyed = false;\n\n /** Seeking while playing flag */\n private seekingWhilePlaying = false;\n\n /** Seek resume timeout */\n private seekResumeTimeout: number | null = null;\n\n /** Initial source URL */\n private initialSrc?: string;\n\n /**\n * Create a new ScarlettPlayer.\n *\n * @param options - Player configuration\n */\n constructor(options: PlayerOptions) {\n // Resolve container (string selector or HTMLElement)\n if (typeof options.container === 'string') {\n const el = document.querySelector(options.container);\n if (!el || !(el instanceof HTMLElement)) {\n throw new Error(`ScarlettPlayer: container not found: ${options.container}`);\n }\n this.container = el;\n } else if (options.container instanceof HTMLElement) {\n this.container = options.container;\n } else {\n throw new Error('ScarlettPlayer requires a valid HTMLElement container or CSS selector');\n }\n\n // Store initial source\n this.initialSrc = options.src;\n\n // Initialize core systems\n this.eventBus = new EventBus();\n this.stateManager = new StateManager({\n autoplay: options.autoplay ?? false,\n loop: options.loop ?? false,\n volume: options.volume ?? 1.0,\n muted: options.muted ?? false,\n });\n this.logger = new Logger({\n level: options.logLevel ?? 'warn',\n scope: 'ScarlettPlayer',\n });\n this.errorHandler = new ErrorHandler(this.eventBus, this.logger);\n this.pluginManager = new PluginManager(\n this.eventBus,\n this.stateManager,\n this.logger,\n { container: this.container }\n );\n\n // Register plugins if provided\n if (options.plugins) {\n for (const plugin of options.plugins) {\n this.pluginManager.register(plugin);\n }\n }\n\n this.logger.info('ScarlettPlayer initialized', {\n autoplay: options.autoplay,\n plugins: options.plugins?.length ?? 0,\n });\n\n // Emit ready event after initialization\n this.eventBus.emit('player:ready', undefined);\n }\n\n /**\n * Initialize the player asynchronously.\n * Initializes non-provider plugins and loads initial source if provided.\n */\n async init(): Promise<void> {\n this.checkDestroyed();\n\n // Initialize non-provider plugins (UI, feature, analytics, utility)\n // Providers are initialized on-demand when load() is called\n for (const [id, record] of (this.pluginManager as any).plugins) {\n if (record.plugin.type !== 'provider' && record.state === 'registered') {\n await this.pluginManager.initPlugin(id);\n }\n }\n\n // Load initial source if provided\n if (this.initialSrc) {\n await this.load(this.initialSrc);\n }\n\n return Promise.resolve();\n }\n\n /**\n * Load a media source.\n *\n * Selects appropriate provider plugin and loads the source.\n *\n * @param source - Media source URL\n * @returns Promise that resolves when source is loaded\n *\n * @example\n * ```ts\n * await player.load('video.m3u8');\n * ```\n */\n async load(source: string): Promise<void> {\n this.checkDestroyed();\n\n try {\n this.logger.info('Loading source', { source });\n\n // Reset playback state when loading new source\n this.stateManager.update({\n playing: false,\n paused: true,\n ended: false,\n buffering: true,\n currentTime: 0,\n duration: 0,\n bufferedAmount: 0,\n playbackState: 'loading',\n });\n\n // Destroy previous provider if switching\n if (this._currentProvider) {\n const previousProviderId = this._currentProvider.id;\n this.logger.info('Destroying previous provider', { provider: previousProviderId });\n await this.pluginManager.destroyPlugin(previousProviderId);\n this._currentProvider = null;\n }\n\n // Select provider FIRST (before init)\n const provider = this.pluginManager.selectProvider(source);\n if (!provider) {\n this.errorHandler.throw(\n ErrorCode.PROVIDER_NOT_FOUND,\n `No provider found for source: ${source}`,\n {\n fatal: true,\n context: { source },\n }\n );\n return;\n }\n\n this._currentProvider = provider;\n this.logger.info('Provider selected', { provider: provider.id });\n\n // Init ONLY the selected provider (not all plugins)\n await this.pluginManager.initPlugin(provider.id);\n\n // Update state\n this.stateManager.set('source', { src: source, type: this.detectMimeType(source) });\n\n // Call provider's loadSource method and wait for it to complete\n // The provider will emit media:loaded when actually ready\n if (typeof (provider as any).loadSource === 'function') {\n await (provider as any).loadSource(source);\n }\n\n // Auto-play if enabled\n if (this.stateManager.getValue('autoplay')) {\n await this.play();\n }\n } catch (error) {\n this.errorHandler.handle(error as Error, {\n operation: 'load',\n source,\n });\n }\n }\n\n /**\n * Start playback.\n *\n * @returns Promise that resolves when playback starts\n *\n * @example\n * ```ts\n * await player.play();\n * ```\n */\n async play(): Promise<void> {\n this.checkDestroyed();\n\n try {\n this.logger.debug('Play requested');\n\n // Update state\n this.stateManager.update({\n playing: true,\n paused: false,\n playbackState: 'playing',\n });\n\n // Emit play event\n this.eventBus.emit('playback:play', undefined);\n } catch (error) {\n this.errorHandler.handle(error as Error, { operation: 'play' });\n }\n }\n\n /**\n * Pause playback.\n *\n * @example\n * ```ts\n * player.pause();\n * ```\n */\n pause(): void {\n this.checkDestroyed();\n\n try {\n this.logger.debug('Pause requested');\n\n // Clear seeking while playing flag (user explicitly paused)\n this.seekingWhilePlaying = false;\n if (this.seekResumeTimeout !== null) {\n clearTimeout(this.seekResumeTimeout);\n this.seekResumeTimeout = null;\n }\n\n // Update state\n this.stateManager.update({\n playing: false,\n paused: true,\n playbackState: 'paused',\n });\n\n // Emit pause event\n this.eventBus.emit('playback:pause', undefined);\n } catch (error) {\n this.errorHandler.handle(error as Error, { operation: 'pause' });\n }\n }\n\n /**\n * Seek to a specific time.\n *\n * @param time - Time in seconds\n *\n * @example\n * ```ts\n * player.seek(30); // Seek to 30 seconds\n * ```\n */\n seek(time: number): void {\n this.checkDestroyed();\n\n try {\n this.logger.debug('Seek requested', { time });\n\n // Remember if we were playing before seeking\n const wasPlaying = this.stateManager.getValue('playing');\n\n if (wasPlaying) {\n this.seekingWhilePlaying = true;\n }\n\n // Clear any existing resume timeout\n if (this.seekResumeTimeout !== null) {\n clearTimeout(this.seekResumeTimeout);\n this.seekResumeTimeout = null;\n }\n\n // Emit seeking event\n this.eventBus.emit('playback:seeking', { time });\n\n // Update state\n this.stateManager.set('currentTime', time);\n\n // If we were playing, set up a debounced resume\n // This handles multiple rapid seeks gracefully\n if (this.seekingWhilePlaying) {\n this.seekResumeTimeout = setTimeout(() => {\n if (this.seekingWhilePlaying && this.stateManager.getValue('playing')) {\n this.logger.debug('Resuming playback after seek');\n this.seekingWhilePlaying = false;\n this.eventBus.emit('playback:play', undefined);\n }\n this.seekResumeTimeout = null;\n }, 300) as unknown as number; // 300ms debounce for rapid seeks\n }\n } catch (error) {\n this.errorHandler.handle(error as Error, { operation: 'seek', time });\n }\n }\n\n /**\n * Set volume.\n *\n * @param volume - Volume 0-1\n *\n * @example\n * ```ts\n * player.setVolume(0.5); // 50% volume\n * ```\n */\n setVolume(volume: number): void {\n this.checkDestroyed();\n\n const clampedVolume = Math.max(0, Math.min(1, volume));\n\n this.stateManager.set('volume', clampedVolume);\n this.eventBus.emit('volume:change', {\n volume: clampedVolume,\n muted: this.stateManager.getValue('muted'),\n });\n }\n\n /**\n * Set muted state.\n *\n * @param muted - Mute flag\n *\n * @example\n * ```ts\n * player.setMuted(true);\n * ```\n */\n setMuted(muted: boolean): void {\n this.checkDestroyed();\n\n this.stateManager.set('muted', muted);\n this.eventBus.emit('volume:mute', { muted });\n }\n\n /**\n * Set playback rate.\n *\n * @param rate - Playback rate (e.g., 1.0 = normal, 2.0 = 2x speed)\n *\n * @example\n * ```ts\n * player.setPlaybackRate(1.5); // 1.5x speed\n * ```\n */\n setPlaybackRate(rate: number): void {\n this.checkDestroyed();\n\n this.stateManager.set('playbackRate', rate);\n this.eventBus.emit('playback:ratechange', { rate });\n }\n\n /**\n * Set autoplay state.\n *\n * When enabled, videos will automatically play after loading.\n *\n * @param autoplay - Autoplay flag\n *\n * @example\n * ```ts\n * player.setAutoplay(true);\n * await player.load('video.mp4'); // Will auto-play\n * ```\n */\n setAutoplay(autoplay: boolean): void {\n this.checkDestroyed();\n\n this.stateManager.set('autoplay', autoplay);\n this.logger.debug('Autoplay set', { autoplay });\n }\n\n /**\n * Subscribe to an event.\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = player.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Later: unsubscribe\n * unsub();\n * ```\n */\n on<T extends EventName>(event: T, handler: EventHandlerFn<T>): () => void {\n this.checkDestroyed();\n return this.eventBus.on(event, handler);\n }\n\n /**\n * Subscribe to an event once.\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * player.once('player:ready', () => {\n * console.log('Player ready!');\n * });\n * ```\n */\n once<T extends EventName>(event: T, handler: EventHandlerFn<T>): () => void {\n this.checkDestroyed();\n return this.eventBus.once(event, handler);\n }\n\n /**\n * Get a plugin by name.\n *\n * @param name - Plugin name\n * @returns Plugin instance or null\n *\n * @example\n * ```ts\n * const hls = player.getPlugin('hls-plugin');\n * ```\n */\n getPlugin<T extends Plugin>(name: string): T | null {\n this.checkDestroyed();\n return this.pluginManager.getPlugin<T>(name);\n }\n\n /**\n * Register a plugin.\n *\n * @param plugin - Plugin to register\n *\n * @example\n * ```ts\n * player.registerPlugin(myPlugin);\n * ```\n */\n registerPlugin(plugin: Plugin): void {\n this.checkDestroyed();\n this.pluginManager.register(plugin);\n }\n\n /**\n * Get current state snapshot.\n *\n * @returns Readonly state snapshot\n *\n * @example\n * ```ts\n * const state = player.getState();\n * console.log(state.playing, state.currentTime);\n * ```\n */\n getState(): Readonly<StateStore> {\n this.checkDestroyed();\n return this.stateManager.snapshot();\n }\n\n // ===== Quality Methods (proxied to provider) =====\n\n /**\n * Get available quality levels from the current provider.\n * @returns Array of quality levels or empty array if not available\n */\n getQualities(): QualityLevel[] {\n this.checkDestroyed();\n if (!this._currentProvider) return [];\n\n const provider = this._currentProvider as any;\n if (typeof provider.getLevels === 'function') {\n return provider.getLevels();\n }\n return [];\n }\n\n /**\n * Set quality level (-1 for auto).\n * @param index - Quality level index\n */\n setQuality(index: number): void {\n this.checkDestroyed();\n if (!this._currentProvider) {\n this.logger.warn('No provider available for quality change');\n return;\n }\n\n const provider = this._currentProvider as any;\n if (typeof provider.setLevel === 'function') {\n provider.setLevel(index);\n this.eventBus.emit('quality:change', {\n quality: index === -1 ? 'auto' : `level-${index}`,\n auto: index === -1,\n });\n }\n }\n\n /**\n * Get current quality level index (-1 = auto).\n */\n getCurrentQuality(): number {\n this.checkDestroyed();\n if (!this._currentProvider) return -1;\n\n const provider = this._currentProvider as any;\n if (typeof provider.getCurrentLevel === 'function') {\n return provider.getCurrentLevel();\n }\n return -1;\n }\n\n // ===== Fullscreen Methods =====\n\n /**\n * Request fullscreen mode.\n */\n async requestFullscreen(): Promise<void> {\n this.checkDestroyed();\n\n try {\n if (this.container.requestFullscreen) {\n await this.container.requestFullscreen();\n } else if ((this.container as any).webkitRequestFullscreen) {\n await (this.container as any).webkitRequestFullscreen();\n }\n this.stateManager.set('fullscreen', true);\n this.eventBus.emit('fullscreen:change', { fullscreen: true });\n } catch (error) {\n this.logger.error('Fullscreen request failed', { error });\n }\n }\n\n /**\n * Exit fullscreen mode.\n */\n async exitFullscreen(): Promise<void> {\n this.checkDestroyed();\n\n try {\n if (document.exitFullscreen) {\n await document.exitFullscreen();\n } else if ((document as any).webkitExitFullscreen) {\n await (document as any).webkitExitFullscreen();\n }\n this.stateManager.set('fullscreen', false);\n this.eventBus.emit('fullscreen:change', { fullscreen: false });\n } catch (error) {\n this.logger.error('Exit fullscreen failed', { error });\n }\n }\n\n /**\n * Toggle fullscreen mode.\n */\n async toggleFullscreen(): Promise<void> {\n if (this.fullscreen) {\n await this.exitFullscreen();\n } else {\n await this.requestFullscreen();\n }\n }\n\n // ===== Casting Methods (proxied to plugins) =====\n\n /**\n * Request AirPlay (proxied to airplay plugin).\n */\n requestAirPlay(): void {\n this.checkDestroyed();\n const airplay = this.pluginManager.getPlugin('airplay');\n if (airplay && typeof (airplay as any).showPicker === 'function') {\n (airplay as any).showPicker();\n } else {\n this.logger.warn('AirPlay plugin not available');\n }\n }\n\n /**\n * Request Chromecast session (proxied to chromecast plugin).\n */\n async requestChromecast(): Promise<void> {\n this.checkDestroyed();\n const chromecast = this.pluginManager.getPlugin('chromecast');\n if (chromecast && typeof (chromecast as any).requestSession === 'function') {\n await (chromecast as any).requestSession();\n } else {\n this.logger.warn('Chromecast plugin not available');\n }\n }\n\n /**\n * Stop casting (AirPlay or Chromecast).\n */\n stopCasting(): void {\n this.checkDestroyed();\n\n const airplay = this.pluginManager.getPlugin('airplay');\n if (airplay && typeof (airplay as any).stop === 'function') {\n (airplay as any).stop();\n }\n\n const chromecast = this.pluginManager.getPlugin('chromecast');\n if (chromecast && typeof (chromecast as any).stopSession === 'function') {\n (chromecast as any).stopSession();\n }\n }\n\n // ===== Live Stream Methods =====\n\n /**\n * Seek to live edge (for live streams).\n */\n seekToLive(): void {\n this.checkDestroyed();\n\n // Check if stream is live\n const isLive = this.stateManager.getValue('live');\n if (!isLive) {\n this.logger.warn('Not a live stream');\n return;\n }\n\n // Try provider's getLiveInfo for live sync position\n if (this._currentProvider) {\n const provider = this._currentProvider as any;\n if (typeof provider.getLiveInfo === 'function') {\n const liveInfo = provider.getLiveInfo();\n if (liveInfo?.liveSyncPosition !== undefined) {\n this.seek(liveInfo.liveSyncPosition);\n return;\n }\n }\n }\n\n // Fallback: seek to duration (edge)\n const duration = this.stateManager.getValue('duration');\n if (duration > 0) {\n this.seek(duration);\n }\n }\n\n /**\n * Destroy the player and cleanup all resources.\n *\n * @example\n * ```ts\n * player.destroy();\n * ```\n */\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n\n this.logger.info('Destroying player');\n\n // Clear any pending seek resume timeout\n if (this.seekResumeTimeout !== null) {\n clearTimeout(this.seekResumeTimeout);\n this.seekResumeTimeout = null;\n }\n\n // Emit destroy event\n this.eventBus.emit('player:destroy', undefined);\n\n // Destroy plugins\n this.pluginManager.destroyAll();\n\n // Cleanup core systems\n this.eventBus.destroy();\n this.stateManager.destroy();\n\n this.destroyed = true;\n this.logger.info('Player destroyed');\n }\n\n // ===== State Getters =====\n\n /**\n * Get playing state.\n */\n get playing(): boolean {\n return this.stateManager.getValue('playing');\n }\n\n /**\n * Get paused state.\n */\n get paused(): boolean {\n return this.stateManager.getValue('paused');\n }\n\n /**\n * Get current time in seconds.\n */\n get currentTime(): number {\n return this.stateManager.getValue('currentTime');\n }\n\n /**\n * Get duration in seconds.\n */\n get duration(): number {\n return this.stateManager.getValue('duration');\n }\n\n /**\n * Get volume (0-1).\n */\n get volume(): number {\n return this.stateManager.getValue('volume');\n }\n\n /**\n * Get muted state.\n */\n get muted(): boolean {\n return this.stateManager.getValue('muted');\n }\n\n /**\n * Get playback rate.\n */\n get playbackRate(): number {\n return this.stateManager.getValue('playbackRate');\n }\n\n /**\n * Get buffered amount (0-1).\n */\n get bufferedAmount(): number {\n return this.stateManager.getValue('bufferedAmount');\n }\n\n /**\n * Get current provider plugin.\n */\n get currentProvider(): Plugin | null {\n return this._currentProvider;\n }\n\n /**\n * Get fullscreen state.\n */\n get fullscreen(): boolean {\n return this.stateManager.getValue('fullscreen');\n }\n\n /**\n * Get live stream state.\n */\n get live(): boolean {\n return this.stateManager.getValue('live');\n }\n\n /**\n * Get autoplay state.\n */\n get autoplay(): boolean {\n return this.stateManager.getValue('autoplay');\n }\n\n /**\n * Check if player is destroyed.\n * @private\n */\n private checkDestroyed(): void {\n if (this.destroyed) {\n throw new Error('Cannot call methods on destroyed player');\n }\n }\n\n /**\n * Detect MIME type from source URL.\n * @private\n */\n private detectMimeType(source: string): string {\n const ext = source.split('.').pop()?.toLowerCase();\n\n switch (ext) {\n case 'm3u8':\n return 'application/x-mpegURL';\n case 'mpd':\n return 'application/dash+xml';\n case 'mp4':\n return 'video/mp4';\n case 'webm':\n return 'video/webm';\n case 'ogg':\n return 'video/ogg';\n default:\n return 'video/mp4'; // Default fallback\n }\n }\n}\n\n/**\n * Create a ScarlettPlayer instance and initialize it.\n *\n * Convenience factory function that creates and initializes\n * the player in a single async call.\n *\n * @param options - Player configuration\n * @returns Promise resolving to initialized player\n *\n * @example\n * ```ts\n * const player = await createPlayer({\n * container: '#player',\n * src: 'video.m3u8',\n * plugins: [hlsPlugin()],\n * });\n *\n * player.play();\n * ```\n */\nexport async function createPlayer(options: PlayerOptions): Promise<ScarlettPlayer> {\n const player = new ScarlettPlayer(options);\n await player.init();\n return player;\n}\n"],"names":["effect","ErrorCode"],"mappings":"AAWA,MAAM,gBAAgB;AAAA,EACpB,SAAS;AACX;AAMO,IAAI,gBAAqC;AAMzC,SAAS,iBAAiBA,SAAmC;AAClE,gBAAc,UAAUA;AACxB,kBAAgBA;AAClB;AAMO,SAAS,mBAAwC;AACtD,SAAO,cAAc;AACvB;AA2BO,SAAS,OAAO,IAA+B;AACpD,QAAM,UAAU,MAAM;AAEpB,qBAAiB,OAAO;AACxB,QAAI;AACF,SAAA;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,sCAAsC,KAAK;AACzD,YAAM;AAAA,IACR,UAAA;AAEE,uBAAiB,IAAI;AAAA,IACvB;AAAA,EACF;AAGA,UAAA;AAGA,SAAO,MAAM;AAAA,EAEb;AACF;ACxDO,MAAM,OAAU;AAAA,EAIrB,YAAY,cAAiB;AAF7B,SAAQ,kCAAkB,IAAA;AAGxB,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAS;AAEP,QAAI,eAAe;AACjB,WAAK,YAAY,IAAI,aAAa;AAAA,IACpC;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,UAAmB;AAErB,QAAI,OAAO,GAAG,KAAK,OAAO,QAAQ,GAAG;AACnC;AAAA,IACF;AAEA,SAAK,QAAQ;AACb,SAAK,OAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,SAAkC;AACvC,SAAK,IAAI,QAAQ,KAAK,KAAK,CAAC;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,UAAqC;AAC7C,SAAK,YAAY,IAAI,QAAQ;AAC7B,WAAO,MAAM,KAAK,YAAY,OAAO,QAAQ;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAe;AACrB,SAAK,YAAY,QAAQ,CAAA,eAAc;AACrC,UAAI;AACF,mBAAA;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,iDAAiD,KAAK;AAAA,MACtE;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AACd,SAAK,YAAY,MAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qBAA6B;AAC3B,WAAO,KAAK,YAAY;AAAA,EAC1B;AACF;AAcO,SAAS,OAAU,cAA4B;AACpD,SAAO,IAAI,OAAO,YAAY;AAChC;AC5GO,MAAM,SAAY;AAAA,EAQvB,YAAY,aAAsB;AANlC,SAAQ,QAAQ;AAChB,SAAQ,kCAAkB,IAAA;AAE1B,SAAQ,mCAAmB,IAAA;AAIzB,SAAK,cAAc;AAEnB,SAAK,qBAAqB,MAAM,KAAK,WAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAS;AACP,QAAI,KAAK,OAAO;AAEd,YAAM,aAAa,iBAAA;AACnB,uBAAiB,KAAK,kBAAkB;AAExC,UAAI;AACF,aAAK,QAAQ,KAAK,YAAA;AAClB,aAAK,QAAQ;AAAA,MACf,UAAA;AACE,yBAAiB,UAAU;AAAA,MAC7B;AAAA,IACF;AAGA,QAAI,eAAe;AACjB,WAAK,YAAY,IAAI,aAAa;AAAA,IACpC;AAEA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAmB;AACjB,UAAM,WAAW,KAAK;AACtB,SAAK,QAAQ;AAIb,QAAI,CAAC,YAAY,KAAK,YAAY,OAAO,GAAG;AAC1C,WAAK,kBAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,UAAqC;AAC7C,SAAK,YAAY,IAAI,QAAQ;AAC7B,WAAO,MAAM,KAAK,YAAY,OAAO,QAAQ;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAA0B;AAChC,SAAK,YAAY,QAAQ,CAAA,eAAc;AACrC,UAAI;AACF,mBAAA;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,mDAAmD,KAAK;AAAA,MACxE;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,SAAK,aAAa,QAAQ,CAAA,UAAS,MAAA,CAAO;AAC1C,SAAK,aAAa,MAAA;AAClB,SAAK,YAAY,MAAA;AACjB,SAAK,QAAQ;AACb,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qBAA6B;AAC3B,WAAO,KAAK,YAAY;AAAA,EAC1B;AACF;AAcO,SAAS,SAAY,aAAmC;AAC7D,SAAO,IAAI,SAAS,WAAW;AACjC;AC9HA,MAAM,gBAA4B;AAAA;AAAA,EAEhC,eAAe;AAAA,EACf,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA;AAAA,EAGT,aAAa;AAAA,EACb,UAAU;AAAA,EACV,UAAU;AAAA,EACV,gBAAgB;AAAA;AAAA,EAGhB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA;AAAA,EAGR,QAAQ;AAAA,EACR,OAAO;AAAA;AAAA,EAGP,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,iBAAiB;AAAA;AAAA,EAGjB,WAAW,CAAA;AAAA,EACX,gBAAgB;AAAA,EAChB,aAAa,CAAA;AAAA,EACb,mBAAmB;AAAA,EACnB,YAAY,CAAA;AAAA,EACZ,kBAAkB;AAAA;AAAA,EAGlB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,eAAe;AAAA,EACf,aAAa;AAAA,EACb,gBAAgB;AAAA;AAAA,EAGhB,UAAU,CAAA;AAAA,EACV,gBAAgB;AAAA;AAAA,EAGhB,OAAO;AAAA;AAAA,EAGP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,MAAM;AAAA;AAAA,EAGN,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,kBAAkB;AAAA;AAAA,EAGlB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,SAAS;AACX;AAgCO,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYxB,YAAY,cAAoC;AAVhD,SAAQ,8BAAc,IAAA;AAGtB,SAAQ,wCAAwB,IAAA;AAQ9B,SAAK,kBAAkB,YAAY;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,WAAuC;AAC/D,UAAM,eAAe,EAAE,GAAG,eAAe,GAAG,UAAA;AAG5C,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,YAAM,WAAW;AACjB,YAAM,cAAc,OAAO,KAAK;AAGhC,kBAAY,UAAU,MAAM;AAC1B,aAAK,wBAAwB,QAAQ;AAAA,MACvC,CAAC;AAED,WAAK,QAAQ,IAAI,UAAU,WAAW;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,IAAwB,KAA+B;AACrD,UAAM,cAAc,KAAK,QAAQ,IAAI,GAAG;AACxC,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,qCAAqC,GAAG,EAAE;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,SAA6B,KAAuB;AAClD,WAAO,KAAK,IAAI,GAAG,EAAE,IAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,IAAwB,KAAQ,OAA4B;AAC1D,SAAK,IAAI,GAAG,EAAE,IAAI,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,OAAO,SAA4B;AACjC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,YAAM,WAAW;AACjB,UAAI,KAAK,QAAQ,IAAI,QAAQ,GAAG;AAC9B,aAAK,IAAI,UAAU,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,eACE,KACA,UACY;AACZ,UAAM,cAAc,KAAK,IAAI,GAAG;AAChC,WAAO,YAAY,UAAU,MAAM;AACjC,eAAS,YAAY,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,UAAU,UAAyD;AACjE,SAAK,kBAAkB,IAAI,QAAQ;AACnC,WAAO,MAAM,KAAK,kBAAkB,OAAO,QAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,wBAA4C,KAAc;AAChE,UAAM,cAAc,KAAK,IAAI,GAAG;AAChC,UAAM,QAAQ,YAAY,IAAA;AAE1B,UAAM,QAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA,eAAe;AAAA;AAAA,IAAA;AAGjB,SAAK,kBAAkB,QAAQ,CAAA,eAAc;AAC3C,UAAI;AACF,mBAAW,KAAK;AAAA,MAClB,SAAS,OAAO;AACd,gBAAQ,MAAM,8CAA8C,KAAK;AAAA,MACnE;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QAAc;AACZ,SAAK,OAAO,aAAa;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAA6B,KAAc;AACzC,UAAM,eAAe,cAAc,GAAG;AACtC,SAAK,IAAI,KAAK,YAAY;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,WAAiC;AAC/B,UAAM,WAAgC,CAAA;AAEtC,eAAW,CAAC,KAAK,WAAW,KAAK,KAAK,SAAS;AAC5C,eAAiB,GAAG,IAAI,YAAY,IAAA;AAAA,IACvC;AAEA,WAAO,OAAO,OAAO,QAAsB;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,mBAAmB,KAAuB;AACxC,WAAO,KAAK,QAAQ,IAAI,GAAG,GAAG,wBAAwB;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAgB;AAEd,SAAK,QAAQ,QAAQ,CAAA,gBAAe,YAAY,SAAS;AACzD,SAAK,QAAQ,MAAA;AAGb,SAAK,kBAAkB,MAAA;AAAA,EACzB;AACF;ACtWA,MAAM,kBAAiD;AAAA,EACrD,cAAc;AAAA,EACd,OAAO;AAAA,EACP,cAAc;AAChB;AA+BO,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBpB,YAAY,SAA+B;AAhB3C,SAAQ,gCAAgB,IAAA;AAGxB,SAAQ,oCAAoB,IAAA;AAG5B,SAAQ,mCAAmB,IAAA;AAWzB,SAAK,UAAU,EAAE,GAAG,iBAAiB,GAAG,QAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,GAAwB,OAAU,SAAsC;AACtE,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,KAAK;AAAA,IACrC;AAEA,UAAM,WAAW,KAAK,UAAU,IAAI,KAAK;AACzC,aAAS,IAAI,OAAO;AAGpB,SAAK,kBAAkB,KAAK;AAE5B,WAAO,MAAM,KAAK,IAAI,OAAO,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,KAA0B,OAAU,SAAsC;AACxE,QAAI,CAAC,KAAK,cAAc,IAAI,KAAK,GAAG;AAClC,WAAK,cAAc,IAAI,OAAO,oBAAI,KAAK;AAAA,IACzC;AAEA,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK;AAC7C,aAAS,IAAI,OAAO;AAGpB,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,KAAK;AAAA,IACrC;AAEA,WAAO,MAAM;AACX,eAAS,OAAO,OAAO;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,IAAyB,OAAU,SAAgC;AACjE,UAAM,WAAW,KAAK,UAAU,IAAI,KAAK;AACzC,QAAI,UAAU;AACZ,eAAS,OAAO,OAAO;AACvB,UAAI,SAAS,SAAS,GAAG;AACvB,aAAK,UAAU,OAAO,KAAK;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,eAAe,KAAK,cAAc,IAAI,KAAK;AACjD,QAAI,cAAc;AAChB,mBAAa,OAAO,OAAO;AAC3B,UAAI,aAAa,SAAS,GAAG;AAC3B,aAAK,cAAc,OAAO,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,KAA0B,OAAU,SAAgC;AAElE,UAAM,qBAAqB,KAAK,gBAAgB,OAAO,OAAO;AAC9D,QAAI,uBAAuB,MAAM;AAE/B;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,UAAU,IAAI,KAAK;AACzC,QAAI,UAAU;AAEZ,YAAM,gBAAgB,MAAM,KAAK,QAAQ;AACzC,oBAAc,QAAQ,CAAA,YAAW;AAC/B,aAAK,gBAAgB,SAAS,kBAAkB;AAAA,MAClD,CAAC;AAAA,IACH;AAGA,UAAM,eAAe,KAAK,cAAc,IAAI,KAAK;AACjD,QAAI,cAAc;AAEhB,YAAM,gBAAgB,MAAM,KAAK,YAAY;AAC7C,oBAAc,QAAQ,CAAA,YAAW;AAC/B,aAAK,gBAAgB,SAAS,kBAAkB;AAAA,MAClD,CAAC;AAED,WAAK,cAAc,OAAO,KAAK;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,UACJ,OACA,SACe;AAEf,UAAM,qBAAqB,MAAM,KAAK,qBAAqB,OAAO,OAAO;AACzE,QAAI,uBAAuB,MAAM;AAE/B;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,UAAU,IAAI,KAAK;AACzC,QAAI,UAAU;AACZ,YAAM,WAAW,MAAM,KAAK,QAAQ,EAAE;AAAA,QAAI,CAAA,YACxC,KAAK,qBAAqB,SAAS,kBAAkB;AAAA,MAAA;AAEvD,YAAM,QAAQ,IAAI,QAAQ;AAAA,IAC5B;AAGA,UAAM,eAAe,KAAK,cAAc,IAAI,KAAK;AACjD,QAAI,cAAc;AAChB,YAAM,gBAAgB,MAAM,KAAK,YAAY;AAC7C,YAAM,WAAW,cAAc;AAAA,QAAI,CAAA,YACjC,KAAK,qBAAqB,SAAS,kBAAkB;AAAA,MAAA;AAEvD,YAAM,QAAQ,IAAI,QAAQ;AAE1B,WAAK,cAAc,OAAO,KAAK;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBA,UACE,OACA,aACY;AACZ,QAAI,CAAC,KAAK,QAAQ,cAAc;AAC9B,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,QAAI,CAAC,KAAK,aAAa,IAAI,KAAK,GAAG;AACjC,WAAK,aAAa,IAAI,OAAO,oBAAI,KAAK;AAAA,IACxC;AAEA,UAAM,kBAAkB,KAAK,aAAa,IAAI,KAAK;AACnD,oBAAgB,IAAI,WAAW;AAE/B,WAAO,MAAM;AACX,sBAAgB,OAAO,WAAW;AAClC,UAAI,gBAAgB,SAAS,GAAG;AAC9B,aAAK,aAAa,OAAO,KAAK;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,mBAAmB,OAAyB;AAC1C,QAAI,OAAO;AACT,WAAK,UAAU,OAAO,KAAK;AAC3B,WAAK,cAAc,OAAO,KAAK;AAAA,IACjC,OAAO;AACL,WAAK,UAAU,MAAA;AACf,WAAK,cAAc,MAAA;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,cAAc,OAA0B;AACtC,UAAM,eAAe,KAAK,UAAU,IAAI,KAAK,GAAG,QAAQ;AACxD,UAAM,YAAY,KAAK,cAAc,IAAI,KAAK,GAAG,QAAQ;AACzD,WAAO,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAgB;AACd,SAAK,UAAU,MAAA;AACf,SAAK,cAAc,MAAA;AACnB,SAAK,aAAa,MAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACN,OACA,SACwB;AACxB,QAAI,CAAC,KAAK,QAAQ,cAAc;AAC9B,aAAO;AAAA,IACT;AAEA,UAAM,kBAAkB,KAAK,aAAa,IAAI,KAAK;AACnD,QAAI,CAAC,mBAAmB,gBAAgB,SAAS,GAAG;AAClD,aAAO;AAAA,IACT;AAEA,QAAI,iBAAyC;AAE7C,eAAW,eAAe,iBAAiB;AACzC,UAAI;AACF,yBAAiB,YAAY,cAAqB;AAClD,YAAI,mBAAmB,MAAM;AAE3B,iBAAO;AAAA,QACT;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,oCAAoC,KAAK;AAAA,MAEzD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBACZ,OACA,SACiC;AACjC,QAAI,CAAC,KAAK,QAAQ,cAAc;AAC9B,aAAO;AAAA,IACT;AAEA,UAAM,kBAAkB,KAAK,aAAa,IAAI,KAAK;AACnD,QAAI,CAAC,mBAAmB,gBAAgB,SAAS,GAAG;AAClD,aAAO;AAAA,IACT;AAEA,QAAI,iBAAyC;AAE7C,eAAW,eAAe,iBAAiB;AACzC,UAAI;AACF,cAAM,SAAS,YAAY,cAAqB;AAChD,yBAAkB,kBAAkB,UAAU,MAAM,SAAS;AAC7D,YAAI,mBAAmB,MAAM;AAE3B,iBAAO;AAAA,QACT;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,oCAAoC,KAAK;AAAA,MAEzD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACN,SACA,SACM;AACN,QAAI;AACF,cAAQ,OAAO;AAAA,IACjB,SAAS,OAAO;AACd,cAAQ,MAAM,sCAAsC,KAAK;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBACZ,SACA,SACe;AACf,QAAI;AACF,YAAM,SAAS,QAAQ,OAAO;AAC9B,UAAI,kBAAkB,SAAS;AAC7B,cAAM;AAAA,MACR;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,sCAAsC,KAAK;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,OAAwB;AAChD,UAAM,QAAQ,KAAK,cAAc,KAAK;AACtC,QAAI,QAAQ,KAAK,QAAQ,cAAc;AACrC,cAAQ;AAAA,QACN,6BAA6B,KAAK,QAAQ,YAAY,yBAAyB,KAAK,oBAClE,KAAK;AAAA,MAAA;AAAA,IAE3B;AAAA,EACF;AACF;ACxaA,MAAM,aAAyB,CAAC,SAAS,QAAQ,QAAQ,OAAO;AAMhE,MAAM,wBAAoC,CAAC,UAAU;AACnD,QAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,KAAK,MAAM;AAClD,QAAM,UAAU,GAAG,MAAM,IAAI,MAAM,OAAO;AAC1C,QAAM,WAAW,MAAM,YAAY;AAEnC,UAAQ,MAAM,OAAA;AAAA,IACZ,KAAK;AACH,cAAQ,MAAM,SAAS,QAAQ;AAC/B;AAAA,IACF,KAAK;AACH,cAAQ,KAAK,SAAS,QAAQ;AAC9B;AAAA,IACF,KAAK;AACH,cAAQ,KAAK,SAAS,QAAQ;AAC9B;AAAA,IACF,KAAK;AACH,cAAQ,MAAM,SAAS,QAAQ;AAC/B;AAAA,EAAA;AAEN;AAoCO,MAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBlB,YAAY,SAAyB;AACnC,SAAK,QAAQ,SAAS,SAAS;AAC/B,SAAK,QAAQ,SAAS;AACtB,SAAK,UAAU,SAAS,WAAW;AACnC,SAAK,WAAW,SAAS,YAAY,CAAC,qBAAqB;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,OAAuB;AAC3B,WAAO,IAAI,OAAO;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK,QAAQ,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK;AAAA,MAC/C,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,IAAA,CAChB;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,SAAiB,UAAsC;AAC3D,SAAK,IAAI,SAAS,SAAS,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,KAAK,SAAiB,UAAsC;AAC1D,SAAK,IAAI,QAAQ,SAAS,QAAQ;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,KAAK,SAAiB,UAAsC;AAC1D,SAAK,IAAI,QAAQ,SAAS,QAAQ;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,SAAiB,UAAsC;AAC3D,SAAK,IAAI,SAAS,SAAS,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,SAAS,OAAuB;AAC9B,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,WAAW,SAAwB;AACjC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,WAAW,SAA2B;AACpC,SAAK,SAAS,KAAK,OAAO;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,cAAc,SAA2B;AACvC,UAAM,QAAQ,KAAK,SAAS,QAAQ,OAAO;AAC3C,QAAI,UAAU,IAAI;AAChB,WAAK,SAAS,OAAO,OAAO,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,IACN,OACA,SACA,UACM;AACN,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,UAAU,KAAK,GAAG;AAC3C;AAAA,IACF;AAEA,UAAM,QAAkB;AAAA,MACtB;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAA;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ;AAAA,IAAA;AAGF,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI;AACF,gBAAQ,KAAK;AAAA,MACf,SAAS,OAAO;AAEd,gBAAQ,MAAM,2BAA2B,KAAK;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,OAA0B;AAC1C,WAAO,WAAW,QAAQ,KAAK,KAAK,WAAW,QAAQ,KAAK,KAAK;AAAA,EACnE;AACF;AAgBO,SAAS,aAAa,OAAwB;AACnD,SAAO,IAAI,OAAO,EAAE,OAAO;AAC7B;ACxUO,IAAK,8BAAAC,eAAL;AAELA,aAAA,sBAAA,IAAuB;AACvBA,aAAA,oBAAA,IAAqB;AAGrBA,aAAA,oBAAA,IAAqB;AACrBA,aAAA,uBAAA,IAAwB;AAGxBA,aAAA,qBAAA,IAAsB;AACtBA,aAAA,kBAAA,IAAmB;AAGnBA,aAAA,iBAAA,IAAkB;AAClBA,aAAA,oBAAA,IAAqB;AACrBA,aAAA,qBAAA,IAAsB;AAGtBA,aAAA,eAAA,IAAgB;AAnBN,SAAAA;AAAA,GAAA,aAAA,CAAA,CAAA;AAqFL,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBxB,YAAY,UAAoB,QAAgB,SAA+B;AAZ/E,SAAQ,SAAwB,CAAA;AAa9B,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,aAAa,SAAS,cAAc;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,OAAO,OAA4B,SAA4C;AAC7E,UAAM,cAAc,KAAK,eAAe,OAAO,OAAO;AAGtD,SAAK,aAAa,WAAW;AAG7B,SAAK,SAAS,WAAW;AAGzB,SAAK,SAAS,KAAK,SAAS,WAAW;AAEvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MACE,MACA,SACA,SAKa;AACb,UAAM,QAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,OAAO,SAAS,SAAS,KAAK,YAAY,IAAI;AAAA,MAC9C,WAAW,KAAK,IAAA;AAAA,MAChB,SAAS,SAAS;AAAA,MAClB,eAAe,SAAS;AAAA,IAAA;AAG1B,WAAO,KAAK,OAAO,OAAO,SAAS,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,aAAqC;AACnC,WAAO,CAAC,GAAG,KAAK,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,eAAmC;AACjC,WAAO,KAAK,OAAO,KAAK,OAAO,SAAS,CAAC,KAAK;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,eAAqB;AACnB,SAAK,SAAS,CAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,gBAAyB;AACvB,WAAO,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,KAAK;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eACN,OACA,SACa;AACb,QAAI,KAAK,cAAc,KAAK,GAAG;AAC7B,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,EAAE,GAAG,MAAM,SAAS,GAAG,QAAA;AAAA,MAAQ;AAAA,IAE5C;AAGA,WAAO;AAAA,MACL,MAAM,KAAK,aAAa,KAAK;AAAA,MAC7B,SAAS,MAAM;AAAA,MACf,OAAO,KAAK,QAAQ,KAAK;AAAA,MACzB,WAAW,KAAK,IAAA;AAAA,MAChB;AAAA,MACA,eAAe;AAAA,IAAA;AAAA,EAEnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,OAAyB;AAC5C,UAAM,UAAU,MAAM,QAAQ,YAAA;AAE9B,QAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,SAAS,QAAQ,GAAG;AAC9B,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,SAAS,QAAQ,GAAG;AAC9B,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,SAAS,QAAQ,GAAG;AAC9B,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,SAAS,UAAU,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,QAAQ,OAAuB;AACrC,WAAO,KAAK,YAAY,KAAK,aAAa,KAAK,CAAC;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,MAA0B;AAC5C,UAAM,aAAa;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA;AAAA,IAAA;AAEF,WAAO,WAAW,SAAS,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,OAAkC;AACtD,WACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,aAAa,SACb,WAAW,SACX,eAAe;AAAA,EAEnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,OAA0B;AAC7C,SAAK,OAAO,KAAK,KAAK;AAGtB,QAAI,KAAK,OAAO,SAAS,KAAK,YAAY;AACxC,WAAK,OAAO,MAAA;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAS,OAA0B;AACzC,UAAM,aAAa,IAAI,MAAM,IAAI,KAAK,MAAM,OAAO;AAEnD,QAAI,MAAM,OAAO;AACf,WAAK,OAAO,MAAM,YAAY;AAAA,QAC5B,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,MAAA,CAChB;AAAA,IACH,OAAO;AACL,WAAK,OAAO,KAAK,YAAY;AAAA,QAC3B,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,MAAA,CAChB;AAAA,IACH;AAAA,EACF;AACF;ACjUO,MAAM,UAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4B3C,YAAY,UAAkB,MAAqB;AARnD,SAAQ,aAAgC,CAAA;AAStC,SAAK,WAAW;AAChB,SAAK,eAAe,KAAK;AACzB,SAAK,WAAW,KAAK;AACrB,SAAK,YAAY,KAAK;AACtB,SAAK,cAAc,KAAK;AAGxB,SAAK,SAAS;AAAA,MACZ,OAAO,CAAC,KAAa,aAAmC,KAAK,OAAO,MAAM,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ;AAAA,MAC1G,MAAM,CAAC,KAAa,aAAmC,KAAK,OAAO,KAAK,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ;AAAA,MACxG,MAAM,CAAC,KAAa,aAAmC,KAAK,OAAO,KAAK,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ;AAAA,MACxG,OAAO,CAAC,KAAa,aAAmC,KAAK,OAAO,MAAM,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ;AAAA,IAAA;AAAA,EAE9G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAA6B,KAAuB;AAClD,WAAO,KAAK,aAAa,SAAS,GAAG;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAA6B,KAAQ,OAA4B;AAC/D,SAAK,aAAa,IAAI,KAAK,KAAK;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,GAAwB,OAAU,SAAsC;AACtE,WAAO,KAAK,SAAS,GAAG,OAAO,OAAO;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAyB,OAAU,SAAgC;AACjE,SAAK,SAAS,IAAI,OAAO,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAA0B,OAAU,SAAgC;AAClE,SAAK,SAAS,KAAK,OAAO,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAuB,IAAsB;AAC3C,WAAO,KAAK,YAAe,EAAE;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,SAA2B;AACnC,SAAK,WAAW,KAAK,OAAO;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,UAAyD;AACxE,WAAO,KAAK,aAAa,UAAU,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAoB;AAClB,eAAW,WAAW,KAAK,YAAY;AACrC,UAAI;AACF,gBAAA;AAAA,MACF,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,2BAA2B,EAAE,OAAO;AAAA,MACxD;AAAA,IACF;AACA,SAAK,aAAa,CAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAmC;AACjC,WAAO,KAAK;AAAA,EACd;AACF;AC1LO,MAAM,cAAc;AAAA,EAOzB,YACE,UACA,cACA,QACA,SACA;AAXF,SAAQ,8BAAc,IAAA;AAYpB,SAAK,WAAW;AAChB,SAAK,eAAe;AACpB,SAAK,SAAS;AACd,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA;AAAA,EAGA,SAAiC,QAAmB,QAAkB;AACpE,QAAI,KAAK,QAAQ,IAAI,OAAO,EAAE,GAAG;AAC/B,YAAM,IAAI,MAAM,WAAW,OAAO,EAAE,yBAAyB;AAAA,IAC/D;AAEA,SAAK,eAAe,MAAM;AAE1B,UAAM,MAAM,IAAI,UAAU,OAAO,IAAI;AAAA,MACnC,cAAc,KAAK;AAAA,MACnB,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,WAAW,CAAc,OAAyB,KAAK,eAAe,EAAE;AAAA,IAAA,CACzE;AAED,SAAK,QAAQ,IAAI,OAAO,IAAI;AAAA,MAC1B;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,YAAY,CAAA;AAAA,MACZ;AAAA,IAAA,CACD;AAED,SAAK,OAAO,KAAK,sBAAsB,OAAO,EAAE,EAAE;AAClD,SAAK,SAAS,KAAK,qBAAqB,EAAE,MAAM,OAAO,IAAI,MAAM,OAAO,KAAA,CAAM;AAAA,EAChF;AAAA;AAAA,EAGA,MAAM,WAAW,IAA2B;AAC1C,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,QAAI,CAAC,OAAQ;AAEb,QAAI,OAAO,UAAU,SAAS;AAC5B,YAAM,KAAK,cAAc,EAAE;AAAA,IAC7B;AAEA,SAAK,QAAQ,OAAO,EAAE;AACtB,SAAK,OAAO,KAAK,wBAAwB,EAAE,EAAE;AAAA,EAC/C;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,QAAQ,KAAK,uBAAA;AAEnB,eAAW,MAAM,OAAO;AACtB,YAAM,KAAK,WAAW,EAAE;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,WAAW,IAA2B;AAC1C,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,WAAW,EAAE,aAAa;AAAA,IAC5C;AAEA,QAAI,OAAO,UAAU,QAAS;AAC9B,QAAI,OAAO,UAAU,gBAAgB;AACnC,YAAM,IAAI,MAAM,WAAW,EAAE,0DAA0D;AAAA,IACzF;AAGA,eAAW,SAAS,OAAO,OAAO,gBAAgB,CAAA,GAAI;AACpD,YAAM,MAAM,KAAK,QAAQ,IAAI,KAAK;AAClC,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,MAAM,WAAW,EAAE,gCAAgC,KAAK,GAAG;AAAA,MACvE;AACA,UAAI,IAAI,UAAU,SAAS;AACzB,cAAM,KAAK,WAAW,KAAK;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI;AACF,aAAO,QAAQ;AAEf,UAAI,OAAO,OAAO,eAAe;AAC/B,cAAM,QAAQ,KAAK,aAAa,UAAU,OAAO,OAAO,cAAc,KAAK,OAAO,MAAM,CAAC;AACzF,eAAO,IAAI,UAAU,KAAK;AAAA,MAC5B;AAEA,UAAI,OAAO,OAAO,SAAS;AACzB,cAAM,QAAQ,KAAK,SAAS,GAAG,SAAS,CAAC,QAAQ;AAC/C,iBAAO,OAAO,UAAU,IAAI,iBAAiB,IAAI,MAAM,IAAI,OAAO,CAAC;AAAA,QACrE,CAAC;AACD,eAAO,IAAI,UAAU,KAAK;AAAA,MAC5B;AAEA,YAAM,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO,MAAM;AAElD,aAAO,QAAQ;AACf,WAAK,OAAO,KAAK,iBAAiB,EAAE,EAAE;AACtC,WAAK,SAAS,KAAK,iBAAiB,EAAE,MAAM,IAAI;AAAA,IAClD,SAAS,OAAO;AACd,aAAO,QAAQ;AACf,aAAO,QAAQ;AACf,WAAK,OAAO,MAAM,uBAAuB,EAAE,IAAI,EAAE,OAAO;AACxD,WAAK,SAAS,KAAK,gBAAgB,EAAE,MAAM,IAAI,OAAuB;AACtE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,aAA4B;AAChC,UAAM,QAAQ,KAAK,uBAAA,EAAyB,QAAA;AAE5C,eAAW,MAAM,OAAO;AACtB,YAAM,KAAK,cAAc,EAAE;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,cAAc,IAA2B;AAC7C,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,QAAI,CAAC,UAAU,OAAO,UAAU,QAAS;AAEzC,QAAI;AACF,YAAM,OAAO,OAAO,QAAA;AACpB,aAAO,IAAI,YAAA;AAEX,aAAO,QAAQ;AACf,WAAK,OAAO,KAAK,qBAAqB,EAAE,EAAE;AAC1C,WAAK,SAAS,KAAK,oBAAoB,EAAE,MAAM,IAAI;AAAA,IACrD,SAAS,OAAO;AACd,WAAK,OAAO,MAAM,0BAA0B,EAAE,IAAI,EAAE,OAAO;AAE3D,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,UAAqC,IAAsB;AACzD,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,WAAO,SAAU,OAAO,SAAe;AAAA,EACzC;AAAA;AAAA,EAGA,eAA0C,IAAsB;AAC9D,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,WAAO,QAAQ,UAAU,UAAW,OAAO,SAAe;AAAA,EAC5D;AAAA;AAAA,EAGA,UAAU,IAAqB;AAC7B,WAAO,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC5B;AAAA;AAAA,EAGA,eAAe,IAAgC;AAC7C,WAAO,KAAK,QAAQ,IAAI,EAAE,GAAG,SAAS;AAAA,EACxC;AAAA;AAAA,EAGA,eAAyB;AACvB,WAAO,MAAM,KAAK,KAAK,QAAQ,MAAM;AAAA,EACvC;AAAA;AAAA,EAGA,kBAA4B;AAC1B,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAA,CAAQ,EACpC,OAAO,CAAC,MAAM,EAAE,UAAU,OAAO,EACjC,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,EACxB;AAAA;AAAA,EAGA,iBAAiB,MAAwB;AACvC,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAA,CAAQ,EACpC,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,IAAI,EACpC,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,EACxB;AAAA;AAAA,EAGA,eAAe,QAA+B;AAC5C,UAAM,YAAY,KAAK,iBAAiB,UAAU;AAClD,eAAW,YAAY,WAAW;AAChC,YAAM,UAAW,SAAiB;AAClC,UAAI,OAAO,YAAY,cAAc,QAAQ,MAAM,GAAG;AACpD,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,yBAAmC;AACzC,UAAM,8BAAc,IAAA;AACpB,UAAM,+BAAe,IAAA;AACrB,UAAM,SAAmB,CAAA;AAEzB,UAAM,QAAQ,CAAC,IAAY,OAAiB,CAAA,MAAO;AACjD,UAAI,QAAQ,IAAI,EAAE,EAAG;AAErB,UAAI,SAAS,IAAI,EAAE,GAAG;AACpB,cAAM,QAAQ,CAAC,GAAG,MAAM,EAAE,EAAE,KAAK,MAAM;AACvC,cAAM,IAAI,MAAM,iCAAiC,KAAK,EAAE;AAAA,MAC1D;AAEA,YAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,UAAI,CAAC,OAAQ;AAEb,eAAS,IAAI,EAAE;AAEf,iBAAW,SAAS,OAAO,OAAO,gBAAgB,CAAA,GAAI;AACpD,YAAI,KAAK,QAAQ,IAAI,KAAK,GAAG;AAC3B,gBAAM,OAAO,CAAC,GAAG,MAAM,EAAE,CAAC;AAAA,QAC5B;AAAA,MACF;AAEA,eAAS,OAAO,EAAE;AAClB,cAAQ,IAAI,EAAE;AACd,aAAO,KAAK,EAAE;AAAA,IAChB;AAEA,eAAW,MAAM,KAAK,QAAQ,KAAA,GAAQ;AACpC,YAAM,EAAE;AAAA,IACV;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,eAAe,QAAsB;AAC3C,QAAI,CAAC,OAAO,MAAM,OAAO,OAAO,OAAO,UAAU;AAC/C,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,QAAI,CAAC,OAAO,QAAQ,OAAO,OAAO,SAAS,UAAU;AACnD,YAAM,IAAI,MAAM,WAAW,OAAO,EAAE,0BAA0B;AAAA,IAChE;AACA,QAAI,CAAC,OAAO,WAAW,OAAO,OAAO,YAAY,UAAU;AACzD,YAAM,IAAI,MAAM,WAAW,OAAO,EAAE,6BAA6B;AAAA,IACnE;AACA,QAAI,CAAC,OAAO,QAAQ,OAAO,OAAO,SAAS,UAAU;AACnD,YAAM,IAAI,MAAM,WAAW,OAAO,EAAE,0BAA0B;AAAA,IAChE;AACA,QAAI,OAAO,OAAO,SAAS,YAAY;AACrC,YAAM,IAAI,MAAM,WAAW,OAAO,EAAE,8BAA8B;AAAA,IACpE;AACA,QAAI,OAAO,OAAO,YAAY,YAAY;AACxC,YAAM,IAAI,MAAM,WAAW,OAAO,EAAE,gCAAgC;AAAA,IACtE;AAAA,EACF;AACF;AChMO,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuC1B,YAAY,SAAwB;AAnBpC,SAAQ,mBAAkC;AAG1C,SAAQ,YAAY;AAGpB,SAAQ,sBAAsB;AAG9B,SAAQ,oBAAmC;AAYzC,QAAI,OAAO,QAAQ,cAAc,UAAU;AACzC,YAAM,KAAK,SAAS,cAAc,QAAQ,SAAS;AACnD,UAAI,CAAC,MAAM,EAAE,cAAc,cAAc;AACvC,cAAM,IAAI,MAAM,wCAAwC,QAAQ,SAAS,EAAE;AAAA,MAC7E;AACA,WAAK,YAAY;AAAA,IACnB,WAAW,QAAQ,qBAAqB,aAAa;AACnD,WAAK,YAAY,QAAQ;AAAA,IAC3B,OAAO;AACL,YAAM,IAAI,MAAM,uEAAuE;AAAA,IACzF;AAGA,SAAK,aAAa,QAAQ;AAG1B,SAAK,WAAW,IAAI,SAAA;AACpB,SAAK,eAAe,IAAI,aAAa;AAAA,MACnC,UAAU,QAAQ,YAAY;AAAA,MAC9B,MAAM,QAAQ,QAAQ;AAAA,MACtB,QAAQ,QAAQ,UAAU;AAAA,MAC1B,OAAO,QAAQ,SAAS;AAAA,IAAA,CACzB;AACD,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,OAAO,QAAQ,YAAY;AAAA,MAC3B,OAAO;AAAA,IAAA,CACR;AACD,SAAK,eAAe,IAAI,aAAa,KAAK,UAAU,KAAK,MAAM;AAC/D,SAAK,gBAAgB,IAAI;AAAA,MACvB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,EAAE,WAAW,KAAK,UAAA;AAAA,IAAU;AAI9B,QAAI,QAAQ,SAAS;AACnB,iBAAW,UAAU,QAAQ,SAAS;AACpC,aAAK,cAAc,SAAS,MAAM;AAAA,MACpC;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,8BAA8B;AAAA,MAC7C,UAAU,QAAQ;AAAA,MAClB,SAAS,QAAQ,SAAS,UAAU;AAAA,IAAA,CACrC;AAGD,SAAK,SAAS,KAAK,gBAAgB,MAAS;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAsB;AAC1B,SAAK,eAAA;AAIL,eAAW,CAAC,IAAI,MAAM,KAAM,KAAK,cAAsB,SAAS;AAC9D,UAAI,OAAO,OAAO,SAAS,cAAc,OAAO,UAAU,cAAc;AACtE,cAAM,KAAK,cAAc,WAAW,EAAE;AAAA,MACxC;AAAA,IACF;AAGA,QAAI,KAAK,YAAY;AACnB,YAAM,KAAK,KAAK,KAAK,UAAU;AAAA,IACjC;AAEA,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,KAAK,QAA+B;AACxC,SAAK,eAAA;AAEL,QAAI;AACF,WAAK,OAAO,KAAK,kBAAkB,EAAE,QAAQ;AAG7C,WAAK,aAAa,OAAO;AAAA,QACvB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,WAAW;AAAA,QACX,aAAa;AAAA,QACb,UAAU;AAAA,QACV,gBAAgB;AAAA,QAChB,eAAe;AAAA,MAAA,CAChB;AAGD,UAAI,KAAK,kBAAkB;AACzB,cAAM,qBAAqB,KAAK,iBAAiB;AACjD,aAAK,OAAO,KAAK,gCAAgC,EAAE,UAAU,oBAAoB;AACjF,cAAM,KAAK,cAAc,cAAc,kBAAkB;AACzD,aAAK,mBAAmB;AAAA,MAC1B;AAGA,YAAM,WAAW,KAAK,cAAc,eAAe,MAAM;AACzD,UAAI,CAAC,UAAU;AACb,aAAK,aAAa;AAAA,UAChB,UAAU;AAAA,UACV,iCAAiC,MAAM;AAAA,UACvC;AAAA,YACE,OAAO;AAAA,YACP,SAAS,EAAE,OAAA;AAAA,UAAO;AAAA,QACpB;AAEF;AAAA,MACF;AAEA,WAAK,mBAAmB;AACxB,WAAK,OAAO,KAAK,qBAAqB,EAAE,UAAU,SAAS,IAAI;AAG/D,YAAM,KAAK,cAAc,WAAW,SAAS,EAAE;AAG/C,WAAK,aAAa,IAAI,UAAU,EAAE,KAAK,QAAQ,MAAM,KAAK,eAAe,MAAM,EAAA,CAAG;AAIlF,UAAI,OAAQ,SAAiB,eAAe,YAAY;AACtD,cAAO,SAAiB,WAAW,MAAM;AAAA,MAC3C;AAGA,UAAI,KAAK,aAAa,SAAS,UAAU,GAAG;AAC1C,cAAM,KAAK,KAAA;AAAA,MACb;AAAA,IACF,SAAS,OAAO;AACd,WAAK,aAAa,OAAO,OAAgB;AAAA,QACvC,WAAW;AAAA,QACX;AAAA,MAAA,CACD;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,OAAsB;AAC1B,SAAK,eAAA;AAEL,QAAI;AACF,WAAK,OAAO,MAAM,gBAAgB;AAGlC,WAAK,aAAa,OAAO;AAAA,QACvB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe;AAAA,MAAA,CAChB;AAGD,WAAK,SAAS,KAAK,iBAAiB,MAAS;AAAA,IAC/C,SAAS,OAAO;AACd,WAAK,aAAa,OAAO,OAAgB,EAAE,WAAW,QAAQ;AAAA,IAChE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QAAc;AACZ,SAAK,eAAA;AAEL,QAAI;AACF,WAAK,OAAO,MAAM,iBAAiB;AAGnC,WAAK,sBAAsB;AAC3B,UAAI,KAAK,sBAAsB,MAAM;AACnC,qBAAa,KAAK,iBAAiB;AACnC,aAAK,oBAAoB;AAAA,MAC3B;AAGA,WAAK,aAAa,OAAO;AAAA,QACvB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,eAAe;AAAA,MAAA,CAChB;AAGD,WAAK,SAAS,KAAK,kBAAkB,MAAS;AAAA,IAChD,SAAS,OAAO;AACd,WAAK,aAAa,OAAO,OAAgB,EAAE,WAAW,SAAS;AAAA,IACjE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,KAAK,MAAoB;AACvB,SAAK,eAAA;AAEL,QAAI;AACF,WAAK,OAAO,MAAM,kBAAkB,EAAE,MAAM;AAG5C,YAAM,aAAa,KAAK,aAAa,SAAS,SAAS;AAEvD,UAAI,YAAY;AACd,aAAK,sBAAsB;AAAA,MAC7B;AAGA,UAAI,KAAK,sBAAsB,MAAM;AACnC,qBAAa,KAAK,iBAAiB;AACnC,aAAK,oBAAoB;AAAA,MAC3B;AAGA,WAAK,SAAS,KAAK,oBAAoB,EAAE,MAAM;AAG/C,WAAK,aAAa,IAAI,eAAe,IAAI;AAIzC,UAAI,KAAK,qBAAqB;AAC5B,aAAK,oBAAoB,WAAW,MAAM;AACxC,cAAI,KAAK,uBAAuB,KAAK,aAAa,SAAS,SAAS,GAAG;AACrE,iBAAK,OAAO,MAAM,8BAA8B;AAChD,iBAAK,sBAAsB;AAC3B,iBAAK,SAAS,KAAK,iBAAiB,MAAS;AAAA,UAC/C;AACA,eAAK,oBAAoB;AAAA,QAC3B,GAAG,GAAG;AAAA,MACR;AAAA,IACF,SAAS,OAAO;AACd,WAAK,aAAa,OAAO,OAAgB,EAAE,WAAW,QAAQ,MAAM;AAAA,IACtE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,UAAU,QAAsB;AAC9B,SAAK,eAAA;AAEL,UAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AAErD,SAAK,aAAa,IAAI,UAAU,aAAa;AAC7C,SAAK,SAAS,KAAK,iBAAiB;AAAA,MAClC,QAAQ;AAAA,MACR,OAAO,KAAK,aAAa,SAAS,OAAO;AAAA,IAAA,CAC1C;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAS,OAAsB;AAC7B,SAAK,eAAA;AAEL,SAAK,aAAa,IAAI,SAAS,KAAK;AACpC,SAAK,SAAS,KAAK,eAAe,EAAE,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,gBAAgB,MAAoB;AAClC,SAAK,eAAA;AAEL,SAAK,aAAa,IAAI,gBAAgB,IAAI;AAC1C,SAAK,SAAS,KAAK,uBAAuB,EAAE,MAAM;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,YAAY,UAAyB;AACnC,SAAK,eAAA;AAEL,SAAK,aAAa,IAAI,YAAY,QAAQ;AAC1C,SAAK,OAAO,MAAM,gBAAgB,EAAE,UAAU;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,GAAwB,OAAU,SAAwC;AACxE,SAAK,eAAA;AACL,WAAO,KAAK,SAAS,GAAG,OAAO,OAAO;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,KAA0B,OAAU,SAAwC;AAC1E,SAAK,eAAA;AACL,WAAO,KAAK,SAAS,KAAK,OAAO,OAAO;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,UAA4B,MAAwB;AAClD,SAAK,eAAA;AACL,WAAO,KAAK,cAAc,UAAa,IAAI;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eAAe,QAAsB;AACnC,SAAK,eAAA;AACL,SAAK,cAAc,SAAS,MAAM;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,WAAiC;AAC/B,SAAK,eAAA;AACL,WAAO,KAAK,aAAa,SAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAA+B;AAC7B,SAAK,eAAA;AACL,QAAI,CAAC,KAAK,iBAAkB,QAAO,CAAA;AAEnC,UAAM,WAAW,KAAK;AACtB,QAAI,OAAO,SAAS,cAAc,YAAY;AAC5C,aAAO,SAAS,UAAA;AAAA,IAClB;AACA,WAAO,CAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,OAAqB;AAC9B,SAAK,eAAA;AACL,QAAI,CAAC,KAAK,kBAAkB;AAC1B,WAAK,OAAO,KAAK,0CAA0C;AAC3D;AAAA,IACF;AAEA,UAAM,WAAW,KAAK;AACtB,QAAI,OAAO,SAAS,aAAa,YAAY;AAC3C,eAAS,SAAS,KAAK;AACvB,WAAK,SAAS,KAAK,kBAAkB;AAAA,QACnC,SAAS,UAAU,KAAK,SAAS,SAAS,KAAK;AAAA,QAC/C,MAAM,UAAU;AAAA,MAAA,CACjB;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA4B;AAC1B,SAAK,eAAA;AACL,QAAI,CAAC,KAAK,iBAAkB,QAAO;AAEnC,UAAM,WAAW,KAAK;AACtB,QAAI,OAAO,SAAS,oBAAoB,YAAY;AAClD,aAAO,SAAS,gBAAA;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBAAmC;AACvC,SAAK,eAAA;AAEL,QAAI;AACF,UAAI,KAAK,UAAU,mBAAmB;AACpC,cAAM,KAAK,UAAU,kBAAA;AAAA,MACvB,WAAY,KAAK,UAAkB,yBAAyB;AAC1D,cAAO,KAAK,UAAkB,wBAAA;AAAA,MAChC;AACA,WAAK,aAAa,IAAI,cAAc,IAAI;AACxC,WAAK,SAAS,KAAK,qBAAqB,EAAE,YAAY,MAAM;AAAA,IAC9D,SAAS,OAAO;AACd,WAAK,OAAO,MAAM,6BAA6B,EAAE,OAAO;AAAA,IAC1D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAgC;AACpC,SAAK,eAAA;AAEL,QAAI;AACF,UAAI,SAAS,gBAAgB;AAC3B,cAAM,SAAS,eAAA;AAAA,MACjB,WAAY,SAAiB,sBAAsB;AACjD,cAAO,SAAiB,qBAAA;AAAA,MAC1B;AACA,WAAK,aAAa,IAAI,cAAc,KAAK;AACzC,WAAK,SAAS,KAAK,qBAAqB,EAAE,YAAY,OAAO;AAAA,IAC/D,SAAS,OAAO;AACd,WAAK,OAAO,MAAM,0BAA0B,EAAE,OAAO;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAkC;AACtC,QAAI,KAAK,YAAY;AACnB,YAAM,KAAK,eAAA;AAAA,IACb,OAAO;AACL,YAAM,KAAK,kBAAA;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAuB;AACrB,SAAK,eAAA;AACL,UAAM,UAAU,KAAK,cAAc,UAAU,SAAS;AACtD,QAAI,WAAW,OAAQ,QAAgB,eAAe,YAAY;AAC/D,cAAgB,WAAA;AAAA,IACnB,OAAO;AACL,WAAK,OAAO,KAAK,8BAA8B;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAmC;AACvC,SAAK,eAAA;AACL,UAAM,aAAa,KAAK,cAAc,UAAU,YAAY;AAC5D,QAAI,cAAc,OAAQ,WAAmB,mBAAmB,YAAY;AAC1E,YAAO,WAAmB,eAAA;AAAA,IAC5B,OAAO;AACL,WAAK,OAAO,KAAK,iCAAiC;AAAA,IACpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoB;AAClB,SAAK,eAAA;AAEL,UAAM,UAAU,KAAK,cAAc,UAAU,SAAS;AACtD,QAAI,WAAW,OAAQ,QAAgB,SAAS,YAAY;AACzD,cAAgB,KAAA;AAAA,IACnB;AAEA,UAAM,aAAa,KAAK,cAAc,UAAU,YAAY;AAC5D,QAAI,cAAc,OAAQ,WAAmB,gBAAgB,YAAY;AACtE,iBAAmB,YAAA;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAmB;AACjB,SAAK,eAAA;AAGL,UAAM,SAAS,KAAK,aAAa,SAAS,MAAM;AAChD,QAAI,CAAC,QAAQ;AACX,WAAK,OAAO,KAAK,mBAAmB;AACpC;AAAA,IACF;AAGA,QAAI,KAAK,kBAAkB;AACzB,YAAM,WAAW,KAAK;AACtB,UAAI,OAAO,SAAS,gBAAgB,YAAY;AAC9C,cAAM,WAAW,SAAS,YAAA;AAC1B,YAAI,UAAU,qBAAqB,QAAW;AAC5C,eAAK,KAAK,SAAS,gBAAgB;AACnC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,aAAa,SAAS,UAAU;AACtD,QAAI,WAAW,GAAG;AAChB,WAAK,KAAK,QAAQ;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAgB;AACd,QAAI,KAAK,WAAW;AAClB;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,mBAAmB;AAGpC,QAAI,KAAK,sBAAsB,MAAM;AACnC,mBAAa,KAAK,iBAAiB;AACnC,WAAK,oBAAoB;AAAA,IAC3B;AAGA,SAAK,SAAS,KAAK,kBAAkB,MAAS;AAG9C,SAAK,cAAc,WAAA;AAGnB,SAAK,SAAS,QAAA;AACd,SAAK,aAAa,QAAA;AAElB,SAAK,YAAY;AACjB,SAAK,OAAO,KAAK,kBAAkB;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,UAAmB;AACrB,WAAO,KAAK,aAAa,SAAS,SAAS;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAkB;AACpB,WAAO,KAAK,aAAa,SAAS,QAAQ;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,cAAsB;AACxB,WAAO,KAAK,aAAa,SAAS,aAAa;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAmB;AACrB,WAAO,KAAK,aAAa,SAAS,UAAU;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAiB;AACnB,WAAO,KAAK,aAAa,SAAS,QAAQ;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,QAAiB;AACnB,WAAO,KAAK,aAAa,SAAS,OAAO;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAuB;AACzB,WAAO,KAAK,aAAa,SAAS,cAAc;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,aAAa,SAAS,gBAAgB;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,kBAAiC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,aAAsB;AACxB,WAAO,KAAK,aAAa,SAAS,YAAY;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAgB;AAClB,WAAO,KAAK,aAAa,SAAS,MAAM;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAoB;AACtB,WAAO,KAAK,aAAa,SAAS,UAAU;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAuB;AAC7B,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,QAAwB;AAC7C,UAAM,MAAM,OAAO,MAAM,GAAG,EAAE,IAAA,GAAO,YAAA;AAErC,YAAQ,KAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AACF;AAsBA,eAAsB,aAAa,SAAiD;AAClF,QAAM,SAAS,IAAI,eAAe,OAAO;AACzC,QAAM,OAAO,KAAA;AACb,SAAO;AACT;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/state/effect.ts","../src/state/signal.ts","../src/state/computed.ts","../src/state/state-manager.ts","../src/events/event-bus.ts","../src/logger.ts","../src/error-handler.ts","../src/plugin-api.ts","../src/plugin-manager.ts","../src/scarlett-player.ts"],"sourcesContent":["/**\n * Effect tracking for automatic dependency management in signals.\n *\n * When a signal is accessed within an effect, it automatically\n * subscribes the effect to that signal's updates.\n */\n\n/**\n * Effect context that can be modified\n * @internal\n */\nconst effectContext = {\n current: null as (() => void) | null,\n};\n\n/**\n * Currently executing effect (for dependency tracking)\n * @internal\n */\nexport let currentEffect: (() => void) | null = null;\n\n/**\n * Set the current effect context (used internally by computed)\n * @internal\n */\nexport function setCurrentEffect(effect: (() => void) | null): void {\n effectContext.current = effect;\n currentEffect = effect;\n}\n\n/**\n * Get the current effect context\n * @internal\n */\nexport function getCurrentEffect(): (() => void) | null {\n return effectContext.current;\n}\n\n/**\n * Unsubscribe function returned by effect()\n */\nexport type UnsubscribeFn = () => void;\n\n/**\n * Create a reactive effect that runs when its dependencies change.\n *\n * The effect runs immediately and tracks any signals accessed during execution.\n * When those signals change, the effect re-runs automatically.\n *\n * @param fn - Function to run as an effect\n * @returns Unsubscribe function to stop the effect\n *\n * @example\n * ```ts\n * const count = signal(0);\n *\n * effect(() => {\n * console.log('Count:', count.get());\n * });\n *\n * count.set(1); // Logs: \"Count: 1\"\n * ```\n */\nexport function effect(fn: () => void): UnsubscribeFn {\n const execute = () => {\n // Set as current effect for dependency tracking\n setCurrentEffect(execute);\n try {\n fn();\n } catch (error) {\n console.error('[Scarlett Player] Error in effect:', error);\n throw error;\n } finally {\n // Clear current effect\n setCurrentEffect(null);\n }\n };\n\n // Run immediately to establish dependencies\n execute();\n\n // Return cleanup function (can be extended for unsubscribing)\n return () => {\n // Future: Add unsubscribe logic if needed\n };\n}\n","/**\n * Signal - Core reactive primitive for Scarlett Player.\n *\n * Signals are observable values that automatically track dependencies\n * and notify subscribers when the value changes.\n *\n * Target size: ~500 bytes minified\n */\n\nimport { currentEffect, type UnsubscribeFn } from './effect';\n\n/**\n * A reactive signal that holds a value and notifies subscribers on changes.\n *\n * @template T - The type of value held by this signal\n *\n * @example\n * ```ts\n * const count = new Signal(0);\n *\n * // Subscribe to changes\n * const unsub = count.subscribe(() => {\n * console.log('Count changed:', count.get());\n * });\n *\n * count.set(1); // Logs: \"Count changed: 1\"\n * unsub(); // Stop listening\n * ```\n */\nexport class Signal<T> {\n private value: T;\n private subscribers = new Set<() => void>();\n\n constructor(initialValue: T) {\n this.value = initialValue;\n }\n\n /**\n * Get the current value and track dependency if called within an effect.\n *\n * @returns Current value\n */\n get(): T {\n // Track dependency if in effect context\n if (currentEffect) {\n this.subscribers.add(currentEffect);\n }\n return this.value;\n }\n\n /**\n * Set a new value and notify subscribers if changed.\n *\n * @param newValue - New value to set\n */\n set(newValue: T): void {\n // Skip if value hasn't changed\n if (Object.is(this.value, newValue)) {\n return;\n }\n\n this.value = newValue;\n this.notify();\n }\n\n /**\n * Update the value using a function.\n *\n * @param updater - Function that receives current value and returns new value\n *\n * @example\n * ```ts\n * const count = new Signal(0);\n * count.update(n => n + 1); // Increments by 1\n * ```\n */\n update(updater: (current: T) => T): void {\n this.set(updater(this.value));\n }\n\n /**\n * Subscribe to changes without automatic dependency tracking.\n *\n * @param callback - Function to call when value changes\n * @returns Unsubscribe function\n */\n subscribe(callback: () => void): UnsubscribeFn {\n this.subscribers.add(callback);\n return () => this.subscribers.delete(callback);\n }\n\n /**\n * Notify all subscribers of a change.\n * @internal\n */\n private notify(): void {\n this.subscribers.forEach(subscriber => {\n try {\n subscriber();\n } catch (error) {\n console.error('[Scarlett Player] Error in signal subscriber:', error);\n }\n });\n }\n\n /**\n * Clean up all subscriptions.\n * Call this when destroying the signal.\n */\n destroy(): void {\n this.subscribers.clear();\n }\n\n /**\n * Get the current number of subscribers (for debugging).\n * @internal\n */\n getSubscriberCount(): number {\n return this.subscribers.size;\n }\n}\n\n/**\n * Helper function to create a signal.\n *\n * @param initialValue - Initial value for the signal\n * @returns New signal instance\n *\n * @example\n * ```ts\n * const playing = signal(false);\n * playing.set(true);\n * ```\n */\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n","/**\n * Computed - Derived reactive values for Scarlett Player.\n *\n * Computed values are lazy-evaluated and cached until dependencies change.\n *\n * Target size: ~400 bytes minified\n */\n\nimport { currentEffect, setCurrentEffect, getCurrentEffect, type UnsubscribeFn } from './effect';\n\n/**\n * A computed signal that derives its value from other signals.\n *\n * The computation is lazy (only runs when accessed) and cached\n * until dependencies change.\n *\n * @template T - The type of computed value\n *\n * @example\n * ```ts\n * const count = signal(0);\n * const doubled = new Computed(() => count.get() * 2);\n *\n * doubled.get(); // 0\n * count.set(5);\n * doubled.get(); // 10\n * ```\n */\nexport class Computed<T> {\n private value: T | undefined;\n private dirty = true;\n private subscribers = new Set<() => void>();\n private computation: () => T;\n private dependencies = new Set<UnsubscribeFn>();\n private invalidateCallback: () => void;\n\n constructor(computation: () => T) {\n this.computation = computation;\n // Create invalidate callback once to avoid creating new functions\n this.invalidateCallback = () => this.invalidate();\n }\n\n /**\n * Get the computed value, tracking dependency if in effect context.\n *\n * Recomputes if dirty, otherwise returns cached value.\n *\n * @returns Computed value\n */\n get(): T {\n if (this.dirty) {\n // Run computation with this computed as the current effect\n const prevEffect = getCurrentEffect();\n setCurrentEffect(this.invalidateCallback);\n\n try {\n this.value = this.computation();\n this.dirty = false;\n } finally {\n setCurrentEffect(prevEffect);\n }\n }\n\n // Track dependency if in effect context\n if (currentEffect) {\n this.subscribers.add(currentEffect);\n }\n\n return this.value!;\n }\n\n /**\n * Mark the computed value as dirty (needs recomputation).\n *\n * Called when a dependency changes.\n * @internal\n */\n invalidate(): void {\n const wasDirty = this.dirty;\n this.dirty = true;\n\n // Always notify subscribers when invalidated, even if already dirty\n // This ensures subscribers know when dependencies have changed\n if (!wasDirty || this.subscribers.size > 0) {\n this.notifySubscribers();\n }\n }\n\n /**\n * Subscribe to computed value changes.\n *\n * @param callback - Function to call when computed value may have changed\n * @returns Unsubscribe function\n */\n subscribe(callback: () => void): UnsubscribeFn {\n this.subscribers.add(callback);\n return () => this.subscribers.delete(callback);\n }\n\n /**\n * Notify subscribers that this computed value needs recomputation.\n * @internal\n */\n private notifySubscribers(): void {\n this.subscribers.forEach(subscriber => {\n try {\n subscriber();\n } catch (error) {\n console.error('[Scarlett Player] Error in computed subscriber:', error);\n }\n });\n }\n\n /**\n * Clean up all subscriptions.\n */\n destroy(): void {\n this.dependencies.forEach(unsub => unsub());\n this.dependencies.clear();\n this.subscribers.clear();\n this.value = undefined;\n this.dirty = true;\n }\n\n /**\n * Get the current number of subscribers (for debugging).\n * @internal\n */\n getSubscriberCount(): number {\n return this.subscribers.size;\n }\n}\n\n/**\n * Helper function to create a computed signal.\n *\n * @param computation - Function that computes the derived value\n * @returns New computed instance\n *\n * @example\n * ```ts\n * const playing = signal(false);\n * const paused = computed(() => !playing.get());\n * ```\n */\nexport function computed<T>(computation: () => T): Computed<T> {\n return new Computed(computation);\n}\n","/**\n * StateManager - Centralized reactive state management for Scarlett Player.\n *\n * Manages all player state using reactive signals. Each state property\n * is a Signal that can be observed for changes.\n *\n * Target size: ~1-2KB (excluding type definitions)\n */\n\nimport { signal, type Signal } from './signal';\nimport type {\n StateStore,\n StateKey,\n StateValue,\n StateUpdate,\n StateChangeEvent,\n} from '../types/state';\n\n/**\n * Default initial values for all state properties.\n */\nconst DEFAULT_STATE: StateStore = {\n // Core Playback State\n playbackState: 'idle',\n playing: false,\n paused: true,\n ended: false,\n buffering: false,\n waiting: false,\n seeking: false,\n\n // Time & Duration\n currentTime: 0,\n duration: NaN,\n buffered: null,\n bufferedAmount: 0,\n\n // Media Info\n mediaType: 'unknown',\n source: null,\n title: '',\n poster: '',\n\n // Volume & Audio\n volume: 1.0,\n muted: false,\n\n // Playback Controls\n playbackRate: 1.0,\n fullscreen: false,\n pip: false,\n controlsVisible: true,\n\n // Quality & Tracks\n qualities: [],\n currentQuality: null,\n audioTracks: [],\n currentAudioTrack: null,\n textTracks: [],\n currentTextTrack: null,\n\n // Live/DVR State (TSP features)\n live: false,\n liveEdge: true,\n seekableRange: null,\n liveLatency: 0,\n lowLatencyMode: false,\n\n // Chapters (TSP features)\n chapters: [],\n currentChapter: null,\n\n // Error State\n error: null,\n\n // Network & Performance\n bandwidth: 0,\n autoplay: false,\n loop: false,\n\n // Casting State\n airplayAvailable: false,\n airplayActive: false,\n chromecastAvailable: false,\n chromecastActive: false,\n\n // UI State\n interacting: false,\n hovering: false,\n focused: false,\n};\n\n/**\n * StateManager manages all player state using reactive signals.\n *\n * Each state property is a Signal that automatically tracks dependencies\n * and notifies subscribers when changed.\n *\n * @example\n * ```ts\n * const state = new StateManager();\n *\n * // Get a signal\n * const playingSignal = state.get('playing');\n * playingSignal.get(); // false\n *\n * // Set a value\n * state.set('playing', true);\n *\n * // Subscribe to changes\n * state.subscribe((event) => {\n * console.log(`${event.key} changed to`, event.value);\n * });\n *\n * // Batch updates\n * state.update({\n * playing: true,\n * currentTime: 10,\n * volume: 0.8,\n * });\n * ```\n */\nexport class StateManager {\n /** Internal map of state signals */\n private signals = new Map<StateKey, Signal<any>>();\n\n /** Global state change subscribers */\n private changeSubscribers = new Set<(event: StateChangeEvent) => void>();\n\n /**\n * Create a new StateManager with default initial state.\n *\n * @param initialState - Optional partial initial state (merged with defaults)\n */\n constructor(initialState?: Partial<StateStore>) {\n this.initializeSignals(initialState);\n }\n\n /**\n * Initialize all state signals with default or provided values.\n * @private\n */\n private initializeSignals(overrides?: Partial<StateStore>): void {\n const initialState = { ...DEFAULT_STATE, ...overrides };\n\n // Create signals for all state properties\n for (const [key, value] of Object.entries(initialState)) {\n const stateKey = key as StateKey;\n const stateSignal = signal(value);\n\n // Subscribe to each signal to emit global change events\n stateSignal.subscribe(() => {\n this.notifyChangeSubscribers(stateKey);\n });\n\n this.signals.set(stateKey, stateSignal);\n }\n }\n\n /**\n * Get the signal for a state property.\n *\n * @param key - State property key\n * @returns Signal for the property\n *\n * @example\n * ```ts\n * const playingSignal = state.get('playing');\n * playingSignal.get(); // false\n * playingSignal.set(true);\n * ```\n */\n get<K extends StateKey>(key: K): Signal<StateValue<K>> {\n const stateSignal = this.signals.get(key);\n if (!stateSignal) {\n throw new Error(`[StateManager] Unknown state key: ${key}`);\n }\n return stateSignal as Signal<StateValue<K>>;\n }\n\n /**\n * Get the current value of a state property (convenience method).\n *\n * @param key - State property key\n * @returns Current value\n *\n * @example\n * ```ts\n * state.getValue('playing'); // false\n * ```\n */\n getValue<K extends StateKey>(key: K): StateValue<K> {\n return this.get(key).get();\n }\n\n /**\n * Set the value of a state property.\n *\n * @param key - State property key\n * @param value - New value\n *\n * @example\n * ```ts\n * state.set('playing', true);\n * state.set('currentTime', 10.5);\n * ```\n */\n set<K extends StateKey>(key: K, value: StateValue<K>): void {\n this.get(key).set(value);\n }\n\n /**\n * Update multiple state properties at once (batch update).\n *\n * More efficient than calling set() multiple times.\n *\n * @param updates - Partial state object with updates\n *\n * @example\n * ```ts\n * state.update({\n * playing: true,\n * currentTime: 0,\n * volume: 1.0,\n * });\n * ```\n */\n update(updates: StateUpdate): void {\n for (const [key, value] of Object.entries(updates)) {\n const stateKey = key as StateKey;\n if (this.signals.has(stateKey)) {\n this.set(stateKey, value);\n }\n }\n }\n\n /**\n * Subscribe to changes on a specific state property.\n *\n * @param key - State property key\n * @param callback - Callback function receiving new value\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = state.subscribe('playing', (value) => {\n * console.log('Playing:', value);\n * });\n * ```\n */\n subscribeToKey<K extends StateKey>(\n key: K,\n callback: (value: StateValue<K>) => void\n ): () => void {\n const stateSignal = this.get(key);\n return stateSignal.subscribe(() => {\n callback(stateSignal.get());\n });\n }\n\n /**\n * Subscribe to all state changes.\n *\n * Receives a StateChangeEvent for every state property change.\n *\n * @param callback - Callback function receiving change events\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = state.subscribe((event) => {\n * console.log(`${event.key} changed:`, event.value);\n * });\n * ```\n */\n subscribe(callback: (event: StateChangeEvent) => void): () => void {\n this.changeSubscribers.add(callback);\n return () => this.changeSubscribers.delete(callback);\n }\n\n /**\n * Notify all global change subscribers.\n * @private\n */\n private notifyChangeSubscribers<K extends StateKey>(key: K): void {\n const stateSignal = this.get(key);\n const value = stateSignal.get();\n\n const event: StateChangeEvent<K> = {\n key,\n value,\n previousValue: value, // Note: We don't track previous values in this simple impl\n };\n\n this.changeSubscribers.forEach(subscriber => {\n try {\n subscriber(event);\n } catch (error) {\n console.error('[StateManager] Error in change subscriber:', error);\n }\n });\n }\n\n /**\n * Reset all state to default values.\n *\n * @example\n * ```ts\n * state.reset();\n * ```\n */\n reset(): void {\n this.update(DEFAULT_STATE);\n }\n\n /**\n * Reset a specific state property to its default value.\n *\n * @param key - State property key\n *\n * @example\n * ```ts\n * state.resetKey('playing');\n * ```\n */\n resetKey<K extends StateKey>(key: K): void {\n const defaultValue = DEFAULT_STATE[key] as StateValue<K>;\n this.set(key, defaultValue);\n }\n\n /**\n * Get a snapshot of all current state values.\n *\n * @returns Frozen snapshot of current state\n *\n * @example\n * ```ts\n * const snapshot = state.snapshot();\n * console.log(snapshot.playing, snapshot.currentTime);\n * ```\n */\n snapshot(): Readonly<StateStore> {\n const snapshot: Partial<StateStore> = {};\n\n for (const [key, stateSignal] of this.signals) {\n (snapshot as any)[key] = stateSignal.get();\n }\n\n return Object.freeze(snapshot as StateStore);\n }\n\n /**\n * Get the number of subscribers for a state property (for debugging).\n *\n * @param key - State property key\n * @returns Number of subscribers\n * @internal\n */\n getSubscriberCount(key: StateKey): number {\n return this.signals.get(key)?.getSubscriberCount() ?? 0;\n }\n\n /**\n * Destroy the state manager and cleanup all signals.\n *\n * @example\n * ```ts\n * state.destroy();\n * ```\n */\n destroy(): void {\n // Destroy all signals\n this.signals.forEach(stateSignal => stateSignal.destroy());\n this.signals.clear();\n\n // Clear change subscribers\n this.changeSubscribers.clear();\n }\n}\n","/**\n * EventBus - Type-safe event system for Scarlett Player.\n *\n * Provides pub/sub event communication between player components and plugins\n * with optional interceptors for event modification/cancellation.\n *\n * Target size: ~1KB\n */\n\nimport type {\n EventName,\n EventPayload,\n EventHandler,\n EventInterceptor,\n EventEmitterOptions,\n} from '../types/events';\n\n/**\n * Default options for EventBus.\n */\nconst DEFAULT_OPTIONS: Required<EventEmitterOptions> = {\n maxListeners: 100,\n async: false,\n interceptors: true,\n};\n\n/**\n * EventBus provides type-safe event emission and subscription.\n *\n * Features:\n * - Type-safe events based on PlayerEventMap\n * - Event interceptors for modification/cancellation\n * - One-time subscriptions with once()\n * - Async event emission\n * - Error handling for handlers\n *\n * @example\n * ```ts\n * const events = new EventBus();\n *\n * // Subscribe to event\n * events.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Emit event\n * events.emit('playback:play', undefined);\n *\n * // Intercept events\n * events.intercept('playback:timeupdate', (payload) => {\n * // Modify payload or return null to cancel\n * return { currentTime: Math.floor(payload.currentTime) };\n * });\n * ```\n */\nexport class EventBus {\n /** Event listeners map */\n private listeners = new Map<EventName, Set<EventHandler<any>>>();\n\n /** One-time listeners (removed after first call) */\n private onceListeners = new Map<EventName, Set<EventHandler<any>>>();\n\n /** Event interceptors map */\n private interceptors = new Map<EventName, Set<EventInterceptor<any>>>();\n\n /** Configuration options */\n private options: Required<EventEmitterOptions>;\n\n /**\n * Create a new EventBus.\n *\n * @param options - Optional configuration\n */\n constructor(options?: EventEmitterOptions) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n /**\n * Subscribe to an event.\n *\n * @param event - Event name\n * @param handler - Event handler function\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = events.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Later: unsubscribe\n * unsub();\n * ```\n */\n on<T extends EventName>(event: T, handler: EventHandler<T>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n const handlers = this.listeners.get(event)!;\n handlers.add(handler);\n\n // Warn if max listeners exceeded\n this.checkMaxListeners(event);\n\n return () => this.off(event, handler);\n }\n\n /**\n * Subscribe to an event once (auto-unsubscribe after first call).\n *\n * @param event - Event name\n * @param handler - Event handler function\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * events.once('player:ready', () => {\n * console.log('Player ready!');\n * });\n * ```\n */\n once<T extends EventName>(event: T, handler: EventHandler<T>): () => void {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n\n const handlers = this.onceListeners.get(event)!;\n handlers.add(handler);\n\n // Also track in regular listeners for counting\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n return () => {\n handlers.delete(handler);\n };\n }\n\n /**\n * Unsubscribe from an event.\n *\n * @param event - Event name\n * @param handler - Event handler function to remove\n *\n * @example\n * ```ts\n * const handler = () => console.log('Playing!');\n * events.on('playback:play', handler);\n * events.off('playback:play', handler);\n * ```\n */\n off<T extends EventName>(event: T, handler: EventHandler<T>): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this.listeners.delete(event);\n }\n }\n\n const onceHandlers = this.onceListeners.get(event);\n if (onceHandlers) {\n onceHandlers.delete(handler);\n if (onceHandlers.size === 0) {\n this.onceListeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event synchronously.\n *\n * Runs interceptors first, then calls all handlers.\n *\n * @param event - Event name\n * @param payload - Event payload\n *\n * @example\n * ```ts\n * events.emit('playback:play', undefined);\n * events.emit('playback:timeupdate', { currentTime: 10.5 });\n * ```\n */\n emit<T extends EventName>(event: T, payload: EventPayload<T>): void {\n // Run interceptors\n const interceptedPayload = this.runInterceptors(event, payload);\n if (interceptedPayload === null) {\n // Event cancelled by interceptor\n return;\n }\n\n // Call regular handlers\n const handlers = this.listeners.get(event);\n if (handlers) {\n // Create array to avoid calling handlers added during iteration\n const handlersArray = Array.from(handlers);\n handlersArray.forEach(handler => {\n this.safeCallHandler(handler, interceptedPayload);\n });\n }\n\n // Call once handlers\n const onceHandlers = this.onceListeners.get(event);\n if (onceHandlers) {\n // Create array to avoid modification during iteration\n const handlersArray = Array.from(onceHandlers);\n handlersArray.forEach(handler => {\n this.safeCallHandler(handler, interceptedPayload);\n });\n // Clear once handlers after calling\n this.onceListeners.delete(event);\n }\n }\n\n /**\n * Emit an event asynchronously (next tick).\n *\n * @param event - Event name\n * @param payload - Event payload\n * @returns Promise that resolves when all handlers complete\n *\n * @example\n * ```ts\n * await events.emitAsync('media:loaded', { src: 'video.mp4', type: 'video/mp4' });\n * ```\n */\n async emitAsync<T extends EventName>(\n event: T,\n payload: EventPayload<T>\n ): Promise<void> {\n // Run interceptors\n const interceptedPayload = await this.runInterceptorsAsync(event, payload);\n if (interceptedPayload === null) {\n // Event cancelled by interceptor\n return;\n }\n\n // Call regular handlers\n const handlers = this.listeners.get(event);\n if (handlers) {\n const promises = Array.from(handlers).map(handler =>\n this.safeCallHandlerAsync(handler, interceptedPayload)\n );\n await Promise.all(promises);\n }\n\n // Call once handlers\n const onceHandlers = this.onceListeners.get(event);\n if (onceHandlers) {\n const handlersArray = Array.from(onceHandlers);\n const promises = handlersArray.map(handler =>\n this.safeCallHandlerAsync(handler, interceptedPayload)\n );\n await Promise.all(promises);\n // Clear once handlers after calling\n this.onceListeners.delete(event);\n }\n }\n\n /**\n * Add an event interceptor.\n *\n * Interceptors run before handlers and can modify or cancel events.\n *\n * @param event - Event name\n * @param interceptor - Interceptor function\n * @returns Remove interceptor function\n *\n * @example\n * ```ts\n * events.intercept('playback:timeupdate', (payload) => {\n * // Round time to 2 decimals\n * return { currentTime: Math.round(payload.currentTime * 100) / 100 };\n * });\n *\n * // Cancel events\n * events.intercept('playback:play', (payload) => {\n * if (notReady) return null; // Cancel event\n * return payload;\n * });\n * ```\n */\n intercept<T extends EventName>(\n event: T,\n interceptor: EventInterceptor<T>\n ): () => void {\n if (!this.options.interceptors) {\n return () => {}; // No-op if interceptors disabled\n }\n\n if (!this.interceptors.has(event)) {\n this.interceptors.set(event, new Set());\n }\n\n const interceptorsSet = this.interceptors.get(event)!;\n interceptorsSet.add(interceptor);\n\n return () => {\n interceptorsSet.delete(interceptor);\n if (interceptorsSet.size === 0) {\n this.interceptors.delete(event);\n }\n };\n }\n\n /**\n * Remove all listeners for an event (or all events if no event specified).\n *\n * @param event - Optional event name\n *\n * @example\n * ```ts\n * events.removeAllListeners('playback:play'); // Remove all playback:play listeners\n * events.removeAllListeners(); // Remove ALL listeners\n * ```\n */\n removeAllListeners(event?: EventName): void {\n if (event) {\n this.listeners.delete(event);\n this.onceListeners.delete(event);\n } else {\n this.listeners.clear();\n this.onceListeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event.\n *\n * @param event - Event name\n * @returns Number of listeners\n *\n * @example\n * ```ts\n * events.listenerCount('playback:play'); // 3\n * ```\n */\n listenerCount(event: EventName): number {\n const regularCount = this.listeners.get(event)?.size ?? 0;\n const onceCount = this.onceListeners.get(event)?.size ?? 0;\n return regularCount + onceCount;\n }\n\n /**\n * Destroy event bus and cleanup all listeners/interceptors.\n *\n * @example\n * ```ts\n * events.destroy();\n * ```\n */\n destroy(): void {\n this.listeners.clear();\n this.onceListeners.clear();\n this.interceptors.clear();\n }\n\n /**\n * Run interceptors synchronously.\n * @private\n */\n private runInterceptors<T extends EventName>(\n event: T,\n payload: EventPayload<T>\n ): EventPayload<T> | null {\n if (!this.options.interceptors) {\n return payload;\n }\n\n const interceptorsSet = this.interceptors.get(event);\n if (!interceptorsSet || interceptorsSet.size === 0) {\n return payload;\n }\n\n let currentPayload: EventPayload<T> | null = payload;\n\n for (const interceptor of interceptorsSet) {\n try {\n currentPayload = interceptor(currentPayload as any) as EventPayload<T> | null;\n if (currentPayload === null) {\n // Event cancelled\n return null;\n }\n } catch (error) {\n console.error('[EventBus] Error in interceptor:', error);\n // Continue with other interceptors\n }\n }\n\n return currentPayload;\n }\n\n /**\n * Run interceptors asynchronously.\n * @private\n */\n private async runInterceptorsAsync<T extends EventName>(\n event: T,\n payload: EventPayload<T>\n ): Promise<EventPayload<T> | null> {\n if (!this.options.interceptors) {\n return payload;\n }\n\n const interceptorsSet = this.interceptors.get(event);\n if (!interceptorsSet || interceptorsSet.size === 0) {\n return payload;\n }\n\n let currentPayload: EventPayload<T> | null = payload;\n\n for (const interceptor of interceptorsSet) {\n try {\n const result = interceptor(currentPayload as any);\n currentPayload = (result instanceof Promise ? await result : result) as EventPayload<T> | null;\n if (currentPayload === null) {\n // Event cancelled\n return null;\n }\n } catch (error) {\n console.error('[EventBus] Error in interceptor:', error);\n // Continue with other interceptors\n }\n }\n\n return currentPayload;\n }\n\n /**\n * Safely call a handler with error handling.\n * @private\n */\n private safeCallHandler<T extends EventName>(\n handler: EventHandler<T>,\n payload: EventPayload<T>\n ): void {\n try {\n handler(payload);\n } catch (error) {\n console.error('[EventBus] Error in event handler:', error);\n }\n }\n\n /**\n * Safely call a handler asynchronously with error handling.\n * @private\n */\n private async safeCallHandlerAsync<T extends EventName>(\n handler: EventHandler<T>,\n payload: EventPayload<T>\n ): Promise<void> {\n try {\n const result = handler(payload);\n if (result instanceof Promise) {\n await result;\n }\n } catch (error) {\n console.error('[EventBus] Error in event handler:', error);\n }\n }\n\n /**\n * Check if max listeners exceeded and warn.\n * @private\n */\n private checkMaxListeners(event: EventName): void {\n const count = this.listenerCount(event);\n if (count > this.options.maxListeners) {\n console.warn(\n `[EventBus] Max listeners (${this.options.maxListeners}) exceeded for event: ${event}. ` +\n `Current count: ${count}. This may indicate a memory leak.`\n );\n }\n }\n}\n","/**\n * Logger - Structured logging system for Scarlett Player.\n *\n * Provides leveled logging with plugin-scoped child loggers,\n * structured metadata, and custom log handlers.\n *\n * Target size: ~0.3-0.5KB\n */\n\n/**\n * Log severity levels.\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Structured log entry.\n */\nexport interface LogEntry {\n /** Severity level */\n level: LogLevel;\n /** Log message */\n message: string;\n /** Timestamp (milliseconds since epoch) */\n timestamp: number;\n /** Optional scope (e.g., plugin name) */\n scope?: string;\n /** Optional structured metadata */\n metadata?: Record<string, any>;\n}\n\n/**\n * Custom log handler function.\n */\nexport type LogHandler = (entry: LogEntry) => void;\n\n/**\n * Logger options.\n */\nexport interface LoggerOptions {\n /** Minimum log level to output (default: 'warn') */\n level?: LogLevel;\n /** Logger scope (e.g., plugin name) */\n scope?: string;\n /** Enable/disable logging (default: true) */\n enabled?: boolean;\n /** Custom log handlers (default: console handler) */\n handlers?: LogHandler[];\n}\n\n/**\n * Log level ordering for threshold comparison.\n */\nconst LOG_LEVELS: LogLevel[] = ['debug', 'info', 'warn', 'error'];\n\n/**\n * Default console handler for log entries.\n * @private\n */\nconst defaultConsoleHandler: LogHandler = (entry) => {\n const prefix = entry.scope ? `[${entry.scope}]` : '[ScarlettPlayer]';\n const message = `${prefix} ${entry.message}`;\n const metadata = entry.metadata ?? '';\n\n switch (entry.level) {\n case 'debug':\n console.debug(message, metadata);\n break;\n case 'info':\n console.info(message, metadata);\n break;\n case 'warn':\n console.warn(message, metadata);\n break;\n case 'error':\n console.error(message, metadata);\n break;\n }\n};\n\n/**\n * Logger provides structured, leveled logging with plugin scoping.\n *\n * Features:\n * - Log levels: debug, info, warn, error\n * - Plugin-scoped child loggers\n * - Structured metadata support\n * - Custom log handlers\n * - Dynamic level and enable/disable\n *\n * @example\n * ```ts\n * // Main player logger\n * const logger = new Logger({ level: 'warn' });\n * logger.info('Player initialized');\n *\n * // Plugin logger (scoped)\n * const pluginLogger = logger.child('hls-plugin');\n * pluginLogger.debug('Manifest loaded', { url: 'video.m3u8' });\n * // Output: [ScarlettPlayer:hls-plugin] Manifest loaded\n *\n * // Custom handler for analytics\n * logger.addHandler((entry) => {\n * if (entry.level === 'error') {\n * sendToAnalytics(entry);\n * }\n * });\n *\n * // Change level dynamically\n * if (import.meta.env.DEV) {\n * logger.setLevel('debug');\n * }\n * ```\n */\nexport class Logger {\n /** Minimum log level threshold */\n private level: LogLevel;\n\n /** Logger scope (e.g., plugin name) */\n private scope?: string;\n\n /** Log handlers */\n private handlers: LogHandler[];\n\n /** Enable/disable logging */\n private enabled: boolean;\n\n /**\n * Create a new Logger.\n *\n * @param options - Logger configuration\n */\n constructor(options?: LoggerOptions) {\n this.level = options?.level ?? 'warn';\n this.scope = options?.scope;\n this.enabled = options?.enabled ?? true;\n this.handlers = options?.handlers ?? [defaultConsoleHandler];\n }\n\n /**\n * Create a child logger with a scope.\n *\n * Child loggers inherit parent settings and chain scopes.\n *\n * @param scope - Child logger scope\n * @returns New child logger\n *\n * @example\n * ```ts\n * const logger = new Logger();\n * const hlsLogger = logger.child('hls-plugin');\n * hlsLogger.info('Loading manifest');\n * // Output: [ScarlettPlayer:hls-plugin] Loading manifest\n * ```\n */\n child(scope: string): Logger {\n return new Logger({\n level: this.level,\n scope: this.scope ? `${this.scope}:${scope}` : scope,\n enabled: this.enabled,\n handlers: this.handlers,\n });\n }\n\n /**\n * Log a debug message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.debug('Request sent', { url: '/api/video' });\n * ```\n */\n debug(message: string, metadata?: Record<string, any>): void {\n this.log('debug', message, metadata);\n }\n\n /**\n * Log an info message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.info('Player ready');\n * ```\n */\n info(message: string, metadata?: Record<string, any>): void {\n this.log('info', message, metadata);\n }\n\n /**\n * Log a warning message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.warn('Low buffer', { buffered: 2.5 });\n * ```\n */\n warn(message: string, metadata?: Record<string, any>): void {\n this.log('warn', message, metadata);\n }\n\n /**\n * Log an error message.\n *\n * @param message - Log message\n * @param metadata - Optional structured metadata\n *\n * @example\n * ```ts\n * logger.error('Playback failed', { code: 'MEDIA_ERR_DECODE' });\n * ```\n */\n error(message: string, metadata?: Record<string, any>): void {\n this.log('error', message, metadata);\n }\n\n /**\n * Set the minimum log level threshold.\n *\n * @param level - New log level\n *\n * @example\n * ```ts\n * logger.setLevel('debug'); // Show all logs\n * logger.setLevel('error'); // Show only errors\n * ```\n */\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n /**\n * Enable or disable logging.\n *\n * @param enabled - Enable flag\n *\n * @example\n * ```ts\n * logger.setEnabled(false); // Disable all logging\n * ```\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /**\n * Add a custom log handler.\n *\n * @param handler - Log handler function\n *\n * @example\n * ```ts\n * logger.addHandler((entry) => {\n * if (entry.level === 'error') {\n * sendToAnalytics(entry);\n * }\n * });\n * ```\n */\n addHandler(handler: LogHandler): void {\n this.handlers.push(handler);\n }\n\n /**\n * Remove a custom log handler.\n *\n * @param handler - Log handler function to remove\n *\n * @example\n * ```ts\n * logger.removeHandler(myHandler);\n * ```\n */\n removeHandler(handler: LogHandler): void {\n const index = this.handlers.indexOf(handler);\n if (index !== -1) {\n this.handlers.splice(index, 1);\n }\n }\n\n /**\n * Core logging implementation.\n * @private\n */\n private log(\n level: LogLevel,\n message: string,\n metadata?: Record<string, any>\n ): void {\n if (!this.enabled || !this.shouldLog(level)) {\n return;\n }\n\n const entry: LogEntry = {\n level,\n message,\n timestamp: Date.now(),\n scope: this.scope,\n metadata,\n };\n\n for (const handler of this.handlers) {\n try {\n handler(entry);\n } catch (error) {\n // Don't let handler errors break logging\n console.error('[Logger] Handler error:', error);\n }\n }\n }\n\n /**\n * Check if a log level should be output.\n * @private\n */\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(this.level);\n }\n}\n\n/**\n * Create a new logger instance.\n *\n * Convenience factory function.\n *\n * @param scope - Optional logger scope\n * @returns New Logger instance\n *\n * @example\n * ```ts\n * const logger = createLogger('my-plugin');\n * logger.info('Plugin initialized');\n * ```\n */\nexport function createLogger(scope?: string): Logger {\n return new Logger({ scope });\n}\n","/**\n * ErrorHandler - Centralized error handling for Scarlett Player.\n *\n * Provides error classification, logging, history tracking, and event emission\n * for all player errors.\n *\n * Target size: ~0.4-0.6KB\n */\n\nimport type { EventBus } from './events/event-bus';\nimport type { Logger } from './logger';\n\n/**\n * Player error codes.\n */\nexport enum ErrorCode {\n // Source loading errors\n SOURCE_NOT_SUPPORTED = 'SOURCE_NOT_SUPPORTED',\n SOURCE_LOAD_FAILED = 'SOURCE_LOAD_FAILED',\n\n // Provider errors\n PROVIDER_NOT_FOUND = 'PROVIDER_NOT_FOUND',\n PROVIDER_SETUP_FAILED = 'PROVIDER_SETUP_FAILED',\n\n // Plugin errors\n PLUGIN_SETUP_FAILED = 'PLUGIN_SETUP_FAILED',\n PLUGIN_NOT_FOUND = 'PLUGIN_NOT_FOUND',\n\n // Playback errors\n PLAYBACK_FAILED = 'PLAYBACK_FAILED',\n MEDIA_DECODE_ERROR = 'MEDIA_DECODE_ERROR',\n MEDIA_NETWORK_ERROR = 'MEDIA_NETWORK_ERROR',\n\n // General errors\n UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n}\n\n/**\n * Structured player error.\n */\nexport interface PlayerError {\n /** Error code */\n code: ErrorCode;\n /** Error message */\n message: string;\n /** Whether error is fatal (unrecoverable) */\n fatal: boolean;\n /** Timestamp (milliseconds since epoch) */\n timestamp: number;\n /** Optional context (what was happening) */\n context?: Record<string, any>;\n /** Original error if wrapped */\n originalError?: Error;\n}\n\n/**\n * ErrorHandler options.\n */\nexport interface ErrorHandlerOptions {\n /** Maximum error history to keep (default: 10) */\n maxHistory?: number;\n}\n\n/**\n * ErrorHandler manages all player errors with classification and history.\n *\n * Features:\n * - Error classification (fatal vs recoverable)\n * - Error code mapping\n * - Error event emission\n * - Error history tracking\n * - Context capture\n * - Logger integration\n *\n * @example\n * ```ts\n * const errorHandler = new ErrorHandler(eventBus, logger);\n *\n * // Handle native error\n * try {\n * // Some operation\n * } catch (error) {\n * errorHandler.handle(error as Error, {\n * operation: 'loadSource',\n * src: 'video.mp4'\n * });\n * }\n *\n * // Throw specific error\n * errorHandler.throw(\n * ErrorCode.SOURCE_NOT_SUPPORTED,\n * 'MP4 files are not supported',\n * { fatal: true, context: { src: 'video.mp4' } }\n * );\n *\n * // Check error history\n * const lastError = errorHandler.getLastError();\n * const hasFatal = errorHandler.hasFatalError();\n * ```\n */\nexport class ErrorHandler {\n /** Event bus for error emission */\n private eventBus: EventBus;\n\n /** Logger for error logging */\n private logger: Logger;\n\n /** Error history */\n private errors: PlayerError[] = [];\n\n /** Maximum history size */\n private maxHistory: number;\n\n /**\n * Create a new ErrorHandler.\n *\n * @param eventBus - Event bus for error emission\n * @param logger - Logger for error logging\n * @param options - Optional configuration\n */\n constructor(eventBus: EventBus, logger: Logger, options?: ErrorHandlerOptions) {\n this.eventBus = eventBus;\n this.logger = logger;\n this.maxHistory = options?.maxHistory ?? 10;\n }\n\n /**\n * Handle an error.\n *\n * Normalizes, logs, emits, and tracks the error.\n *\n * @param error - Error to handle (native or PlayerError)\n * @param context - Optional context (what was happening)\n * @returns Normalized PlayerError\n *\n * @example\n * ```ts\n * try {\n * loadVideo();\n * } catch (error) {\n * errorHandler.handle(error as Error, { src: 'video.mp4' });\n * }\n * ```\n */\n handle(error: Error | PlayerError, context?: Record<string, any>): PlayerError {\n const playerError = this.normalizeError(error, context);\n\n // Add to history\n this.addToHistory(playerError);\n\n // Log the error\n this.logError(playerError);\n\n // Emit error event\n this.eventBus.emit('error', playerError);\n\n return playerError;\n }\n\n /**\n * Create and handle an error from code.\n *\n * @param code - Error code\n * @param message - Error message\n * @param options - Optional error options\n * @returns Created PlayerError\n *\n * @example\n * ```ts\n * errorHandler.throw(\n * ErrorCode.SOURCE_NOT_SUPPORTED,\n * 'MP4 not supported',\n * { fatal: true, context: { type: 'video/mp4' } }\n * );\n * ```\n */\n throw(\n code: ErrorCode,\n message: string,\n options?: {\n fatal?: boolean;\n context?: Record<string, any>;\n originalError?: Error;\n }\n ): PlayerError {\n const error: PlayerError = {\n code,\n message,\n fatal: options?.fatal ?? this.isFatalCode(code),\n timestamp: Date.now(),\n context: options?.context,\n originalError: options?.originalError,\n };\n\n return this.handle(error, options?.context);\n }\n\n /**\n * Get error history.\n *\n * @returns Readonly copy of error history\n *\n * @example\n * ```ts\n * const history = errorHandler.getHistory();\n * console.log(`${history.length} errors occurred`);\n * ```\n */\n getHistory(): readonly PlayerError[] {\n return [...this.errors];\n }\n\n /**\n * Get last error that occurred.\n *\n * @returns Last error or null if none\n *\n * @example\n * ```ts\n * const lastError = errorHandler.getLastError();\n * if (lastError?.fatal) {\n * showErrorMessage(lastError.message);\n * }\n * ```\n */\n getLastError(): PlayerError | null {\n return this.errors[this.errors.length - 1] ?? null;\n }\n\n /**\n * Clear error history.\n *\n * @example\n * ```ts\n * errorHandler.clearHistory();\n * ```\n */\n clearHistory(): void {\n this.errors = [];\n }\n\n /**\n * Check if any fatal errors occurred.\n *\n * @returns True if any fatal error in history\n *\n * @example\n * ```ts\n * if (errorHandler.hasFatalError()) {\n * player.reset();\n * }\n * ```\n */\n hasFatalError(): boolean {\n return this.errors.some((e) => e.fatal);\n }\n\n /**\n * Normalize error to PlayerError.\n * @private\n */\n private normalizeError(\n error: Error | PlayerError,\n context?: Record<string, any>\n ): PlayerError {\n if (this.isPlayerError(error)) {\n return {\n ...error,\n context: { ...error.context, ...context },\n };\n }\n\n // Convert native Error to PlayerError\n return {\n code: this.getErrorCode(error),\n message: error.message,\n fatal: this.isFatal(error),\n timestamp: Date.now(),\n context,\n originalError: error,\n };\n }\n\n /**\n * Determine error code from native Error.\n * @private\n */\n private getErrorCode(error: Error): ErrorCode {\n const message = error.message.toLowerCase();\n\n if (message.includes('network')) {\n return ErrorCode.MEDIA_NETWORK_ERROR;\n }\n if (message.includes('decode')) {\n return ErrorCode.MEDIA_DECODE_ERROR;\n }\n if (message.includes('source')) {\n return ErrorCode.SOURCE_LOAD_FAILED;\n }\n if (message.includes('plugin')) {\n return ErrorCode.PLUGIN_SETUP_FAILED;\n }\n if (message.includes('provider')) {\n return ErrorCode.PROVIDER_SETUP_FAILED;\n }\n\n return ErrorCode.UNKNOWN_ERROR;\n }\n\n /**\n * Determine if error is fatal.\n * @private\n */\n private isFatal(error: Error): boolean {\n return this.isFatalCode(this.getErrorCode(error));\n }\n\n /**\n * Determine if error code is fatal.\n * @private\n */\n private isFatalCode(code: ErrorCode): boolean {\n const fatalCodes = [\n ErrorCode.SOURCE_NOT_SUPPORTED,\n ErrorCode.PROVIDER_NOT_FOUND,\n ErrorCode.MEDIA_DECODE_ERROR,\n ];\n return fatalCodes.includes(code);\n }\n\n /**\n * Type guard for PlayerError.\n * @private\n */\n private isPlayerError(error: any): error is PlayerError {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n 'message' in error &&\n 'fatal' in error &&\n 'timestamp' in error\n );\n }\n\n /**\n * Add error to history.\n * @private\n */\n private addToHistory(error: PlayerError): void {\n this.errors.push(error);\n\n // Keep only max history\n if (this.errors.length > this.maxHistory) {\n this.errors.shift();\n }\n }\n\n /**\n * Log error with appropriate level.\n * @private\n */\n private logError(error: PlayerError): void {\n const logMessage = `[${error.code}] ${error.message}`;\n\n if (error.fatal) {\n this.logger.error(logMessage, {\n code: error.code,\n context: error.context,\n });\n } else {\n this.logger.warn(logMessage, {\n code: error.code,\n context: error.context,\n });\n }\n }\n}\n","/**\n * PluginAPI - Scoped API surface for plugins.\n *\n * Wraps StateManager and EventBus to provide a controlled interface\n * for plugins to interact with player state and events.\n *\n * Target size: ~0.5KB\n */\n\nimport type { StateManager } from './state/state-manager';\nimport type { EventBus } from './events/event-bus';\nimport type { Logger } from './logger';\nimport type { StateKey, StateValue, StateChangeEvent } from './types/state';\nimport type { EventName, EventPayload, EventHandler } from './types/events';\nimport type { IPluginAPI } from './types/plugin';\n\n/**\n * PluginAPI dependencies.\n */\nexport interface PluginAPIDeps {\n stateManager: StateManager;\n eventBus: EventBus;\n logger: Logger;\n container: HTMLElement;\n getPlugin: <T = unknown>(id: string) => T | null;\n}\n\n/**\n * PluginAPI provides a scoped interface for plugins to interact with the player.\n *\n * Instead of giving plugins direct access to StateManager and EventBus,\n * PluginAPI provides controlled methods that can be scoped, logged, and monitored.\n *\n * @example\n * ```ts\n * // Inside a plugin's init() method:\n * init(api: IPluginAPI) {\n * // Get state\n * const isPlaying = api.getState('playing');\n *\n * // Set state\n * api.setState('volume', 0.8);\n *\n * // Subscribe to events\n * const unsub = api.on('playback:play', () => {\n * console.log('Playback started');\n * });\n *\n * // Emit events\n * api.emit('plugin:ready', { name: this.id });\n *\n * // Register cleanup\n * api.onDestroy(unsub);\n * }\n * ```\n */\nexport class PluginAPI implements IPluginAPI {\n /** Plugin ID this API belongs to */\n readonly pluginId: string;\n\n /** Player container element */\n readonly container: HTMLElement;\n\n /** Scoped logger for this plugin */\n readonly logger: IPluginAPI['logger'];\n\n /** State manager reference */\n private stateManager: StateManager;\n\n /** Event bus reference */\n private eventBus: EventBus;\n\n /** Function to get other plugins */\n private getPluginFn: <T = unknown>(id: string) => T | null;\n\n /** Cleanup functions registered by this plugin */\n private cleanupFns: Array<() => void> = [];\n\n /**\n * Create a new PluginAPI.\n *\n * @param pluginId - ID of the plugin this API belongs to\n * @param deps - Dependencies (stateManager, eventBus, logger, container, getPlugin)\n */\n constructor(pluginId: string, deps: PluginAPIDeps) {\n this.pluginId = pluginId;\n this.stateManager = deps.stateManager;\n this.eventBus = deps.eventBus;\n this.container = deps.container;\n this.getPluginFn = deps.getPlugin;\n\n // Create scoped logger for this plugin\n this.logger = {\n debug: (msg: string, metadata?: Record<string, any>) => deps.logger.debug(`[${pluginId}] ${msg}`, metadata),\n info: (msg: string, metadata?: Record<string, any>) => deps.logger.info(`[${pluginId}] ${msg}`, metadata),\n warn: (msg: string, metadata?: Record<string, any>) => deps.logger.warn(`[${pluginId}] ${msg}`, metadata),\n error: (msg: string, metadata?: Record<string, any>) => deps.logger.error(`[${pluginId}] ${msg}`, metadata),\n };\n }\n\n /**\n * Get a state value.\n *\n * @param key - State property key\n * @returns Current state value\n */\n getState<K extends StateKey>(key: K): StateValue<K> {\n return this.stateManager.getValue(key);\n }\n\n /**\n * Set a state value.\n *\n * @param key - State property key\n * @param value - New state value\n */\n setState<K extends StateKey>(key: K, value: StateValue<K>): void {\n this.stateManager.set(key, value);\n }\n\n /**\n * Subscribe to an event.\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n on<T extends EventName>(event: T, handler: EventHandler<T>): () => void {\n return this.eventBus.on(event, handler);\n }\n\n /**\n * Unsubscribe from an event.\n *\n * @param event - Event name\n * @param handler - Event handler to remove\n */\n off<T extends EventName>(event: T, handler: EventHandler<T>): void {\n this.eventBus.off(event, handler);\n }\n\n /**\n * Emit an event.\n *\n * @param event - Event name\n * @param payload - Event payload\n */\n emit<T extends EventName>(event: T, payload: EventPayload<T>): void {\n this.eventBus.emit(event, payload);\n }\n\n /**\n * Get another plugin by ID (if ready).\n *\n * @param id - Plugin ID\n * @returns Plugin instance or null if not found/ready\n */\n getPlugin<T = unknown>(id: string): T | null {\n return this.getPluginFn<T>(id);\n }\n\n /**\n * Register a cleanup function to run when plugin is destroyed.\n *\n * @param cleanup - Cleanup function\n */\n onDestroy(cleanup: () => void): void {\n this.cleanupFns.push(cleanup);\n }\n\n /**\n * Subscribe to state changes.\n *\n * @param callback - Callback function called on any state change\n * @returns Unsubscribe function\n */\n subscribeToState(callback: (event: StateChangeEvent) => void): () => void {\n return this.stateManager.subscribe(callback);\n }\n\n /**\n * Run all registered cleanup functions.\n * Called by PluginManager when destroying the plugin.\n *\n * @internal\n */\n runCleanups(): void {\n for (const cleanup of this.cleanupFns) {\n try {\n cleanup();\n } catch (error) {\n this.logger.error('Cleanup function failed', { error });\n }\n }\n this.cleanupFns = [];\n }\n\n /**\n * Get all registered cleanup functions.\n *\n * @returns Array of cleanup functions\n * @internal\n */\n getCleanupFns(): Array<() => void> {\n return this.cleanupFns;\n }\n}\n","/**\n * PluginManager - Plugin lifecycle and dependency management with\n * topological dependency resolution and circular dependency detection.\n */\n\nimport type { EventBus } from './events/event-bus';\nimport type { StateManager } from './state/state-manager';\nimport type { Logger } from './logger';\nimport type { Plugin, PluginState, PluginConfig, PluginDescriptor } from './types/plugin';\nimport { PluginAPI } from './plugin-api';\n\nexport interface PluginManagerOptions {\n container: HTMLElement;\n}\n\n/** @internal */\ninterface PluginRecord extends PluginDescriptor {\n api: PluginAPI;\n}\n\nexport class PluginManager {\n private plugins = new Map<string, PluginRecord>();\n private eventBus: EventBus;\n private stateManager: StateManager;\n private logger: Logger;\n private container: HTMLElement;\n\n constructor(\n eventBus: EventBus,\n stateManager: StateManager,\n logger: Logger,\n options: PluginManagerOptions\n ) {\n this.eventBus = eventBus;\n this.stateManager = stateManager;\n this.logger = logger;\n this.container = options.container;\n }\n\n /** Register a plugin with optional configuration. */\n register<T extends PluginConfig>(plugin: Plugin<T>, config?: T): void {\n if (this.plugins.has(plugin.id)) {\n throw new Error(`Plugin \"${plugin.id}\" is already registered`);\n }\n\n this.validatePlugin(plugin);\n\n const api = new PluginAPI(plugin.id, {\n stateManager: this.stateManager,\n eventBus: this.eventBus,\n logger: this.logger,\n container: this.container,\n getPlugin: <T = unknown>(id: string): T | null => this.getReadyPlugin(id) as T | null,\n });\n\n this.plugins.set(plugin.id, {\n plugin,\n state: 'registered',\n config,\n cleanupFns: [],\n api,\n });\n\n this.logger.info(`Plugin registered: ${plugin.id}`);\n this.eventBus.emit('plugin:registered', { name: plugin.id, type: plugin.type });\n }\n\n /** Unregister a plugin. Destroys it first if active. */\n async unregister(id: string): Promise<void> {\n const record = this.plugins.get(id);\n if (!record) return;\n\n if (record.state === 'ready') {\n await this.destroyPlugin(id);\n }\n\n this.plugins.delete(id);\n this.logger.info(`Plugin unregistered: ${id}`);\n }\n\n /** Initialize all registered plugins in dependency order. */\n async initAll(): Promise<void> {\n const order = this.resolveDependencyOrder();\n\n for (const id of order) {\n await this.initPlugin(id);\n }\n }\n\n /** Initialize a specific plugin. */\n async initPlugin(id: string): Promise<void> {\n const record = this.plugins.get(id);\n if (!record) {\n throw new Error(`Plugin \"${id}\" not found`);\n }\n\n if (record.state === 'ready') return;\n if (record.state === 'initializing') {\n throw new Error(`Plugin \"${id}\" is already initializing (possible circular dependency)`);\n }\n\n // Ensure dependencies are ready\n for (const depId of record.plugin.dependencies || []) {\n const dep = this.plugins.get(depId);\n if (!dep) {\n throw new Error(`Plugin \"${id}\" depends on missing plugin \"${depId}\"`);\n }\n if (dep.state !== 'ready') {\n await this.initPlugin(depId);\n }\n }\n\n try {\n record.state = 'initializing';\n\n if (record.plugin.onStateChange) {\n const unsub = this.stateManager.subscribe(record.plugin.onStateChange.bind(record.plugin));\n record.api.onDestroy(unsub);\n }\n\n if (record.plugin.onError) {\n const unsub = this.eventBus.on('error', (err) => {\n record.plugin.onError?.(err.originalError || new Error(err.message));\n });\n record.api.onDestroy(unsub);\n }\n\n await record.plugin.init(record.api, record.config);\n\n record.state = 'ready';\n this.logger.info(`Plugin ready: ${id}`);\n this.eventBus.emit('plugin:active', { name: id });\n } catch (error) {\n record.state = 'error';\n record.error = error as Error;\n this.logger.error(`Plugin init failed: ${id}`, { error });\n this.eventBus.emit('plugin:error', { name: id, error: error as Error });\n throw error;\n }\n }\n\n /** Destroy all plugins in reverse dependency order. */\n async destroyAll(): Promise<void> {\n const order = this.resolveDependencyOrder().reverse();\n\n for (const id of order) {\n await this.destroyPlugin(id);\n }\n }\n\n /** Destroy a specific plugin. */\n async destroyPlugin(id: string): Promise<void> {\n const record = this.plugins.get(id);\n if (!record || record.state !== 'ready') return;\n\n try {\n await record.plugin.destroy();\n record.api.runCleanups();\n // Reset to 'registered' so it can be re-initialized later\n record.state = 'registered';\n this.logger.info(`Plugin destroyed: ${id}`);\n this.eventBus.emit('plugin:destroyed', { name: id });\n } catch (error) {\n this.logger.error(`Plugin destroy failed: ${id}`, { error });\n // Even on error, reset state so plugin can be retried\n record.state = 'registered';\n }\n }\n\n /** Get a plugin by ID (returns any registered plugin). */\n getPlugin<T extends Plugin = Plugin>(id: string): T | null {\n const record = this.plugins.get(id);\n return record ? (record.plugin as T) : null;\n }\n\n /** Get a plugin by ID only if ready (used by PluginAPI). */\n getReadyPlugin<T extends Plugin = Plugin>(id: string): T | null {\n const record = this.plugins.get(id);\n return record?.state === 'ready' ? (record.plugin as T) : null;\n }\n\n /** Check if a plugin is registered. */\n hasPlugin(id: string): boolean {\n return this.plugins.has(id);\n }\n\n /** Get plugin state. */\n getPluginState(id: string): PluginState | null {\n return this.plugins.get(id)?.state ?? null;\n }\n\n /** Get all registered plugin IDs. */\n getPluginIds(): string[] {\n return Array.from(this.plugins.keys());\n }\n\n /** Get all ready plugins. */\n getReadyPlugins(): Plugin[] {\n return Array.from(this.plugins.values())\n .filter((r) => r.state === 'ready')\n .map((r) => r.plugin);\n }\n\n /** Get plugins by type. */\n getPluginsByType(type: string): Plugin[] {\n return Array.from(this.plugins.values())\n .filter((r) => r.plugin.type === type)\n .map((r) => r.plugin);\n }\n\n /** Select a provider plugin that can play a source. */\n selectProvider(source: string): Plugin | null {\n const providers = this.getPluginsByType('provider');\n for (const provider of providers) {\n const canPlay = (provider as any).canPlay;\n if (typeof canPlay === 'function' && canPlay(source)) {\n return provider;\n }\n }\n return null;\n }\n\n /** Resolve plugin initialization order using topological sort. */\n private resolveDependencyOrder(): string[] {\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const sorted: string[] = [];\n\n const visit = (id: string, path: string[] = []) => {\n if (visited.has(id)) return;\n\n if (visiting.has(id)) {\n const cycle = [...path, id].join(' -> ');\n throw new Error(`Circular dependency detected: ${cycle}`);\n }\n\n const record = this.plugins.get(id);\n if (!record) return;\n\n visiting.add(id);\n\n for (const depId of record.plugin.dependencies || []) {\n if (this.plugins.has(depId)) {\n visit(depId, [...path, id]);\n }\n }\n\n visiting.delete(id);\n visited.add(id);\n sorted.push(id);\n };\n\n for (const id of this.plugins.keys()) {\n visit(id);\n }\n\n return sorted;\n }\n\n /** Validate plugin has required properties. */\n private validatePlugin(plugin: Plugin): void {\n if (!plugin.id || typeof plugin.id !== 'string') {\n throw new Error('Plugin must have a valid id');\n }\n if (!plugin.name || typeof plugin.name !== 'string') {\n throw new Error(`Plugin \"${plugin.id}\" must have a valid name`);\n }\n if (!plugin.version || typeof plugin.version !== 'string') {\n throw new Error(`Plugin \"${plugin.id}\" must have a valid version`);\n }\n if (!plugin.type || typeof plugin.type !== 'string') {\n throw new Error(`Plugin \"${plugin.id}\" must have a valid type`);\n }\n if (typeof plugin.init !== 'function') {\n throw new Error(`Plugin \"${plugin.id}\" must have an init() method`);\n }\n if (typeof plugin.destroy !== 'function') {\n throw new Error(`Plugin \"${plugin.id}\" must have a destroy() method`);\n }\n }\n}\n","/**\n * ScarlettPlayer - Main player class integrating all core systems.\n *\n * Provides the public API for video playback, plugin management,\n * state access, and event handling.\n *\n * Target size: ~1-1.5KB\n */\n\nimport { EventBus } from './events/event-bus';\nimport { StateManager } from './state/state-manager';\nimport { Logger } from './logger';\nimport { ErrorHandler, ErrorCode } from './error-handler';\nimport { PluginManager } from './plugin-manager';\nimport type { Plugin } from './types/plugin';\nimport type { EventName, EventHandler as EventHandlerFn } from './types/events';\nimport type { StateStore } from './types/state';\n\n/**\n * Player configuration options.\n */\nexport interface PlayerOptions {\n /** HTML container element or CSS selector */\n container: HTMLElement | string;\n /** Initial source URL */\n src?: string;\n /** Poster image URL */\n poster?: string;\n /** Initial log level (default: 'warn') */\n logLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Autoplay (default: false) */\n autoplay?: boolean;\n /** Loop playback (default: false) */\n loop?: boolean;\n /** Initial volume 0-1 (default: 1.0) */\n volume?: number;\n /** Start muted (default: false) */\n muted?: boolean;\n /** Plugins to register on initialization */\n plugins?: Plugin[];\n}\n\n/**\n * Quality level interface for proxy methods.\n */\nexport interface QualityLevel {\n id: string;\n label: string;\n width: number;\n height: number;\n bitrate: number;\n active: boolean;\n}\n\n/**\n * ScarlettPlayer - Lightweight, plugin-based video player.\n *\n * Features:\n * - Plugin-based architecture\n * - Reactive state management\n * - Type-safe event system\n * - Automatic provider selection\n * - Live/DVR support (TSP)\n * - Chapter/marker support (TSP)\n *\n * @example\n * ```ts\n * const player = new ScarlettPlayer({\n * container: document.getElementById('player'),\n * plugins: [hlsPlugin, controlsPlugin],\n * });\n *\n * // Load and play\n * await player.load('video.m3u8');\n * player.play();\n *\n * // Listen to events\n * player.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Access state\n * console.log(player.playing, player.currentTime);\n *\n * // Cleanup\n * player.destroy();\n * ```\n */\nexport class ScarlettPlayer {\n /** Player container element */\n readonly container: HTMLElement;\n\n /** Event bus */\n private eventBus: EventBus;\n\n /** State manager */\n private stateManager: StateManager;\n\n /** Logger */\n private logger: Logger;\n\n /** Error handler */\n private errorHandler: ErrorHandler;\n\n /** Plugin manager */\n private pluginManager: PluginManager;\n\n /** Current media provider plugin */\n private _currentProvider: Plugin | null = null;\n\n /** Player destroyed flag */\n private destroyed = false;\n\n /** Seeking while playing flag */\n private seekingWhilePlaying = false;\n\n /** Seek resume timeout */\n private seekResumeTimeout: number | null = null;\n\n /** Initial source URL */\n private initialSrc?: string;\n\n /**\n * Create a new ScarlettPlayer.\n *\n * @param options - Player configuration\n */\n constructor(options: PlayerOptions) {\n // Resolve container (string selector or HTMLElement)\n if (typeof options.container === 'string') {\n const el = document.querySelector(options.container);\n if (!el || !(el instanceof HTMLElement)) {\n throw new Error(`ScarlettPlayer: container not found: ${options.container}`);\n }\n this.container = el;\n } else if (options.container instanceof HTMLElement) {\n this.container = options.container;\n } else {\n throw new Error('ScarlettPlayer requires a valid HTMLElement container or CSS selector');\n }\n\n // Store initial source\n this.initialSrc = options.src;\n\n // Initialize core systems\n this.eventBus = new EventBus();\n this.stateManager = new StateManager({\n autoplay: options.autoplay ?? false,\n loop: options.loop ?? false,\n volume: options.volume ?? 1.0,\n muted: options.muted ?? false,\n poster: options.poster ?? '',\n });\n this.logger = new Logger({\n level: options.logLevel ?? 'warn',\n scope: 'ScarlettPlayer',\n });\n this.errorHandler = new ErrorHandler(this.eventBus, this.logger);\n this.pluginManager = new PluginManager(\n this.eventBus,\n this.stateManager,\n this.logger,\n { container: this.container }\n );\n\n // Register plugins if provided\n if (options.plugins) {\n for (const plugin of options.plugins) {\n this.pluginManager.register(plugin);\n }\n }\n\n this.logger.info('ScarlettPlayer initialized', {\n autoplay: options.autoplay,\n plugins: options.plugins?.length ?? 0,\n });\n\n // Emit ready event after initialization\n this.eventBus.emit('player:ready', undefined);\n }\n\n /**\n * Initialize the player asynchronously.\n * Initializes non-provider plugins and loads initial source if provided.\n */\n async init(): Promise<void> {\n this.checkDestroyed();\n\n // Initialize non-provider plugins (UI, feature, analytics, utility)\n // Providers are initialized on-demand when load() is called\n for (const [id, record] of (this.pluginManager as any).plugins) {\n if (record.plugin.type !== 'provider' && record.state === 'registered') {\n await this.pluginManager.initPlugin(id);\n }\n }\n\n // Load initial source if provided\n if (this.initialSrc) {\n await this.load(this.initialSrc);\n }\n\n return Promise.resolve();\n }\n\n /**\n * Load a media source.\n *\n * Selects appropriate provider plugin and loads the source.\n *\n * @param source - Media source URL\n * @returns Promise that resolves when source is loaded\n *\n * @example\n * ```ts\n * await player.load('video.m3u8');\n * ```\n */\n async load(source: string): Promise<void> {\n this.checkDestroyed();\n\n try {\n this.logger.info('Loading source', { source });\n\n // Reset playback state when loading new source\n this.stateManager.update({\n playing: false,\n paused: true,\n ended: false,\n buffering: true,\n currentTime: 0,\n duration: 0,\n bufferedAmount: 0,\n playbackState: 'loading',\n });\n\n // Destroy previous provider if switching\n if (this._currentProvider) {\n const previousProviderId = this._currentProvider.id;\n this.logger.info('Destroying previous provider', { provider: previousProviderId });\n await this.pluginManager.destroyPlugin(previousProviderId);\n this._currentProvider = null;\n }\n\n // Select provider FIRST (before init)\n const provider = this.pluginManager.selectProvider(source);\n if (!provider) {\n this.errorHandler.throw(\n ErrorCode.PROVIDER_NOT_FOUND,\n `No provider found for source: ${source}`,\n {\n fatal: true,\n context: { source },\n }\n );\n return;\n }\n\n this._currentProvider = provider;\n this.logger.info('Provider selected', { provider: provider.id });\n\n // Init ONLY the selected provider (not all plugins)\n await this.pluginManager.initPlugin(provider.id);\n\n // Update state\n this.stateManager.set('source', { src: source, type: this.detectMimeType(source) });\n\n // Call provider's loadSource method and wait for it to complete\n // The provider will emit media:loaded when actually ready\n if (typeof (provider as any).loadSource === 'function') {\n await (provider as any).loadSource(source);\n }\n\n // Auto-play if enabled\n if (this.stateManager.getValue('autoplay')) {\n await this.play();\n }\n } catch (error) {\n this.errorHandler.handle(error as Error, {\n operation: 'load',\n source,\n });\n }\n }\n\n /**\n * Start playback.\n *\n * @returns Promise that resolves when playback starts\n *\n * @example\n * ```ts\n * await player.play();\n * ```\n */\n async play(): Promise<void> {\n this.checkDestroyed();\n\n try {\n this.logger.debug('Play requested');\n\n // Emit play event - provider will update state when playback actually starts\n // Don't set playing:true optimistically as it causes state sync issues\n this.eventBus.emit('playback:play', undefined);\n } catch (error) {\n this.errorHandler.handle(error as Error, { operation: 'play' });\n }\n }\n\n /**\n * Pause playback.\n *\n * @example\n * ```ts\n * player.pause();\n * ```\n */\n pause(): void {\n this.checkDestroyed();\n\n try {\n this.logger.debug('Pause requested');\n\n // Clear seeking while playing flag (user explicitly paused)\n this.seekingWhilePlaying = false;\n if (this.seekResumeTimeout !== null) {\n clearTimeout(this.seekResumeTimeout);\n this.seekResumeTimeout = null;\n }\n\n // Emit pause event - provider will update state when playback actually pauses\n // Don't set paused:true optimistically as it causes state sync issues\n this.eventBus.emit('playback:pause', undefined);\n } catch (error) {\n this.errorHandler.handle(error as Error, { operation: 'pause' });\n }\n }\n\n /**\n * Seek to a specific time.\n *\n * @param time - Time in seconds\n *\n * @example\n * ```ts\n * player.seek(30); // Seek to 30 seconds\n * ```\n */\n seek(time: number): void {\n this.checkDestroyed();\n\n try {\n this.logger.debug('Seek requested', { time });\n\n // Remember if we were playing before seeking\n const wasPlaying = this.stateManager.getValue('playing');\n\n if (wasPlaying) {\n this.seekingWhilePlaying = true;\n }\n\n // Clear any existing resume timeout\n if (this.seekResumeTimeout !== null) {\n clearTimeout(this.seekResumeTimeout);\n this.seekResumeTimeout = null;\n }\n\n // Emit seeking event\n this.eventBus.emit('playback:seeking', { time });\n\n // Update state\n this.stateManager.set('currentTime', time);\n\n // If we were playing, set up a debounced resume\n // This handles multiple rapid seeks gracefully\n if (this.seekingWhilePlaying) {\n this.seekResumeTimeout = setTimeout(() => {\n if (this.seekingWhilePlaying && this.stateManager.getValue('playing')) {\n this.logger.debug('Resuming playback after seek');\n this.seekingWhilePlaying = false;\n this.eventBus.emit('playback:play', undefined);\n }\n this.seekResumeTimeout = null;\n }, 300) as unknown as number; // 300ms debounce for rapid seeks\n }\n } catch (error) {\n this.errorHandler.handle(error as Error, { operation: 'seek', time });\n }\n }\n\n /**\n * Set volume.\n *\n * @param volume - Volume 0-1\n *\n * @example\n * ```ts\n * player.setVolume(0.5); // 50% volume\n * ```\n */\n setVolume(volume: number): void {\n this.checkDestroyed();\n\n const clampedVolume = Math.max(0, Math.min(1, volume));\n\n this.stateManager.set('volume', clampedVolume);\n this.eventBus.emit('volume:change', {\n volume: clampedVolume,\n muted: this.stateManager.getValue('muted'),\n });\n }\n\n /**\n * Set muted state.\n *\n * @param muted - Mute flag\n *\n * @example\n * ```ts\n * player.setMuted(true);\n * ```\n */\n setMuted(muted: boolean): void {\n this.checkDestroyed();\n\n this.stateManager.set('muted', muted);\n this.eventBus.emit('volume:mute', { muted });\n }\n\n /**\n * Set playback rate.\n *\n * @param rate - Playback rate (e.g., 1.0 = normal, 2.0 = 2x speed)\n *\n * @example\n * ```ts\n * player.setPlaybackRate(1.5); // 1.5x speed\n * ```\n */\n setPlaybackRate(rate: number): void {\n this.checkDestroyed();\n\n this.stateManager.set('playbackRate', rate);\n this.eventBus.emit('playback:ratechange', { rate });\n }\n\n /**\n * Set autoplay state.\n *\n * When enabled, videos will automatically play after loading.\n *\n * @param autoplay - Autoplay flag\n *\n * @example\n * ```ts\n * player.setAutoplay(true);\n * await player.load('video.mp4'); // Will auto-play\n * ```\n */\n setAutoplay(autoplay: boolean): void {\n this.checkDestroyed();\n\n this.stateManager.set('autoplay', autoplay);\n this.logger.debug('Autoplay set', { autoplay });\n }\n\n /**\n * Subscribe to an event.\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * const unsub = player.on('playback:play', () => {\n * console.log('Playing!');\n * });\n *\n * // Later: unsubscribe\n * unsub();\n * ```\n */\n on<T extends EventName>(event: T, handler: EventHandlerFn<T>): () => void {\n this.checkDestroyed();\n return this.eventBus.on(event, handler);\n }\n\n /**\n * Subscribe to an event once.\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n *\n * @example\n * ```ts\n * player.once('player:ready', () => {\n * console.log('Player ready!');\n * });\n * ```\n */\n once<T extends EventName>(event: T, handler: EventHandlerFn<T>): () => void {\n this.checkDestroyed();\n return this.eventBus.once(event, handler);\n }\n\n /**\n * Get a plugin by name.\n *\n * @param name - Plugin name\n * @returns Plugin instance or null\n *\n * @example\n * ```ts\n * const hls = player.getPlugin('hls-plugin');\n * ```\n */\n getPlugin<T extends Plugin>(name: string): T | null {\n this.checkDestroyed();\n return this.pluginManager.getPlugin<T>(name);\n }\n\n /**\n * Register a plugin.\n *\n * @param plugin - Plugin to register\n *\n * @example\n * ```ts\n * player.registerPlugin(myPlugin);\n * ```\n */\n registerPlugin(plugin: Plugin): void {\n this.checkDestroyed();\n this.pluginManager.register(plugin);\n }\n\n /**\n * Get current state snapshot.\n *\n * @returns Readonly state snapshot\n *\n * @example\n * ```ts\n * const state = player.getState();\n * console.log(state.playing, state.currentTime);\n * ```\n */\n getState(): Readonly<StateStore> {\n this.checkDestroyed();\n return this.stateManager.snapshot();\n }\n\n // ===== Quality Methods (proxied to provider) =====\n\n /**\n * Get available quality levels from the current provider.\n * @returns Array of quality levels or empty array if not available\n */\n getQualities(): QualityLevel[] {\n this.checkDestroyed();\n if (!this._currentProvider) return [];\n\n const provider = this._currentProvider as any;\n if (typeof provider.getLevels === 'function') {\n return provider.getLevels();\n }\n return [];\n }\n\n /**\n * Set quality level (-1 for auto).\n * @param index - Quality level index\n */\n setQuality(index: number): void {\n this.checkDestroyed();\n if (!this._currentProvider) {\n this.logger.warn('No provider available for quality change');\n return;\n }\n\n const provider = this._currentProvider as any;\n if (typeof provider.setLevel === 'function') {\n provider.setLevel(index);\n this.eventBus.emit('quality:change', {\n quality: index === -1 ? 'auto' : `level-${index}`,\n auto: index === -1,\n });\n }\n }\n\n /**\n * Get current quality level index (-1 = auto).\n */\n getCurrentQuality(): number {\n this.checkDestroyed();\n if (!this._currentProvider) return -1;\n\n const provider = this._currentProvider as any;\n if (typeof provider.getCurrentLevel === 'function') {\n return provider.getCurrentLevel();\n }\n return -1;\n }\n\n // ===== Fullscreen Methods =====\n\n /**\n * Request fullscreen mode.\n */\n async requestFullscreen(): Promise<void> {\n this.checkDestroyed();\n\n try {\n if (this.container.requestFullscreen) {\n await this.container.requestFullscreen();\n } else if ((this.container as any).webkitRequestFullscreen) {\n await (this.container as any).webkitRequestFullscreen();\n }\n this.stateManager.set('fullscreen', true);\n this.eventBus.emit('fullscreen:change', { fullscreen: true });\n } catch (error) {\n this.logger.error('Fullscreen request failed', { error });\n }\n }\n\n /**\n * Exit fullscreen mode.\n */\n async exitFullscreen(): Promise<void> {\n this.checkDestroyed();\n\n try {\n if (document.exitFullscreen) {\n await document.exitFullscreen();\n } else if ((document as any).webkitExitFullscreen) {\n await (document as any).webkitExitFullscreen();\n }\n this.stateManager.set('fullscreen', false);\n this.eventBus.emit('fullscreen:change', { fullscreen: false });\n } catch (error) {\n this.logger.error('Exit fullscreen failed', { error });\n }\n }\n\n /**\n * Toggle fullscreen mode.\n */\n async toggleFullscreen(): Promise<void> {\n if (this.fullscreen) {\n await this.exitFullscreen();\n } else {\n await this.requestFullscreen();\n }\n }\n\n // ===== Casting Methods (proxied to plugins) =====\n\n /**\n * Request AirPlay (proxied to airplay plugin).\n */\n requestAirPlay(): void {\n this.checkDestroyed();\n const airplay = this.pluginManager.getPlugin('airplay');\n if (airplay && typeof (airplay as any).showPicker === 'function') {\n (airplay as any).showPicker();\n } else {\n this.logger.warn('AirPlay plugin not available');\n }\n }\n\n /**\n * Request Chromecast session (proxied to chromecast plugin).\n */\n async requestChromecast(): Promise<void> {\n this.checkDestroyed();\n const chromecast = this.pluginManager.getPlugin('chromecast');\n if (chromecast && typeof (chromecast as any).requestSession === 'function') {\n await (chromecast as any).requestSession();\n } else {\n this.logger.warn('Chromecast plugin not available');\n }\n }\n\n /**\n * Stop casting (AirPlay or Chromecast).\n */\n stopCasting(): void {\n this.checkDestroyed();\n\n const airplay = this.pluginManager.getPlugin('airplay');\n if (airplay && typeof (airplay as any).stop === 'function') {\n (airplay as any).stop();\n }\n\n const chromecast = this.pluginManager.getPlugin('chromecast');\n if (chromecast && typeof (chromecast as any).stopSession === 'function') {\n (chromecast as any).stopSession();\n }\n }\n\n // ===== Live Stream Methods =====\n\n /**\n * Seek to live edge (for live streams).\n */\n seekToLive(): void {\n this.checkDestroyed();\n\n // Check if stream is live\n const isLive = this.stateManager.getValue('live');\n if (!isLive) {\n this.logger.warn('Not a live stream');\n return;\n }\n\n // Try provider's getLiveInfo for live sync position\n if (this._currentProvider) {\n const provider = this._currentProvider as any;\n if (typeof provider.getLiveInfo === 'function') {\n const liveInfo = provider.getLiveInfo();\n if (liveInfo?.liveSyncPosition !== undefined) {\n this.seek(liveInfo.liveSyncPosition);\n return;\n }\n }\n }\n\n // Fallback: seek to duration (edge)\n const duration = this.stateManager.getValue('duration');\n if (duration > 0) {\n this.seek(duration);\n }\n }\n\n /**\n * Destroy the player and cleanup all resources.\n *\n * @example\n * ```ts\n * player.destroy();\n * ```\n */\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n\n this.logger.info('Destroying player');\n\n // Clear any pending seek resume timeout\n if (this.seekResumeTimeout !== null) {\n clearTimeout(this.seekResumeTimeout);\n this.seekResumeTimeout = null;\n }\n\n // Emit destroy event\n this.eventBus.emit('player:destroy', undefined);\n\n // Destroy plugins\n this.pluginManager.destroyAll();\n\n // Cleanup core systems\n this.eventBus.destroy();\n this.stateManager.destroy();\n\n this.destroyed = true;\n this.logger.info('Player destroyed');\n }\n\n // ===== State Getters =====\n\n /**\n * Get playing state.\n */\n get playing(): boolean {\n return this.stateManager.getValue('playing');\n }\n\n /**\n * Get paused state.\n */\n get paused(): boolean {\n return this.stateManager.getValue('paused');\n }\n\n /**\n * Get current time in seconds.\n */\n get currentTime(): number {\n return this.stateManager.getValue('currentTime');\n }\n\n /**\n * Get duration in seconds.\n */\n get duration(): number {\n return this.stateManager.getValue('duration');\n }\n\n /**\n * Get volume (0-1).\n */\n get volume(): number {\n return this.stateManager.getValue('volume');\n }\n\n /**\n * Get muted state.\n */\n get muted(): boolean {\n return this.stateManager.getValue('muted');\n }\n\n /**\n * Get playback rate.\n */\n get playbackRate(): number {\n return this.stateManager.getValue('playbackRate');\n }\n\n /**\n * Get buffered amount (0-1).\n */\n get bufferedAmount(): number {\n return this.stateManager.getValue('bufferedAmount');\n }\n\n /**\n * Get current provider plugin.\n */\n get currentProvider(): Plugin | null {\n return this._currentProvider;\n }\n\n /**\n * Get fullscreen state.\n */\n get fullscreen(): boolean {\n return this.stateManager.getValue('fullscreen');\n }\n\n /**\n * Get live stream state.\n */\n get live(): boolean {\n return this.stateManager.getValue('live');\n }\n\n /**\n * Get autoplay state.\n */\n get autoplay(): boolean {\n return this.stateManager.getValue('autoplay');\n }\n\n /**\n * Check if player is destroyed.\n * @private\n */\n private checkDestroyed(): void {\n if (this.destroyed) {\n throw new Error('Cannot call methods on destroyed player');\n }\n }\n\n /**\n * Detect MIME type from source URL.\n * @private\n */\n private detectMimeType(source: string): string {\n const ext = source.split('.').pop()?.toLowerCase();\n\n switch (ext) {\n case 'm3u8':\n return 'application/x-mpegURL';\n case 'mpd':\n return 'application/dash+xml';\n case 'mp4':\n return 'video/mp4';\n case 'webm':\n return 'video/webm';\n case 'ogg':\n return 'video/ogg';\n default:\n return 'video/mp4'; // Default fallback\n }\n }\n}\n\n/**\n * Create a ScarlettPlayer instance and initialize it.\n *\n * Convenience factory function that creates and initializes\n * the player in a single async call.\n *\n * @param options - Player configuration\n * @returns Promise resolving to initialized player\n *\n * @example\n * ```ts\n * const player = await createPlayer({\n * container: '#player',\n * src: 'video.m3u8',\n * plugins: [hlsPlugin()],\n * });\n *\n * player.play();\n * ```\n */\nexport async function createPlayer(options: PlayerOptions): Promise<ScarlettPlayer> {\n const player = new ScarlettPlayer(options);\n await player.init();\n return player;\n}\n"],"names":["effect","ErrorCode"],"mappings":"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"}
|