@livepeer-frameworks/player-core 0.0.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.
Files changed (120) hide show
  1. package/dist/cjs/index.js +19493 -0
  2. package/dist/cjs/index.js.map +1 -0
  3. package/dist/esm/index.js +19398 -0
  4. package/dist/esm/index.js.map +1 -0
  5. package/dist/player.css +2140 -0
  6. package/dist/types/core/ABRController.d.ts +164 -0
  7. package/dist/types/core/CodecUtils.d.ts +54 -0
  8. package/dist/types/core/Disposable.d.ts +61 -0
  9. package/dist/types/core/EventEmitter.d.ts +73 -0
  10. package/dist/types/core/GatewayClient.d.ts +144 -0
  11. package/dist/types/core/InteractionController.d.ts +121 -0
  12. package/dist/types/core/LiveDurationProxy.d.ts +102 -0
  13. package/dist/types/core/MetaTrackManager.d.ts +220 -0
  14. package/dist/types/core/MistReporter.d.ts +163 -0
  15. package/dist/types/core/MistSignaling.d.ts +148 -0
  16. package/dist/types/core/PlayerController.d.ts +665 -0
  17. package/dist/types/core/PlayerInterface.d.ts +230 -0
  18. package/dist/types/core/PlayerManager.d.ts +182 -0
  19. package/dist/types/core/PlayerRegistry.d.ts +27 -0
  20. package/dist/types/core/QualityMonitor.d.ts +184 -0
  21. package/dist/types/core/ScreenWakeLockManager.d.ts +70 -0
  22. package/dist/types/core/SeekingUtils.d.ts +142 -0
  23. package/dist/types/core/StreamStateClient.d.ts +108 -0
  24. package/dist/types/core/SubtitleManager.d.ts +111 -0
  25. package/dist/types/core/TelemetryReporter.d.ts +79 -0
  26. package/dist/types/core/TimeFormat.d.ts +97 -0
  27. package/dist/types/core/TimerManager.d.ts +83 -0
  28. package/dist/types/core/UrlUtils.d.ts +81 -0
  29. package/dist/types/core/detector.d.ts +149 -0
  30. package/dist/types/core/index.d.ts +49 -0
  31. package/dist/types/core/scorer.d.ts +167 -0
  32. package/dist/types/core/selector.d.ts +9 -0
  33. package/dist/types/index.d.ts +45 -0
  34. package/dist/types/lib/utils.d.ts +2 -0
  35. package/dist/types/players/DashJsPlayer.d.ts +102 -0
  36. package/dist/types/players/HlsJsPlayer.d.ts +70 -0
  37. package/dist/types/players/MewsWsPlayer/SourceBufferManager.d.ts +119 -0
  38. package/dist/types/players/MewsWsPlayer/WebSocketManager.d.ts +60 -0
  39. package/dist/types/players/MewsWsPlayer/index.d.ts +220 -0
  40. package/dist/types/players/MewsWsPlayer/types.d.ts +89 -0
  41. package/dist/types/players/MistPlayer.d.ts +25 -0
  42. package/dist/types/players/MistWebRTCPlayer/index.d.ts +133 -0
  43. package/dist/types/players/NativePlayer.d.ts +143 -0
  44. package/dist/types/players/VideoJsPlayer.d.ts +59 -0
  45. package/dist/types/players/WebCodecsPlayer/JitterBuffer.d.ts +118 -0
  46. package/dist/types/players/WebCodecsPlayer/LatencyProfiles.d.ts +64 -0
  47. package/dist/types/players/WebCodecsPlayer/RawChunkParser.d.ts +63 -0
  48. package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +174 -0
  49. package/dist/types/players/WebCodecsPlayer/WebSocketController.d.ts +164 -0
  50. package/dist/types/players/WebCodecsPlayer/index.d.ts +149 -0
  51. package/dist/types/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.d.ts +105 -0
  52. package/dist/types/players/WebCodecsPlayer/types.d.ts +395 -0
  53. package/dist/types/players/WebCodecsPlayer/worker/decoder.worker.d.ts +13 -0
  54. package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +197 -0
  55. package/dist/types/players/index.d.ts +14 -0
  56. package/dist/types/styles/index.d.ts +11 -0
  57. package/dist/types/types.d.ts +363 -0
  58. package/dist/types/vanilla/FrameWorksPlayer.d.ts +143 -0
  59. package/dist/types/vanilla/index.d.ts +19 -0
  60. package/dist/workers/decoder.worker.js +989 -0
  61. package/dist/workers/decoder.worker.js.map +1 -0
  62. package/package.json +80 -0
  63. package/src/core/ABRController.ts +550 -0
  64. package/src/core/CodecUtils.ts +257 -0
  65. package/src/core/Disposable.ts +120 -0
  66. package/src/core/EventEmitter.ts +113 -0
  67. package/src/core/GatewayClient.ts +439 -0
  68. package/src/core/InteractionController.ts +712 -0
  69. package/src/core/LiveDurationProxy.ts +270 -0
  70. package/src/core/MetaTrackManager.ts +753 -0
  71. package/src/core/MistReporter.ts +543 -0
  72. package/src/core/MistSignaling.ts +346 -0
  73. package/src/core/PlayerController.ts +2829 -0
  74. package/src/core/PlayerInterface.ts +432 -0
  75. package/src/core/PlayerManager.ts +900 -0
  76. package/src/core/PlayerRegistry.ts +149 -0
  77. package/src/core/QualityMonitor.ts +597 -0
  78. package/src/core/ScreenWakeLockManager.ts +163 -0
  79. package/src/core/SeekingUtils.ts +364 -0
  80. package/src/core/StreamStateClient.ts +457 -0
  81. package/src/core/SubtitleManager.ts +297 -0
  82. package/src/core/TelemetryReporter.ts +308 -0
  83. package/src/core/TimeFormat.ts +205 -0
  84. package/src/core/TimerManager.ts +209 -0
  85. package/src/core/UrlUtils.ts +179 -0
  86. package/src/core/detector.ts +382 -0
  87. package/src/core/index.ts +140 -0
  88. package/src/core/scorer.ts +553 -0
  89. package/src/core/selector.ts +16 -0
  90. package/src/global.d.ts +11 -0
  91. package/src/index.ts +75 -0
  92. package/src/lib/utils.ts +6 -0
  93. package/src/players/DashJsPlayer.ts +642 -0
  94. package/src/players/HlsJsPlayer.ts +483 -0
  95. package/src/players/MewsWsPlayer/SourceBufferManager.ts +572 -0
  96. package/src/players/MewsWsPlayer/WebSocketManager.ts +241 -0
  97. package/src/players/MewsWsPlayer/index.ts +1065 -0
  98. package/src/players/MewsWsPlayer/types.ts +106 -0
  99. package/src/players/MistPlayer.ts +188 -0
  100. package/src/players/MistWebRTCPlayer/index.ts +703 -0
  101. package/src/players/NativePlayer.ts +820 -0
  102. package/src/players/VideoJsPlayer.ts +643 -0
  103. package/src/players/WebCodecsPlayer/JitterBuffer.ts +299 -0
  104. package/src/players/WebCodecsPlayer/LatencyProfiles.ts +151 -0
  105. package/src/players/WebCodecsPlayer/RawChunkParser.ts +151 -0
  106. package/src/players/WebCodecsPlayer/SyncController.ts +456 -0
  107. package/src/players/WebCodecsPlayer/WebSocketController.ts +564 -0
  108. package/src/players/WebCodecsPlayer/index.ts +1650 -0
  109. package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +379 -0
  110. package/src/players/WebCodecsPlayer/types.ts +542 -0
  111. package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +1360 -0
  112. package/src/players/WebCodecsPlayer/worker/types.ts +276 -0
  113. package/src/players/index.ts +22 -0
  114. package/src/styles/animations.css +21 -0
  115. package/src/styles/index.ts +52 -0
  116. package/src/styles/player.css +2126 -0
  117. package/src/styles/tailwind.css +1015 -0
  118. package/src/types.ts +421 -0
  119. package/src/vanilla/FrameWorksPlayer.ts +367 -0
  120. package/src/vanilla/index.ts +22 -0
@@ -0,0 +1,164 @@
1
+ import type { ABRMode, ABROptions, PlaybackQuality, QualityLevel } from '../types';
2
+ export interface ABRControllerConfig {
3
+ /** ABR options */
4
+ options?: Partial<ABROptions>;
5
+ /** Callback to get available qualities */
6
+ getQualities: () => QualityLevel[];
7
+ /** Callback to select a quality */
8
+ selectQuality: (id: string | 'auto') => void;
9
+ /** Callback to get current quality */
10
+ getCurrentQuality?: () => QualityLevel | null;
11
+ /** Callback to get bandwidth estimate (bits per second) - typically from player stats */
12
+ getBandwidthEstimate?: () => Promise<number>;
13
+ /** Debug logging */
14
+ debug?: boolean;
15
+ }
16
+ export type ABRDecision = 'upgrade' | 'downgrade' | 'maintain' | 'none';
17
+ /**
18
+ * ABRController - Adaptive Bitrate Controller
19
+ *
20
+ * Manages automatic quality selection based on:
21
+ * - ABR_resize: Matches video resolution to viewport size
22
+ * - ABR_bitrate: Switches quality based on playback performance
23
+ * - auto: Combines both modes
24
+ * - manual: No automatic switching
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const abr = new ABRController({
29
+ * options: { mode: 'auto' },
30
+ * getQualities: () => player.getQualities(),
31
+ * selectQuality: (id) => player.selectQuality(id),
32
+ * });
33
+ *
34
+ * abr.start(videoElement);
35
+ * abr.onQualityChange((quality) => console.log('Quality:', quality.score));
36
+ * ```
37
+ */
38
+ export declare class ABRController {
39
+ private options;
40
+ private config;
41
+ private videoElement;
42
+ private currentQualityId;
43
+ private lastDecision;
44
+ private lastDecisionTime;
45
+ private resizeObserver;
46
+ private qualityChangeCallbacks;
47
+ private debug;
48
+ private timers;
49
+ private bandwidthHistory;
50
+ private static readonly BANDWIDTH_HISTORY_SIZE;
51
+ private static readonly MONITORING_INTERVAL_MS;
52
+ private static readonly UPGRADE_COOLDOWN_MS;
53
+ private static readonly DOWNGRADE_COOLDOWN_MS;
54
+ private lastUpgradeTime;
55
+ private lastDowngradeTime;
56
+ private static readonly UPGRADE_HEADROOM;
57
+ private static readonly UPGRADE_HOLD_THRESHOLD;
58
+ private static readonly DOWNGRADE_THRESHOLD;
59
+ private currentQualityBitrate;
60
+ constructor(config: ABRControllerConfig);
61
+ /**
62
+ * Start ABR control
63
+ */
64
+ start(videoElement: HTMLVideoElement): void;
65
+ /**
66
+ * Stop ABR control
67
+ */
68
+ stop(): void;
69
+ /**
70
+ * Start active bandwidth monitoring loop
71
+ * Continuously monitors bandwidth and proactively switches quality
72
+ */
73
+ private startActiveMonitoring;
74
+ /**
75
+ * Check current bandwidth and switch quality if needed
76
+ *
77
+ * Uses hysteresis (D2) and separate cooldowns (D3) to prevent oscillation:
78
+ * - Downgrade: immediate response (0ms cooldown), triggers at 0.8x
79
+ * - Upgrade: 5s cooldown, requires 1.5x headroom, holds until 1.2x
80
+ */
81
+ private checkBandwidthAndSwitch;
82
+ /**
83
+ * Get bandwidth estimate from player stats
84
+ */
85
+ private getBandwidthEstimate;
86
+ /**
87
+ * Get smoothed bandwidth from history
88
+ */
89
+ private getSmoothedBandwidth;
90
+ /**
91
+ * Get current bandwidth estimate (for external use)
92
+ */
93
+ getCurrentBandwidth(): number;
94
+ /**
95
+ * Setup resize observer for viewport-based quality selection
96
+ */
97
+ private setupResizeObserver;
98
+ /**
99
+ * Handle viewport resize (ABR_resize mode)
100
+ */
101
+ private handleResize;
102
+ /**
103
+ * Handle quality degradation (ABR_bitrate mode)
104
+ *
105
+ * Called by QualityMonitor when playback quality drops
106
+ */
107
+ handleQualityDegraded(quality: PlaybackQuality): void;
108
+ /**
109
+ * Handle quality improvement opportunity
110
+ *
111
+ * Called when conditions are good enough to try higher quality
112
+ */
113
+ handleQualityImproved(quality: PlaybackQuality): void;
114
+ /**
115
+ * Find best quality level for given resolution
116
+ */
117
+ private findBestQualityForResolution;
118
+ /**
119
+ * Find a lower quality level
120
+ */
121
+ private findLowerQuality;
122
+ /**
123
+ * Find a higher quality level
124
+ */
125
+ private findHigherQuality;
126
+ /**
127
+ * Check if quality is within configured constraints
128
+ */
129
+ private isWithinConstraints;
130
+ /**
131
+ * Select a quality level
132
+ */
133
+ private selectQuality;
134
+ /**
135
+ * Register callback for quality changes
136
+ */
137
+ onQualityChange(callback: (level: QualityLevel) => void): () => void;
138
+ /**
139
+ * Manually set quality (switches to manual mode temporarily)
140
+ */
141
+ setQuality(id: string | 'auto'): void;
142
+ /**
143
+ * Get current ABR mode
144
+ */
145
+ getMode(): ABRMode;
146
+ /**
147
+ * Set ABR mode at runtime.
148
+ * Restarts monitoring if video element is attached.
149
+ */
150
+ setMode(mode: ABRMode): void;
151
+ /**
152
+ * Update ABR options
153
+ */
154
+ updateOptions(options: Partial<ABROptions>): void;
155
+ /**
156
+ * Get last ABR decision
157
+ */
158
+ getLastDecision(): ABRDecision;
159
+ /**
160
+ * Debug logging
161
+ */
162
+ private log;
163
+ }
164
+ export default ABRController;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * CodecUtils - Codec string translation utilities
3
+ *
4
+ * Based on MistMetaPlayer's MistUtil.tracks.translateCodec functionality.
5
+ * Translates MistServer codec names to browser-compatible codec strings.
6
+ */
7
+ export interface TrackInfo {
8
+ type: string;
9
+ codec: string;
10
+ init?: string;
11
+ codecstring?: string;
12
+ width?: number;
13
+ height?: number;
14
+ bps?: number;
15
+ fpks?: number;
16
+ }
17
+ /**
18
+ * Translate a MistServer codec name to a browser-compatible codec string
19
+ *
20
+ * @param track - Track info from MistServer
21
+ * @returns Browser-compatible codec string (e.g., "avc1.64001f")
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * translateCodec({ codec: 'H264', type: 'video' })
26
+ * // => 'avc1.42E01E' (baseline profile, level 3.0 default)
27
+ *
28
+ * translateCodec({ codec: 'AAC', type: 'audio' })
29
+ * // => 'mp4a.40.2'
30
+ * ```
31
+ */
32
+ export declare function translateCodec(track: TrackInfo): string;
33
+ /**
34
+ * Check if a codec is supported by the browser via MediaSource
35
+ *
36
+ * @param codecString - Codec string to check
37
+ * @param containerType - Container type (default: 'video/mp4')
38
+ * @returns true if supported
39
+ */
40
+ export declare function isCodecSupported(codecString: string, containerType?: string): boolean;
41
+ /**
42
+ * Get the best supported codec from a list of tracks
43
+ *
44
+ * @param tracks - Array of track info
45
+ * @param type - Track type to filter ('video' or 'audio')
46
+ * @returns Best supported track or null
47
+ */
48
+ export declare function getBestSupportedTrack(tracks: TrackInfo[], type: 'video' | 'audio'): TrackInfo | null;
49
+ declare const _default: {
50
+ translateCodec: typeof translateCodec;
51
+ isCodecSupported: typeof isCodecSupported;
52
+ getBestSupportedTrack: typeof getBestSupportedTrack;
53
+ };
54
+ export default _default;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Disposable interface for consistent cleanup across all core classes.
3
+ *
4
+ * All classes that manage resources (timers, event listeners, WebSockets, etc.)
5
+ * should implement this interface to ensure proper cleanup.
6
+ */
7
+ /**
8
+ * Interface for objects that need cleanup
9
+ */
10
+ export interface Disposable {
11
+ /**
12
+ * Clean up all resources held by this object.
13
+ * Safe to call multiple times - subsequent calls should be no-ops.
14
+ */
15
+ dispose(): void;
16
+ /**
17
+ * Whether this object has been disposed
18
+ */
19
+ readonly disposed: boolean;
20
+ }
21
+ /**
22
+ * Base class for disposable objects that provides:
23
+ * - disposed flag tracking
24
+ * - Double-dispose protection
25
+ * - Template method for subclass cleanup
26
+ */
27
+ export declare abstract class BaseDisposable implements Disposable {
28
+ private _disposed;
29
+ /**
30
+ * Whether this object has been disposed
31
+ */
32
+ get disposed(): boolean;
33
+ /**
34
+ * Dispose of this object, releasing all resources.
35
+ * Safe to call multiple times.
36
+ */
37
+ dispose(): void;
38
+ /**
39
+ * Subclasses implement this to clean up their resources.
40
+ * Called exactly once when dispose() is first called.
41
+ */
42
+ protected abstract onDispose(): void;
43
+ /**
44
+ * Throw if this object has been disposed.
45
+ * Use at the start of methods that shouldn't run after disposal.
46
+ */
47
+ protected throwIfDisposed(operation?: string): void;
48
+ /**
49
+ * Check if disposed without throwing - useful for conditional guards
50
+ */
51
+ protected guardDisposed(): boolean;
52
+ }
53
+ /**
54
+ * Utility to dispose multiple disposables at once
55
+ */
56
+ export declare function disposeAll(...disposables: (Disposable | null | undefined)[]): void;
57
+ /**
58
+ * Create a composite disposable that disposes multiple items
59
+ */
60
+ export declare function createCompositeDisposable(...disposables: (Disposable | (() => void))[]): Disposable;
61
+ export default BaseDisposable;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * EventEmitter.ts
3
+ *
4
+ * A lightweight, typed event emitter for framework-agnostic components.
5
+ * Used by GatewayClient, StreamStateClient, and PlayerController.
6
+ */
7
+ type Listener<T> = (data: T) => void;
8
+ /**
9
+ * Typed event emitter that provides type-safe event handling.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * interface MyEvents {
14
+ * stateChange: { state: string };
15
+ * error: { message: string };
16
+ * }
17
+ *
18
+ * class MyClass extends TypedEventEmitter<MyEvents> {
19
+ * doSomething() {
20
+ * this.emit('stateChange', { state: 'ready' });
21
+ * }
22
+ * }
23
+ *
24
+ * const instance = new MyClass();
25
+ * const unsub = instance.on('stateChange', ({ state }) => console.log(state));
26
+ * unsub(); // unsubscribe
27
+ * ```
28
+ */
29
+ export declare class TypedEventEmitter<Events extends Record<string, any>> {
30
+ private listeners;
31
+ /**
32
+ * Subscribe to an event.
33
+ * @param event - The event name to listen for
34
+ * @param listener - Callback function invoked when the event is emitted
35
+ * @returns Unsubscribe function
36
+ */
37
+ on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): () => void;
38
+ /**
39
+ * Subscribe to an event only once.
40
+ * The listener is automatically removed after the first invocation.
41
+ * @param event - The event name to listen for
42
+ * @param listener - Callback function invoked when the event is emitted
43
+ * @returns Unsubscribe function
44
+ */
45
+ once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): () => void;
46
+ /**
47
+ * Unsubscribe from an event.
48
+ * @param event - The event name
49
+ * @param listener - The callback to remove
50
+ */
51
+ off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void;
52
+ /**
53
+ * Emit an event to all subscribers.
54
+ * @param event - The event name
55
+ * @param data - The event payload
56
+ */
57
+ protected emit<K extends keyof Events>(event: K, data: Events[K]): void;
58
+ /**
59
+ * Remove all listeners for all events.
60
+ */
61
+ removeAllListeners(): void;
62
+ /**
63
+ * Remove all listeners for a specific event.
64
+ * @param event - The event name
65
+ */
66
+ removeListeners<K extends keyof Events>(event: K): void;
67
+ /**
68
+ * Check if there are any listeners for an event.
69
+ * @param event - The event name
70
+ */
71
+ hasListeners<K extends keyof Events>(event: K): boolean;
72
+ }
73
+ export default TypedEventEmitter;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * GatewayClient.ts
3
+ *
4
+ * Framework-agnostic client for resolving viewer endpoints from the Gateway GraphQL API.
5
+ * Extracted from useViewerEndpoints.ts for use in headless core.
6
+ */
7
+ import { TypedEventEmitter } from './EventEmitter';
8
+ import type { ContentEndpoints, ContentType } from '../types';
9
+ export type GatewayStatus = 'idle' | 'loading' | 'ready' | 'error';
10
+ export interface GatewayClientConfig {
11
+ /** Gateway GraphQL endpoint URL */
12
+ gatewayUrl: string;
13
+ /** Content type to resolve */
14
+ contentType: ContentType;
15
+ /** Content identifier (stream name) */
16
+ contentId: string;
17
+ /** Optional auth token for private streams */
18
+ authToken?: string;
19
+ /** Maximum retry attempts (default: 3) */
20
+ maxRetries?: number;
21
+ /** Initial retry delay in ms (default: 500) */
22
+ initialDelayMs?: number;
23
+ }
24
+ export interface GatewayClientEvents {
25
+ /** Emitted when status changes */
26
+ statusChange: {
27
+ status: GatewayStatus;
28
+ error?: string;
29
+ };
30
+ /** Emitted when endpoints are successfully resolved */
31
+ endpointsResolved: {
32
+ endpoints: ContentEndpoints;
33
+ };
34
+ }
35
+ type CircuitBreakerState = 'closed' | 'open' | 'half-open';
36
+ /**
37
+ * Client for resolving viewer endpoints from the Gateway GraphQL API.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const client = new GatewayClient({
42
+ * gatewayUrl: 'https://gateway.example.com/graphql',
43
+ * contentType: 'live',
44
+ * contentId: 'my-stream',
45
+ * });
46
+ *
47
+ * client.on('statusChange', ({ status }) => console.log('Status:', status));
48
+ * client.on('endpointsResolved', ({ endpoints }) => console.log('Endpoints:', endpoints));
49
+ *
50
+ * const endpoints = await client.resolve();
51
+ * ```
52
+ */
53
+ export declare class GatewayClient extends TypedEventEmitter<GatewayClientEvents> {
54
+ private config;
55
+ private status;
56
+ private endpoints;
57
+ private error;
58
+ private abortController;
59
+ private inFlightRequest;
60
+ private cacheTimestamp;
61
+ private cacheTtlMs;
62
+ private circuitState;
63
+ private consecutiveFailures;
64
+ private circuitOpenedAt;
65
+ constructor(config: GatewayClientConfig);
66
+ /**
67
+ * Resolve endpoints from the gateway.
68
+ * F2: Returns cached result if still valid, deduplicates concurrent requests.
69
+ * F3: Respects circuit breaker state.
70
+ * @param forceRefresh - If true, bypasses cache and fetches fresh data
71
+ * @returns Promise resolving to ContentEndpoints
72
+ * @throws Error if resolution fails after retries or circuit is open
73
+ */
74
+ resolve(forceRefresh?: boolean): Promise<ContentEndpoints>;
75
+ /**
76
+ * F2: Check if cache is still valid
77
+ */
78
+ private isCacheValid;
79
+ /**
80
+ * F2: Set cache TTL (for testing or custom requirements)
81
+ */
82
+ setCacheTtl(ttlMs: number): void;
83
+ /**
84
+ * F2: Invalidate the cache manually
85
+ */
86
+ invalidateCache(): void;
87
+ /**
88
+ * F3: Check if a request can be attempted based on circuit state
89
+ */
90
+ private canAttemptRequest;
91
+ /**
92
+ * F3: Record a successful request
93
+ */
94
+ private onSuccess;
95
+ /**
96
+ * F3: Record a failed request
97
+ */
98
+ private onFailure;
99
+ /**
100
+ * F3: Get current circuit breaker state (for monitoring/debugging)
101
+ */
102
+ getCircuitState(): {
103
+ state: CircuitBreakerState;
104
+ failures: number;
105
+ openedAt: number | null;
106
+ };
107
+ /**
108
+ * F3: Manually reset the circuit breaker
109
+ */
110
+ resetCircuitBreaker(): void;
111
+ /**
112
+ * Internal method to perform the actual resolution.
113
+ * @returns Promise resolving to ContentEndpoints
114
+ */
115
+ private doResolve;
116
+ /**
117
+ * Abort any in-flight request.
118
+ */
119
+ abort(): void;
120
+ /**
121
+ * Get current status.
122
+ */
123
+ getStatus(): GatewayStatus;
124
+ /**
125
+ * Get resolved endpoints (null if not yet resolved).
126
+ */
127
+ getEndpoints(): ContentEndpoints | null;
128
+ /**
129
+ * Get error message (null if no error).
130
+ */
131
+ getError(): string | null;
132
+ /**
133
+ * Update configuration and reset state.
134
+ * F2: Also clears cache and in-flight request
135
+ * F3: Resets circuit breaker (new config = fresh start)
136
+ */
137
+ updateConfig(config: Partial<GatewayClientConfig>): void;
138
+ /**
139
+ * Clean up resources.
140
+ */
141
+ destroy(): void;
142
+ private setStatus;
143
+ }
144
+ export default GatewayClient;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * InteractionController - Unified keyboard and gesture handling for video players
3
+ *
4
+ * Features:
5
+ * - Hold space for 2x speed (VOD/clips only, tap = play/pause)
6
+ * - Click/touch and hold for 2x speed
7
+ * - Comprehensive keyboard shortcuts
8
+ * - Double-tap to skip on mobile
9
+ * - All interactions disabled for live streams (where applicable)
10
+ */
11
+ export interface InteractionControllerConfig {
12
+ container: HTMLElement;
13
+ videoElement: HTMLVideoElement;
14
+ isLive: boolean;
15
+ onPlayPause: () => void;
16
+ onSeek: (delta: number) => void;
17
+ onVolumeChange: (delta: number) => void;
18
+ onMuteToggle: () => void;
19
+ onFullscreenToggle: () => void;
20
+ onCaptionsToggle?: () => void;
21
+ onLoopToggle?: () => void;
22
+ onSpeedChange: (speed: number, isHolding: boolean) => void;
23
+ onSeekPercent?: (percent: number) => void;
24
+ speedHoldValue?: number;
25
+ /** Idle timeout in ms (default 5000). Set to 0 to disable. */
26
+ idleTimeout?: number;
27
+ /** Callback fired when user becomes idle */
28
+ onIdle?: () => void;
29
+ /** Callback fired when user becomes active after being idle */
30
+ onActive?: () => void;
31
+ }
32
+ export interface InteractionState {
33
+ isHoldingSpeed: boolean;
34
+ previousSpeed: number;
35
+ holdSpeed: number;
36
+ /** Whether the user is currently idle (no interaction for idleTimeout) */
37
+ isIdle: boolean;
38
+ }
39
+ export declare class InteractionController {
40
+ private config;
41
+ private state;
42
+ private isAttached;
43
+ private spaceKeyDownTime;
44
+ private spaceIsHeld;
45
+ private holdCheckTimeout;
46
+ private pointerDownTime;
47
+ private pointerIsHeld;
48
+ private pointerHoldTimeout;
49
+ private lastTapTime;
50
+ private lastTapX;
51
+ private pendingTapTimeout;
52
+ private idleTimeout;
53
+ private lastInteractionTime;
54
+ private boundKeyDown;
55
+ private boundKeyUp;
56
+ private boundPointerDown;
57
+ private boundPointerUp;
58
+ private boundPointerCancel;
59
+ private boundContextMenu;
60
+ private boundMouseMove;
61
+ constructor(config: InteractionControllerConfig);
62
+ /**
63
+ * Attach event listeners to container
64
+ */
65
+ attach(): void;
66
+ /**
67
+ * Detach event listeners and cleanup
68
+ */
69
+ detach(): void;
70
+ /**
71
+ * Check if currently holding for speed boost
72
+ */
73
+ isHoldingSpeed(): boolean;
74
+ /**
75
+ * Check if user is currently idle (no interaction for idleTimeout)
76
+ */
77
+ isIdle(): boolean;
78
+ /**
79
+ * Get current interaction state
80
+ */
81
+ getState(): InteractionState;
82
+ /**
83
+ * Update config (e.g., when isLive changes)
84
+ */
85
+ updateConfig(updates: Partial<InteractionControllerConfig>): void;
86
+ private handleKeyDown;
87
+ private handleKeyUp;
88
+ private handleSpaceDown;
89
+ private handleSpaceUp;
90
+ private handlePointerDown;
91
+ private handlePointerUp;
92
+ private handlePointerCancel;
93
+ private cancelPointerHold;
94
+ private handleContextMenu;
95
+ private engageSpeedHold;
96
+ private releaseSpeedHold;
97
+ private adjustPlaybackSpeed;
98
+ private handleMouseMove;
99
+ /**
100
+ * Record that an interaction occurred and reset idle timer
101
+ */
102
+ recordInteraction(): void;
103
+ /**
104
+ * Reset the idle timer
105
+ */
106
+ private resetIdleTimer;
107
+ /**
108
+ * Manually mark as active (e.g., when controls become visible)
109
+ */
110
+ markActive(): void;
111
+ /**
112
+ * Pause idle tracking (e.g., when controls are visible)
113
+ */
114
+ pauseIdleTracking(): void;
115
+ /**
116
+ * Resume idle tracking
117
+ */
118
+ resumeIdleTracking(): void;
119
+ private isInputElement;
120
+ private isControlElement;
121
+ }