@codenkay/video-nsgplayer-core 3.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 +8 -0
- package/dist/index.cjs +190 -83
- 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 +189 -83
- 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 = "
|
|
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 = "
|
|
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 = "
|
|
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,87 +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
|
-
|
|
920
|
-
|
|
921
|
-
}) : context.url;
|
|
922
|
-
context.url = rewriteHlsRequestUrl(originalUrl, store, options);
|
|
923
|
-
if (usingKeyProxy) {
|
|
924
|
-
const accessToken = options.getKeyAccessToken?.() ?? null;
|
|
925
|
-
if (!accessToken) {
|
|
926
|
-
this.inner.load(context, config, callbacks);
|
|
927
|
-
return;
|
|
1045
|
+
if (!isKey) {
|
|
1046
|
+
if (store.hasParams()) {
|
|
1047
|
+
context.url = rewriteHlsRequestUrl(originalUrl, store, {
|
|
1048
|
+
...options,
|
|
1049
|
+
keyProxyUrlBuilder: void 0
|
|
1050
|
+
});
|
|
928
1051
|
}
|
|
929
|
-
|
|
930
|
-
...callbacks,
|
|
931
|
-
onError: (error, errContext, networkDetails, stats) => {
|
|
932
|
-
const code = error?.code;
|
|
933
|
-
const retryable = code === 0 || code === 502 || code === 403 || code === 401 || /Cloudflare|HTML|DOCTYPE|blocked/i.test(error?.text ?? "");
|
|
934
|
-
if (!retryable) {
|
|
935
|
-
callbacks.onError(error, errContext, networkDetails, stats);
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
this.keyAbort?.abort();
|
|
939
|
-
this.keyAbort = new AbortController();
|
|
940
|
-
const bearerContext = { ...context, url: signedKeyUrl };
|
|
941
|
-
void loadEncryptionKeyWithFetch(
|
|
942
|
-
bearerContext,
|
|
943
|
-
callbacks,
|
|
944
|
-
accessToken,
|
|
945
|
-
this.keyAbort.signal
|
|
946
|
-
).catch((fetchError) => {
|
|
947
|
-
callbacks.onError(
|
|
948
|
-
{
|
|
949
|
-
code: 0,
|
|
950
|
-
text: fetchError instanceof Error ? fetchError.message : error.text || "enc.key proxy and Bearer fetch failed"
|
|
951
|
-
},
|
|
952
|
-
bearerContext,
|
|
953
|
-
null,
|
|
954
|
-
stats
|
|
955
|
-
);
|
|
956
|
-
});
|
|
957
|
-
}
|
|
958
|
-
};
|
|
959
|
-
this.inner.load(context, config, proxyCallbacks);
|
|
1052
|
+
this.inner.load(context, config, callbacks);
|
|
960
1053
|
return;
|
|
961
1054
|
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
}).finally(() => {
|
|
991
|
-
clearTimeout(timer);
|
|
992
|
-
});
|
|
993
|
-
return;
|
|
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);
|
|
994
1083
|
}
|
|
995
|
-
}
|
|
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;
|
|
996
1098
|
} catch {
|
|
997
1099
|
}
|
|
998
1100
|
this.inner.load(context, config, callbacks);
|
|
@@ -1062,7 +1164,8 @@ var HlsEngine = class {
|
|
|
1062
1164
|
const loader = createAuthParamsLoader(Hls, authParams, {
|
|
1063
1165
|
videoId,
|
|
1064
1166
|
keyProxyUrlBuilder,
|
|
1065
|
-
getKeyAccessToken
|
|
1167
|
+
getKeyAccessToken,
|
|
1168
|
+
keyProxyMaxFailures: this.options.keyProxyMaxFailures
|
|
1066
1169
|
});
|
|
1067
1170
|
this.hls = new Hls({
|
|
1068
1171
|
enableWorker: hlsConfig.enableWorker,
|
|
@@ -1487,10 +1590,11 @@ function createVideoPlayer(options) {
|
|
|
1487
1590
|
videoId: options.videoId,
|
|
1488
1591
|
keyProxyUrlBuilder: config.streaming.keyProxyUrlBuilder,
|
|
1489
1592
|
// Enterprise AES key auth:
|
|
1490
|
-
// 1) keyProxyUrlBuilder (same-origin BFF) when configured
|
|
1593
|
+
// 1) keyProxyUrlBuilder (same-origin BFF) when configured — max 2 failures
|
|
1491
1594
|
// 2) else getKeyAccessToken / AuthManager Bearer via browser fetch
|
|
1492
1595
|
// 3) else signed query + XHR (CDN hosts)
|
|
1493
1596
|
getKeyAccessToken: config.streaming.getKeyAccessToken ?? (() => authManager.getAccessToken()),
|
|
1597
|
+
keyProxyMaxFailures: config.streaming.keyProxyMaxFailures,
|
|
1494
1598
|
hlsConfig: config.streaming.hls,
|
|
1495
1599
|
logger,
|
|
1496
1600
|
callbacks: {
|
|
@@ -1808,7 +1912,8 @@ function createVideoPlayer(options) {
|
|
|
1808
1912
|
engine: "hls",
|
|
1809
1913
|
hls: { ...config.streaming.hls, ...partial?.streaming?.hls },
|
|
1810
1914
|
keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder ?? config.streaming.keyProxyUrlBuilder,
|
|
1811
|
-
getKeyAccessToken: partial?.streaming?.getKeyAccessToken ?? config.streaming.getKeyAccessToken ?? (() => authManager.getAccessToken())
|
|
1915
|
+
getKeyAccessToken: partial?.streaming?.getKeyAccessToken ?? config.streaming.getKeyAccessToken ?? (() => authManager.getAccessToken()),
|
|
1916
|
+
keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures ?? config.streaming.keyProxyMaxFailures
|
|
1812
1917
|
},
|
|
1813
1918
|
logging: { ...config.logging, ...partial?.logging },
|
|
1814
1919
|
debug: { ...config.debug, ...partial?.debug },
|
|
@@ -1839,6 +1944,7 @@ export {
|
|
|
1839
1944
|
DEFAULT_THEME,
|
|
1840
1945
|
DEFAULT_WATERMARK,
|
|
1841
1946
|
EventEmitter,
|
|
1947
|
+
KEY_PROXY_MAX_FAILURES,
|
|
1842
1948
|
PACKAGE_VERSION,
|
|
1843
1949
|
PLAYBACK_RATES,
|
|
1844
1950
|
PlaybackSourceManager,
|