@codenkay/video-nsgplayer-core 2.0.0 → 3.0.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.
- package/CHANGELOG.md +20 -0
- package/dist/index.cjs +194 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -11
- package/dist/index.d.ts +24 -11
- package/dist/index.js +193 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -151,6 +151,12 @@ type StreamingConfig = {
|
|
|
151
151
|
* Use when the BFF cannot reach Appextech (Cloudflare challenge on server IP).
|
|
152
152
|
*/
|
|
153
153
|
getKeyAccessToken?: () => string | null | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Max same-origin key-proxy failures before the session permanently switches
|
|
156
|
+
* to browser Bearer / signed-query (default 2). Prevents hls.js from hammering
|
|
157
|
+
* a Cloudflare-blocked BFF (9–10× 502s).
|
|
158
|
+
*/
|
|
159
|
+
keyProxyMaxFailures?: number;
|
|
154
160
|
};
|
|
155
161
|
type LoggingConfig = {
|
|
156
162
|
enabled?: boolean;
|
|
@@ -198,6 +204,7 @@ type PlayerConfig = Required<{
|
|
|
198
204
|
hls: Required<NonNullable<StreamingConfig["hls"]>>;
|
|
199
205
|
keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
|
|
200
206
|
getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
|
|
207
|
+
keyProxyMaxFailures?: StreamingConfig["keyProxyMaxFailures"];
|
|
201
208
|
};
|
|
202
209
|
logging: Required<LoggingConfig>;
|
|
203
210
|
debug: Required<DebugConfig>;
|
|
@@ -279,7 +286,7 @@ type PlayerEventMap = {
|
|
|
279
286
|
};
|
|
280
287
|
|
|
281
288
|
declare const PLAYBACK_RATES: readonly [0.5, 0.75, 1, 1.25, 1.5, 2];
|
|
282
|
-
declare const PACKAGE_VERSION = "0.1
|
|
289
|
+
declare const PACKAGE_VERSION = "3.0.1";
|
|
283
290
|
declare const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig>;
|
|
284
291
|
declare const DEFAULT_CONTROLS: Required<ControlsConfig>;
|
|
285
292
|
declare const DEFAULT_THEME: Required<ThemeConfig>;
|
|
@@ -312,6 +319,7 @@ type PlayerConfigPartial = Partial<{
|
|
|
312
319
|
hls?: Partial<PlayerConfig["streaming"]["hls"]>;
|
|
313
320
|
keyProxyUrlBuilder?: PlayerConfig["streaming"]["keyProxyUrlBuilder"];
|
|
314
321
|
getKeyAccessToken?: PlayerConfig["streaming"]["getKeyAccessToken"];
|
|
322
|
+
keyProxyMaxFailures?: PlayerConfig["streaming"]["keyProxyMaxFailures"];
|
|
315
323
|
};
|
|
316
324
|
logging: Partial<PlayerConfig["logging"]>;
|
|
317
325
|
debug: Partial<PlayerConfig["debug"]>;
|
|
@@ -431,6 +439,7 @@ type HlsEngineOptions = {
|
|
|
431
439
|
videoId?: string;
|
|
432
440
|
keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
|
|
433
441
|
getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
|
|
442
|
+
keyProxyMaxFailures?: StreamingConfig["keyProxyMaxFailures"];
|
|
434
443
|
hlsConfig: {
|
|
435
444
|
enableWorker: boolean;
|
|
436
445
|
lowLatencyMode: boolean;
|
|
@@ -646,15 +655,21 @@ declare class RefreshManager {
|
|
|
646
655
|
|
|
647
656
|
type HlsLoaderInstance = {
|
|
648
657
|
stats: LoaderStats;
|
|
658
|
+
context: LoaderContext | null;
|
|
649
659
|
load(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks<LoaderContext>): void;
|
|
650
660
|
destroy(): void;
|
|
651
|
-
abort
|
|
661
|
+
abort(): void;
|
|
652
662
|
};
|
|
653
|
-
|
|
663
|
+
/** Constructor shape compatible with `Hls.DefaultConfig.loader`. */
|
|
664
|
+
type HlsLoaderConstructor = new (config: object) => HlsLoaderInstance;
|
|
665
|
+
/** Max same-origin BFF key attempts before the session circuit opens. */
|
|
666
|
+
declare const KEY_PROXY_MAX_FAILURES = 2;
|
|
654
667
|
type AuthParamsLoaderOptions = {
|
|
655
668
|
videoId?: string;
|
|
656
669
|
keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
|
|
657
670
|
getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
|
|
671
|
+
/** Override max BFF key failures before permanent browser fallback (default 2). */
|
|
672
|
+
keyProxyMaxFailures?: number;
|
|
658
673
|
};
|
|
659
674
|
declare function isEncryptionKeyUrl(rawUrl: string, baseOrigin?: string): boolean;
|
|
660
675
|
/**
|
|
@@ -664,26 +679,24 @@ declare function isEncryptionKeyUrl(rawUrl: string, baseOrigin?: string): boolea
|
|
|
664
679
|
* custom wrapper, `extends` / nested `inner.load()` chains blow Firefox's
|
|
665
680
|
* stack (`InternalError: too much recursion`).
|
|
666
681
|
*/
|
|
667
|
-
declare function resolveBuiltinHlsLoader(HlsClass: typeof Hls):
|
|
682
|
+
declare function resolveBuiltinHlsLoader(HlsClass: typeof Hls): HlsLoaderConstructor;
|
|
668
683
|
/**
|
|
669
684
|
* Rewrites an HLS request URL so signed auth query params are present.
|
|
670
685
|
*
|
|
671
686
|
* AES `enc.key` handling (enterprise priority order):
|
|
672
687
|
* 1. `keyProxyUrlBuilder` — same-origin BFF (production; server IP must pass CDN/WAF)
|
|
673
688
|
* 2. Otherwise keep CDN/API URL and apply signed `token`/`expires` (and related) query
|
|
674
|
-
* params — same auth model as segments on Appextech CDN hosts
|
|
675
689
|
* 3. Optional `getKeyAccessToken` is applied at load-time (Bearer), not in this rewrite
|
|
676
690
|
*/
|
|
677
691
|
declare function rewriteHlsRequestUrl(rawUrl: string, store: AuthParamsStore, options?: AuthParamsLoaderOptions, baseOrigin?: string): string;
|
|
678
692
|
/**
|
|
679
693
|
* hls.js loader that:
|
|
680
694
|
* - Re-applies signed auth query params on every media request
|
|
681
|
-
* - Loads AES `enc.key` via BFF
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
* HMR, or a polluted DefaultConfig cannot nest `super.load()` into recursion.
|
|
695
|
+
* - Loads AES `enc.key` via controlled BFF (≤2) → Bearer → query XHR
|
|
696
|
+
* with a **session circuit breaker** so a dead Cloudflare BFF is not
|
|
697
|
+
* hammered by hls.js retries (which previously caused 9–10× 502s).
|
|
685
698
|
*/
|
|
686
|
-
declare function createAuthParamsLoader(HlsClass: typeof Hls, store: AuthParamsStore, options?: AuthParamsLoaderOptions):
|
|
699
|
+
declare function createAuthParamsLoader(HlsClass: typeof Hls, store: AuthParamsStore, options?: AuthParamsLoaderOptions): HlsLoaderConstructor;
|
|
687
700
|
|
|
688
701
|
declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>, depth?: number): unknown;
|
|
689
702
|
/**
|
|
@@ -692,4 +705,4 @@ declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>
|
|
|
692
705
|
*/
|
|
693
706
|
declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
|
|
694
707
|
|
|
695
|
-
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerAudioTrack, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerTextTrack, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type TextTrackSelection, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
|
708
|
+
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, KEY_PROXY_MAX_FAILURES, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerAudioTrack, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerTextTrack, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type TextTrackSelection, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
package/dist/index.d.ts
CHANGED
|
@@ -151,6 +151,12 @@ type StreamingConfig = {
|
|
|
151
151
|
* Use when the BFF cannot reach Appextech (Cloudflare challenge on server IP).
|
|
152
152
|
*/
|
|
153
153
|
getKeyAccessToken?: () => string | null | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Max same-origin key-proxy failures before the session permanently switches
|
|
156
|
+
* to browser Bearer / signed-query (default 2). Prevents hls.js from hammering
|
|
157
|
+
* a Cloudflare-blocked BFF (9–10× 502s).
|
|
158
|
+
*/
|
|
159
|
+
keyProxyMaxFailures?: number;
|
|
154
160
|
};
|
|
155
161
|
type LoggingConfig = {
|
|
156
162
|
enabled?: boolean;
|
|
@@ -198,6 +204,7 @@ type PlayerConfig = Required<{
|
|
|
198
204
|
hls: Required<NonNullable<StreamingConfig["hls"]>>;
|
|
199
205
|
keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
|
|
200
206
|
getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
|
|
207
|
+
keyProxyMaxFailures?: StreamingConfig["keyProxyMaxFailures"];
|
|
201
208
|
};
|
|
202
209
|
logging: Required<LoggingConfig>;
|
|
203
210
|
debug: Required<DebugConfig>;
|
|
@@ -279,7 +286,7 @@ type PlayerEventMap = {
|
|
|
279
286
|
};
|
|
280
287
|
|
|
281
288
|
declare const PLAYBACK_RATES: readonly [0.5, 0.75, 1, 1.25, 1.5, 2];
|
|
282
|
-
declare const PACKAGE_VERSION = "0.1
|
|
289
|
+
declare const PACKAGE_VERSION = "3.0.1";
|
|
283
290
|
declare const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig>;
|
|
284
291
|
declare const DEFAULT_CONTROLS: Required<ControlsConfig>;
|
|
285
292
|
declare const DEFAULT_THEME: Required<ThemeConfig>;
|
|
@@ -312,6 +319,7 @@ type PlayerConfigPartial = Partial<{
|
|
|
312
319
|
hls?: Partial<PlayerConfig["streaming"]["hls"]>;
|
|
313
320
|
keyProxyUrlBuilder?: PlayerConfig["streaming"]["keyProxyUrlBuilder"];
|
|
314
321
|
getKeyAccessToken?: PlayerConfig["streaming"]["getKeyAccessToken"];
|
|
322
|
+
keyProxyMaxFailures?: PlayerConfig["streaming"]["keyProxyMaxFailures"];
|
|
315
323
|
};
|
|
316
324
|
logging: Partial<PlayerConfig["logging"]>;
|
|
317
325
|
debug: Partial<PlayerConfig["debug"]>;
|
|
@@ -431,6 +439,7 @@ type HlsEngineOptions = {
|
|
|
431
439
|
videoId?: string;
|
|
432
440
|
keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
|
|
433
441
|
getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
|
|
442
|
+
keyProxyMaxFailures?: StreamingConfig["keyProxyMaxFailures"];
|
|
434
443
|
hlsConfig: {
|
|
435
444
|
enableWorker: boolean;
|
|
436
445
|
lowLatencyMode: boolean;
|
|
@@ -646,15 +655,21 @@ declare class RefreshManager {
|
|
|
646
655
|
|
|
647
656
|
type HlsLoaderInstance = {
|
|
648
657
|
stats: LoaderStats;
|
|
658
|
+
context: LoaderContext | null;
|
|
649
659
|
load(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks<LoaderContext>): void;
|
|
650
660
|
destroy(): void;
|
|
651
|
-
abort
|
|
661
|
+
abort(): void;
|
|
652
662
|
};
|
|
653
|
-
|
|
663
|
+
/** Constructor shape compatible with `Hls.DefaultConfig.loader`. */
|
|
664
|
+
type HlsLoaderConstructor = new (config: object) => HlsLoaderInstance;
|
|
665
|
+
/** Max same-origin BFF key attempts before the session circuit opens. */
|
|
666
|
+
declare const KEY_PROXY_MAX_FAILURES = 2;
|
|
654
667
|
type AuthParamsLoaderOptions = {
|
|
655
668
|
videoId?: string;
|
|
656
669
|
keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
|
|
657
670
|
getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
|
|
671
|
+
/** Override max BFF key failures before permanent browser fallback (default 2). */
|
|
672
|
+
keyProxyMaxFailures?: number;
|
|
658
673
|
};
|
|
659
674
|
declare function isEncryptionKeyUrl(rawUrl: string, baseOrigin?: string): boolean;
|
|
660
675
|
/**
|
|
@@ -664,26 +679,24 @@ declare function isEncryptionKeyUrl(rawUrl: string, baseOrigin?: string): boolea
|
|
|
664
679
|
* custom wrapper, `extends` / nested `inner.load()` chains blow Firefox's
|
|
665
680
|
* stack (`InternalError: too much recursion`).
|
|
666
681
|
*/
|
|
667
|
-
declare function resolveBuiltinHlsLoader(HlsClass: typeof Hls):
|
|
682
|
+
declare function resolveBuiltinHlsLoader(HlsClass: typeof Hls): HlsLoaderConstructor;
|
|
668
683
|
/**
|
|
669
684
|
* Rewrites an HLS request URL so signed auth query params are present.
|
|
670
685
|
*
|
|
671
686
|
* AES `enc.key` handling (enterprise priority order):
|
|
672
687
|
* 1. `keyProxyUrlBuilder` — same-origin BFF (production; server IP must pass CDN/WAF)
|
|
673
688
|
* 2. Otherwise keep CDN/API URL and apply signed `token`/`expires` (and related) query
|
|
674
|
-
* params — same auth model as segments on Appextech CDN hosts
|
|
675
689
|
* 3. Optional `getKeyAccessToken` is applied at load-time (Bearer), not in this rewrite
|
|
676
690
|
*/
|
|
677
691
|
declare function rewriteHlsRequestUrl(rawUrl: string, store: AuthParamsStore, options?: AuthParamsLoaderOptions, baseOrigin?: string): string;
|
|
678
692
|
/**
|
|
679
693
|
* hls.js loader that:
|
|
680
694
|
* - Re-applies signed auth query params on every media request
|
|
681
|
-
* - Loads AES `enc.key` via BFF
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
* HMR, or a polluted DefaultConfig cannot nest `super.load()` into recursion.
|
|
695
|
+
* - Loads AES `enc.key` via controlled BFF (≤2) → Bearer → query XHR
|
|
696
|
+
* with a **session circuit breaker** so a dead Cloudflare BFF is not
|
|
697
|
+
* hammered by hls.js retries (which previously caused 9–10× 502s).
|
|
685
698
|
*/
|
|
686
|
-
declare function createAuthParamsLoader(HlsClass: typeof Hls, store: AuthParamsStore, options?: AuthParamsLoaderOptions):
|
|
699
|
+
declare function createAuthParamsLoader(HlsClass: typeof Hls, store: AuthParamsStore, options?: AuthParamsLoaderOptions): HlsLoaderConstructor;
|
|
687
700
|
|
|
688
701
|
declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>, depth?: number): unknown;
|
|
689
702
|
/**
|
|
@@ -692,4 +705,4 @@ declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>
|
|
|
692
705
|
*/
|
|
693
706
|
declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
|
|
694
707
|
|
|
695
|
-
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerAudioTrack, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerTextTrack, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type TextTrackSelection, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
|
708
|
+
export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, KEY_PROXY_MAX_FAILURES, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerAudioTrack, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerTextTrack, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type TextTrackSelection, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isEncryptionKeyUrl, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, resolveBuiltinHlsLoader, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };
|
package/dist/index.js
CHANGED
|
@@ -146,7 +146,7 @@ var AuthManager = class {
|
|
|
146
146
|
|
|
147
147
|
// src/config/defaults.ts
|
|
148
148
|
var PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 2];
|
|
149
|
-
var PACKAGE_VERSION = "0.1
|
|
149
|
+
var PACKAGE_VERSION = "3.0.1";
|
|
150
150
|
var DEFAULT_PLAYER_BEHAVIOR = {
|
|
151
151
|
autoplay: true,
|
|
152
152
|
startMuted: true,
|
|
@@ -325,7 +325,8 @@ function mergePlayerConfig(partial) {
|
|
|
325
325
|
...partial?.streaming?.hls
|
|
326
326
|
},
|
|
327
327
|
keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder,
|
|
328
|
-
getKeyAccessToken: partial?.streaming?.getKeyAccessToken
|
|
328
|
+
getKeyAccessToken: partial?.streaming?.getKeyAccessToken,
|
|
329
|
+
keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures
|
|
329
330
|
},
|
|
330
331
|
logging: { ...DEFAULT_PLAYER_CONFIG.logging, ...partial?.logging },
|
|
331
332
|
debug: { ...DEFAULT_PLAYER_CONFIG.debug, ...partial?.debug },
|
|
@@ -768,6 +769,7 @@ function seekToLiveEdge(media, options) {
|
|
|
768
769
|
import { XhrLoader as BuiltinXhrLoader } from "hls.js";
|
|
769
770
|
var ENC_KEY_PATH_RE = /enc\.key$/i;
|
|
770
771
|
var BUILTIN_LOADER_NAMES = /* @__PURE__ */ new Set(["XhrLoader", "FetchLoader"]);
|
|
772
|
+
var KEY_PROXY_MAX_FAILURES = 2;
|
|
771
773
|
function isEncryptionKeyUrl(rawUrl, baseOrigin = typeof location !== "undefined" ? location.origin : "http://localhost") {
|
|
772
774
|
try {
|
|
773
775
|
return ENC_KEY_PATH_RE.test(new URL(rawUrl, baseOrigin).pathname);
|
|
@@ -828,6 +830,20 @@ function createLoaderStats() {
|
|
|
828
830
|
buffering: { start: 0, first: 0, end: 0 }
|
|
829
831
|
};
|
|
830
832
|
}
|
|
833
|
+
function isProxyUpstreamBlocked(status, contentType, bodyHead, errorText) {
|
|
834
|
+
if (status === 0 || status === 502 || status === 503 || status === 504) {
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
if (status === 403 || status === 401) return true;
|
|
838
|
+
if (contentType?.includes("text/html")) return true;
|
|
839
|
+
if (/<!DOCTYPE|<html|Just a moment|Cloudflare|blocked/i.test(bodyHead)) {
|
|
840
|
+
return true;
|
|
841
|
+
}
|
|
842
|
+
if (errorText && /Cloudflare|HTML|DOCTYPE|blocked|502/i.test(errorText)) {
|
|
843
|
+
return true;
|
|
844
|
+
}
|
|
845
|
+
return false;
|
|
846
|
+
}
|
|
831
847
|
async function loadEncryptionKeyWithFetch(context, callbacks, accessToken, signal) {
|
|
832
848
|
const stats = createLoaderStats();
|
|
833
849
|
stats.loading.first = performance.now();
|
|
@@ -886,10 +902,122 @@ async function loadEncryptionKeyWithFetch(context, callbacks, accessToken, signa
|
|
|
886
902
|
response
|
|
887
903
|
);
|
|
888
904
|
}
|
|
905
|
+
async function loadEncryptionKeyEnterprise(context, callbacks, plan, signal, state) {
|
|
906
|
+
const stats = createLoaderStats();
|
|
907
|
+
stats.loading.first = performance.now();
|
|
908
|
+
const canTryProxy = Boolean(plan.proxyUrl) && !state.circuitOpen && state.proxyFailures < plan.maxProxyFailures;
|
|
909
|
+
if (canTryProxy && plan.proxyUrl) {
|
|
910
|
+
while (!state.circuitOpen && state.proxyFailures < plan.maxProxyFailures && !signal.aborted) {
|
|
911
|
+
state.proxyFailures += 1;
|
|
912
|
+
try {
|
|
913
|
+
const response = await fetch(plan.proxyUrl, {
|
|
914
|
+
method: "GET",
|
|
915
|
+
headers: { Accept: "*/*" },
|
|
916
|
+
credentials: "same-origin",
|
|
917
|
+
cache: "no-store",
|
|
918
|
+
signal
|
|
919
|
+
});
|
|
920
|
+
const contentType = response.headers.get("content-type");
|
|
921
|
+
const data = await response.arrayBuffer();
|
|
922
|
+
const head = new TextDecoder().decode(data.slice(0, 64));
|
|
923
|
+
if (response.ok && !isProxyUpstreamBlocked(response.status, contentType, head)) {
|
|
924
|
+
const end = performance.now();
|
|
925
|
+
stats.loading.end = end;
|
|
926
|
+
stats.loaded = data.byteLength;
|
|
927
|
+
stats.total = data.byteLength;
|
|
928
|
+
callbacks.onSuccess(
|
|
929
|
+
{
|
|
930
|
+
url: response.url || plan.proxyUrl,
|
|
931
|
+
data,
|
|
932
|
+
code: response.status
|
|
933
|
+
},
|
|
934
|
+
stats,
|
|
935
|
+
{ ...context, url: plan.proxyUrl },
|
|
936
|
+
response
|
|
937
|
+
);
|
|
938
|
+
return "ok";
|
|
939
|
+
}
|
|
940
|
+
if (isProxyUpstreamBlocked(
|
|
941
|
+
response.status,
|
|
942
|
+
contentType,
|
|
943
|
+
head,
|
|
944
|
+
response.statusText
|
|
945
|
+
)) {
|
|
946
|
+
if (response.status === 502 || contentType?.includes("text/html") || /Cloudflare|DOCTYPE|blocked/i.test(head)) {
|
|
947
|
+
state.circuitOpen = true;
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
callbacks.onError(
|
|
953
|
+
{
|
|
954
|
+
code: response.status,
|
|
955
|
+
text: `enc.key proxy HTTP ${response.status}`
|
|
956
|
+
},
|
|
957
|
+
{ ...context, url: plan.proxyUrl },
|
|
958
|
+
response,
|
|
959
|
+
stats
|
|
960
|
+
);
|
|
961
|
+
return "ok";
|
|
962
|
+
} catch (error) {
|
|
963
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
964
|
+
callbacks.onError(
|
|
965
|
+
{ code: 0, text: "enc.key proxy aborted/timeout" },
|
|
966
|
+
context,
|
|
967
|
+
null,
|
|
968
|
+
stats
|
|
969
|
+
);
|
|
970
|
+
return "ok";
|
|
971
|
+
}
|
|
972
|
+
state.circuitOpen = true;
|
|
973
|
+
break;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
state.circuitOpen = true;
|
|
977
|
+
}
|
|
978
|
+
if (plan.accessToken) {
|
|
979
|
+
try {
|
|
980
|
+
await loadEncryptionKeyWithFetch(
|
|
981
|
+
{ ...context, url: plan.signedKeyUrl },
|
|
982
|
+
callbacks,
|
|
983
|
+
plan.accessToken,
|
|
984
|
+
signal
|
|
985
|
+
);
|
|
986
|
+
return "ok";
|
|
987
|
+
} catch (error) {
|
|
988
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
989
|
+
callbacks.onError(
|
|
990
|
+
{ code: 0, text: "enc.key fetch aborted/timeout" },
|
|
991
|
+
{ ...context, url: plan.signedKeyUrl },
|
|
992
|
+
null,
|
|
993
|
+
stats
|
|
994
|
+
);
|
|
995
|
+
return "ok";
|
|
996
|
+
}
|
|
997
|
+
if (error instanceof TypeError || error instanceof Error && /Failed to fetch|NetworkError|CORS/i.test(error.message)) {
|
|
998
|
+
return "try_xhr";
|
|
999
|
+
}
|
|
1000
|
+
callbacks.onError(
|
|
1001
|
+
{
|
|
1002
|
+
code: 0,
|
|
1003
|
+
text: error instanceof Error ? error.message : "enc.key Bearer fetch failed"
|
|
1004
|
+
},
|
|
1005
|
+
{ ...context, url: plan.signedKeyUrl },
|
|
1006
|
+
null,
|
|
1007
|
+
stats
|
|
1008
|
+
);
|
|
1009
|
+
return "ok";
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return "try_xhr";
|
|
1013
|
+
}
|
|
889
1014
|
function createAuthParamsLoader(HlsClass, store, options = {}) {
|
|
890
1015
|
const BaseLoader = resolveBuiltinHlsLoader(HlsClass);
|
|
1016
|
+
const maxProxyFailures = typeof options.keyProxyMaxFailures === "number" && options.keyProxyMaxFailures >= 0 ? options.keyProxyMaxFailures : KEY_PROXY_MAX_FAILURES;
|
|
1017
|
+
const keyProxyState = { proxyFailures: 0, circuitOpen: false };
|
|
891
1018
|
return class AuthParamsLoader {
|
|
892
1019
|
constructor(config) {
|
|
1020
|
+
this.context = null;
|
|
893
1021
|
this.keyAbort = null;
|
|
894
1022
|
this.inner = new BaseLoader(config);
|
|
895
1023
|
this.stats = this.inner.stats;
|
|
@@ -897,14 +1025,16 @@ function createAuthParamsLoader(HlsClass, store, options = {}) {
|
|
|
897
1025
|
abort() {
|
|
898
1026
|
this.keyAbort?.abort();
|
|
899
1027
|
this.keyAbort = null;
|
|
900
|
-
this.inner.abort
|
|
1028
|
+
this.inner.abort();
|
|
901
1029
|
}
|
|
902
1030
|
destroy() {
|
|
903
1031
|
this.keyAbort?.abort();
|
|
904
1032
|
this.keyAbort = null;
|
|
1033
|
+
this.context = null;
|
|
905
1034
|
this.inner.destroy();
|
|
906
1035
|
}
|
|
907
1036
|
load(context, config, callbacks) {
|
|
1037
|
+
this.context = context;
|
|
908
1038
|
if (!context.url) {
|
|
909
1039
|
this.inner.load(context, config, callbacks);
|
|
910
1040
|
return;
|
|
@@ -912,44 +1042,59 @@ function createAuthParamsLoader(HlsClass, store, options = {}) {
|
|
|
912
1042
|
try {
|
|
913
1043
|
const originalUrl = context.url;
|
|
914
1044
|
const isKey = isEncryptionKeyUrl(originalUrl);
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1045
|
+
if (!isKey) {
|
|
1046
|
+
if (store.hasParams()) {
|
|
1047
|
+
context.url = rewriteHlsRequestUrl(originalUrl, store, {
|
|
1048
|
+
...options,
|
|
1049
|
+
keyProxyUrlBuilder: void 0
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
920
1052
|
this.inner.load(context, config, callbacks);
|
|
921
1053
|
return;
|
|
922
1054
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1055
|
+
const signedKeyUrl = rewriteHlsRequestUrl(originalUrl, store, {
|
|
1056
|
+
...options,
|
|
1057
|
+
keyProxyUrlBuilder: void 0
|
|
1058
|
+
});
|
|
1059
|
+
const proxyConfigured = Boolean(
|
|
1060
|
+
options.keyProxyUrlBuilder && options.videoId
|
|
1061
|
+
);
|
|
1062
|
+
const proxyUrl = proxyConfigured && !keyProxyState.circuitOpen ? rewriteHlsRequestUrl(originalUrl, store, options) : null;
|
|
1063
|
+
const accessToken = options.getKeyAccessToken?.() ?? null;
|
|
1064
|
+
this.keyAbort?.abort();
|
|
1065
|
+
this.keyAbort = new AbortController();
|
|
1066
|
+
const timeoutMs = typeof config?.timeout === "number" && config.timeout > 0 ? config.timeout : 2e4;
|
|
1067
|
+
const timer = setTimeout(() => this.keyAbort?.abort(), timeoutMs);
|
|
1068
|
+
void loadEncryptionKeyEnterprise(
|
|
1069
|
+
context,
|
|
1070
|
+
callbacks,
|
|
1071
|
+
{
|
|
1072
|
+
proxyUrl,
|
|
1073
|
+
signedKeyUrl,
|
|
1074
|
+
accessToken,
|
|
1075
|
+
maxProxyFailures
|
|
1076
|
+
},
|
|
1077
|
+
this.keyAbort.signal,
|
|
1078
|
+
keyProxyState
|
|
1079
|
+
).then((result) => {
|
|
1080
|
+
if (result === "try_xhr") {
|
|
1081
|
+
context.url = signedKeyUrl;
|
|
1082
|
+
this.inner.load(context, config, callbacks);
|
|
951
1083
|
}
|
|
952
|
-
}
|
|
1084
|
+
}).catch((error) => {
|
|
1085
|
+
callbacks.onError(
|
|
1086
|
+
{
|
|
1087
|
+
code: 0,
|
|
1088
|
+
text: error instanceof Error ? error.message : "enc.key load failed"
|
|
1089
|
+
},
|
|
1090
|
+
context,
|
|
1091
|
+
null,
|
|
1092
|
+
createLoaderStats()
|
|
1093
|
+
);
|
|
1094
|
+
}).finally(() => {
|
|
1095
|
+
clearTimeout(timer);
|
|
1096
|
+
});
|
|
1097
|
+
return;
|
|
953
1098
|
} catch {
|
|
954
1099
|
}
|
|
955
1100
|
this.inner.load(context, config, callbacks);
|
|
@@ -1019,7 +1164,8 @@ var HlsEngine = class {
|
|
|
1019
1164
|
const loader = createAuthParamsLoader(Hls, authParams, {
|
|
1020
1165
|
videoId,
|
|
1021
1166
|
keyProxyUrlBuilder,
|
|
1022
|
-
getKeyAccessToken
|
|
1167
|
+
getKeyAccessToken,
|
|
1168
|
+
keyProxyMaxFailures: this.options.keyProxyMaxFailures
|
|
1023
1169
|
});
|
|
1024
1170
|
this.hls = new Hls({
|
|
1025
1171
|
enableWorker: hlsConfig.enableWorker,
|
|
@@ -1443,12 +1589,12 @@ function createVideoPlayer(options) {
|
|
|
1443
1589
|
volume: config.player.volume,
|
|
1444
1590
|
videoId: options.videoId,
|
|
1445
1591
|
keyProxyUrlBuilder: config.streaming.keyProxyUrlBuilder,
|
|
1446
|
-
//
|
|
1447
|
-
//
|
|
1448
|
-
//
|
|
1449
|
-
//
|
|
1450
|
-
|
|
1451
|
-
|
|
1592
|
+
// Enterprise AES key auth:
|
|
1593
|
+
// 1) keyProxyUrlBuilder (same-origin BFF) when configured — max 2 failures
|
|
1594
|
+
// 2) else getKeyAccessToken / AuthManager Bearer via browser fetch
|
|
1595
|
+
// 3) else signed query + XHR (CDN hosts)
|
|
1596
|
+
getKeyAccessToken: config.streaming.getKeyAccessToken ?? (() => authManager.getAccessToken()),
|
|
1597
|
+
keyProxyMaxFailures: config.streaming.keyProxyMaxFailures,
|
|
1452
1598
|
hlsConfig: config.streaming.hls,
|
|
1453
1599
|
logger,
|
|
1454
1600
|
callbacks: {
|
|
@@ -1766,7 +1912,8 @@ function createVideoPlayer(options) {
|
|
|
1766
1912
|
engine: "hls",
|
|
1767
1913
|
hls: { ...config.streaming.hls, ...partial?.streaming?.hls },
|
|
1768
1914
|
keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder ?? config.streaming.keyProxyUrlBuilder,
|
|
1769
|
-
getKeyAccessToken: partial?.streaming?.getKeyAccessToken ?? config.streaming.getKeyAccessToken
|
|
1915
|
+
getKeyAccessToken: partial?.streaming?.getKeyAccessToken ?? config.streaming.getKeyAccessToken ?? (() => authManager.getAccessToken()),
|
|
1916
|
+
keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures ?? config.streaming.keyProxyMaxFailures
|
|
1770
1917
|
},
|
|
1771
1918
|
logging: { ...config.logging, ...partial?.logging },
|
|
1772
1919
|
debug: { ...config.debug, ...partial?.debug },
|
|
@@ -1797,6 +1944,7 @@ export {
|
|
|
1797
1944
|
DEFAULT_THEME,
|
|
1798
1945
|
DEFAULT_WATERMARK,
|
|
1799
1946
|
EventEmitter,
|
|
1947
|
+
KEY_PROXY_MAX_FAILURES,
|
|
1800
1948
|
PACKAGE_VERSION,
|
|
1801
1949
|
PLAYBACK_RATES,
|
|
1802
1950
|
PlaybackSourceManager,
|