@lumra/core 0.1.1 → 0.1.3

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/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @lumra/core
2
+
3
+ Headless media player engine for Lumra. Wraps the native `<video>` element with HLS adaptive streaming, a plugin system, quality switching, and a typed event emitter.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @lumra/core
9
+ ```
10
+
11
+ ## Basic usage
12
+
13
+ ```ts
14
+ import { createPlayer } from '@lumra/core'
15
+
16
+ const player = createPlayer({
17
+ target: '#my-video', // CSS selector or HTMLVideoElement
18
+ src: 'https://example.com/stream.m3u8',
19
+ autoplay: false,
20
+ muted: false,
21
+ })
22
+
23
+ player.on('play', () => console.log('playing'))
24
+ player.on('pause', () => console.log('paused'))
25
+ player.on('timeupdate', ({ currentTime, duration }) => console.log(currentTime, duration))
26
+ player.on('ended', () => console.log('ended'))
27
+ player.on('error', ({ code, message }) => console.error(code, message))
28
+
29
+ // Playback control
30
+ await player.play()
31
+ player.pause()
32
+ player.seek(30) // seek to 30 seconds
33
+ player.setVolume(0.8) // 0–1
34
+ player.mute()
35
+ player.unmute()
36
+
37
+ // Source switching
38
+ player.setSrc('https://example.com/other.m3u8')
39
+
40
+ // Cleanup
41
+ player.destroy()
42
+ ```
43
+
44
+ ## HLS & adaptive streaming
45
+
46
+ HLS streams (`.m3u8`) are detected automatically and loaded via hls.js. Safari uses native HLS.
47
+
48
+ ```ts
49
+ const player = createPlayer({
50
+ target: '#video',
51
+ src: 'https://example.com/stream.m3u8',
52
+ hlsConfig: { maxBufferLength: 30 }, // pass any hls.js config here
53
+ })
54
+ ```
55
+
56
+ ## Quality switching
57
+
58
+ ```ts
59
+ // Get available quality levels (populated after the HLS manifest loads)
60
+ const levels = player.getQualityLevels()
61
+ // [{ index: -1, label: 'Auto' }, { index: 0, label: '1080p', bitrate: 5000000 }, ...]
62
+
63
+ // Set quality — index -1 = ABR auto
64
+ player.setQuality(0) // lock to first level
65
+ player.setQuality(-1) // back to auto
66
+
67
+ player.on('qualitychange', ({ level, auto }) => console.log(level, auto))
68
+ player.on('levelchange', ({ level }) => console.log(level))
69
+
70
+ // Live stream detection
71
+ console.log(player.isLive) // true for live HLS
72
+ console.log(player.isHls) // true when hls.js is active
73
+ ```
74
+
75
+ ## Plugin system
76
+
77
+ ```ts
78
+ import { createPlayer } from '@lumra/core'
79
+ import type { Plugin, PlayerInstance } from '@lumra/core'
80
+
81
+ const myPlugin: Plugin = {
82
+ name: 'my-plugin',
83
+ init(player: PlayerInstance) {
84
+ player.on('play', () => console.log('plugin saw play'))
85
+ },
86
+ destroy() {
87
+ // cleanup — called when player.destroy() is called
88
+ },
89
+ }
90
+
91
+ player.use(myPlugin)
92
+ ```
93
+
94
+ ## Events reference
95
+
96
+ | Event | Payload |
97
+ |---|---|
98
+ | `play` | — |
99
+ | `pause` | — |
100
+ | `ended` | — |
101
+ | `timeupdate` | `{ currentTime, duration }` |
102
+ | `volumechange` | `{ volume, muted }` |
103
+ | `seeking` | `{ time }` |
104
+ | `seeked` | `{ time }` |
105
+ | `buffering` | — |
106
+ | `ready` | — |
107
+ | `error` | `{ code, message }` |
108
+ | `qualitychange` | `{ level, auto }` |
109
+ | `levelchange` | `{ level }` |
110
+ | `destroy` | — |
111
+
112
+ ---
113
+
114
+ © 2026 Reel Foundry AU. All rights reserved.
115
+ MIT License — see [LICENSE](../../LICENSE)
package/dist/index.cjs CHANGED
@@ -150,6 +150,7 @@ var Player = class extends EventEmitter {
150
150
  { index: -1, height: 0, bitrate: 0, label: "Auto" },
151
151
  ...levels
152
152
  ];
153
+ this.emit("manifest", void 0);
153
154
  });
154
155
  hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {
155
156
  this.emit("levelchange", { level: data.level });
@@ -164,6 +165,7 @@ var Player = class extends EventEmitter {
164
165
  }
165
166
  if (this.video.canPlayType("application/vnd.apple.mpegurl")) {
166
167
  this.video.src = src;
168
+ void Promise.resolve().then(() => this.emit("manifest", void 0));
167
169
  return;
168
170
  }
169
171
  this.emit("error", { code: -1, message: "HLS is not supported in this browser" });
@@ -171,6 +173,7 @@ var Player = class extends EventEmitter {
171
173
  }
172
174
  this.destroyHls();
173
175
  this.video.src = src;
176
+ void Promise.resolve().then(() => this.emit("manifest", void 0));
174
177
  }
175
178
  destroyHls() {
176
179
  if (this.hls) {
@@ -258,6 +261,9 @@ var Player = class extends EventEmitter {
258
261
  get hlsInstance() {
259
262
  return this.hls;
260
263
  }
264
+ get element() {
265
+ return this.video;
266
+ }
261
267
  };
262
268
 
263
269
  // src/index.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
1
+ {"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n // Signal that the source is ready for play() — fires before segment\n // buffering so callers can call play() within the user-gesture window.\n this.emit('manifest', undefined as void)\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n get element(): HTMLVideoElement { return this.video }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
package/dist/index.d.cts CHANGED
@@ -18,6 +18,7 @@ type PlayerEventMap = {
18
18
  };
19
19
  buffering: void;
20
20
  ready: void;
21
+ manifest: void;
21
22
  error: {
22
23
  code: number;
23
24
  message: string;
@@ -81,6 +82,8 @@ interface PlayerInstance {
81
82
  readonly isLive: boolean;
82
83
  readonly isHls: boolean;
83
84
  readonly hlsInstance: unknown | null;
85
+ /** The underlying HTMLVideoElement — available to plugins that need direct DOM access (e.g. WebGL overlays) */
86
+ readonly element: HTMLVideoElement;
84
87
  }
85
88
 
86
89
  declare class EventEmitter {
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ type PlayerEventMap = {
18
18
  };
19
19
  buffering: void;
20
20
  ready: void;
21
+ manifest: void;
21
22
  error: {
22
23
  code: number;
23
24
  message: string;
@@ -81,6 +82,8 @@ interface PlayerInstance {
81
82
  readonly isLive: boolean;
82
83
  readonly isHls: boolean;
83
84
  readonly hlsInstance: unknown | null;
85
+ /** The underlying HTMLVideoElement — available to plugins that need direct DOM access (e.g. WebGL overlays) */
86
+ readonly element: HTMLVideoElement;
84
87
  }
85
88
 
86
89
  declare class EventEmitter {
package/dist/index.js CHANGED
@@ -148,6 +148,7 @@ var Player = class extends EventEmitter {
148
148
  { index: -1, height: 0, bitrate: 0, label: "Auto" },
149
149
  ...levels
150
150
  ];
151
+ this.emit("manifest", void 0);
151
152
  });
152
153
  hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {
153
154
  this.emit("levelchange", { level: data.level });
@@ -162,6 +163,7 @@ var Player = class extends EventEmitter {
162
163
  }
163
164
  if (this.video.canPlayType("application/vnd.apple.mpegurl")) {
164
165
  this.video.src = src;
166
+ void Promise.resolve().then(() => this.emit("manifest", void 0));
165
167
  return;
166
168
  }
167
169
  this.emit("error", { code: -1, message: "HLS is not supported in this browser" });
@@ -169,6 +171,7 @@ var Player = class extends EventEmitter {
169
171
  }
170
172
  this.destroyHls();
171
173
  this.video.src = src;
174
+ void Promise.resolve().then(() => this.emit("manifest", void 0));
172
175
  }
173
176
  destroyHls() {
174
177
  if (this.hls) {
@@ -256,6 +259,9 @@ var Player = class extends EventEmitter {
256
259
  get hlsInstance() {
257
260
  return this.hls;
258
261
  }
262
+ get element() {
263
+ return this.video;
264
+ }
259
265
  };
260
266
 
261
267
  // src/index.ts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
1
+ {"version":3,"sources":["../src/events.ts","../src/hls.ts","../src/player.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PlayerEvent, PlayerEventListener, PlayerEventMap } from './types'\n\ntype ListenerMap = {\n [E in PlayerEvent]?: Set<PlayerEventListener<E>>\n}\n\nexport class EventEmitter {\n private listeners: ListenerMap = {}\n\n on<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n if (!this.listeners[event]) {\n this.listeners[event] = new Set() as ListenerMap[E]\n }\n ;(this.listeners[event] as Set<PlayerEventListener<E>>).add(listener)\n }\n\n off<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n (this.listeners[event] as Set<PlayerEventListener<E>> | undefined)?.delete(listener)\n }\n\n once<E extends PlayerEvent>(event: E, listener: PlayerEventListener<E>): void {\n const wrapper: PlayerEventListener<E> = (data) => {\n listener(data)\n this.off(event, wrapper)\n }\n this.on(event, wrapper)\n }\n\n emit<E extends PlayerEvent>(event: E, data: PlayerEventMap[E]): void {\n const set = this.listeners[event] as Set<PlayerEventListener<E>> | undefined\n if (!set) return\n for (const listener of set) {\n try {\n listener(data)\n } catch (err) {\n console.error(`[lumra] Error in \"${event}\" listener:`, err)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners = {}\n }\n}\n","import type Hls from 'hls.js'\n\nlet HlsModule: typeof Hls | null = null\n\nexport async function loadHls(): Promise<typeof Hls | null> {\n if (HlsModule) return HlsModule\n try {\n const mod = await import('hls.js')\n HlsModule = mod.default\n return HlsModule\n } catch {\n return null\n }\n}\n\nexport function isHlsSupported(): boolean {\n try {\n // Synchronous check using the cached module\n return HlsModule ? HlsModule.isSupported() : false\n } catch {\n return false\n }\n}\n\nexport function isHlsSource(src: string): boolean {\n return src.includes('.m3u8') || src.includes('application/x-mpegURL')\n}\n","import type Hls from 'hls.js'\nimport { EventEmitter } from './events'\nimport { isHlsSource, loadHls } from './hls'\nimport type { Plugin, PlayerInstance, PlayerOptions, QualityLevel } from './types'\n\nfunction levelLabel(height: number): string {\n if (height >= 2160) return '4K'\n if (height >= 1080) return '1080p'\n if (height >= 720) return '720p'\n if (height >= 480) return '480p'\n if (height >= 360) return '360p'\n return `${height}p`\n}\n\nexport class Player extends EventEmitter implements PlayerInstance {\n private video: HTMLVideoElement\n private hls: Hls | null = null\n private plugins: Map<string, Plugin> = new Map()\n private _src = ''\n private _destroyed = false\n private _isLive = false\n private _qualityAuto = true\n private _hlsLevels: QualityLevel[] = []\n\n constructor(private readonly options: PlayerOptions) {\n super()\n this.video = this.resolveTarget(options.target)\n this.applyOptions()\n this.bindNativeEvents()\n if (options.src) {\n void this.setSrcAsync(options.src)\n }\n }\n\n private resolveTarget(target: string | HTMLVideoElement): HTMLVideoElement {\n if (target instanceof HTMLVideoElement) return target\n const el = document.querySelector(target)\n if (!(el instanceof HTMLVideoElement)) {\n throw new Error(`[lumra] Target \"${target}\" is not a <video> element`)\n }\n return el\n }\n\n private applyOptions(): void {\n const { muted = false, volume = 1, loop = false, autoplay = false } = this.options\n this.video.muted = muted\n this.video.volume = volume\n this.video.loop = loop\n this.video.autoplay = autoplay\n }\n\n private bindNativeEvents(): void {\n this.video.addEventListener('play', () => this.emit('play', undefined as void))\n this.video.addEventListener('pause', () => this.emit('pause', undefined as void))\n this.video.addEventListener('ended', () => this.emit('ended', undefined as void))\n this.video.addEventListener('waiting', () => this.emit('buffering', undefined as void))\n this.video.addEventListener('canplay', () => this.emit('ready', undefined as void))\n this.video.addEventListener('volumechange', () =>\n this.emit('volumechange', { volume: this.video.volume, muted: this.video.muted })\n )\n this.video.addEventListener('timeupdate', () =>\n this.emit('timeupdate', {\n currentTime: this.video.currentTime,\n duration: this.video.duration || 0,\n })\n )\n this.video.addEventListener('seeking', () =>\n this.emit('seeking', { time: this.video.currentTime })\n )\n this.video.addEventListener('seeked', () =>\n this.emit('seeked', { time: this.video.currentTime })\n )\n this.video.addEventListener('error', () => {\n const err = this.video.error\n this.emit('error', {\n code: err?.code ?? -1,\n message: err?.message ?? 'Unknown media error',\n })\n })\n }\n\n private async setSrcAsync(src: string): Promise<void> {\n this._src = src\n\n if (isHlsSource(src)) {\n const Hls = await loadHls()\n if (Hls && Hls.isSupported()) {\n this.destroyHls()\n const hls = new Hls(this.options.hlsConfig ?? {})\n this.hls = hls\n hls.loadSource(src)\n hls.attachMedia(this.video)\n\n hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n this._isLive = (data as { live?: boolean }).live === true\n const levels: QualityLevel[] = hls.levels.map((l, i) => ({\n index: i,\n height: l.height,\n bitrate: l.bitrate,\n label: levelLabel(l.height),\n }))\n this._hlsLevels = [\n { index: -1, height: 0, bitrate: 0, label: 'Auto' },\n ...levels,\n ]\n // Signal that the source is ready for play() — fires before segment\n // buffering so callers can call play() within the user-gesture window.\n this.emit('manifest', undefined as void)\n })\n\n hls.on(Hls.Events.LEVEL_SWITCHED, (_event, data) => {\n this.emit('levelchange', { level: data.level })\n this.emit('qualitychange', { level: data.level, auto: this._qualityAuto })\n })\n\n hls.on(Hls.Events.ERROR, (_event, data) => {\n if (data.fatal) {\n this.emit('error', { code: -2, message: data.details ?? 'HLS fatal error' })\n }\n })\n\n return\n }\n // Fallback: native HLS (Safari)\n if (this.video.canPlayType('application/vnd.apple.mpegurl')) {\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n return\n }\n this.emit('error', { code: -1, message: 'HLS is not supported in this browser' })\n return\n }\n\n this.destroyHls()\n this.video.src = src\n void Promise.resolve().then(() => this.emit('manifest', undefined as void))\n }\n\n private destroyHls(): void {\n if (this.hls) {\n this.hls.destroy()\n this.hls = null\n }\n }\n\n async play(): Promise<void> {\n await this.video.play()\n }\n\n pause(): void {\n this.video.pause()\n }\n\n seek(time: number): void {\n this.video.currentTime = time\n }\n\n setVolume(volume: number): void {\n this.video.volume = Math.max(0, Math.min(1, volume))\n }\n\n mute(): void {\n this.video.muted = true\n }\n\n unmute(): void {\n this.video.muted = false\n }\n\n setSrc(src: string): void {\n void this.setSrcAsync(src)\n }\n\n use(plugin: Plugin): void {\n if (this.plugins.has(plugin.name)) {\n console.warn(`[lumra] Plugin \"${plugin.name}\" is already registered`)\n return\n }\n plugin.init(this)\n this.plugins.set(plugin.name, plugin)\n this.emit('plugin:register', { name: plugin.name })\n }\n\n destroy(): void {\n if (this._destroyed) return\n this._destroyed = true\n for (const plugin of this.plugins.values()) {\n plugin.destroy()\n }\n this.plugins.clear()\n this.destroyHls()\n this.video.pause()\n this.video.removeAttribute('src')\n this.video.load()\n this.emit('destroy', undefined as void)\n this.removeAllListeners()\n }\n\n getQualityLevels(): QualityLevel[] {\n return this._hlsLevels\n }\n\n setQuality(levelIndex: number): void {\n if (!this.hls) return\n this._qualityAuto = levelIndex === -1\n this.hls.currentLevel = levelIndex\n this.emit('qualitychange', { level: levelIndex, auto: this._qualityAuto })\n }\n\n get currentTime(): number { return this.video.currentTime }\n get duration(): number { return this.video.duration || 0 }\n get paused(): boolean { return this.video.paused }\n get volume(): number { return this.video.volume }\n get muted(): boolean { return this.video.muted }\n get src(): string { return this._src }\n get isLive(): boolean { return this._isLive }\n get isHls(): boolean { return this.hls !== null }\n get hlsInstance(): unknown | null { return this.hls }\n get element(): HTMLVideoElement { return this.video }\n}\n","import { Player } from './player'\nimport type { PlayerOptions, PlayerInstance } from './types'\n\nexport function createPlayer(options: PlayerOptions): PlayerInstance {\n return new Player(options)\n}\n\nexport type { PlayerOptions, PlayerInstance, Plugin, PlayerEvent, PlayerEventMap, PlayerEventListener, QualityLevel } from './types'\nexport { EventEmitter } from './events'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumra/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },