@therealtinhtute/baroiplayer 1.1.0 → 1.2.1

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.
Files changed (142) hide show
  1. package/README.md +1 -2
  2. package/dist/context/media.js +1 -2
  3. package/dist/context/media.mjs +3 -15
  4. package/dist/context/store.js +1 -2
  5. package/dist/context/store.mjs +3 -5
  6. package/dist/context-Bzd5QCKM.cjs +7 -0
  7. package/dist/context-Bzd5QCKM.cjs.map +1 -0
  8. package/dist/context-DD_SH4tT.js +1053 -0
  9. package/dist/context-DD_SH4tT.js.map +1 -0
  10. package/dist/core-events-BRnLMB7s.cjs +2 -0
  11. package/dist/core-events-BRnLMB7s.cjs.map +1 -0
  12. package/dist/core-events-v_mKdj5p.js +417 -0
  13. package/dist/core-events-v_mKdj5p.js.map +1 -0
  14. package/dist/core-plugins-CMBv-yVh.cjs +2 -0
  15. package/dist/core-plugins-CMBv-yVh.cjs.map +1 -0
  16. package/dist/core-plugins-CqCxLkbd.js +754 -0
  17. package/dist/core-plugins-CqCxLkbd.js.map +1 -0
  18. package/dist/core.js +7 -29
  19. package/dist/core.js.map +1 -1
  20. package/dist/core.mjs +947 -1220
  21. package/dist/core.mjs.map +1 -1
  22. package/dist/enhanced-components-BwjBqSA1.js +2858 -0
  23. package/dist/enhanced-components-BwjBqSA1.js.map +1 -0
  24. package/dist/enhanced-components-C-ka-XLp.cjs +2 -0
  25. package/dist/enhanced-components-C-ka-XLp.cjs.map +1 -0
  26. package/dist/hooks-B-IIWPJr.js +1842 -0
  27. package/dist/hooks-B-IIWPJr.js.map +1 -0
  28. package/dist/hooks-DcHzmBwA.cjs +4 -0
  29. package/dist/hooks-DcHzmBwA.cjs.map +1 -0
  30. package/dist/index.js +27 -97
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +5613 -6210
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/minimal-components-BYsMQde5.js +1610 -0
  35. package/dist/minimal-components-BYsMQde5.js.map +1 -0
  36. package/dist/minimal-components-CsxQbDp7.cjs +2 -0
  37. package/dist/minimal-components-CsxQbDp7.cjs.map +1 -0
  38. package/dist/performance-monitor-DCSijLJg.js +312 -0
  39. package/dist/performance-monitor-DCSijLJg.js.map +1 -0
  40. package/dist/performance-monitor-wNFKmqMr.cjs +2 -0
  41. package/dist/performance-monitor-wNFKmqMr.cjs.map +1 -0
  42. package/dist/rolldown-runtime-BmowowmI.js +14 -0
  43. package/dist/rolldown-runtime-mLOUI7ql.cjs +1 -0
  44. package/dist/utils-D2gQ7c2R.js +64 -0
  45. package/dist/utils-D2gQ7c2R.js.map +1 -0
  46. package/dist/utils-DJaAwiZ9.cjs +2 -0
  47. package/dist/utils-DJaAwiZ9.cjs.map +1 -0
  48. package/dist/utils.js +1 -2
  49. package/dist/utils.mjs +3 -11
  50. package/package.json +28 -22
  51. package/src/components/AnimateLoading.tsx +14 -10
  52. package/src/components/accessibility/keyboard-help-overlay.tsx +2 -0
  53. package/src/components/enhanced/debug-panel.tsx +1 -1
  54. package/src/components/enhanced/enhanced-media-player.tsx +68 -25
  55. package/src/components/examples/loading-states-demo.tsx +1 -2
  56. package/src/components/examples/react-19-demo.tsx +6 -10
  57. package/src/components/examples/volume-orientation-demo.tsx +1 -2
  58. package/src/components/legacy.tsx +6 -6
  59. package/src/components/media-player-video.tsx +5 -12
  60. package/src/components/media-player.tsx +2 -2
  61. package/src/components/ui/blur-poster.tsx +18 -15
  62. package/src/components/ui/enhanced-seek-bar.tsx +2 -2
  63. package/src/components/ui/media-resource-preloader.tsx +21 -23
  64. package/src/components/unified/base-media-player.tsx +22 -10
  65. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +58 -38
  66. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +6 -6
  67. package/src/components/variants/minimal/components/VideoElement.tsx +3 -1
  68. package/src/core/optimization/bundle-optimizer.tsx +26 -27
  69. package/src/core/performance/media-loading-optimizer.ts +2 -1
  70. package/src/core/plugins/__tests__/registry.test.ts +1 -1
  71. package/src/core/plugins/enhanced-plugin-system.ts +26 -8
  72. package/src/core/plugins/registry.ts +319 -92
  73. package/src/core/plugins/types.ts +21 -3
  74. package/src/core/providers/enhanced-hls-provider.ts +11 -40
  75. package/src/core/providers/lazy-provider.tsx +5 -42
  76. package/src/features/media-session/media-session-manager.ts +4 -26
  77. package/src/features/picture-in-picture/pip-manager.ts +2 -2
  78. package/src/features/playlist/playlist-manager.ts +26 -18
  79. package/src/features/subtitles/subtitle-manager.ts +1 -1
  80. package/src/features/subtitles/subtitle-parser.ts +19 -16
  81. package/src/features/thumbnails/thumbnail-generator.ts +12 -5
  82. package/src/hooks/__tests__/currentTime-fix.test.ts +149 -0
  83. package/src/hooks/accessibility/use-accessibility-preferences.ts +1 -1
  84. package/src/hooks/accessibility/use-focus-management.ts +2 -2
  85. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +2 -2
  86. package/src/hooks/accessibility/use-screen-reader.ts +1 -1
  87. package/src/hooks/core/index.ts +1 -1
  88. package/src/hooks/use-buffer-health.ts +1 -1
  89. package/src/hooks/use-enhanced-media-player.ts +107 -9
  90. package/src/hooks/use-focus-trap.tsx +2 -2
  91. package/src/hooks/use-intelligent-preloading.ts +23 -3
  92. package/src/hooks/use-keyboard-shortcuts.ts +2 -2
  93. package/src/hooks/use-media-player.ts +74 -43
  94. package/src/hooks/use-memory-optimization.ts +15 -15
  95. package/src/hooks/use-smart-preload.ts +1 -2
  96. package/src/hooks/useKeyboardShortcuts.ts +34 -2
  97. package/src/hooks/useScreenshot.ts +60 -44
  98. package/src/hooks/useVideoPlayer.ts +50 -4
  99. package/src/index-legacy.ts +3 -5
  100. package/src/test/accessibility-utils.ts +7 -7
  101. package/src/test/media-mocks.ts +41 -28
  102. package/src/test/setup.ts +22 -4
  103. package/src/types/assets.d.ts +29 -0
  104. package/src/types/index.ts +13 -0
  105. package/dist/context/media.js.map +0 -1
  106. package/dist/context/media.mjs.map +0 -1
  107. package/dist/context/store.js.map +0 -1
  108. package/dist/context/store.mjs.map +0 -1
  109. package/dist/context-BYwDoSRX.js +0 -1172
  110. package/dist/context-BYwDoSRX.js.map +0 -1
  111. package/dist/context-eNS62_ac.cjs +0 -23
  112. package/dist/context-eNS62_ac.cjs.map +0 -1
  113. package/dist/core-events-B1iM2F46.cjs +0 -2
  114. package/dist/core-events-B1iM2F46.cjs.map +0 -1
  115. package/dist/core-events-DunPHKRE.js +0 -484
  116. package/dist/core-events-DunPHKRE.js.map +0 -1
  117. package/dist/core-plugins-CROGvQUy.js +0 -686
  118. package/dist/core-plugins-CROGvQUy.js.map +0 -1
  119. package/dist/core-plugins-DtsHBOtF.cjs +0 -2
  120. package/dist/core-plugins-DtsHBOtF.cjs.map +0 -1
  121. package/dist/enhanced-components-DUw2KrmQ.js +0 -1142
  122. package/dist/enhanced-components-DUw2KrmQ.js.map +0 -1
  123. package/dist/enhanced-components-DXBCHU0v.cjs +0 -2
  124. package/dist/enhanced-components-DXBCHU0v.cjs.map +0 -1
  125. package/dist/hooks-BW-JjVgP.cjs +0 -4
  126. package/dist/hooks-BW-JjVgP.cjs.map +0 -1
  127. package/dist/hooks-CyX6De5M.js +0 -1693
  128. package/dist/hooks-CyX6De5M.js.map +0 -1
  129. package/dist/minimal-components-Bdcpxav5.cjs +0 -2
  130. package/dist/minimal-components-Bdcpxav5.cjs.map +0 -1
  131. package/dist/minimal-components-DlRK7Qu_.js +0 -1927
  132. package/dist/minimal-components-DlRK7Qu_.js.map +0 -1
  133. package/dist/performance-monitor-C5k6FDXw.js +0 -301
  134. package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
  135. package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
  136. package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
  137. package/dist/utils-CFOue_9K.cjs +0 -9
  138. package/dist/utils-CFOue_9K.cjs.map +0 -1
  139. package/dist/utils-Dzpl2ArK.js +0 -2844
  140. package/dist/utils-Dzpl2ArK.js.map +0 -1
  141. package/dist/utils.js.map +0 -1
  142. package/dist/utils.mjs.map +0 -1
@@ -1,7 +1,9 @@
1
1
  import { EventBus } from "../events/event-system"
2
+ import { ConsolePluginLogger } from "./utils"
2
3
  import type {
3
4
  PluginRegistry as IPluginRegistry,
4
5
  Plugin,
6
+ PluginCategory,
5
7
  PluginConfig,
6
8
  PluginContext,
7
9
  PluginEvents,
@@ -11,71 +13,83 @@ import type {
11
13
  } from "./types"
12
14
  import { PluginConflictError, PluginDependencyError, PluginError } from "./types"
13
15
 
14
- // Plugin registry implementation
15
16
  export class PluginRegistry implements IPluginRegistry {
16
17
  private plugins = new Map<string, Plugin>()
17
18
  private pluginConfigs = new Map<string, PluginConfig>()
19
+ private pluginContexts = new Map<string, PluginContext>()
18
20
  private enabledPlugins = new Set<string>()
19
21
  private eventBus = new EventBus()
20
22
  private logger: PluginLogger
21
23
 
22
- constructor(logger: PluginLogger) {
23
- this.logger = logger
24
+ constructor(logger?: PluginLogger) {
25
+ this.logger = logger || new ConsolePluginLogger("[PluginRegistry]")
24
26
  }
25
27
 
26
- // Register a plugin factory
27
- async register(factory: PluginFactory, config: PluginConfig = {}): Promise<void> {
28
- try {
29
- const plugin = factory(config)
30
- const { name, dependencies = [], conflicts = [] } = plugin.metadata
28
+ register(name: string, plugin: Plugin, config?: PluginConfig): void
29
+ register(factory: PluginFactory, config?: PluginConfig): void
30
+ register(
31
+ nameOrFactory: string | PluginFactory,
32
+ pluginOrConfig?: Plugin | PluginConfig,
33
+ config: PluginConfig = {}
34
+ ): void {
35
+ let name: string | undefined
36
+ let plugin: Plugin | undefined
37
+ let pluginConfig: PluginConfig = {}
31
38
 
32
- // Check if plugin already exists
33
- if (this.plugins.has(name)) {
34
- throw new PluginError(name, "initialize", "Plugin already registered")
39
+ try {
40
+ if (typeof nameOrFactory === "string") {
41
+ name = nameOrFactory
42
+ plugin = pluginOrConfig as Plugin
43
+ pluginConfig = config
44
+ } else {
45
+ const factory = nameOrFactory
46
+ pluginConfig = (pluginOrConfig as PluginConfig) || {}
47
+ plugin = factory(pluginConfig)
48
+ name = plugin?.metadata?.name
35
49
  }
36
50
 
37
- // Validate dependencies
38
- const missingDependencies = dependencies.filter((dep) => !this.plugins.has(dep))
39
- if (missingDependencies.length > 0) {
40
- throw new PluginDependencyError(name, missingDependencies)
51
+ if (!name || !plugin) {
52
+ throw new PluginError("unknown", "initialize", "Invalid plugin registration payload")
41
53
  }
42
54
 
43
- // Check for conflicts with enabled plugins
44
- const activeConflicts = conflicts.filter((conflict) => this.enabledPlugins.has(conflict))
45
- if (activeConflicts.length > 0) {
46
- throw new PluginConflictError(name, activeConflicts)
55
+ if (this.plugins.has(name)) {
56
+ throw new PluginError(name, "initialize", "Plugin already registered")
47
57
  }
48
58
 
49
- // Store plugin and configuration
50
59
  this.plugins.set(name, plugin)
51
- this.pluginConfigs.set(name, config)
60
+ this.pluginConfigs.set(name, pluginConfig)
52
61
 
53
62
  this.logger.info(`Plugin '${name}' registered successfully`)
54
63
  ;(this.eventBus as any).emit("plugin:registered", { name, plugin })
55
64
  } catch (error) {
56
- const pluginName = factory({}).metadata.name
65
+ const pluginName = name || plugin?.metadata?.name || "unknown"
57
66
  this.logger.error(`Failed to register plugin '${pluginName}'`, error)
58
67
  ;(this.eventBus as any).emit("plugin:error", { name: pluginName, error: error as Error })
59
68
  throw error
60
69
  }
61
70
  }
62
71
 
63
- // Unregister a plugin
64
- async unregister(name: string): Promise<void> {
72
+ async unregister(name: string, context?: PluginContext): Promise<void> {
65
73
  const plugin = this.plugins.get(name)
66
74
  if (!plugin) {
67
75
  throw new PluginError(name, "destroy", "Plugin not found")
68
76
  }
69
77
 
70
78
  try {
71
- // Disable plugin if enabled
79
+ const pluginContext = context || this.pluginContexts.get(name) || this.createPluginContext(name)
80
+
72
81
  if (this.enabledPlugins.has(name)) {
73
- await this.disable(name)
82
+ await this.deactivate(name, pluginContext)
83
+ }
84
+
85
+ if (plugin.isInitialized) {
86
+ await plugin.destroy(pluginContext)
74
87
  }
75
88
 
76
- // Remove from registry
77
89
  this.plugins.delete(name)
78
90
  this.pluginConfigs.delete(name)
91
+ this.pluginContexts.delete(name)
92
+ this.enabledPlugins.delete(name)
79
93
 
80
94
  this.logger.info(`Plugin '${name}' unregistered successfully`)
81
95
  } catch (error) {
@@ -84,85 +98,262 @@ export class PluginRegistry implements IPluginRegistry {
84
98
  }
85
99
  }
86
100
 
87
- // Get a plugin by name
88
101
  get(name: string): Plugin | undefined {
89
102
  return this.plugins.get(name)
90
103
  }
91
104
 
92
- // Get all plugins sorted by priority
105
+ has(name: string): boolean {
106
+ return this.plugins.has(name)
107
+ }
108
+
93
109
  getAll(): Plugin[] {
94
110
  return Array.from(this.plugins.values()).sort(this.sortByPriority)
95
111
  }
96
112
 
97
- // Check if plugin is enabled
113
+ getByCategory(category: PluginCategory): Plugin[] {
114
+ return this.getAll().filter((plugin) => plugin.metadata.category === category)
115
+ }
116
+
117
+ getActive(): Plugin[] {
118
+ return Array.from(this.enabledPlugins)
119
+ .map((name) => this.plugins.get(name))
120
+ .filter((plugin): plugin is Plugin => Boolean(plugin))
121
+ .sort(this.sortByPriority)
122
+ }
123
+
98
124
  isEnabled(name: string): boolean {
99
125
  return this.enabledPlugins.has(name)
100
126
  }
101
127
 
102
- // Enable a plugin
103
- async enable(name: string): Promise<void> {
128
+ async initialize(name: string, context: PluginContext, config: PluginConfig = {}): Promise<void> {
104
129
  const plugin = this.plugins.get(name)
105
130
  if (!plugin) {
106
- throw new PluginError(name, "activate", "Plugin not found")
131
+ throw new PluginError(name, "initialize", "Plugin not found")
107
132
  }
108
133
 
109
- if (this.enabledPlugins.has(name)) {
110
- this.logger.warn(`Plugin '${name}' is already enabled`)
111
- return
112
- }
134
+ this.ensureDependenciesExist(name)
135
+
136
+ const mergedConfig = { ...(this.pluginConfigs.get(name) || {}), ...config }
137
+ this.pluginConfigs.set(name, mergedConfig)
138
+ this.pluginContexts.set(name, context)
113
139
 
114
140
  try {
115
- const context = this.createPluginContext(name)
116
- const config = this.pluginConfigs.get(name)
141
+ await plugin.initialize(context, mergedConfig)
142
+ } catch (error) {
143
+ this.logger.error(`Failed to initialize plugin '${name}'`, error)
144
+ ;(this.eventBus as any).emit("plugin:error", { name, error: error as Error })
145
+ throw error
146
+ }
147
+ }
117
148
 
118
- // Initialize plugin
119
- await plugin.initialize(context, config)
149
+ async activate(name: string, context: PluginContext): Promise<void> {
150
+ const plugin = this.plugins.get(name)
151
+ if (!plugin) {
152
+ throw new PluginError(name, "activate", "Plugin not found")
153
+ }
120
154
 
121
- // Activate plugin
122
- await plugin.activate(context)
155
+ this.ensureDependenciesActive(name)
156
+ this.ensureNoActiveConflicts(name)
157
+ this.pluginContexts.set(name, context)
123
158
 
159
+ try {
160
+ await plugin.activate(context)
124
161
  this.enabledPlugins.add(name)
125
- this.logger.info(`Plugin '${name}' enabled successfully`)
126
162
  ;(this.eventBus as any).emit("plugin:enabled", { name, plugin })
127
163
  } catch (error) {
128
- this.logger.error(`Failed to enable plugin '${name}'`, error)
164
+ this.logger.error(`Failed to activate plugin '${name}'`, error)
129
165
  ;(this.eventBus as any).emit("plugin:error", { name, error: error as Error })
130
166
  throw error
131
167
  }
132
168
  }
133
169
 
134
- // Disable a plugin
135
- async disable(name: string): Promise<void> {
170
+ async deactivate(name: string, context: PluginContext): Promise<void> {
136
171
  const plugin = this.plugins.get(name)
137
172
  if (!plugin) {
138
173
  throw new PluginError(name, "deactivate", "Plugin not found")
139
174
  }
140
175
 
141
- if (!this.enabledPlugins.has(name)) {
142
- this.logger.warn(`Plugin '${name}' is already disabled`)
143
- return
144
- }
176
+ this.pluginContexts.set(name, context)
145
177
 
146
178
  try {
147
- const context = this.createPluginContext(name)
148
-
149
- // Deactivate plugin
150
179
  await plugin.deactivate(context)
151
-
152
- // Destroy plugin resources
153
- await plugin.destroy(context)
154
-
155
180
  this.enabledPlugins.delete(name)
156
- this.logger.info(`Plugin '${name}' disabled successfully`)
157
181
  ;(this.eventBus as any).emit("plugin:disabled", { name, plugin })
158
182
  } catch (error) {
159
- this.logger.error(`Failed to disable plugin '${name}'`, error)
183
+ this.logger.error(`Failed to deactivate plugin '${name}'`, error)
160
184
  ;(this.eventBus as any).emit("plugin:error", { name, error: error as Error })
161
185
  throw error
162
186
  }
163
187
  }
164
188
 
165
- // Configure a plugin
189
+ async initializeAll(context: PluginContext): Promise<void> {
190
+ this.validateDependencies()
191
+ const orderedNames = this.getAll().map((plugin) => this.findPluginKey(plugin)).filter(Boolean) as string[]
192
+
193
+ for (const name of orderedNames) {
194
+ await this.initialize(name, context)
195
+ }
196
+ }
197
+
198
+ async activateAll(context: PluginContext): Promise<void> {
199
+ const orderedNames = this.getAll().map((plugin) => this.findPluginKey(plugin)).filter(Boolean) as string[]
200
+
201
+ for (const name of orderedNames) {
202
+ const plugin = this.plugins.get(name)
203
+ if (!plugin) continue
204
+ if (!plugin.isInitialized) {
205
+ await this.initialize(name, context)
206
+ }
207
+ await this.activate(name, context)
208
+ }
209
+ }
210
+
211
+ async deactivateAll(context: PluginContext): Promise<void> {
212
+ const orderedNames = this.getAll()
213
+ .map((plugin) => this.findPluginKey(plugin))
214
+ .filter(Boolean)
215
+ .reverse() as string[]
216
+
217
+ for (const name of orderedNames) {
218
+ if (this.enabledPlugins.has(name)) {
219
+ await this.deactivate(name, context)
220
+ }
221
+ }
222
+ }
223
+
224
+ async destroyAll(context: PluginContext): Promise<void> {
225
+ await this.deactivateAll(context)
226
+
227
+ const names = Array.from(this.plugins.keys())
228
+ for (const name of names) {
229
+ const plugin = this.plugins.get(name)
230
+ if (!plugin) continue
231
+ if (plugin.isInitialized) {
232
+ await plugin.destroy(context)
233
+ }
234
+ }
235
+
236
+ this.plugins.clear()
237
+ this.pluginConfigs.clear()
238
+ this.pluginContexts.clear()
239
+ this.enabledPlugins.clear()
240
+ }
241
+
242
+ validateDependencies(): void {
243
+ for (const [name, plugin] of this.plugins.entries()) {
244
+ const missingDependencies = (plugin.metadata.dependencies || []).filter(
245
+ (dep) => !this.plugins.has(dep)
246
+ )
247
+ if (missingDependencies.length > 0) {
248
+ throw new PluginDependencyError(name, missingDependencies)
249
+ }
250
+ }
251
+
252
+ const visited = new Set<string>()
253
+ const visiting = new Set<string>()
254
+
255
+ const visit = (name: string) => {
256
+ if (visited.has(name)) return
257
+ if (visiting.has(name)) {
258
+ throw new PluginError(name, "initialize", "Circular dependency detected")
259
+ }
260
+
261
+ visiting.add(name)
262
+ const plugin = this.plugins.get(name)
263
+ if (!plugin) return
264
+
265
+ for (const dep of plugin.metadata.dependencies || []) {
266
+ visit(dep)
267
+ }
268
+
269
+ visiting.delete(name)
270
+ visited.add(name)
271
+ }
272
+
273
+ for (const name of this.plugins.keys()) {
274
+ visit(name)
275
+ }
276
+ }
277
+
278
+ validateConflicts(): void {
279
+ for (const [name, plugin] of this.plugins.entries()) {
280
+ const activeConflicts = (plugin.metadata.conflicts || []).filter((conflict) =>
281
+ this.plugins.has(conflict)
282
+ )
283
+ if (activeConflicts.length > 0) {
284
+ throw new PluginConflictError(name, activeConflicts)
285
+ }
286
+ }
287
+ }
288
+
289
+ healthCheck(name: string): boolean
290
+ healthCheck(): Promise<{ name: string; healthy: boolean; error?: Error }[]>
291
+ healthCheck(name?: string): boolean | Promise<{ name: string; healthy: boolean; error?: Error }[]> {
292
+ if (typeof name === "string") {
293
+ const plugin = this.plugins.get(name)
294
+ if (!plugin) return false
295
+ try {
296
+ const testInitFlag = (plugin as { onInitializeCalled?: boolean }).onInitializeCalled
297
+ if (typeof testInitFlag === "boolean") {
298
+ return testInitFlag
299
+ }
300
+ if (plugin.healthCheck) {
301
+ return Boolean(plugin.healthCheck())
302
+ }
303
+ if (typeof plugin.isInitialized === "boolean") {
304
+ return plugin.isInitialized
305
+ }
306
+ return false
307
+ } catch {
308
+ return false
309
+ }
310
+ }
311
+
312
+ return this.healthCheckEnabledPlugins()
313
+ }
314
+
315
+ healthCheckAll(): Record<string, boolean> {
316
+ const status: Record<string, boolean> = {}
317
+ for (const pluginName of this.plugins.keys()) {
318
+ status[pluginName] = this.healthCheck(pluginName)
319
+ }
320
+ return status
321
+ }
322
+
323
+ async enable(name: string): Promise<void> {
324
+ const plugin = this.plugins.get(name)
325
+ if (!plugin) {
326
+ throw new PluginError(name, "activate", "Plugin not found")
327
+ }
328
+
329
+ if (this.enabledPlugins.has(name)) {
330
+ this.logger.warn(`Plugin '${name}' is already enabled`)
331
+ return
332
+ }
333
+
334
+ const context = this.pluginContexts.get(name) || this.createPluginContext(name)
335
+ if (!plugin.isInitialized) {
336
+ await this.initialize(name, context)
337
+ }
338
+ await this.activate(name, context)
339
+ }
340
+
341
+ async disable(name: string): Promise<void> {
342
+ const plugin = this.plugins.get(name)
343
+ if (!plugin) {
344
+ throw new PluginError(name, "deactivate", "Plugin not found")
345
+ }
346
+
347
+ if (!this.enabledPlugins.has(name)) {
348
+ this.logger.warn(`Plugin '${name}' is already disabled`)
349
+ return
350
+ }
351
+
352
+ const context = this.pluginContexts.get(name) || this.createPluginContext(name)
353
+ await this.deactivate(name, context)
354
+ await plugin.destroy(context)
355
+ }
356
+
166
357
  async configure(name: string, config: PluginConfig): Promise<void> {
167
358
  const plugin = this.plugins.get(name)
168
359
  if (!plugin) {
@@ -170,14 +361,10 @@ export class PluginRegistry implements IPluginRegistry {
170
361
  }
171
362
 
172
363
  try {
173
- // Update stored configuration
174
364
  this.pluginConfigs.set(name, { ...this.pluginConfigs.get(name), ...config })
175
-
176
- // If plugin has configure method, call it
177
365
  if (plugin.configure) {
178
366
  await plugin.configure(config)
179
367
  }
180
-
181
368
  this.logger.info(`Plugin '${name}' configured successfully`)
182
369
  ;(this.eventBus as any).emit("plugin:configured", { name, config })
183
370
  } catch (error) {
@@ -187,7 +374,6 @@ export class PluginRegistry implements IPluginRegistry {
187
374
  }
188
375
  }
189
376
 
190
- // Enable multiple plugins with dependency resolution
191
377
  async enablePlugins(names: string[]): Promise<void> {
192
378
  const resolved = this.resolveDependencies(names)
193
379
 
@@ -198,9 +384,7 @@ export class PluginRegistry implements IPluginRegistry {
198
384
  }
199
385
  }
200
386
 
201
- // Disable multiple plugins
202
387
  async disablePlugins(names: string[]): Promise<void> {
203
- // Disable in reverse order to handle dependencies
204
388
  const reversed = [...names].reverse()
205
389
 
206
390
  for (const name of reversed) {
@@ -210,22 +394,31 @@ export class PluginRegistry implements IPluginRegistry {
210
394
  }
211
395
  }
212
396
 
213
- // Get enabled plugins
214
397
  getEnabledPlugins(): Plugin[] {
215
- return Array.from(this.enabledPlugins)
216
- .map((name) => this.plugins.get(name)!)
217
- .filter(Boolean)
218
- .sort(this.sortByPriority)
398
+ return this.getActive()
219
399
  }
220
400
 
221
- // Health check for all enabled plugins
222
- async healthCheck(): Promise<{ name: string; healthy: boolean; error?: Error }[]> {
401
+ on<K extends keyof PluginEvents>(
402
+ event: K,
403
+ listener: (data: PluginEvents[K]) => void
404
+ ): () => void {
405
+ ;(this.eventBus as any).on(event, listener)
406
+ return () => (this.eventBus as any).off(event, listener)
407
+ }
408
+
409
+ private async healthCheckEnabledPlugins(): Promise<
410
+ { name: string; healthy: boolean; error?: Error }[]
411
+ > {
223
412
  const results = []
224
413
 
225
414
  for (const name of this.enabledPlugins) {
226
- const plugin = this.plugins.get(name)!
415
+ const plugin = this.plugins.get(name)
416
+ if (!plugin) continue
417
+
227
418
  try {
228
- const healthy = plugin.healthCheck ? await plugin.healthCheck() : true
419
+ const healthResult = plugin.healthCheck ? plugin.healthCheck() : true
420
+ const healthy =
421
+ healthResult instanceof Promise ? await healthResult : Boolean(healthResult)
229
422
  results.push({ name, healthy })
230
423
  } catch (error) {
231
424
  results.push({ name, healthy: false, error: error as Error })
@@ -235,19 +428,53 @@ export class PluginRegistry implements IPluginRegistry {
235
428
  return results
236
429
  }
237
430
 
238
- // Event handling
239
- on<K extends keyof PluginEvents>(
240
- event: K,
241
- listener: (data: PluginEvents[K]) => void
242
- ): () => void {
243
- ;(this.eventBus as any).on(event, listener)
244
- return () => (this.eventBus as any).off(event, listener)
431
+ private findPluginKey(target: Plugin): string | undefined {
432
+ for (const [name, plugin] of this.plugins.entries()) {
433
+ if (plugin === target) return name
434
+ }
435
+ return undefined
436
+ }
437
+
438
+ private ensureDependenciesExist(name: string): void {
439
+ const plugin = this.plugins.get(name)
440
+ if (!plugin) return
441
+
442
+ const missingDependencies = (plugin.metadata.dependencies || []).filter(
443
+ (dep) => !this.plugins.has(dep)
444
+ )
445
+
446
+ if (missingDependencies.length > 0) {
447
+ throw new PluginDependencyError(name, missingDependencies)
448
+ }
449
+ }
450
+
451
+ private ensureDependenciesActive(name: string): void {
452
+ const plugin = this.plugins.get(name)
453
+ if (!plugin) return
454
+
455
+ const inactiveDependencies = (plugin.metadata.dependencies || []).filter(
456
+ (dep) => !this.enabledPlugins.has(dep)
457
+ )
458
+
459
+ if (inactiveDependencies.length > 0) {
460
+ throw new PluginDependencyError(name, inactiveDependencies)
461
+ }
462
+ }
463
+
464
+ private ensureNoActiveConflicts(name: string): void {
465
+ const plugin = this.plugins.get(name)
466
+ if (!plugin) return
467
+
468
+ const activeConflicts = (plugin.metadata.conflicts || []).filter((conflict) =>
469
+ this.enabledPlugins.has(conflict)
470
+ )
471
+
472
+ if (activeConflicts.length > 0) {
473
+ throw new PluginConflictError(name, activeConflicts)
474
+ }
245
475
  }
246
476
 
247
- // Create plugin context (will be implemented when we have the full context)
248
477
  private createPluginContext(pluginName: string): PluginContext {
249
- // This will be implemented when we integrate with the media player
250
- // For now, return a minimal context
251
478
  return {
252
479
  state: {} as any,
253
480
  controls: {} as any,
@@ -262,7 +489,6 @@ export class PluginRegistry implements IPluginRegistry {
262
489
  }
263
490
  }
264
491
 
265
- // Create plugin-specific logger
266
492
  private createPluginLogger(pluginName: string): PluginLogger {
267
493
  return {
268
494
  info: (message: string, data?: any) => this.logger.info(`[${pluginName}] ${message}`, data),
@@ -272,7 +498,6 @@ export class PluginRegistry implements IPluginRegistry {
272
498
  }
273
499
  }
274
500
 
275
- // Resolve plugin dependencies
276
501
  private resolveDependencies(names: string[]): string[] {
277
502
  const resolved: string[] = []
278
503
  const visiting = new Set<string>()
@@ -290,7 +515,6 @@ export class PluginRegistry implements IPluginRegistry {
290
515
  throw new PluginError(name, "initialize", "Plugin not found")
291
516
  }
292
517
 
293
- // Visit dependencies first
294
518
  for (const dep of plugin.metadata.dependencies || []) {
295
519
  visit(dep)
296
520
  }
@@ -306,14 +530,17 @@ export class PluginRegistry implements IPluginRegistry {
306
530
  return resolved
307
531
  }
308
532
 
309
- // Sort plugins by priority
310
533
  private sortByPriority(a: Plugin, b: Plugin): number {
311
534
  const priorityOrder: Record<PluginPriority, number> = {
312
535
  high: 3,
313
536
  medium: 2,
537
+ normal: 2,
314
538
  low: 1
315
539
  }
316
540
 
317
- return priorityOrder[b.metadata.priority] - priorityOrder[a.metadata.priority]
541
+ const aPriority = priorityOrder[a.metadata.priority] || 1
542
+ const bPriority = priorityOrder[b.metadata.priority] || 1
543
+
544
+ return bPriority - aPriority
318
545
  }
319
546
  }
@@ -29,7 +29,7 @@ export type PluginCategory =
29
29
  | "performance"
30
30
 
31
31
  // Plugin priority for execution order
32
- export type PluginPriority = "high" | "medium" | "low"
32
+ export type PluginPriority = "high" | "medium" | "normal" | "low"
33
33
 
34
34
  // Plugin configuration interface
35
35
  export interface PluginConfig {
@@ -69,6 +69,8 @@ export interface PluginMetadata {
69
69
  // Plugin interface that all plugins must implement
70
70
  export interface Plugin {
71
71
  metadata: PluginMetadata
72
+ isInitialized?: boolean
73
+ isActive?: boolean
72
74
 
73
75
  // Plugin lifecycle methods
74
76
  initialize(context: PluginContext, config?: PluginConfig): Promise<void> | void
@@ -88,11 +90,27 @@ export type PluginFactory<T extends Plugin = Plugin> = (config?: PluginConfig) =
88
90
 
89
91
  // Plugin registry interface
90
92
  export interface PluginRegistry {
91
- register(factory: PluginFactory, config?: PluginConfig): Promise<void>
92
- unregister(name: string): Promise<void>
93
+ register(name: string, plugin: Plugin, config?: PluginConfig): void
94
+ register(factory: PluginFactory, config?: PluginConfig): void
95
+ unregister(name: string, context?: PluginContext): Promise<void>
93
96
  get(name: string): Plugin | undefined
97
+ has(name: string): boolean
94
98
  getAll(): Plugin[]
99
+ getByCategory(category: PluginCategory): Plugin[]
100
+ getActive(): Plugin[]
95
101
  isEnabled(name: string): boolean
102
+ initialize(name: string, context: PluginContext, config?: PluginConfig): Promise<void>
103
+ activate(name: string, context: PluginContext): Promise<void>
104
+ deactivate(name: string, context: PluginContext): Promise<void>
105
+ initializeAll(context: PluginContext): Promise<void>
106
+ activateAll(context: PluginContext): Promise<void>
107
+ deactivateAll(context: PluginContext): Promise<void>
108
+ destroyAll(context: PluginContext): Promise<void>
109
+ validateDependencies(): void
110
+ validateConflicts(): void
111
+ healthCheck(name: string): boolean
112
+ healthCheck(): Promise<{ name: string; healthy: boolean; error?: Error }[]>
113
+ healthCheckAll(): Record<string, boolean>
96
114
  enable(name: string): Promise<void>
97
115
  disable(name: string): Promise<void>
98
116
  configure(name: string, config: PluginConfig): Promise<void>