@codenkay/video-nsgplayer-core 4.0.0 → 5.1.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors/PlayerError.ts","../src/auth/AuthManager.ts","../src/config/defaults.ts","../src/events/EventEmitter.ts","../src/security/redaction.ts","../src/logging/Logger.ts","../src/auth/AuthParamsStore.ts","../src/playback/PlaybackSourceManager.ts","../src/playback/RefreshManager.ts","../src/playback/liveEdge.ts","../src/streaming/authParamsLoader.ts","../src/streaming/HlsEngine.ts","../src/player/createVideoPlayer.ts"],"sourcesContent":["export { createVideoPlayer, type VideoPlayer } from \"./player/createVideoPlayer\";\nexport {\n DEFAULT_PLAYER_CONFIG,\n DEFAULT_PLAYER_BEHAVIOR,\n DEFAULT_CONTROLS,\n DEFAULT_THEME,\n DEFAULT_WATERMARK,\n PLAYBACK_RATES,\n PACKAGE_VERSION,\n mergePlayerConfig,\n themeToCssVars,\n assertNoSecretsInConfig,\n isPlainObject,\n SECRET_SCAN_MAX_DEPTH,\n} from \"./config/defaults\";\nexport {\n PlayerErrorCode,\n createPlayerError,\n redactSensitive,\n type PlayerError,\n} from \"./errors/PlayerError\";\nexport { AuthParamsStore } from \"./auth/AuthParamsStore\";\nexport { AuthManager } from \"./auth/AuthManager\";\nexport { PlaybackSourceManager } from \"./playback/PlaybackSourceManager\";\nexport { RefreshManager } from \"./playback/RefreshManager\";\nexport {\n rewriteHlsRequestUrl,\n createAuthParamsLoader,\n resolveBuiltinHlsLoader,\n isEncryptionKeyUrl,\n KEY_PROXY_MAX_FAILURES,\n type HlsModuleLike,\n type HlsLoaderConstructor,\n} from \"./streaming/authParamsLoader\";\nexport {\n DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS,\n getLiveEdgeTime,\n isAtLiveEdge,\n seekToLiveEdge,\n type LiveMediaSnapshot,\n type SeekToLiveResult,\n} from \"./playback/liveEdge\";\nexport { EventEmitter } from \"./events/EventEmitter\";\nexport { redactObject, redactValue } from \"./security/redaction\";\nexport type * from \"./types\";\n","export enum PlayerErrorCode {\n INVALID_CONFIGURATION = \"INVALID_CONFIGURATION\",\n AUTHENTICATION_FAILED = \"AUTHENTICATION_FAILED\",\n AUTH_TOKEN_REFRESH_FAILED = \"AUTH_TOKEN_REFRESH_FAILED\",\n TOKEN_EXPIRED = \"TOKEN_EXPIRED\",\n TOKEN_REFRESH_FAILED = \"TOKEN_REFRESH_FAILED\",\n SOURCE_RESOLUTION_FAILED = \"SOURCE_RESOLUTION_FAILED\",\n MANIFEST_LOAD_FAILED = \"MANIFEST_LOAD_FAILED\",\n SEGMENT_LOAD_FAILED = \"SEGMENT_LOAD_FAILED\",\n NETWORK_ERROR = \"NETWORK_ERROR\",\n PLAYBACK_ERROR = \"PLAYBACK_ERROR\",\n UNSUPPORTED_BROWSER = \"UNSUPPORTED_BROWSER\",\n AUTOPLAY_BLOCKED = \"AUTOPLAY_BLOCKED\",\n UNKNOWN = \"UNKNOWN\",\n}\n\nexport type PlayerError = {\n code: PlayerErrorCode;\n message: string;\n category: \"config\" | \"auth\" | \"network\" | \"playback\" | \"unknown\";\n fatal: boolean;\n retryable: boolean;\n timestamp: number;\n cause?: unknown;\n};\n\nexport function createPlayerError(\n code: PlayerErrorCode,\n message: string,\n options?: Partial<Omit<PlayerError, \"code\" | \"message\" | \"timestamp\">>,\n): PlayerError {\n return {\n code,\n message: redactSensitive(message),\n category: options?.category ?? \"unknown\",\n fatal: options?.fatal ?? true,\n retryable: options?.retryable ?? false,\n timestamp: Date.now(),\n cause: options?.cause,\n };\n}\n\nexport function redactSensitive(input: string): string {\n return input\n .replace(/(Bearer\\s+)[^\\s]+/gi, \"$1[REDACTED]\")\n .replace(/([?&](token|expires|signature|sig)=)[^&]+/gi, \"$1[REDACTED]\")\n .replace(/(Authorization:\\s*)[^\\s]+/gi, \"$1[REDACTED]\");\n}\n","import {\n createPlayerError,\n PlayerErrorCode,\n} from \"../errors/PlayerError\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n AuthConfig,\n AuthToken,\n AuthTokenProviderContext,\n} from \"../types\";\n\n/**\n * Manages provider auth-token lifecycle (independent from signed playback URL).\n * Single-flight refresh; never stores clientSecret.\n * Unauthorized recoveries are bounded to prevent infinite 401 → refresh loops.\n */\nexport class AuthManager {\n private token: AuthToken | null = null;\n private inFlight: Promise<AuthToken> | null = null;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private destroyed = false;\n /** Consecutive unauthorized refresh attempts (reset on success). */\n private unauthorizedAttempts = 0;\n private readonly maxUnauthorizedRetries: number;\n\n constructor(\n private readonly auth: AuthConfig | undefined,\n private readonly refreshBeforeExpiryMs: number,\n private readonly logger: Logger,\n private readonly onRefreshed?: (token: AuthToken) => void,\n private readonly onError?: (message: string, retryable: boolean) => void,\n maxUnauthorizedRetries = 1,\n ) {\n this.maxUnauthorizedRetries = Math.max(0, maxUnauthorizedRetries);\n }\n\n getAccessToken(): string | null {\n return this.token?.accessToken ?? null;\n }\n\n getExpiresAt(): number | null {\n return this.token?.expiresAt ?? null;\n }\n\n async ensureToken(\n context: AuthTokenProviderContext,\n ): Promise<AuthToken | null> {\n if (!this.auth?.getToken) return null;\n if (this.destroyed) return null;\n\n if (\n this.token &&\n context.reason !== \"unauthorized\" &&\n context.reason !== \"manual\" &&\n this.token.expiresAt - Date.now() > this.refreshBeforeExpiryMs\n ) {\n return this.token;\n }\n\n return this.refresh(context);\n }\n\n async refresh(context: AuthTokenProviderContext): Promise<AuthToken> {\n if (!this.auth?.getToken) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"auth.getToken is required for authenticated playback\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n\n if (context.reason === \"unauthorized\") {\n if (this.unauthorizedAttempts >= this.maxUnauthorizedRetries) {\n const message =\n \"Auth token refresh aborted: exceeded bounded unauthorized retry limit\";\n this.onError?.(message, false);\n throw createPlayerError(\n PlayerErrorCode.AUTH_TOKEN_REFRESH_FAILED,\n message,\n { category: \"auth\", fatal: true, retryable: false },\n );\n }\n this.unauthorizedAttempts += 1;\n }\n\n if (this.inFlight) return this.inFlight;\n\n this.inFlight = (async () => {\n try {\n const next = await this.auth!.getToken(context);\n if (\n !next?.accessToken ||\n typeof next.expiresAt !== \"number\" ||\n next.expiresAt <= 0\n ) {\n throw createPlayerError(\n PlayerErrorCode.AUTHENTICATION_FAILED,\n \"auth.getToken returned an invalid token payload\",\n { category: \"auth\", fatal: true, retryable: true },\n );\n }\n this.token = next;\n if (context.reason !== \"unauthorized\") {\n this.unauthorizedAttempts = 0;\n }\n this.scheduleProactiveRefresh();\n this.onRefreshed?.(next);\n this.logger.debug(\"Auth token refreshed\", {\n reason: context.reason,\n expiresAt: next.expiresAt,\n });\n return next;\n } catch (error) {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n (error as { code: string }).code ===\n PlayerErrorCode.AUTH_TOKEN_REFRESH_FAILED\n ) {\n throw error;\n }\n const message =\n error instanceof Error ? error.message : \"Auth token refresh failed\";\n const retryable = this.unauthorizedAttempts <= this.maxUnauthorizedRetries;\n this.onError?.(message, retryable);\n throw createPlayerError(\n PlayerErrorCode.AUTH_TOKEN_REFRESH_FAILED,\n message,\n { category: \"auth\", fatal: !retryable, retryable, cause: error },\n );\n } finally {\n this.inFlight = null;\n }\n })();\n\n return this.inFlight;\n }\n\n private scheduleProactiveRefresh(): void {\n if (this.timer) clearTimeout(this.timer);\n if (!this.token || this.destroyed) return;\n const delay = Math.max(\n 5_000,\n this.token.expiresAt - Date.now() - this.refreshBeforeExpiryMs,\n );\n this.timer = setTimeout(() => {\n void this.refresh({\n reason: \"expiring\",\n videoId: undefined,\n }).catch(() => {\n /* onError already notified */\n });\n }, delay);\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n this.token = null;\n this.inFlight = null;\n }\n}\n","import type {\n ControlsConfig,\n PlayerBehaviorConfig,\n PlayerConfig,\n ThemeConfig,\n WatermarkConfig,\n} from \"../types\";\n\nexport const PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 2] as const;\n\nexport const PACKAGE_VERSION = \"3.0.3\";\n\nexport const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig> = {\n autoplay: true,\n startMuted: true,\n volume: 1,\n startPosition: 0,\n skipSeconds: 10,\n speedOptionCount: PLAYBACK_RATES.length,\n zoomEnabled: true,\n defaultZoom: 1,\n playbackRates: PLAYBACK_RATES,\n};\n\nexport const DEFAULT_CONTROLS: Required<ControlsConfig> = {\n enabled: true,\n showQuality: true,\n showSpeed: true,\n showCaptions: true,\n showAudio: true,\n showVolume: true,\n showFullscreen: true,\n showZoom: true,\n showSkip: true,\n showLive: true,\n seekCueDurationMs: 720,\n keyboardShortcuts: true,\n persistQualityPreference: false,\n};\n\nexport const DEFAULT_THEME: Required<ThemeConfig> = {\n playIconPreset: \"triangle\",\n playButtonBackground: \"#ffffff\",\n playButtonIconColor: \"#ffffff\",\n seekTrackColor: \"#334155\",\n seekProgressColor: \"#38bdf8\",\n seekBufferedColor: \"#64748b\",\n timeColor: \"#e2e8f0\",\n controlIconColor: \"#f1f5f9\",\n focusRingColor: \"#38bdf8\",\n spinnerColor: \"#38bdf8\",\n volumeIconColor: \"#f1f5f9\",\n volumeTrackColor: \"#334155\",\n volumeProgressColor: \"#38bdf8\",\n qualityOptionTextColor: \"#e2e8f0\",\n qualityOptionBackground: \"#020617\",\n qualityOptionActiveBackground: \"#0c4a6e\",\n qualityOptionActiveTextColor: \"#bae6fd\",\n speedOptionTextColor: \"#e2e8f0\",\n speedOptionBackground: \"#020617\",\n speedOptionActiveBackground: \"#0c4a6e\",\n speedOptionActiveTextColor: \"#bae6fd\",\n zoomIconColor: \"#f1f5f9\",\n skipIconColor: \"#f1f5f9\",\n skipCueBackground: \"#ffffff\",\n skipCueTextColor: \"#ffffff\",\n liveDotColor: \"#ef4444\",\n};\n\nexport const DEFAULT_WATERMARK: Required<WatermarkConfig> = {\n enabled: true,\n text: \"\",\n durationMs: 10_000,\n intervalMaxMs: 300_000,\n};\n\nexport const DEFAULT_PLAYER_CONFIG: PlayerConfig = {\n player: DEFAULT_PLAYER_BEHAVIOR,\n controls: DEFAULT_CONTROLS,\n theme: DEFAULT_THEME,\n watermark: DEFAULT_WATERMARK,\n streaming: {\n engine: \"hls\",\n hls: {\n enableWorker: true,\n // VOD + AES-128: LL mode causes ABR thrash → bufferAppendError on MSE.\n lowLatencyMode: false,\n backBufferLength: 90,\n fatalRecoveryLimit: 3,\n },\n },\n logging: { enabled: false, level: \"error\" },\n debug: { enabled: false, network: false, events: false, state: false },\n accessibility: { reducedMotion: false },\n};\n\nconst FORBIDDEN_SECRET_KEYS = [\n \"clientsecret\",\n \"apisecret\",\n \"privatekey\",\n \"video_api_secret\",\n \"basicauthpassword\",\n \"password\",\n] as const;\n\n/** Never descend into these — DOM hosts or credential callback bags. */\nconst SKIP_DEEP_SCAN_KEYS = new Set([\n \"mount\",\n \"auth\",\n \"playback\",\n \"gettoken\",\n \"getsource\",\n \"refreshsource\",\n \"keyproxyurlbuilder\",\n \"getkeyaccesstoken\",\n]);\n\n/** Hard cap so pathological graphs cannot blow the stack. */\nexport const SECRET_SCAN_MAX_DEPTH = 32;\n\n/**\n * True only for JSON-like plain objects (`{}` / `Object.create(null)`).\n * Excludes DOM nodes, class instances, arrays, dates, etc.\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n if (Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction normalizeConfigKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nfunction isForbiddenSecretKey(key: string): boolean {\n const lower = normalizeConfigKey(key);\n return FORBIDDEN_SECRET_KEYS.some((k) => lower.includes(k));\n}\n\nfunction throwForbidden(path: string, key: string): never {\n throw new Error(\n `INVALID_CONFIGURATION: Forbidden secret key \"${path}${key}\" must never be passed to the browser SDK. Keep clientSecret on your server/BFF and use auth.getToken().`,\n );\n}\n\n/**\n * Scans plain config objects for forbidden secret key names.\n *\n * Enterprise guarantees:\n * - Never deep-walks DOM / host / class instances (plain-object only)\n * - Does not descend into `mount` / `auth` / `playback` (shallow key check only)\n * - Cycle-safe via WeakSet\n * - Depth-capped + iterative (no call-stack recursion)\n */\nexport function assertNoSecretsInConfig(raw: unknown): void {\n if (!isPlainObject(raw) && !Array.isArray(raw)) return;\n\n const seen = new WeakSet<object>();\n const stack: Array<{ value: unknown; path: string; depth: number }> = [\n { value: raw, path: \"\", depth: 0 },\n ];\n\n while (stack.length > 0) {\n const current = stack.pop()!;\n if (current.depth > SECRET_SCAN_MAX_DEPTH) continue;\n\n const { value, path, depth } = current;\n\n if (Array.isArray(value)) {\n if (seen.has(value)) continue;\n seen.add(value);\n for (let i = 0; i < value.length; i += 1) {\n const item = value[i];\n if (isPlainObject(item) || Array.isArray(item)) {\n stack.push({ value: item, path: `${path}[${i}]`, depth: depth + 1 });\n }\n }\n continue;\n }\n\n if (!isPlainObject(value)) continue;\n if (seen.has(value)) continue;\n seen.add(value);\n\n for (const [key, child] of Object.entries(value)) {\n const normalized = normalizeConfigKey(key);\n\n if (isForbiddenSecretKey(key)) {\n throwForbidden(path, key);\n }\n\n // mount: host node — never inspect further\n if (normalized === \"mount\") continue;\n\n // auth / playback / callback fields: shallow secret-key check only\n if (SKIP_DEEP_SCAN_KEYS.has(normalized)) {\n if (isPlainObject(child)) {\n for (const nestedKey of Object.keys(child)) {\n if (isForbiddenSecretKey(nestedKey)) {\n throwForbidden(`${path}${key}.`, nestedKey);\n }\n }\n }\n continue;\n }\n\n if (isPlainObject(child) || Array.isArray(child)) {\n stack.push({\n value: child,\n path: path ? `${path}${key}.` : `${key}.`,\n depth: depth + 1,\n });\n }\n }\n }\n}\n\nexport type PlayerConfigPartial = Partial<{\n player: Partial<PlayerBehaviorConfig>;\n controls: Partial<ControlsConfig>;\n theme: Partial<ThemeConfig>;\n watermark: Partial<WatermarkConfig>;\n streaming: {\n engine?: \"hls\";\n hls?: Partial<PlayerConfig[\"streaming\"][\"hls\"]>;\n keyProxyUrlBuilder?: PlayerConfig[\"streaming\"][\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: PlayerConfig[\"streaming\"][\"getKeyAccessToken\"];\n keyProxyMaxFailures?: PlayerConfig[\"streaming\"][\"keyProxyMaxFailures\"];\n };\n logging: Partial<PlayerConfig[\"logging\"]>;\n debug: Partial<PlayerConfig[\"debug\"]>;\n accessibility: Partial<PlayerConfig[\"accessibility\"]>;\n}>;\n\nexport function mergePlayerConfig(partial?: PlayerConfigPartial): PlayerConfig {\n assertNoSecretsInConfig(partial);\n return {\n player: { ...DEFAULT_PLAYER_BEHAVIOR, ...partial?.player },\n controls: { ...DEFAULT_CONTROLS, ...partial?.controls },\n theme: { ...DEFAULT_THEME, ...partial?.theme },\n watermark: { ...DEFAULT_WATERMARK, ...partial?.watermark },\n streaming: {\n engine: \"hls\",\n hls: {\n ...DEFAULT_PLAYER_CONFIG.streaming.hls,\n ...partial?.streaming?.hls,\n },\n keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder,\n getKeyAccessToken: partial?.streaming?.getKeyAccessToken,\n keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures,\n },\n logging: { ...DEFAULT_PLAYER_CONFIG.logging, ...partial?.logging },\n debug: { ...DEFAULT_PLAYER_CONFIG.debug, ...partial?.debug },\n accessibility: {\n ...DEFAULT_PLAYER_CONFIG.accessibility,\n ...partial?.accessibility,\n },\n };\n}\n\n/** Maps theme colors to CSS custom properties for UI adapters. */\nexport function themeToCssVars(\n theme: Required<ThemeConfig>,\n): Record<string, string> {\n return {\n \"--player-play-btn-bg\": theme.playButtonBackground,\n \"--player-play-btn-icon\": theme.playButtonIconColor,\n \"--player-seek-track\": theme.seekTrackColor,\n \"--player-seek-progress\": theme.seekProgressColor,\n \"--player-seek-buffered\": theme.seekBufferedColor,\n \"--player-time\": theme.timeColor,\n \"--player-control-icon\": theme.controlIconColor,\n \"--player-focus-ring\": theme.focusRingColor,\n \"--player-spinner\": theme.spinnerColor,\n \"--player-volume-icon\": theme.volumeIconColor,\n \"--player-volume-track\": theme.volumeTrackColor,\n \"--player-volume-progress\": theme.volumeProgressColor,\n \"--player-quality-text\": theme.qualityOptionTextColor,\n \"--player-quality-bg\": theme.qualityOptionBackground,\n \"--player-quality-active-bg\": theme.qualityOptionActiveBackground,\n \"--player-quality-active-text\": theme.qualityOptionActiveTextColor,\n \"--player-speed-text\": theme.speedOptionTextColor,\n \"--player-speed-bg\": theme.speedOptionBackground,\n \"--player-speed-active-bg\": theme.speedOptionActiveBackground,\n \"--player-speed-active-text\": theme.speedOptionActiveTextColor,\n \"--player-zoom-icon\": theme.zoomIconColor,\n \"--player-skip-icon\": theme.skipIconColor,\n \"--player-skip-cue-bg\": theme.skipCueBackground,\n \"--player-skip-cue-text\": theme.skipCueTextColor,\n \"--player-live-dot\": theme.liveDotColor,\n };\n}\n","import type { PlayerEventMap } from \"../types\";\n\ntype Handler<T> = T extends void ? () => void : (payload: T) => void;\n\nexport class EventEmitter {\n private listeners = new Map<keyof PlayerEventMap, Set<Function>>();\n\n on<K extends keyof PlayerEventMap>(\n event: K,\n handler: Handler<PlayerEventMap[K]>,\n ): () => void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(handler);\n return () => this.off(event, handler);\n }\n\n off<K extends keyof PlayerEventMap>(\n event: K,\n handler: Handler<PlayerEventMap[K]>,\n ): void {\n this.listeners.get(event)?.delete(handler);\n }\n\n emit<K extends keyof PlayerEventMap>(\n event: K,\n ...args: PlayerEventMap[K] extends void ? [] : [PlayerEventMap[K]]\n ): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const handler of set) {\n try {\n (handler as Function)(...args);\n } catch {\n // never let listener failures break the player\n }\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","const SENSITIVE_KEYS =\n /^(authorization|cookie|set-cookie|x-api-key|token|accessToken|access_token|clientSecret|password)$/i;\n\nconst REDACT_MAX_DEPTH = 32;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n if (Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction redactStringUrl(value: string): string {\n if (!/^https?:\\/\\//i.test(value) || !/[?&](token|expires)=/i.test(value)) {\n return value;\n }\n try {\n const url = new URL(value);\n for (const param of [\"token\", \"expires\", \"signature\", \"sig\"]) {\n if (url.searchParams.has(param)) {\n url.searchParams.set(param, \"[REDACTED]\");\n }\n }\n return url.toString();\n } catch {\n return \"[REDACTED_URL]\";\n }\n}\n\nexport function redactValue(\n key: string,\n value: unknown,\n seen: WeakSet<object> = new WeakSet(),\n depth = 0,\n): unknown {\n if (SENSITIVE_KEYS.test(key)) return \"[REDACTED]\";\n if (typeof value === \"string\") return redactStringUrl(value);\n if (Array.isArray(value)) {\n if (depth >= REDACT_MAX_DEPTH || seen.has(value)) return \"[REDACTED_CYCLE]\";\n seen.add(value);\n return value.map((item, index) =>\n redactValue(String(index), item, seen, depth + 1),\n );\n }\n if (isPlainObject(value)) {\n return redactObject(value, seen, depth + 1);\n }\n return value;\n}\n\n/**\n * Redacts sensitive fields. Cycle-safe and depth-capped.\n * Only walks plain objects/arrays — never DOM / host graphs.\n */\nexport function redactObject(\n obj: Record<string, unknown>,\n seen: WeakSet<object> = new WeakSet(),\n depth = 0,\n): Record<string, unknown> {\n if (depth > REDACT_MAX_DEPTH) return { \"[REDACTED]\": \"max_depth\" };\n if (seen.has(obj)) return { \"[REDACTED]\": \"cycle\" };\n seen.add(obj);\n\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n out[key] = redactValue(key, value, seen, depth);\n }\n return out;\n}\n","import { redactObject } from \"../security/redaction\";\nimport type { LoggingConfig } from \"../types\";\n\nconst LEVELS = [\"silent\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"] as const;\n\nexport class Logger {\n constructor(private config: Required<LoggingConfig>) {}\n\n update(config: Partial<LoggingConfig>): void {\n this.config = { ...this.config, ...config } as Required<LoggingConfig>;\n }\n\n private shouldLog(level: (typeof LEVELS)[number]): boolean {\n if (!this.config.enabled || this.config.level === \"silent\") return false;\n return LEVELS.indexOf(level) <= LEVELS.indexOf(this.config.level);\n }\n\n private write(\n level: \"error\" | \"warn\" | \"info\" | \"debug\",\n message: string,\n details?: Record<string, unknown>,\n ): void {\n if (!this.shouldLog(level)) return;\n const payload = details ? redactObject(details) : undefined;\n const fn = console[level] ?? console.log;\n if (payload) fn(`[nsg-player] ${message}`, payload);\n else fn(`[nsg-player] ${message}`);\n }\n\n error(message: string, details?: Record<string, unknown>): void {\n this.write(\"error\", message, details);\n }\n\n warn(message: string, details?: Record<string, unknown>): void {\n this.write(\"warn\", message, details);\n }\n\n info(message: string, details?: Record<string, unknown>): void {\n this.write(\"info\", message, details);\n }\n\n debug(message: string, details?: Record<string, unknown>): void {\n this.write(\"debug\", message, details);\n }\n}\n","/**\n * Mutable store of the latest playback authorization query parameters.\n * Updated on renewal without recreating the HLS player.\n */\nexport class AuthParamsStore {\n private params: URLSearchParams;\n\n constructor(initial?: URLSearchParams | Record<string, string>) {\n if (initial instanceof URLSearchParams) {\n this.params = new URLSearchParams(initial);\n } else if (initial) {\n this.params = new URLSearchParams(initial);\n } else {\n this.params = new URLSearchParams();\n }\n }\n\n getSnapshot(): URLSearchParams {\n return new URLSearchParams(this.params);\n }\n\n toRecord(): Record<string, string> {\n const out: Record<string, string> = {};\n this.params.forEach((value, key) => {\n out[key] = value;\n });\n return out;\n }\n\n /** True when at least one auth query param is stored. */\n hasParams(): boolean {\n return [...this.params.keys()].length > 0;\n }\n\n toString(): string {\n return this.params.toString();\n }\n\n update(next: URLSearchParams | Record<string, string>): void {\n this.params =\n next instanceof URLSearchParams\n ? new URLSearchParams(next)\n : new URLSearchParams(next);\n }\n\n /**\n * Merges current auth params onto a target URL, preserving unrelated query keys.\n * Critical for child HLS playlists/segments that omit signed query params.\n */\n applyToUrl(rawUrl: string, baseOrigin?: string): string {\n const target = new URL(\n rawUrl,\n baseOrigin ??\n (typeof location !== \"undefined\" ? location.origin : \"http://localhost\"),\n );\n this.params.forEach((value, key) => {\n target.searchParams.set(key, value);\n });\n return target.toString();\n }\n}\n","import {\n createPlayerError,\n PlayerErrorCode,\n} from \"../errors/PlayerError\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n PlaybackCredentialConfig,\n PlaybackSource,\n PlaybackSourceContext,\n} from \"../types\";\nimport { AuthParamsStore } from \"../auth/AuthParamsStore\";\n\n/**\n * Resolves and refreshes signed playback sources via consumer callbacks.\n */\nexport class PlaybackSourceManager {\n private source: PlaybackSource | null = null;\n private inFlight: Promise<PlaybackSource> | null = null;\n readonly authParams = new AuthParamsStore();\n\n constructor(\n private readonly playback: PlaybackCredentialConfig | undefined,\n private readonly logger: Logger,\n ) {}\n\n getSource(): PlaybackSource | null {\n return this.source;\n }\n\n getExpiresAt(): number | null {\n return this.source?.expiresAt ?? null;\n }\n\n async load(\n context: PlaybackSourceContext,\n ): Promise<PlaybackSource> {\n if (!this.playback?.getSource) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"playback.getSource is required when not using sourceUrl\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n return this.run(context, () => this.playback!.getSource(context));\n }\n\n async refresh(\n context: PlaybackSourceContext,\n ): Promise<PlaybackSource> {\n const refresher =\n this.playback?.refreshSource ?? this.playback?.getSource;\n if (!refresher) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"playback.refreshSource or playback.getSource is required\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n return this.run(context, () => refresher(context));\n }\n\n applyDirectSource(source: PlaybackSource): void {\n this.source = source;\n this.applyAuthParams(source);\n }\n\n private async run(\n context: PlaybackSourceContext,\n fn: () => Promise<PlaybackSource>,\n ): Promise<PlaybackSource> {\n if (this.inFlight) return this.inFlight;\n\n this.inFlight = (async () => {\n try {\n const next = await fn();\n if (!next?.url || typeof next.expiresAt !== \"number\") {\n throw createPlayerError(\n PlayerErrorCode.SOURCE_RESOLUTION_FAILED,\n \"Playback source callback returned an invalid payload\",\n { category: \"playback\", fatal: true, retryable: true },\n );\n }\n this.source = next;\n this.applyAuthParams(next);\n this.logger.debug(\"Playback source resolved\", {\n reason: context.reason,\n expiresAt: next.expiresAt,\n });\n return next;\n } catch (error) {\n if (error && typeof error === \"object\" && \"code\" in error) throw error;\n throw createPlayerError(\n PlayerErrorCode.SOURCE_RESOLUTION_FAILED,\n error instanceof Error ? error.message : \"Source resolution failed\",\n { category: \"playback\", fatal: true, retryable: true, cause: error },\n );\n } finally {\n this.inFlight = null;\n }\n })();\n\n return this.inFlight;\n }\n\n private applyAuthParams(source: PlaybackSource): void {\n if (source.authParams) {\n this.authParams.update(source.authParams);\n return;\n }\n try {\n const url = new URL(source.url);\n const params: Record<string, string> = {};\n url.searchParams.forEach((value, key) => {\n params[key] = value;\n });\n if (source.token) params.token = source.token;\n this.authParams.update(params);\n } catch {\n if (source.token) {\n this.authParams.update({ token: source.token });\n }\n }\n }\n\n destroy(): void {\n this.source = null;\n this.inFlight = null;\n }\n}\n","import type { AuthManager } from \"../auth/AuthManager\";\nimport type { Logger } from \"../logging/Logger\";\nimport type { PlaybackSourceManager } from \"./PlaybackSourceManager\";\n\nexport type RefreshReason =\n | \"proactive\"\n | \"frag_error\"\n | \"level_error\"\n | \"key_error\"\n | \"fatal_network\"\n | \"manual\";\n\nexport type RefreshManagerOptions = {\n videoId: string;\n authManager: AuthManager;\n sourceManager: PlaybackSourceManager;\n refreshBeforeExpiryMs: number;\n renewMaxRetries: number;\n renewBackoffMs: number;\n coalesceMs: number;\n logger: Logger;\n isDestroyed: () => boolean;\n onRenewing?: () => void;\n onRenewed?: (expiresAt: number) => void;\n onFatal?: (message: string) => void;\n};\n\n/**\n * Schedules signed-URL renewal (playback clock) with single-flight + coalesce.\n * Ensures auth token is fresh before calling refreshSource.\n */\nexport class RefreshManager {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private coalesceTimer: ReturnType<typeof setTimeout> | null = null;\n private inFlight = false;\n private consecutiveFailures = 0;\n private stopped = false;\n private pendingReason: RefreshReason | null = null;\n\n constructor(private readonly options: RefreshManagerOptions) {}\n\n start(initialExpiresAt: number): void {\n this.schedule(initialExpiresAt);\n }\n\n requestRenew(reason: RefreshReason = \"frag_error\"): void {\n if (this.stopped || this.options.isDestroyed()) return;\n this.pendingReason = reason;\n if (this.coalesceTimer) return;\n this.coalesceTimer = setTimeout(() => {\n this.coalesceTimer = null;\n const reasonToUse = this.pendingReason ?? \"frag_error\";\n this.pendingReason = null;\n void this.renew(reasonToUse);\n }, this.options.coalesceMs);\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer) clearTimeout(this.timer);\n if (this.coalesceTimer) clearTimeout(this.coalesceTimer);\n this.timer = null;\n this.coalesceTimer = null;\n }\n\n private schedule(expiresAt: number): void {\n if (this.timer) clearTimeout(this.timer);\n if (this.stopped) return;\n const delay = Math.max(\n 5_000,\n expiresAt - Date.now() - this.options.refreshBeforeExpiryMs,\n );\n this.timer = setTimeout(() => {\n void this.renew(\"proactive\");\n }, delay);\n }\n\n private async renew(reason: RefreshReason): Promise<void> {\n if (this.stopped || this.options.isDestroyed() || this.inFlight) {\n if (this.inFlight) this.pendingReason = reason;\n return;\n }\n this.inFlight = true;\n this.options.onRenewing?.();\n\n try {\n await this.options.authManager.ensureToken({\n reason: reason === \"proactive\" ? \"expiring\" : \"unauthorized\",\n videoId: this.options.videoId,\n });\n\n const source = await this.options.sourceManager.refresh({\n videoId: this.options.videoId,\n reason:\n reason === \"proactive\"\n ? \"expiring\"\n : reason === \"manual\"\n ? \"manual\"\n : \"auth_error\",\n });\n\n this.consecutiveFailures = 0;\n this.options.onRenewed?.(source.expiresAt);\n this.schedule(source.expiresAt);\n this.options.logger.debug(\"Playback source renewed\", { reason });\n } catch (error) {\n this.consecutiveFailures += 1;\n const message = refreshErrorMessage(error);\n this.options.logger.warn(\"Playback refresh failed\", {\n reason,\n failure: this.consecutiveFailures,\n message,\n });\n\n if (this.consecutiveFailures >= this.options.renewMaxRetries) {\n this.options.onFatal?.(message);\n } else {\n const backoff =\n this.options.renewBackoffMs * this.consecutiveFailures;\n this.timer = setTimeout(() => {\n void this.renew(reason);\n }, backoff);\n }\n } finally {\n this.inFlight = false;\n if (this.pendingReason && !this.stopped) {\n const pending = this.pendingReason;\n this.pendingReason = null;\n void this.renew(pending);\n }\n }\n }\n}\n\nfunction refreshErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof (error as { message: unknown }).message === \"string\" &&\n (error as { message: string }).message\n ) {\n return (error as { message: string }).message;\n }\n return \"Playback refresh failed\";\n}\n","/**\n * Live-edge helpers for HLS DVR / live streams.\n * Uses HTMLMediaElement.seekable when available; falls back to duration.\n */\n\nexport const DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS = 3;\n\nexport type SeekableLike = {\n length: number;\n start: (index: number) => number;\n end: (index: number) => number;\n};\n\nexport type LiveMediaSnapshot = {\n currentTime: number;\n duration: number;\n seekable: SeekableLike;\n};\n\n/**\n * Returns the latest seekable end (live edge), or null when unknown.\n */\nexport function getLiveEdgeTime(\n media: Pick<LiveMediaSnapshot, \"duration\" | \"seekable\">,\n): number | null {\n const { seekable, duration } = media;\n try {\n if (seekable.length > 0) {\n const end = seekable.end(seekable.length - 1);\n if (Number.isFinite(end) && end >= 0) {\n return end;\n }\n }\n } catch {\n // Some browsers throw while seekable is updating mid-load.\n }\n\n if (Number.isFinite(duration) && duration > 0) {\n return duration;\n }\n\n return null;\n}\n\n/**\n * True when playback is within `toleranceSeconds` of the live edge.\n */\nexport function isAtLiveEdge(\n media: LiveMediaSnapshot,\n toleranceSeconds: number = DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS,\n): boolean {\n const edge = getLiveEdgeTime(media);\n if (edge === null) {\n return true;\n }\n const lag = edge - media.currentTime;\n return lag <= Math.max(0, toleranceSeconds);\n}\n\nexport type SeekToLiveResult =\n | { moved: true; edge: number }\n | { moved: false; reason: \"already_at_live\" | \"edge_unavailable\"; edge: number | null };\n\nexport type SeekableMediaElement = {\n currentTime: number;\n duration: number;\n seekable: SeekableLike;\n};\n\n/**\n * Seeks to the live edge. Returns whether the playhead moved.\n */\nexport function seekToLiveEdge(\n media: SeekableMediaElement,\n options?: {\n toleranceSeconds?: number;\n /** Leave a tiny buffer behind the absolute end for decoder stability. */\n edgeOffsetSeconds?: number;\n },\n): SeekToLiveResult {\n const tolerance =\n options?.toleranceSeconds ?? DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS;\n const edgeOffset = options?.edgeOffsetSeconds ?? 0.25;\n const edge = getLiveEdgeTime(media);\n\n if (edge === null) {\n return { moved: false, reason: \"edge_unavailable\", edge: null };\n }\n\n if (isAtLiveEdge(media, tolerance)) {\n return { moved: false, reason: \"already_at_live\", edge };\n }\n\n const target = Math.max(0, edge - edgeOffset);\n media.currentTime = target;\n return { moved: true, edge };\n}\n","import type { AuthParamsStore } from \"../auth/AuthParamsStore\";\nimport type { StreamingConfig } from \"../types\";\n\n/**\n * Local loader types (structurally compatible with hls.js) so the public\n * `.d.ts` does not require a value import of optional peer `hls.js`.\n */\ntype HlsLoaderTiming = { start: number; first: number; end: number };\n\ntype LoaderStats = {\n aborted: boolean;\n loaded: number;\n retry: number;\n total: number;\n chunkCount: number;\n bwEstimate: number;\n loading: HlsLoaderTiming;\n parsing: { start: number; end: number };\n buffering: HlsLoaderTiming;\n};\n\ntype LoaderContext = {\n url: string;\n responseType?: string;\n rangeStart?: number;\n rangeEnd?: number;\n progressData?: boolean;\n [key: string]: unknown;\n};\n\ntype LoaderConfiguration = {\n timeout?: number;\n};\n\ntype LoaderCallbacks<TContext> = {\n onSuccess: (\n response: { url: string; data: ArrayBuffer | string; code?: number },\n stats: LoaderStats,\n context: TContext,\n networkDetails: unknown,\n ) => void;\n onError: (\n error: { code: number; text: string },\n context: TContext,\n networkDetails: unknown,\n stats: LoaderStats,\n ) => void;\n onTimeout?: (...args: unknown[]) => void;\n onAbort?: (...args: unknown[]) => void;\n onProgress?: (...args: unknown[]) => void;\n};\n\ntype HlsLoaderInstance = {\n stats: LoaderStats;\n context: LoaderContext | null;\n load(\n context: LoaderContext,\n config: LoaderConfiguration,\n callbacks: LoaderCallbacks<LoaderContext>,\n ): void;\n destroy(): void;\n abort(): void;\n};\n\n/** Constructor shape compatible with `Hls.DefaultConfig.loader`. */\nexport type HlsLoaderConstructor = new (config: object) => HlsLoaderInstance;\n\n/**\n * Opaque stand-in for `typeof import(\"hls.js\").default` used only inside\n * this module. Public APIs accept `object` so `.d.ts` never imports `hls.js`.\n */\ntype HlsClassLike = {\n DefaultConfig: {\n loader: HlsLoaderConstructor;\n };\n};\n\n/** Public alias — pass `hls.js` default export (typed as object at the boundary). */\nexport type HlsModuleLike = object;\n\nconst ENC_KEY_PATH_RE = /enc\\.key$/i;\nconst BUILTIN_LOADER_NAMES = new Set([\"XhrLoader\", \"FetchLoader\"]);\n\n/**\n * Composition wrappers (AuthParamsLoader) do not sit on XhrLoader's prototype\n * chain. Stash the resolved builtin so polluted DefaultConfig.loader can still\n * unwrap after HMR / repeated player mounts / nested createAuthParamsLoader.\n */\nconst BUILTIN_LOADER_REF = Symbol.for(\n \"@codenkay/video-nsgplayer-core/builtin-hls-loader\",\n);\n\n/** Per-hls.js-module cache of the first successfully resolved builtin loader. */\nconst builtinLoaderByHls = new WeakMap<object, HlsLoaderConstructor>();\n\n/** Max same-origin BFF key attempts before the session circuit opens. */\nexport const KEY_PROXY_MAX_FAILURES = 2;\n\nexport type AuthParamsLoaderOptions = {\n videoId?: string;\n keyProxyUrlBuilder?: StreamingConfig[\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: StreamingConfig[\"getKeyAccessToken\"];\n /** Override max BFF key failures before permanent browser fallback (default 2). */\n keyProxyMaxFailures?: number;\n};\n\nexport function isEncryptionKeyUrl(\n rawUrl: string,\n baseOrigin: string = typeof location !== \"undefined\"\n ? location.origin\n : \"http://localhost\",\n): boolean {\n try {\n return ENC_KEY_PATH_RE.test(new URL(rawUrl, baseOrigin).pathname);\n } catch {\n return /enc\\.key/i.test(rawUrl);\n }\n}\n\nfunction isBuiltinLoaderName(name: string): boolean {\n return BUILTIN_LOADER_NAMES.has(name);\n}\n\nfunction rememberBuiltin(\n HlsClass: HlsClassLike,\n loader: HlsLoaderConstructor,\n): HlsLoaderConstructor {\n if (isBuiltinLoaderName(typeof loader.name === \"string\" ? loader.name : \"\")) {\n builtinLoaderByHls.set(HlsClass, loader);\n }\n return loader;\n}\n\nfunction getStashedBuiltinLoader(\n loader: HlsLoaderConstructor,\n): HlsLoaderConstructor | undefined {\n return (\n loader as unknown as Record<symbol, HlsLoaderConstructor | undefined>\n )[BUILTIN_LOADER_REF];\n}\n\n/**\n * Resolve the builtin loader from the **same** `hls.js` module instance the\n * engine loaded. Never statically import `XhrLoader` — that can pull a second\n * hls.js copy into the app bundle after npm pack/publish and break key loads.\n */\nexport function resolveBuiltinHlsLoader(\n HlsModule: HlsModuleLike,\n): HlsLoaderConstructor {\n const HlsClass = HlsModule as HlsClassLike;\n const cached = builtinLoaderByHls.get(HlsClass);\n if (cached) return cached;\n\n const start = HlsClass.DefaultConfig.loader as unknown as HlsLoaderConstructor;\n let current: HlsLoaderConstructor | null = start;\n const seen = new Set<HlsLoaderConstructor>();\n\n while (current && !seen.has(current)) {\n seen.add(current);\n const name = typeof current.name === \"string\" ? current.name : \"\";\n if (isBuiltinLoaderName(name)) {\n return rememberBuiltin(HlsClass, current);\n }\n\n // Composition wrapper: follow stashed builtin / next base.\n const stashed: HlsLoaderConstructor | undefined =\n getStashedBuiltinLoader(current);\n if (stashed) {\n current = stashed;\n continue;\n }\n\n // Inheritance wrapper: walk prototype chain.\n const parentCtor = Object.getPrototypeOf(current.prototype)\n ?.constructor as HlsLoaderConstructor | undefined;\n if (\n !parentCtor ||\n parentCtor === (Object as unknown as HlsLoaderConstructor) ||\n parentCtor === (Function as unknown as HlsLoaderConstructor)\n ) {\n break;\n }\n current = parentCtor;\n }\n\n // Last resort: cached from an earlier successful resolve on this Hls module.\n const fallback = builtinLoaderByHls.get(HlsClass);\n return fallback ?? start;\n}\n\n/**\n * Rewrites an HLS request URL so signed auth query params are present.\n */\nexport function rewriteHlsRequestUrl(\n rawUrl: string,\n store: AuthParamsStore,\n options: AuthParamsLoaderOptions = {},\n baseOrigin: string = typeof location !== \"undefined\"\n ? location.origin\n : \"http://localhost\",\n): string {\n if (!rawUrl) return rawUrl;\n\n const parsed = new URL(rawUrl, baseOrigin);\n const isKey = ENC_KEY_PATH_RE.test(parsed.pathname);\n\n if (isKey && options.keyProxyUrlBuilder && options.videoId) {\n const snapshot = store.toRecord();\n return options.keyProxyUrlBuilder({\n videoId: options.videoId,\n keyUrl: parsed.toString(),\n token: snapshot.token,\n expires: snapshot.expires,\n username: snapshot.username,\n mobile: snapshot.mobile,\n });\n }\n\n if (!store.hasParams()) return parsed.toString();\n return store.applyToUrl(rawUrl, baseOrigin);\n}\n\nfunction createLoaderStats(): LoaderStats {\n const now = performance.now();\n return {\n aborted: false,\n loaded: 0,\n retry: 0,\n total: 0,\n chunkCount: 0,\n bwEstimate: 0,\n loading: { start: now, first: 0, end: 0 },\n parsing: { start: 0, end: 0 },\n buffering: { start: 0, first: 0, end: 0 },\n };\n}\n\nfunction isProxyUpstreamBlocked(\n status: number,\n contentType: string | null,\n bodyHead: string,\n errorText?: string,\n): boolean {\n if (status === 0 || status === 502 || status === 503 || status === 504) {\n return true;\n }\n if (status === 403 || status === 401) return true;\n if (contentType?.includes(\"text/html\")) return true;\n if (/<!DOCTYPE|<html|Just a moment|Cloudflare|blocked/i.test(bodyHead)) {\n return true;\n }\n if (errorText && /Cloudflare|HTML|DOCTYPE|blocked|502/i.test(errorText)) {\n return true;\n }\n return false;\n}\n\ntype KeyFetchResult =\n | {\n ok: true;\n data: ArrayBuffer;\n response: Response;\n url: string;\n }\n | {\n ok: false;\n status: number;\n text: string;\n cors: boolean;\n response: Response | null;\n };\n\n/**\n * Low-level key GET. Does not invoke hls callbacks (caller decides success/fallback).\n */\nasync function fetchEncryptionKeyBytes(\n url: string,\n accessToken: string | null | undefined,\n signal: AbortSignal,\n): Promise<KeyFetchResult> {\n // Query-only must stay a CORS \"simple\" request (no custom headers / no\n // Authorization) so CDN hosts that allow XHR but reject preflight still work.\n // Bearer is attached only when the caller explicitly requests it (401/403 path).\n const headers: Record<string, string> | undefined = accessToken\n ? { Authorization: `Bearer ${accessToken}`, Accept: \"*/*\" }\n : undefined;\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n ...(headers ? { headers } : {}),\n credentials: \"omit\",\n cache: \"no-store\",\n signal,\n });\n\n if (!response.ok) {\n return {\n ok: false,\n status: response.status,\n text: response.statusText || `enc.key HTTP ${response.status}`,\n cors: false,\n response,\n };\n }\n\n const data = await response.arrayBuffer();\n const head = new TextDecoder().decode(data.slice(0, 32));\n if (/<!DOCTYPE|<html/i.test(head)) {\n return {\n ok: false,\n status: 403,\n text: \"enc.key returned HTML (CDN challenge/block), not an AES key\",\n cors: false,\n response,\n };\n }\n\n return {\n ok: true,\n data,\n response,\n url: response.url || url,\n };\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return {\n ok: false,\n status: 0,\n text: \"enc.key fetch aborted/timeout\",\n cors: false,\n response: null,\n };\n }\n const cors =\n error instanceof TypeError ||\n (error instanceof Error &&\n /Failed to fetch|NetworkError|CORS/i.test(error.message));\n return {\n ok: false,\n status: 0,\n text:\n error instanceof Error ? error.message : \"enc.key fetch failed\",\n cors,\n response: null,\n };\n }\n}\n\n/** AES-128 content keys are exactly 16 bytes; anything else decrypts to garbage MSE. */\nconst AES_128_KEY_BYTES = 16;\n\nfunction normalizeAes128Key(data: ArrayBuffer): ArrayBuffer | null {\n if (data.byteLength === AES_128_KEY_BYTES) {\n // Detach a clean copy so KeyLoader / worker transfers cannot alias a view.\n return data.slice(0);\n }\n return null;\n}\n\nfunction reportKeySuccess(\n context: LoaderContext,\n callbacks: LoaderCallbacks<LoaderContext>,\n result: Extract<KeyFetchResult, { ok: true }>,\n): boolean {\n const key = normalizeAes128Key(result.data);\n if (!key) {\n const stats = createLoaderStats();\n callbacks.onError(\n {\n code: 422,\n text: `enc.key must be ${AES_128_KEY_BYTES} bytes (got ${result.data.byteLength})`,\n },\n context,\n result.response,\n stats,\n );\n return false;\n }\n\n const stats = createLoaderStats();\n const end = performance.now();\n stats.loading.first = stats.loading.start;\n stats.loading.end = end;\n stats.loaded = key.byteLength;\n stats.total = key.byteLength;\n callbacks.onSuccess(\n {\n url: result.url,\n data: key,\n code: result.response.status,\n },\n stats,\n context,\n result.response,\n );\n return true;\n}\n\ntype KeyLoadPlan = {\n proxyUrl: string | null;\n signedKeyUrl: string;\n accessToken: string | null;\n maxProxyFailures: number;\n};\n\ntype KeyLoadLifecycle = {\n /** False when a newer key load superseded this one (intentional abort). */\n isCurrent: () => boolean;\n};\n\n/**\n * Enterprise AES key path:\n * 1. BFF — at most `maxProxyFailures`, then trip session circuit (no 9× 502 spam)\n * 2. Signed-query fetch **without** Authorization (same as working CDN path; no preflight)\n * 3. On 401/403 only — Bearer fetch (API-origin keys)\n * 4. Caller may still try hls XHR if fetch is CORS-blocked\n */\nasync function loadEncryptionKeyEnterprise(\n context: LoaderContext,\n callbacks: LoaderCallbacks<LoaderContext>,\n plan: KeyLoadPlan,\n signal: AbortSignal,\n state: { proxyFailures: number; circuitOpen: boolean },\n lifecycle: KeyLoadLifecycle,\n): Promise<\"ok\" | \"try_xhr\" | \"aborted\"> {\n const stats = createLoaderStats();\n const stillCurrent = () => lifecycle.isCurrent() && !signal.aborted;\n\n const canTryProxy =\n Boolean(plan.proxyUrl) &&\n !state.circuitOpen &&\n state.proxyFailures < plan.maxProxyFailures;\n\n if (canTryProxy && plan.proxyUrl) {\n while (\n !state.circuitOpen &&\n state.proxyFailures < plan.maxProxyFailures &&\n stillCurrent()\n ) {\n state.proxyFailures += 1;\n try {\n const response = await fetch(plan.proxyUrl, {\n method: \"GET\",\n headers: { Accept: \"*/*\" },\n credentials: \"same-origin\",\n cache: \"no-store\",\n signal,\n });\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n const contentType = response.headers.get(\"content-type\");\n const data = await response.arrayBuffer();\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n const head = new TextDecoder().decode(data.slice(0, 64));\n\n if (\n response.ok &&\n !isProxyUpstreamBlocked(response.status, contentType, head)\n ) {\n const key = normalizeAes128Key(data);\n if (!key) {\n callbacks.onError(\n {\n code: 422,\n text: `enc.key proxy returned ${data.byteLength} bytes (need ${AES_128_KEY_BYTES})`,\n },\n { ...context, url: plan.proxyUrl },\n response,\n stats,\n );\n return \"ok\";\n }\n const end = performance.now();\n stats.loading.end = end;\n stats.loaded = key.byteLength;\n stats.total = key.byteLength;\n callbacks.onSuccess(\n {\n url: response.url || plan.proxyUrl,\n data: key,\n code: response.status,\n },\n stats,\n { ...context, url: plan.proxyUrl },\n response,\n );\n return \"ok\";\n }\n\n if (\n isProxyUpstreamBlocked(\n response.status,\n contentType,\n head,\n response.statusText,\n )\n ) {\n if (\n response.status === 502 ||\n contentType?.includes(\"text/html\") ||\n /Cloudflare|DOCTYPE|blocked/i.test(head)\n ) {\n state.circuitOpen = true;\n break;\n }\n continue;\n }\n\n callbacks.onError(\n {\n code: response.status,\n text: `enc.key proxy HTTP ${response.status}`,\n },\n { ...context, url: plan.proxyUrl },\n response,\n stats,\n );\n return \"ok\";\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n // Superseded by a newer key load, or timeout of a stale generation —\n // never report status-0 to hls.js (false CORS fatal in HlsEngine).\n return \"aborted\";\n }\n state.circuitOpen = true;\n break;\n }\n }\n if (!lifecycle.isCurrent()) return \"aborted\";\n state.circuitOpen = true;\n }\n\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n // Query-only first (no Authorization → no CORS preflight). This is the path\n // that worked with local `file:` installs before Bearer-first broke pack/build.\n const queryResult = await fetchEncryptionKeyBytes(\n plan.signedKeyUrl,\n null,\n signal,\n );\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n if (queryResult.ok) {\n reportKeySuccess(\n { ...context, url: plan.signedKeyUrl },\n callbacks,\n queryResult,\n );\n return \"ok\";\n }\n\n // Aborted unsigned fetch — do not escalate; a newer load owns the key.\n if (queryResult.status === 0 && signal.aborted) {\n return \"aborted\";\n }\n\n const needsBearer =\n Boolean(plan.accessToken) &&\n (queryResult.status === 401 ||\n queryResult.status === 403 ||\n // Browser-direct: opaque CORS/network on unsigned GET — try Bearer once\n // Appextech allows ACAO + Authorization (AUTH_MODE=browser, no BFF).\n queryResult.cors ||\n queryResult.status === 0);\n\n if (needsBearer && plan.accessToken) {\n const bearerResult = await fetchEncryptionKeyBytes(\n plan.signedKeyUrl,\n plan.accessToken,\n signal,\n );\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n if (bearerResult.ok) {\n reportKeySuccess(\n { ...context, url: plan.signedKeyUrl },\n callbacks,\n bearerResult,\n );\n return \"ok\";\n }\n if (bearerResult.status === 0 && signal.aborted) {\n return \"aborted\";\n }\n if (bearerResult.cors || bearerResult.status === 0) {\n return \"try_xhr\";\n }\n callbacks.onError(\n {\n code: bearerResult.status,\n text: bearerResult.text,\n },\n { ...context, url: plan.signedKeyUrl },\n bearerResult.response,\n stats,\n );\n return \"ok\";\n }\n\n if (queryResult.cors || queryResult.status === 0) {\n return \"try_xhr\";\n }\n\n callbacks.onError(\n {\n code: queryResult.status,\n text: queryResult.text,\n },\n { ...context, url: plan.signedKeyUrl },\n queryResult.response,\n stats,\n );\n return \"ok\";\n}\n\n/**\n * hls.js loader: auth query rewrite + enterprise AES key loading.\n */\nexport function createAuthParamsLoader(\n HlsModule: HlsModuleLike,\n store: AuthParamsStore,\n options: AuthParamsLoaderOptions = {},\n): HlsLoaderConstructor {\n const HlsClass = HlsModule as HlsClassLike;\n const BaseLoader = resolveBuiltinHlsLoader(HlsClass);\n rememberBuiltin(HlsClass, BaseLoader);\n\n const maxProxyFailures =\n typeof options.keyProxyMaxFailures === \"number\" &&\n options.keyProxyMaxFailures >= 0\n ? options.keyProxyMaxFailures\n : KEY_PROXY_MAX_FAILURES;\n\n const keyProxyState = { proxyFailures: 0, circuitOpen: false };\n\n class AuthParamsLoader {\n readonly stats: LoaderStats;\n context: LoaderContext | null = null;\n private readonly inner: HlsLoaderInstance;\n private keyAbort: AbortController | null = null;\n /** Bumps on each key load so superseded aborts never call onError. */\n private keyLoadGeneration = 0;\n private pendingKeyCallbacks: LoaderCallbacks<LoaderContext> | null = null;\n\n constructor(config: object) {\n this.inner = new BaseLoader(config);\n this.stats = this.inner.stats;\n }\n\n private finishKeyAbort(): void {\n const cbs = this.pendingKeyCallbacks;\n this.pendingKeyCallbacks = null;\n this.keyAbort?.abort();\n this.keyAbort = null;\n if (cbs?.onAbort && this.context) {\n const stats = createLoaderStats();\n stats.aborted = true;\n try {\n cbs.onAbort(stats, this.context, null);\n } catch {\n // KeyLoader abort handlers must not break loader teardown.\n }\n }\n }\n\n abort(): void {\n this.keyLoadGeneration += 1;\n this.finishKeyAbort();\n this.inner.abort();\n }\n\n destroy(): void {\n this.keyLoadGeneration += 1;\n this.finishKeyAbort();\n this.context = null;\n this.inner.destroy();\n }\n\n load(\n context: LoaderContext,\n config: LoaderConfiguration,\n callbacks: LoaderCallbacks<LoaderContext>,\n ): void {\n this.context = context;\n if (!context.url) {\n this.inner.load(context, config, callbacks);\n return;\n }\n\n try {\n const originalUrl = context.url;\n const isKey = isEncryptionKeyUrl(originalUrl);\n\n if (!isKey) {\n if (store.hasParams()) {\n context.url = rewriteHlsRequestUrl(originalUrl, store, {\n ...options,\n keyProxyUrlBuilder: undefined,\n });\n }\n this.inner.load(context, config, callbacks);\n return;\n }\n\n // Always apply signed query to the CDN key URL (never leave unsigned).\n const signedKeyUrl = rewriteHlsRequestUrl(originalUrl, store, {\n ...options,\n keyProxyUrlBuilder: undefined,\n });\n\n const proxyConfigured = Boolean(\n options.keyProxyUrlBuilder && options.videoId,\n );\n const proxyUrl =\n proxyConfigured && !keyProxyState.circuitOpen\n ? rewriteHlsRequestUrl(originalUrl, store, options)\n : null;\n\n const accessToken = options.getKeyAccessToken?.() ?? null;\n\n // Supersede any in-flight key load on this loader instance.\n if (this.keyAbort || this.pendingKeyCallbacks) {\n this.keyLoadGeneration += 1;\n this.finishKeyAbort();\n }\n\n const generation = ++this.keyLoadGeneration;\n this.keyAbort = new AbortController();\n this.pendingKeyCallbacks = callbacks;\n context.responseType = \"arraybuffer\";\n const timeoutMs =\n typeof config?.timeout === \"number\" && config.timeout > 0\n ? config.timeout\n : 20_000;\n const timer = setTimeout(() => this.keyAbort?.abort(), timeoutMs);\n const lifecycle: KeyLoadLifecycle = {\n isCurrent: () => generation === this.keyLoadGeneration,\n };\n\n void loadEncryptionKeyEnterprise(\n context,\n callbacks,\n {\n proxyUrl,\n signedKeyUrl,\n accessToken,\n maxProxyFailures,\n },\n this.keyAbort.signal,\n keyProxyState,\n lifecycle,\n )\n .then((result) => {\n if (!lifecycle.isCurrent()) return;\n if (result === \"aborted\") {\n this.finishKeyAbort();\n return;\n }\n this.pendingKeyCallbacks = null;\n if (result === \"try_xhr\") {\n // Fallback to same-module XhrLoader with signed query (no Bearer).\n context.url = signedKeyUrl;\n this.inner.load(context, config, callbacks);\n }\n })\n .catch((error: unknown) => {\n if (!lifecycle.isCurrent()) return;\n this.pendingKeyCallbacks = null;\n callbacks.onError(\n {\n code: 0,\n text:\n error instanceof Error\n ? error.message\n : \"enc.key load failed\",\n },\n context,\n null,\n createLoaderStats(),\n );\n })\n .finally(() => {\n clearTimeout(timer);\n });\n return;\n } catch {\n // Fall through to default loader.\n }\n\n this.inner.load(context, config, callbacks);\n }\n }\n\n Object.defineProperty(AuthParamsLoader, BUILTIN_LOADER_REF, {\n value: BaseLoader,\n enumerable: false,\n configurable: false,\n });\n\n return AuthParamsLoader;\n}\n","import type { AuthParamsStore } from \"../auth/AuthParamsStore\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n HlsQualityLevel,\n HlsSupportMode,\n PlayerAudioTrack,\n PlayerState,\n PlayerTextTrack,\n QualitySelection,\n StreamingConfig,\n TextTrackSelection,\n} from \"../types\";\nimport { createAuthParamsLoader } from \"./authParamsLoader\";\n\nexport type HlsEngineCallbacks = {\n onStateChange?: (state: PlayerState) => void;\n onSupportMode?: (mode: HlsSupportMode) => void;\n onFatalError?: (message: string) => void;\n onAuthRecoveryNeeded?: (reason: string) => void;\n onQualitiesChange?: (levels: HlsQualityLevel[]) => void;\n onQualitySelectionChange?: (selection: QualitySelection) => void;\n onTextTracksChange?: (tracks: PlayerTextTrack[]) => void;\n onTextTrackSelectionChange?: (selection: TextTrackSelection) => void;\n onAudioTracksChange?: (tracks: PlayerAudioTrack[]) => void;\n onAudioTrackSelectionChange?: (selection: number) => void;\n onEnded?: () => void;\n};\n\nexport type HlsEngineOptions = {\n videoEl: HTMLVideoElement;\n playbackUrl: string;\n authParams: AuthParamsStore;\n autoplay: boolean;\n startMuted: boolean;\n startPosition?: number;\n volume?: number;\n videoId?: string;\n keyProxyUrlBuilder?: StreamingConfig[\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: StreamingConfig[\"getKeyAccessToken\"];\n keyProxyMaxFailures?: StreamingConfig[\"keyProxyMaxFailures\"];\n hlsConfig: {\n enableWorker: boolean;\n lowLatencyMode: boolean;\n backBufferLength: number;\n fatalRecoveryLimit: number;\n };\n logger: Logger;\n callbacks: HlsEngineCallbacks;\n};\n\nfunction isAuthHttpStatus(code: unknown): boolean {\n return code === 401 || code === 403;\n}\n\n/**\n * Dual-path HLS engine: hls.js when supported, otherwise native Safari HLS.\n *\n * Signed CDN playback requires auth query params on every HLS request\n * (playlists, segments, and AES `enc.key` on CDN hosts).\n *\n * Optional `streaming.keyProxyUrlBuilder` (same-origin BFF) or\n * `streaming.getKeyAccessToken` (Bearer only after signed-query 401/403).\n * CDN keys prefer signed query without Authorization (no CORS preflight).\n * when query-signed CDN access is insufficient.\n */\nfunction isGeckoBrowser(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /firefox|gecko\\//i.test(navigator.userAgent);\n}\n\nexport class HlsEngine {\n private hls: import(\"hls.js\").default | null = null;\n private destroyed = false;\n private supportMode: HlsSupportMode = \"unsupported\";\n private networkRecoveryCount = 0;\n private mediaRecoveryCount = 0;\n private qualities: HlsQualityLevel[] = [];\n private qualitySelection: QualitySelection = \"auto\";\n private textTracks: PlayerTextTrack[] = [];\n private textTrackSelection: TextTrackSelection = \"off\";\n private audioTracks: PlayerAudioTrack[] = [];\n private audioTrackSelection = 0;\n private nativeTextTrackCleanup: (() => void) | null = null;\n private startPositionApplied = false;\n private autoplayApplied = false;\n\n constructor(private readonly options: HlsEngineOptions) {}\n\n async start(): Promise<void> {\n const { videoEl, playbackUrl, startMuted, volume } = this.options;\n\n videoEl.muted = startMuted;\n if (typeof volume === \"number\") {\n videoEl.volume = Math.min(1, Math.max(0, volume));\n }\n\n const Hls = (await import(\"hls.js\")).default;\n\n if (Hls.isSupported()) {\n this.supportMode = \"hls.js\";\n this.options.callbacks.onSupportMode?.(\"hls.js\");\n await this.startWithHlsJs(Hls, playbackUrl);\n return;\n }\n\n if (videoEl.canPlayType(\"application/vnd.apple.mpegurl\")) {\n this.supportMode = \"native\";\n this.options.callbacks.onSupportMode?.(\"native\");\n videoEl.src = this.options.authParams.applyToUrl(playbackUrl);\n this.bindMediaEvents();\n this.bindNativeTextTracks();\n this.options.callbacks.onStateChange?.(\"ready\");\n await this.applyStartPositionAndAutoplay();\n return;\n }\n\n this.supportMode = \"unsupported\";\n this.options.callbacks.onSupportMode?.(\"unsupported\");\n this.options.callbacks.onFatalError?.(\n \"HLS is not supported in this browser\",\n );\n }\n\n private async startWithHlsJs(\n Hls: typeof import(\"hls.js\").default,\n playbackUrl: string,\n ): Promise<void> {\n const {\n videoEl,\n authParams,\n hlsConfig,\n callbacks,\n videoId,\n keyProxyUrlBuilder,\n getKeyAccessToken,\n } = this.options;\n\n const loader = createAuthParamsLoader(Hls, authParams, {\n videoId,\n keyProxyUrlBuilder,\n getKeyAccessToken,\n keyProxyMaxFailures: this.options.keyProxyMaxFailures,\n });\n\n // Firefox/Gecko + worker demux/decrypt is a frequent source of\n // bufferAppendError on AES-128 VOD; keep workers elsewhere.\n const enableWorker = hlsConfig.enableWorker && !isGeckoBrowser();\n if (hlsConfig.enableWorker && !enableWorker) {\n this.options.logger.warn(\n \"Disabling hls.js worker on Firefox to avoid MSE bufferAppendError\",\n );\n }\n\n this.hls = new Hls({\n enableWorker,\n // LL mode on short encrypted VOD drives aggressive ABR thrash → MSE errors.\n lowLatencyMode: hlsConfig.lowLatencyMode,\n backBufferLength: hlsConfig.backBufferLength,\n // Stabilize ABR: avoid first-frag-only bandwidth test that immediately\n // hops levels on single-segment Appextech VODs (HAR showed truncated\n // 720p body vs Content-Length during level switches).\n testBandwidth: false,\n abrEwmaDefaultEstimate: 500_000,\n abrBandWidthFactor: 0.8,\n abrBandWidthUpFactor: 0.5,\n maxStarvationDelay: 4,\n capLevelToPlayerSize: true,\n startLevel: -1,\n loader: loader as unknown as typeof Hls.DefaultConfig.loader,\n });\n\n this.hls.attachMedia(videoEl);\n this.hls.loadSource(authParams.applyToUrl(playbackUrl));\n\n this.hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n if (this.destroyed) return;\n this.qualities = (data.levels ?? []).map((level, index) => ({\n index,\n height: level.height ?? 0,\n width: level.width ?? 0,\n bitrate: level.bitrate ?? 0,\n label:\n level.height != null && level.height > 0\n ? `${level.height}p`\n : `Level ${index}`,\n }));\n callbacks.onQualitiesChange?.(this.qualities);\n this.syncHlsSubtitleTracks();\n this.syncHlsAudioTracks();\n callbacks.onStateChange?.(\"ready\");\n // Autoplay immediately; defer resume-seek until media is buffered so we\n // never seek past an empty/short buffer (common with wtime on 5s VODs).\n void this.applyAutoplayOnly();\n });\n\n this.hls.on(Hls.Events.FRAG_BUFFERED, () => {\n if (this.destroyed || this.startPositionApplied) return;\n void this.applyStartPositionOnly();\n });\n\n this.hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, () => {\n if (this.destroyed) return;\n this.syncHlsSubtitleTracks();\n });\n\n this.hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, () => {\n if (this.destroyed) return;\n this.syncHlsAudioTracks();\n });\n\n this.hls.on(Hls.Events.ERROR, (_event, data) => {\n this.handleHlsError(Hls, data);\n });\n\n this.bindMediaEvents();\n }\n\n private handleHlsError(\n Hls: typeof import(\"hls.js\").default,\n data: {\n fatal: boolean;\n type: string;\n details: string;\n response?: { code?: number };\n },\n ): void {\n if (this.destroyed) return;\n const { callbacks, hlsConfig } = this.options;\n const status = data.response?.code;\n\n // Only treat real HTTP auth failures as credential expiry.\n // Status 0 / undefined is usually CORS/abort — renewing cannot fix that.\n const authFailure = isAuthHttpStatus(status);\n\n if (data.details === Hls.ErrorDetails.KEY_LOAD_ERROR) {\n if (authFailure) {\n callbacks.onAuthRecoveryNeeded?.(\"key_error\");\n if (!data.fatal) return;\n } else if (!data.fatal) {\n // Status 0 / missing is almost always an aborted superseded key load\n // during ABR — not CORS. Promoting it to fatal shows a false banner\n // even after /api/.../hls-key returned 200.\n if (!status) {\n return;\n }\n callbacks.onFatalError?.(\n `Encryption key load failed (HTTP ${status}).`,\n );\n return;\n } else if (!status) {\n callbacks.onFatalError?.(\n \"Encryption key load aborted or failed. Retry playback; if it persists, check the key proxy / CDN path.\",\n );\n return;\n }\n }\n\n if (!data.fatal) {\n if (\n authFailure &&\n data.type === Hls.ErrorTypes.NETWORK_ERROR &&\n (data.details === Hls.ErrorDetails.FRAG_LOAD_ERROR ||\n data.details === Hls.ErrorDetails.LEVEL_LOAD_ERROR)\n ) {\n callbacks.onAuthRecoveryNeeded?.(\n data.details === Hls.ErrorDetails.LEVEL_LOAD_ERROR\n ? \"level_error\"\n : \"frag_error\",\n );\n }\n return;\n }\n\n if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {\n this.networkRecoveryCount += 1;\n if (this.networkRecoveryCount <= hlsConfig.fatalRecoveryLimit) {\n if (authFailure) {\n callbacks.onAuthRecoveryNeeded?.(\"fatal_network\");\n }\n this.hls?.startLoad();\n return;\n }\n }\n\n if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {\n this.mediaRecoveryCount += 1;\n if (this.mediaRecoveryCount > hlsConfig.fatalRecoveryLimit) {\n callbacks.onFatalError?.(data.details || \"Fatal HLS error\");\n return;\n }\n\n // bufferAppendError: stop ABR thrash, optionally swap audio codec, then\n // recover MediaSource. Plain recoverMediaError alone re-triggers level\n // hopping on short multi-bitrate VOD (Firefox HAR pattern).\n if (\n data.details === Hls.ErrorDetails.BUFFER_APPEND_ERROR ||\n data.details === Hls.ErrorDetails.BUFFER_FULL_ERROR\n ) {\n this.lockPlaybackToSafeLevel();\n }\n\n if (this.mediaRecoveryCount === 2) {\n this.hls?.swapAudioCodec();\n }\n this.hls?.recoverMediaError();\n return;\n }\n\n callbacks.onFatalError?.(data.details || \"Fatal HLS error\");\n }\n\n /** Pin the next load to the lowest ladder rung after MSE append failures. */\n private lockPlaybackToSafeLevel(): void {\n if (!this.hls || this.qualities.length === 0) return;\n try {\n this.hls.currentLevel = 0;\n this.hls.loadLevel = 0;\n this.hls.nextLoadLevel = 0;\n } catch {\n // Ignore if levels are not ready yet.\n }\n }\n\n private clampStartPosition(raw: number, videoEl: HTMLVideoElement): number {\n let t = Math.max(0, raw);\n const duration = videoEl.duration;\n if (Number.isFinite(duration) && duration > 0) {\n // Leave a small epsilon so we never seek to/past EOS on short VOD.\n t = Math.min(t, Math.max(0, duration - 0.35));\n }\n if (videoEl.seekable.length > 0) {\n const end = videoEl.seekable.end(videoEl.seekable.length - 1);\n if (Number.isFinite(end)) {\n t = Math.min(t, end);\n }\n }\n return t;\n }\n\n private async applyStartPositionOnly(): Promise<void> {\n if (this.destroyed || this.startPositionApplied) return;\n const { videoEl, startPosition } = this.options;\n this.startPositionApplied = true;\n\n if (typeof startPosition !== \"number\" || startPosition <= 0) return;\n\n const seek = () => {\n if (this.destroyed) return;\n try {\n videoEl.currentTime = this.clampStartPosition(startPosition, videoEl);\n } catch {\n // Ignore seek before seekable ranges are ready.\n }\n };\n\n if (videoEl.seekable.length > 0 || Number.isFinite(videoEl.duration)) {\n seek();\n } else {\n videoEl.addEventListener(\"loadedmetadata\", seek, { once: true });\n }\n }\n\n private async applyAutoplayOnly(): Promise<void> {\n if (this.destroyed || this.autoplayApplied) return;\n this.autoplayApplied = true;\n const { videoEl, autoplay } = this.options;\n if (!autoplay) return;\n try {\n await videoEl.play();\n } catch {\n if (!videoEl.muted) {\n videoEl.muted = true;\n try {\n await videoEl.play();\n } catch {\n this.options.logger.warn(\"Autoplay blocked\");\n }\n }\n }\n }\n\n private async applyStartPositionAndAutoplay(): Promise<void> {\n await this.applyStartPositionOnly();\n await this.applyAutoplayOnly();\n }\n\n private bindMediaEvents(): void {\n const { videoEl, callbacks } = this.options;\n videoEl.addEventListener(\"playing\", () =>\n callbacks.onStateChange?.(\"playing\"),\n );\n videoEl.addEventListener(\"pause\", () => {\n if (!videoEl.ended) callbacks.onStateChange?.(\"paused\");\n });\n videoEl.addEventListener(\"waiting\", () =>\n callbacks.onStateChange?.(\"buffering\"),\n );\n videoEl.addEventListener(\"ended\", () => {\n callbacks.onStateChange?.(\"ended\");\n callbacks.onEnded?.();\n });\n }\n\n updateAuthParams(): void {\n if (this.supportMode === \"native\" && this.options.videoEl) {\n const time = this.options.videoEl.currentTime;\n const wasPaused = this.options.videoEl.paused;\n this.options.videoEl.src = this.options.authParams.applyToUrl(\n this.options.playbackUrl,\n );\n this.options.videoEl.currentTime = time;\n if (!wasPaused) void this.options.videoEl.play();\n }\n }\n\n resumeAfterAuthRenew(): void {\n this.networkRecoveryCount = 0;\n this.hls?.startLoad();\n this.updateAuthParams();\n }\n\n setQuality(selection: QualitySelection): void {\n this.qualitySelection = selection;\n if (!this.hls) return;\n this.hls.currentLevel = selection === \"auto\" ? -1 : selection;\n this.options.callbacks.onQualitySelectionChange?.(selection);\n }\n\n getQuality(): QualitySelection {\n return this.qualitySelection;\n }\n\n getQualities(): HlsQualityLevel[] {\n return this.qualities;\n }\n\n getTextTracks(): PlayerTextTrack[] {\n return this.textTracks;\n }\n\n getTextTrackSelection(): TextTrackSelection {\n return this.textTrackSelection;\n }\n\n setTextTrack(selection: TextTrackSelection): void {\n if (this.destroyed) return;\n this.textTrackSelection = selection;\n this.options.callbacks.onTextTrackSelectionChange?.(selection);\n\n if (this.supportMode === \"hls.js\" && this.hls) {\n this.hls.subtitleDisplay = selection !== \"off\";\n this.hls.subtitleTrack = selection === \"off\" ? -1 : selection;\n return;\n }\n\n if (this.supportMode === \"native\" && this.options.videoEl) {\n const tracks = this.options.videoEl.textTracks;\n for (let i = 0; i < tracks.length; i += 1) {\n const track = tracks[i]!;\n track.mode =\n selection !== \"off\" && i === selection ? \"showing\" : \"disabled\";\n }\n }\n }\n\n getAudioTracks(): PlayerAudioTrack[] {\n return this.audioTracks;\n }\n\n getAudioTrackSelection(): number {\n return this.audioTrackSelection;\n }\n\n setAudioTrack(index: number): void {\n if (this.destroyed) return;\n if (\n !Number.isInteger(index) ||\n index < 0 ||\n (this.audioTracks.length > 0 && index >= this.audioTracks.length)\n ) {\n return;\n }\n\n this.audioTrackSelection = index;\n this.options.callbacks.onAudioTrackSelectionChange?.(index);\n\n if (this.supportMode === \"hls.js\" && this.hls) {\n this.hls.audioTrack = index;\n return;\n }\n\n if (this.supportMode === \"native\" && this.options.videoEl) {\n const audioTracks = (\n this.options.videoEl as HTMLVideoElement & {\n audioTracks?: { length: number; [i: number]: { enabled: boolean } };\n }\n ).audioTracks;\n if (audioTracks && audioTracks.length > 0) {\n for (let i = 0; i < audioTracks.length; i += 1) {\n audioTracks[i]!.enabled = i === index;\n }\n }\n }\n }\n\n getSupportMode(): HlsSupportMode {\n return this.supportMode;\n }\n\n private syncHlsSubtitleTracks(): void {\n if (!this.hls) return;\n const tracks: PlayerTextTrack[] = (this.hls.subtitleTracks ?? []).map(\n (track, index) => ({\n index,\n id: String(track.id ?? index),\n label: track.name || track.lang || `Subtitles ${index + 1}`,\n language: track.lang,\n }),\n );\n this.textTracks = tracks;\n this.options.callbacks.onTextTracksChange?.(tracks);\n }\n\n private syncHlsAudioTracks(): void {\n if (!this.hls) return;\n const tracks: PlayerAudioTrack[] = (this.hls.audioTracks ?? []).map(\n (track, index) => ({\n index,\n id: String(track.id ?? index),\n label: track.name || track.lang || `Audio ${index + 1}`,\n language: track.lang,\n }),\n );\n this.audioTracks = tracks;\n this.options.callbacks.onAudioTracksChange?.(tracks);\n if (tracks.length > 0) {\n this.audioTrackSelection = 0;\n this.options.callbacks.onAudioTrackSelectionChange?.(0);\n }\n }\n\n private bindNativeTextTracks(): void {\n const { videoEl } = this.options;\n const syncFromElement = () => {\n if (this.destroyed || this.textTracks.length > 0) return;\n const list = videoEl.textTracks;\n const tracks: PlayerTextTrack[] = [];\n for (let i = 0; i < list.length; i += 1) {\n const track = list[i]!;\n if (track.kind !== \"subtitles\" && track.kind !== \"captions\") continue;\n tracks.push({\n index: tracks.length,\n id: track.id || `native-${tracks.length}`,\n label: track.label || track.language || `Track ${tracks.length + 1}`,\n language: track.language || undefined,\n });\n }\n if (tracks.length === 0) return;\n this.textTracks = tracks;\n this.options.callbacks.onTextTracksChange?.(tracks);\n };\n\n const textTracks = videoEl.textTracks as TextTrackList & {\n addEventListener?: (\n type: string,\n listener: EventListenerOrEventListenerObject,\n ) => void;\n removeEventListener?: (\n type: string,\n listener: EventListenerOrEventListenerObject,\n ) => void;\n };\n textTracks.addEventListener?.(\"addtrack\", syncFromElement);\n syncFromElement();\n this.nativeTextTrackCleanup = () => {\n textTracks.removeEventListener?.(\"addtrack\", syncFromElement);\n };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.nativeTextTrackCleanup?.();\n this.nativeTextTrackCleanup = null;\n this.hls?.destroy();\n this.hls = null;\n const { videoEl } = this.options;\n videoEl.removeAttribute(\"src\");\n videoEl.load();\n }\n}\n","import { AuthManager } from \"../auth/AuthManager\";\nimport {\n assertNoSecretsInConfig,\n mergePlayerConfig,\n PACKAGE_VERSION,\n} from \"../config/defaults\";\nimport {\n createPlayerError,\n PlayerErrorCode,\n type PlayerError,\n} from \"../errors/PlayerError\";\nimport { EventEmitter } from \"../events/EventEmitter\";\nimport { Logger } from \"../logging/Logger\";\nimport { PlaybackSourceManager } from \"../playback/PlaybackSourceManager\";\nimport { RefreshManager } from \"../playback/RefreshManager\";\nimport {\n isAtLiveEdge,\n seekToLiveEdge,\n type SeekToLiveResult,\n} from \"../playback/liveEdge\";\nimport { HlsEngine } from \"../streaming/HlsEngine\";\nimport type {\n BufferedRange,\n CreateVideoPlayerOptions,\n PlayerAudioTrack,\n PlayerConfig,\n PlayerDiagnostics,\n PlayerState,\n PlayerTextTrack,\n QualitySelection,\n TextTrackSelection,\n} from \"../types\";\n\nfunction expiryStatus(\n expiresAt: number | null,\n safetyMs: number,\n): PlayerDiagnostics[\"authExpiryStatus\"] {\n if (expiresAt === null || expiresAt <= 0) return \"unknown\";\n const remaining = expiresAt - Date.now();\n if (remaining <= 0) return \"expired\";\n if (remaining <= safetyMs) return \"expiring_soon\";\n return \"valid\";\n}\n\nfunction generateSessionId(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `ps_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport type VideoPlayer = {\n play: () => Promise<void>;\n pause: () => void;\n seek: (time: number) => void;\n /** Jump to the latest live edge. No-op when already at live. */\n goToLive: () => SeekToLiveResult;\n isLive: () => boolean;\n isAtLiveEdge: () => boolean;\n getCurrentTime: () => number;\n getDuration: () => number;\n setVolume: (volume: number) => void;\n getVolume: () => number;\n mute: () => void;\n unmute: () => void;\n isMuted: () => boolean;\n setPlaybackRate: (rate: number) => void;\n getPlaybackRate: () => number;\n getState: () => PlayerState;\n getBufferedRanges: () => BufferedRange[];\n getQuality: () => QualitySelection;\n setQuality: (selection: QualitySelection | string) => void;\n getAvailableQualities: () => ReturnType<HlsEngine[\"getQualities\"]>;\n getTextTracks: () => PlayerTextTrack[];\n getSelectedTextTrack: () => TextTrackSelection;\n setTextTrack: (selection: TextTrackSelection) => void;\n getAudioTracks: () => PlayerAudioTrack[];\n getSelectedAudioTrack: () => number;\n setAudioTrack: (index: number) => void;\n enterFullscreen: () => Promise<void>;\n exitFullscreen: () => Promise<void>;\n isFullscreen: () => boolean;\n /** Attach fullscreen target container (host UI chrome). Zoom stays UI-only. */\n setFullscreenElement: (el: HTMLElement | null) => void;\n reload: () => Promise<void>;\n destroy: () => void;\n getDiagnostics: () => PlayerDiagnostics;\n getConfig: () => PlayerConfig;\n updateConfig: (partial: Parameters<typeof mergePlayerConfig>[0]) => void;\n on: EventEmitter[\"on\"];\n off: EventEmitter[\"off\"];\n};\n\n/**\n * Creates a framework-agnostic video player.\n * Never pass clientSecret — use auth.getToken / playback.getSource callbacks.\n */\nexport function createVideoPlayer(\n options: CreateVideoPlayerOptions,\n): VideoPlayer {\n // Scan only config-shaped fields — never deep-walk mount (HTMLVideoElement)\n // or credential callback objects (auth / playback).\n assertNoSecretsInConfig({\n videoId: options.videoId,\n sourceUrl: options.sourceUrl,\n player: options.player,\n controls: options.controls,\n theme: options.theme,\n watermark: options.watermark,\n streaming: options.streaming,\n logging: options.logging,\n debug: options.debug,\n accessibility: options.accessibility,\n });\n\n let config = mergePlayerConfig({\n player: options.player,\n controls: options.controls,\n theme: options.theme,\n watermark: options.watermark,\n streaming: options.streaming,\n logging: options.logging,\n debug: options.debug,\n accessibility: options.accessibility,\n });\n\n const events = new EventEmitter();\n const logger = new Logger(config.logging);\n const playbackSessionId = generateSessionId();\n\n let state: PlayerState = \"idle\";\n let destroyed = false;\n let lastError: PlayerError | null = null;\n let videoEl = options.mount ?? null;\n let engine: HlsEngine | null = null;\n let refreshManager: RefreshManager | null = null;\n let fullscreenEl: HTMLElement | null = null;\n let isLiveStream = false;\n let mediaCleanup: (() => void) | null = null;\n\n const setState = (next: PlayerState) => {\n if (destroyed && next !== \"destroyed\") return;\n state = next;\n events.emit(\"statechange\", { state: next });\n };\n\n const bindMediaProgressEvents = (el: HTMLVideoElement) => {\n mediaCleanup?.();\n const onTimeUpdate = () => {\n if (destroyed) return;\n events.emit(\"timeupdate\", {\n currentTime: el.currentTime,\n duration: Number.isFinite(el.duration) ? el.duration : 0,\n });\n };\n const onProgress = () => {\n if (destroyed) return;\n let bufferedEnd = 0;\n try {\n if (el.buffered.length > 0) {\n bufferedEnd = el.buffered.end(el.buffered.length - 1);\n }\n } catch {\n bufferedEnd = 0;\n }\n events.emit(\"progress\", { bufferedEnd });\n };\n // Keep control-bar mute icon in sync when the engine (or browser autoplay\n // policy) flips `video.muted` without going through player.mute()/unmute().\n const onVolumeChange = () => {\n if (destroyed) return;\n events.emit(\"volumechange\", {\n volume: el.volume,\n muted: el.muted,\n });\n };\n el.addEventListener(\"timeupdate\", onTimeUpdate);\n el.addEventListener(\"progress\", onProgress);\n el.addEventListener(\"volumechange\", onVolumeChange);\n mediaCleanup = () => {\n el.removeEventListener(\"timeupdate\", onTimeUpdate);\n el.removeEventListener(\"progress\", onProgress);\n el.removeEventListener(\"volumechange\", onVolumeChange);\n };\n };\n\n const authManager = new AuthManager(\n options.auth,\n options.auth?.refreshBeforeExpiryMs ?? 60_000,\n logger,\n (token) => events.emit(\"authrefresh\", { expiresAt: token.expiresAt }),\n (message, retryable) =>\n events.emit(\"autherror\", { message, retryable }),\n );\n\n const sourceManager = new PlaybackSourceManager(options.playback, logger);\n\n const ensureVideoElement = (): HTMLVideoElement => {\n if (!videoEl) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"A video element must be provided via mount before starting playback\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n return videoEl;\n };\n\n const startPlayback = async (): Promise<void> => {\n if (destroyed) return;\n setState(\"loading\");\n lastError = null;\n\n const videoId = options.videoId ?? \"unknown\";\n\n try {\n await authManager.ensureToken({\n reason: \"initial\",\n videoId: options.videoId,\n });\n\n let playbackUrl: string;\n let expiresAt: number;\n\n if (options.sourceUrl) {\n const source = {\n url: options.sourceUrl,\n expiresAt: Date.now() + 24 * 60 * 60 * 1000,\n live: /\\/hls-web-live\\//i.test(options.sourceUrl),\n };\n sourceManager.applyDirectSource(source);\n playbackUrl = source.url;\n expiresAt = source.expiresAt;\n isLiveStream = Boolean(source.live);\n } else {\n const source = await sourceManager.load({\n videoId,\n reason: \"initial\",\n });\n playbackUrl = source.url;\n expiresAt = source.expiresAt;\n isLiveStream = Boolean(source.live);\n }\n\n const el = ensureVideoElement();\n if (isLiveStream) {\n el.playbackRate = 1;\n }\n bindMediaProgressEvents(el);\n engine?.destroy();\n engine = new HlsEngine({\n videoEl: el,\n playbackUrl,\n authParams: sourceManager.authParams,\n autoplay: config.player.autoplay,\n startMuted: config.player.startMuted,\n startPosition: config.player.startPosition,\n volume: config.player.volume,\n videoId: options.videoId,\n keyProxyUrlBuilder: config.streaming.keyProxyUrlBuilder,\n // Enterprise AES key auth (see authParamsLoader):\n // 1) keyProxyUrlBuilder BFF — max 2 failures then circuit\n // 2) signed-query fetch (no Bearer / no CORS preflight)\n // 3) Bearer only on HTTP 401/403 when getKeyAccessToken is set\n // 4) signed-query XHR fallback if fetch is CORS-blocked\n getKeyAccessToken:\n config.streaming.getKeyAccessToken ??\n (() => authManager.getAccessToken()),\n keyProxyMaxFailures: config.streaming.keyProxyMaxFailures,\n hlsConfig: config.streaming.hls,\n logger,\n callbacks: {\n onStateChange: (s) => {\n setState(s);\n if (s === \"ready\") events.emit(\"ready\");\n if (s === \"playing\") {\n events.emit(\"play\");\n events.emit(\"playing\");\n }\n if (s === \"paused\") events.emit(\"pause\");\n if (s === \"buffering\") events.emit(\"buffering\");\n if (s === \"ended\") events.emit(\"ended\");\n },\n onFatalError: (message) => {\n lastError = createPlayerError(\n PlayerErrorCode.PLAYBACK_ERROR,\n message,\n { category: \"playback\", fatal: true, retryable: true },\n );\n setState(\"error\");\n events.emit(\"error\", {\n code: lastError.code,\n message: lastError.message,\n fatal: true,\n });\n },\n onAuthRecoveryNeeded: (reason) => {\n refreshManager?.requestRenew(\n reason as \"frag_error\" | \"level_error\" | \"key_error\" | \"fatal_network\",\n );\n },\n onQualitiesChange: () => {\n /* consumers poll getAvailableQualities */\n },\n onQualitySelectionChange: (selection) => {\n const level = engine\n ?.getQualities()\n .find((q) => q.index === selection);\n events.emit(\"qualitychange\", {\n selection,\n label: typeof selection === \"number\" ? level?.label : \"auto\",\n });\n },\n onTextTracksChange: (tracks) => {\n events.emit(\"texttrackchange\", {\n tracks,\n selection: engine?.getTextTrackSelection() ?? \"off\",\n });\n },\n onTextTrackSelectionChange: (selection) => {\n events.emit(\"texttrackchange\", {\n tracks: engine?.getTextTracks() ?? [],\n selection,\n });\n },\n onAudioTracksChange: (tracks) => {\n events.emit(\"audiotrackchange\", {\n tracks,\n selection: engine?.getAudioTrackSelection() ?? 0,\n });\n },\n onAudioTrackSelectionChange: (selection) => {\n events.emit(\"audiotrackchange\", {\n tracks: engine?.getAudioTracks() ?? [],\n selection,\n });\n },\n onEnded: () => events.emit(\"ended\"),\n },\n });\n\n await engine.start();\n\n // Emit after engine applies startMuted / volume so the UI does not keep a\n // stale unmuted icon when autoplay later force-mutes (Chrome policy).\n if (!destroyed && videoEl) {\n events.emit(\"volumechange\", {\n volume: videoEl.volume,\n muted: videoEl.muted,\n });\n }\n\n if (!options.sourceUrl && options.playback) {\n refreshManager?.stop();\n refreshManager = new RefreshManager({\n videoId,\n authManager,\n sourceManager,\n refreshBeforeExpiryMs:\n options.playback.refreshBeforeExpiryMs ?? 30_000,\n renewMaxRetries: options.playback.renewMaxRetries ?? 3,\n renewBackoffMs: options.playback.renewBackoffMs ?? 2_000,\n coalesceMs: options.playback.authRecoveryCoalesceMs ?? 1_000,\n logger,\n isDestroyed: () => destroyed,\n onRenewing: () => setState(\"renewing\"),\n onRenewed: (nextExpiresAt) => {\n engine?.resumeAfterAuthRenew();\n if (!destroyed) {\n const el = videoEl;\n if (el && !el.paused && !el.ended) {\n setState(\"playing\");\n } else {\n setState(\"ready\");\n }\n }\n events.emit(\"tokenrefresh\", { expiresAt: nextExpiresAt });\n events.emit(\"sourcechange\", { expiresAt: nextExpiresAt });\n },\n onFatal: (message) => {\n lastError = createPlayerError(\n PlayerErrorCode.TOKEN_REFRESH_FAILED,\n message,\n { category: \"auth\", fatal: true, retryable: true },\n );\n setState(\"error\");\n events.emit(\"error\", {\n code: lastError.code,\n message: lastError.message,\n fatal: true,\n });\n },\n });\n refreshManager.start(expiresAt);\n }\n\n options.analytics?.onEvent?.({\n type: \"PLAYER_INITIALIZED\",\n payload: { videoId, playbackSessionId },\n });\n } catch (error) {\n const playerError =\n error && typeof error === \"object\" && \"code\" in error\n ? (error as PlayerError)\n : createPlayerError(\n PlayerErrorCode.UNKNOWN,\n error instanceof Error ? error.message : \"Failed to start player\",\n { category: \"unknown\", fatal: true, retryable: true, cause: error },\n );\n lastError = playerError;\n setState(\"error\");\n events.emit(\"error\", {\n code: playerError.code,\n message: playerError.message,\n fatal: playerError.fatal,\n });\n throw playerError;\n }\n };\n\n // Auto-start when mount is provided\n if (options.mount) {\n void startPlayback().catch(() => {\n /* error already emitted */\n });\n }\n\n const api: VideoPlayer = {\n async play() {\n await ensureVideoElement().play();\n },\n pause() {\n ensureVideoElement().pause();\n },\n seek(time: number) {\n const el = ensureVideoElement();\n const duration = Number.isFinite(el.duration) ? el.duration : time;\n el.currentTime = Math.min(Math.max(0, time), duration);\n },\n goToLive() {\n const el = ensureVideoElement();\n return seekToLiveEdge(el);\n },\n isLive() {\n return isLiveStream;\n },\n isAtLiveEdge() {\n if (!isLiveStream || !videoEl) {\n return true;\n }\n return isAtLiveEdge(videoEl);\n },\n getCurrentTime() {\n return videoEl?.currentTime ?? 0;\n },\n getDuration() {\n return videoEl?.duration ?? 0;\n },\n setVolume(volume: number) {\n const el = ensureVideoElement();\n el.volume = Math.min(1, Math.max(0, volume));\n events.emit(\"volumechange\", { volume: el.volume, muted: el.muted });\n },\n getVolume() {\n return videoEl?.volume ?? 0;\n },\n mute() {\n const el = ensureVideoElement();\n el.muted = true;\n events.emit(\"volumechange\", { volume: el.volume, muted: true });\n },\n unmute() {\n const el = ensureVideoElement();\n el.muted = false;\n events.emit(\"volumechange\", { volume: el.volume, muted: false });\n },\n isMuted() {\n return videoEl?.muted ?? false;\n },\n setPlaybackRate(rate: number) {\n const el = ensureVideoElement();\n // Live streams always play at 1x — speed controls are hidden.\n el.playbackRate = isLiveStream ? 1 : rate;\n },\n getPlaybackRate() {\n return videoEl?.playbackRate ?? 1;\n },\n getState() {\n return state;\n },\n getBufferedRanges() {\n const el = videoEl;\n if (!el) return [];\n const ranges: BufferedRange[] = [];\n for (let i = 0; i < el.buffered.length; i += 1) {\n ranges.push({ start: el.buffered.start(i), end: el.buffered.end(i) });\n }\n return ranges;\n },\n getQuality() {\n return engine?.getQuality() ?? \"auto\";\n },\n setQuality(selection: QualitySelection | string) {\n if (selection === \"auto\") {\n engine?.setQuality(\"auto\");\n return;\n }\n if (typeof selection === \"number\") {\n engine?.setQuality(selection);\n return;\n }\n const match = engine\n ?.getQualities()\n .find((q) => q.label === selection || `${q.height}p` === selection);\n if (match) engine?.setQuality(match.index);\n },\n getAvailableQualities() {\n return engine?.getQualities() ?? [];\n },\n getTextTracks() {\n return engine?.getTextTracks() ?? [];\n },\n getSelectedTextTrack() {\n return engine?.getTextTrackSelection() ?? \"off\";\n },\n setTextTrack(selection: TextTrackSelection) {\n engine?.setTextTrack(selection);\n },\n getAudioTracks() {\n return engine?.getAudioTracks() ?? [];\n },\n getSelectedAudioTrack() {\n return engine?.getAudioTrackSelection() ?? 0;\n },\n setAudioTrack(index: number) {\n engine?.setAudioTrack(index);\n },\n async enterFullscreen() {\n const target = fullscreenEl ?? videoEl?.parentElement ?? videoEl;\n if (target && \"requestFullscreen\" in target) {\n await target.requestFullscreen();\n events.emit(\"fullscreenchange\", { isFullscreen: true });\n }\n },\n async exitFullscreen() {\n if (document.fullscreenElement) {\n await document.exitFullscreen();\n events.emit(\"fullscreenchange\", { isFullscreen: false });\n }\n },\n isFullscreen() {\n return Boolean(document.fullscreenElement);\n },\n setFullscreenElement(el: HTMLElement | null) {\n fullscreenEl = el;\n },\n async reload() {\n refreshManager?.stop();\n engine?.destroy();\n await startPlayback();\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n mediaCleanup?.();\n mediaCleanup = null;\n refreshManager?.stop();\n refreshManager = null;\n engine?.destroy();\n engine = null;\n authManager.destroy();\n sourceManager.destroy();\n setState(\"destroyed\");\n events.emit(\"destroy\");\n events.removeAll();\n options.analytics?.onEvent?.({ type: \"PLAYER_DESTROYED\" });\n },\n getDiagnostics() {\n const buffered = api.getBufferedRanges();\n return {\n playerVersion: PACKAGE_VERSION,\n currentState: state,\n hlsSupport: engine?.getSupportMode() ?? \"unsupported\",\n videoId: options.videoId ?? null,\n currentTime: api.getCurrentTime(),\n duration: api.getDuration(),\n bufferedEnd: buffered.length ? buffered[buffered.length - 1]!.end : 0,\n currentQuality:\n api.getQuality() === \"auto\"\n ? \"auto\"\n : engine?.getQualities().find((q) => q.index === api.getQuality())\n ?.label ?? null,\n playbackSessionId,\n authExpiryStatus: expiryStatus(\n authManager.getExpiresAt(),\n options.auth?.refreshBeforeExpiryMs ?? 60_000,\n ),\n sourceExpiryStatus: expiryStatus(\n sourceManager.getExpiresAt(),\n options.playback?.refreshBeforeExpiryMs ?? 30_000,\n ),\n lastError: lastError?.message ?? null,\n };\n },\n getConfig() {\n return config;\n },\n updateConfig(partial) {\n config = mergePlayerConfig({\n player: { ...config.player, ...partial?.player },\n controls: { ...config.controls, ...partial?.controls },\n theme: { ...config.theme, ...partial?.theme },\n watermark: { ...config.watermark, ...partial?.watermark },\n streaming: {\n engine: \"hls\",\n hls: { ...config.streaming.hls, ...partial?.streaming?.hls },\n keyProxyUrlBuilder:\n partial?.streaming?.keyProxyUrlBuilder ??\n config.streaming.keyProxyUrlBuilder,\n getKeyAccessToken:\n partial?.streaming?.getKeyAccessToken ??\n config.streaming.getKeyAccessToken ??\n (() => authManager.getAccessToken()),\n keyProxyMaxFailures:\n partial?.streaming?.keyProxyMaxFailures ??\n config.streaming.keyProxyMaxFailures,\n },\n logging: { ...config.logging, ...partial?.logging },\n debug: { ...config.debug, ...partial?.debug },\n accessibility: {\n ...config.accessibility,\n ...partial?.accessibility,\n },\n });\n logger.update(config.logging);\n },\n on: events.on.bind(events),\n off: events.off.bind(events),\n };\n\n // Allow attaching mount after create\n (api as VideoPlayer & { attach: (el: HTMLVideoElement, container?: HTMLElement) => Promise<void> }).attach =\n async (el: HTMLVideoElement, container?: HTMLElement) => {\n videoEl = el;\n fullscreenEl = container ?? null;\n await startPlayback();\n };\n\n return api;\n}\n\nexport type { CreateVideoPlayerOptions };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAK,kBAAL,kBAAKA,qBAAL;AACL,EAAAA,iBAAA,2BAAwB;AACxB,EAAAA,iBAAA,2BAAwB;AACxB,EAAAA,iBAAA,+BAA4B;AAC5B,EAAAA,iBAAA,mBAAgB;AAChB,EAAAA,iBAAA,0BAAuB;AACvB,EAAAA,iBAAA,8BAA2B;AAC3B,EAAAA,iBAAA,0BAAuB;AACvB,EAAAA,iBAAA,yBAAsB;AACtB,EAAAA,iBAAA,mBAAgB;AAChB,EAAAA,iBAAA,oBAAiB;AACjB,EAAAA,iBAAA,yBAAsB;AACtB,EAAAA,iBAAA,sBAAmB;AACnB,EAAAA,iBAAA,aAAU;AAbA,SAAAA;AAAA,GAAA;AA0BL,SAAS,kBACd,MACA,SACA,SACa;AACb,SAAO;AAAA,IACL;AAAA,IACA,SAAS,gBAAgB,OAAO;AAAA,IAChC,UAAU,SAAS,YAAY;AAAA,IAC/B,OAAO,SAAS,SAAS;AAAA,IACzB,WAAW,SAAS,aAAa;AAAA,IACjC,WAAW,KAAK,IAAI;AAAA,IACpB,OAAO,SAAS;AAAA,EAClB;AACF;AAEO,SAAS,gBAAgB,OAAuB;AACrD,SAAO,MACJ,QAAQ,uBAAuB,cAAc,EAC7C,QAAQ,+CAA+C,cAAc,EACrE,QAAQ,+BAA+B,cAAc;AAC1D;;;AC/BO,IAAM,cAAN,MAAkB;AAAA,EASvB,YACmB,MACA,uBACA,QACA,aACA,SACjB,yBAAyB,GACzB;AANiB;AACA;AACA;AACA;AACA;AAbnB,SAAQ,QAA0B;AAClC,SAAQ,WAAsC;AAC9C,SAAQ,QAA8C;AACtD,SAAQ,YAAY;AAEpB;AAAA,SAAQ,uBAAuB;AAW7B,SAAK,yBAAyB,KAAK,IAAI,GAAG,sBAAsB;AAAA,EAClE;AAAA,EAEA,iBAAgC;AAC9B,WAAO,KAAK,OAAO,eAAe;AAAA,EACpC;AAAA,EAEA,eAA8B;AAC5B,WAAO,KAAK,OAAO,aAAa;AAAA,EAClC;AAAA,EAEA,MAAM,YACJ,SAC2B;AAC3B,QAAI,CAAC,KAAK,MAAM,SAAU,QAAO;AACjC,QAAI,KAAK,UAAW,QAAO;AAE3B,QACE,KAAK,SACL,QAAQ,WAAW,kBACnB,QAAQ,WAAW,YACnB,KAAK,MAAM,YAAY,KAAK,IAAI,IAAI,KAAK,uBACzC;AACA,aAAO,KAAK;AAAA,IACd;AAEA,WAAO,KAAK,QAAQ,OAAO;AAAA,EAC7B;AAAA,EAEA,MAAM,QAAQ,SAAuD;AACnE,QAAI,CAAC,KAAK,MAAM,UAAU;AACxB,YAAM;AAAA;AAAA,QAEJ;AAAA,QACA,EAAE,UAAU,UAAU,OAAO,MAAM,WAAW,MAAM;AAAA,MACtD;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,gBAAgB;AACrC,UAAI,KAAK,wBAAwB,KAAK,wBAAwB;AAC5D,cAAM,UACJ;AACF,aAAK,UAAU,SAAS,KAAK;AAC7B,cAAM;AAAA;AAAA,UAEJ;AAAA,UACA,EAAE,UAAU,QAAQ,OAAO,MAAM,WAAW,MAAM;AAAA,QACpD;AAAA,MACF;AACA,WAAK,wBAAwB;AAAA,IAC/B;AAEA,QAAI,KAAK,SAAU,QAAO,KAAK;AAE/B,SAAK,YAAY,YAAY;AAC3B,UAAI;AACF,cAAM,OAAO,MAAM,KAAK,KAAM,SAAS,OAAO;AAC9C,YACE,CAAC,MAAM,eACP,OAAO,KAAK,cAAc,YAC1B,KAAK,aAAa,GAClB;AACA,gBAAM;AAAA;AAAA,YAEJ;AAAA,YACA,EAAE,UAAU,QAAQ,OAAO,MAAM,WAAW,KAAK;AAAA,UACnD;AAAA,QACF;AACA,aAAK,QAAQ;AACb,YAAI,QAAQ,WAAW,gBAAgB;AACrC,eAAK,uBAAuB;AAAA,QAC9B;AACA,aAAK,yBAAyB;AAC9B,aAAK,cAAc,IAAI;AACvB,aAAK,OAAO,MAAM,wBAAwB;AAAA,UACxC,QAAQ,QAAQ;AAAA,UAChB,WAAW,KAAK;AAAA,QAClB,CAAC;AACD,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YACE,SACA,OAAO,UAAU,YACjB,UAAU,SACT,MAA2B,sEAE5B;AACA,gBAAM;AAAA,QACR;AACA,cAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,cAAM,YAAY,KAAK,wBAAwB,KAAK;AACpD,aAAK,UAAU,SAAS,SAAS;AACjC,cAAM;AAAA;AAAA,UAEJ;AAAA,UACA,EAAE,UAAU,QAAQ,OAAO,CAAC,WAAW,WAAW,OAAO,MAAM;AAAA,QACjE;AAAA,MACF,UAAE;AACA,aAAK,WAAW;AAAA,MAClB;AAAA,IACF,GAAG;AAEH,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,2BAAiC;AACvC,QAAI,KAAK,MAAO,cAAa,KAAK,KAAK;AACvC,QAAI,CAAC,KAAK,SAAS,KAAK,UAAW;AACnC,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,MACA,KAAK,MAAM,YAAY,KAAK,IAAI,IAAI,KAAK;AAAA,IAC3C;AACA,SAAK,QAAQ,WAAW,MAAM;AAC5B,WAAK,KAAK,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,CAAC,EAAE,MAAM,MAAM;AAAA,MAEf,CAAC;AAAA,IACH,GAAG,KAAK;AAAA,EACV;AAAA,EAEA,UAAgB;AACd,SAAK,YAAY;AACjB,QAAI,KAAK,MAAO,cAAa,KAAK,KAAK;AACvC,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,WAAW;AAAA,EAClB;AACF;;;AC3JO,IAAM,iBAAiB,CAAC,KAAK,MAAM,GAAG,MAAM,KAAK,CAAC;AAElD,IAAM,kBAAkB;AAExB,IAAM,0BAA0D;AAAA,EACrE,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,aAAa;AAAA,EACb,kBAAkB,eAAe;AAAA,EACjC,aAAa;AAAA,EACb,aAAa;AAAA,EACb,eAAe;AACjB;AAEO,IAAM,mBAA6C;AAAA,EACxD,SAAS;AAAA,EACT,aAAa;AAAA,EACb,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,0BAA0B;AAC5B;AAEO,IAAM,gBAAuC;AAAA,EAClD,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,yBAAyB;AAAA,EACzB,+BAA+B;AAAA,EAC/B,8BAA8B;AAAA,EAC9B,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,6BAA6B;AAAA,EAC7B,4BAA4B;AAAA,EAC5B,eAAe;AAAA,EACf,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,cAAc;AAChB;AAEO,IAAM,oBAA+C;AAAA,EAC1D,SAAS;AAAA,EACT,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,eAAe;AACjB;AAEO,IAAM,wBAAsC;AAAA,EACjD,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AAAA,EACX,WAAW;AAAA,IACT,QAAQ;AAAA,IACR,KAAK;AAAA,MACH,cAAc;AAAA;AAAA,MAEd,gBAAgB;AAAA,MAChB,kBAAkB;AAAA,MAClB,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA,EACA,SAAS,EAAE,SAAS,OAAO,OAAO,QAAQ;AAAA,EAC1C,OAAO,EAAE,SAAS,OAAO,SAAS,OAAO,QAAQ,OAAO,OAAO,MAAM;AAAA,EACrE,eAAe,EAAE,eAAe,MAAM;AACxC;AAEA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,IAAM,wBAAwB;AAM9B,SAAS,cAAc,OAAkD;AAC9E,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,QAAM,QAAQ,OAAO,eAAe,KAAK;AACzC,SAAO,UAAU,OAAO,aAAa,UAAU;AACjD;AAEA,SAAS,mBAAmB,KAAqB;AAC/C,SAAO,IAAI,YAAY,EAAE,QAAQ,cAAc,EAAE;AACnD;AAEA,SAAS,qBAAqB,KAAsB;AAClD,QAAM,QAAQ,mBAAmB,GAAG;AACpC,SAAO,sBAAsB,KAAK,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC;AAC5D;AAEA,SAAS,eAAe,MAAc,KAAoB;AACxD,QAAM,IAAI;AAAA,IACR,gDAAgD,IAAI,GAAG,GAAG;AAAA,EAC5D;AACF;AAWO,SAAS,wBAAwB,KAAoB;AAC1D,MAAI,CAAC,cAAc,GAAG,KAAK,CAAC,MAAM,QAAQ,GAAG,EAAG;AAEhD,QAAM,OAAO,oBAAI,QAAgB;AACjC,QAAM,QAAgE;AAAA,IACpE,EAAE,OAAO,KAAK,MAAM,IAAI,OAAO,EAAE;AAAA,EACnC;AAEA,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI,QAAQ,QAAQ,sBAAuB;AAE3C,UAAM,EAAE,OAAO,MAAM,MAAM,IAAI;AAE/B,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAI,KAAK,IAAI,KAAK,EAAG;AACrB,WAAK,IAAI,KAAK;AACd,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,cAAM,OAAO,MAAM,CAAC;AACpB,YAAI,cAAc,IAAI,KAAK,MAAM,QAAQ,IAAI,GAAG;AAC9C,gBAAM,KAAK,EAAE,OAAO,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,OAAO,QAAQ,EAAE,CAAC;AAAA,QACrE;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,CAAC,cAAc,KAAK,EAAG;AAC3B,QAAI,KAAK,IAAI,KAAK,EAAG;AACrB,SAAK,IAAI,KAAK;AAEd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAM,aAAa,mBAAmB,GAAG;AAEzC,UAAI,qBAAqB,GAAG,GAAG;AAC7B,uBAAe,MAAM,GAAG;AAAA,MAC1B;AAGA,UAAI,eAAe,QAAS;AAG5B,UAAI,oBAAoB,IAAI,UAAU,GAAG;AACvC,YAAI,cAAc,KAAK,GAAG;AACxB,qBAAW,aAAa,OAAO,KAAK,KAAK,GAAG;AAC1C,gBAAI,qBAAqB,SAAS,GAAG;AACnC,6BAAe,GAAG,IAAI,GAAG,GAAG,KAAK,SAAS;AAAA,YAC5C;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,cAAc,KAAK,KAAK,MAAM,QAAQ,KAAK,GAAG;AAChD,cAAM,KAAK;AAAA,UACT,OAAO;AAAA,UACP,MAAM,OAAO,GAAG,IAAI,GAAG,GAAG,MAAM,GAAG,GAAG;AAAA,UACtC,OAAO,QAAQ;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAmBO,SAAS,kBAAkB,SAA6C;AAC7E,0BAAwB,OAAO;AAC/B,SAAO;AAAA,IACL,QAAQ,EAAE,GAAG,yBAAyB,GAAG,SAAS,OAAO;AAAA,IACzD,UAAU,EAAE,GAAG,kBAAkB,GAAG,SAAS,SAAS;AAAA,IACtD,OAAO,EAAE,GAAG,eAAe,GAAG,SAAS,MAAM;AAAA,IAC7C,WAAW,EAAE,GAAG,mBAAmB,GAAG,SAAS,UAAU;AAAA,IACzD,WAAW;AAAA,MACT,QAAQ;AAAA,MACR,KAAK;AAAA,QACH,GAAG,sBAAsB,UAAU;AAAA,QACnC,GAAG,SAAS,WAAW;AAAA,MACzB;AAAA,MACA,oBAAoB,SAAS,WAAW;AAAA,MACxC,mBAAmB,SAAS,WAAW;AAAA,MACvC,qBAAqB,SAAS,WAAW;AAAA,IAC3C;AAAA,IACA,SAAS,EAAE,GAAG,sBAAsB,SAAS,GAAG,SAAS,QAAQ;AAAA,IACjE,OAAO,EAAE,GAAG,sBAAsB,OAAO,GAAG,SAAS,MAAM;AAAA,IAC3D,eAAe;AAAA,MACb,GAAG,sBAAsB;AAAA,MACzB,GAAG,SAAS;AAAA,IACd;AAAA,EACF;AACF;AAGO,SAAS,eACd,OACwB;AACxB,SAAO;AAAA,IACL,wBAAwB,MAAM;AAAA,IAC9B,0BAA0B,MAAM;AAAA,IAChC,uBAAuB,MAAM;AAAA,IAC7B,0BAA0B,MAAM;AAAA,IAChC,0BAA0B,MAAM;AAAA,IAChC,iBAAiB,MAAM;AAAA,IACvB,yBAAyB,MAAM;AAAA,IAC/B,uBAAuB,MAAM;AAAA,IAC7B,oBAAoB,MAAM;AAAA,IAC1B,wBAAwB,MAAM;AAAA,IAC9B,yBAAyB,MAAM;AAAA,IAC/B,4BAA4B,MAAM;AAAA,IAClC,yBAAyB,MAAM;AAAA,IAC/B,uBAAuB,MAAM;AAAA,IAC7B,8BAA8B,MAAM;AAAA,IACpC,gCAAgC,MAAM;AAAA,IACtC,uBAAuB,MAAM;AAAA,IAC7B,qBAAqB,MAAM;AAAA,IAC3B,4BAA4B,MAAM;AAAA,IAClC,8BAA8B,MAAM;AAAA,IACpC,sBAAsB,MAAM;AAAA,IAC5B,sBAAsB,MAAM;AAAA,IAC5B,wBAAwB,MAAM;AAAA,IAC9B,0BAA0B,MAAM;AAAA,IAChC,qBAAqB,MAAM;AAAA,EAC7B;AACF;;;AChSO,IAAM,eAAN,MAAmB;AAAA,EAAnB;AACL,SAAQ,YAAY,oBAAI,IAAyC;AAAA;AAAA,EAEjE,GACE,OACA,SACY;AACZ,QAAI,MAAM,KAAK,UAAU,IAAI,KAAK;AAClC,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,WAAK,UAAU,IAAI,OAAO,GAAG;AAAA,IAC/B;AACA,QAAI,IAAI,OAAO;AACf,WAAO,MAAM,KAAK,IAAI,OAAO,OAAO;AAAA,EACtC;AAAA,EAEA,IACE,OACA,SACM;AACN,SAAK,UAAU,IAAI,KAAK,GAAG,OAAO,OAAO;AAAA,EAC3C;AAAA,EAEA,KACE,UACG,MACG;AACN,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,QAAI,CAAC,IAAK;AACV,eAAW,WAAW,KAAK;AACzB,UAAI;AACF,QAAC,QAAqB,GAAG,IAAI;AAAA,MAC/B,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;;;AC7CA,IAAM,iBACJ;AAEF,IAAM,mBAAmB;AAEzB,SAASC,eAAc,OAAkD;AACvE,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,QAAM,QAAQ,OAAO,eAAe,KAAK;AACzC,SAAO,UAAU,OAAO,aAAa,UAAU;AACjD;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,CAAC,gBAAgB,KAAK,KAAK,KAAK,CAAC,wBAAwB,KAAK,KAAK,GAAG;AACxE,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,eAAW,SAAS,CAAC,SAAS,WAAW,aAAa,KAAK,GAAG;AAC5D,UAAI,IAAI,aAAa,IAAI,KAAK,GAAG;AAC/B,YAAI,aAAa,IAAI,OAAO,YAAY;AAAA,MAC1C;AAAA,IACF;AACA,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,YACd,KACA,OACA,OAAwB,oBAAI,QAAQ,GACpC,QAAQ,GACC;AACT,MAAI,eAAe,KAAK,GAAG,EAAG,QAAO;AACrC,MAAI,OAAO,UAAU,SAAU,QAAO,gBAAgB,KAAK;AAC3D,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,QAAI,SAAS,oBAAoB,KAAK,IAAI,KAAK,EAAG,QAAO;AACzD,SAAK,IAAI,KAAK;AACd,WAAO,MAAM;AAAA,MAAI,CAAC,MAAM,UACtB,YAAY,OAAO,KAAK,GAAG,MAAM,MAAM,QAAQ,CAAC;AAAA,IAClD;AAAA,EACF;AACA,MAAIA,eAAc,KAAK,GAAG;AACxB,WAAO,aAAa,OAAO,MAAM,QAAQ,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAMO,SAAS,aACd,KACA,OAAwB,oBAAI,QAAQ,GACpC,QAAQ,GACiB;AACzB,MAAI,QAAQ,iBAAkB,QAAO,EAAE,cAAc,YAAY;AACjE,MAAI,KAAK,IAAI,GAAG,EAAG,QAAO,EAAE,cAAc,QAAQ;AAClD,OAAK,IAAI,GAAG;AAEZ,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,QAAI,GAAG,IAAI,YAAY,KAAK,OAAO,MAAM,KAAK;AAAA,EAChD;AACA,SAAO;AACT;;;ACjEA,IAAM,SAAS,CAAC,UAAU,SAAS,QAAQ,QAAQ,SAAS,OAAO;AAE5D,IAAM,SAAN,MAAa;AAAA,EAClB,YAAoB,QAAiC;AAAjC;AAAA,EAAkC;AAAA,EAEtD,OAAO,QAAsC;AAC3C,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAO;AAAA,EAC5C;AAAA,EAEQ,UAAU,OAAyC;AACzD,QAAI,CAAC,KAAK,OAAO,WAAW,KAAK,OAAO,UAAU,SAAU,QAAO;AACnE,WAAO,OAAO,QAAQ,KAAK,KAAK,OAAO,QAAQ,KAAK,OAAO,KAAK;AAAA,EAClE;AAAA,EAEQ,MACN,OACA,SACA,SACM;AACN,QAAI,CAAC,KAAK,UAAU,KAAK,EAAG;AAC5B,UAAM,UAAU,UAAU,aAAa,OAAO,IAAI;AAClD,UAAM,KAAK,QAAQ,KAAK,KAAK,QAAQ;AACrC,QAAI,QAAS,IAAG,gBAAgB,OAAO,IAAI,OAAO;AAAA,QAC7C,IAAG,gBAAgB,OAAO,EAAE;AAAA,EACnC;AAAA,EAEA,MAAM,SAAiB,SAAyC;AAC9D,SAAK,MAAM,SAAS,SAAS,OAAO;AAAA,EACtC;AAAA,EAEA,KAAK,SAAiB,SAAyC;AAC7D,SAAK,MAAM,QAAQ,SAAS,OAAO;AAAA,EACrC;AAAA,EAEA,KAAK,SAAiB,SAAyC;AAC7D,SAAK,MAAM,QAAQ,SAAS,OAAO;AAAA,EACrC;AAAA,EAEA,MAAM,SAAiB,SAAyC;AAC9D,SAAK,MAAM,SAAS,SAAS,OAAO;AAAA,EACtC;AACF;;;ACxCO,IAAM,kBAAN,MAAsB;AAAA,EAG3B,YAAY,SAAoD;AAC9D,QAAI,mBAAmB,iBAAiB;AACtC,WAAK,SAAS,IAAI,gBAAgB,OAAO;AAAA,IAC3C,WAAW,SAAS;AAClB,WAAK,SAAS,IAAI,gBAAgB,OAAO;AAAA,IAC3C,OAAO;AACL,WAAK,SAAS,IAAI,gBAAgB;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,cAA+B;AAC7B,WAAO,IAAI,gBAAgB,KAAK,MAAM;AAAA,EACxC;AAAA,EAEA,WAAmC;AACjC,UAAM,MAA8B,CAAC;AACrC,SAAK,OAAO,QAAQ,CAAC,OAAO,QAAQ;AAClC,UAAI,GAAG,IAAI;AAAA,IACb,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,YAAqB;AACnB,WAAO,CAAC,GAAG,KAAK,OAAO,KAAK,CAAC,EAAE,SAAS;AAAA,EAC1C;AAAA,EAEA,WAAmB;AACjB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,OAAO,MAAsD;AAC3D,SAAK,SACH,gBAAgB,kBACZ,IAAI,gBAAgB,IAAI,IACxB,IAAI,gBAAgB,IAAI;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,QAAgB,YAA6B;AACtD,UAAM,SAAS,IAAI;AAAA,MACjB;AAAA,MACA,eACG,OAAO,aAAa,cAAc,SAAS,SAAS;AAAA,IACzD;AACA,SAAK,OAAO,QAAQ,CAAC,OAAO,QAAQ;AAClC,aAAO,aAAa,IAAI,KAAK,KAAK;AAAA,IACpC,CAAC;AACD,WAAO,OAAO,SAAS;AAAA,EACzB;AACF;;;AC7CO,IAAM,wBAAN,MAA4B;AAAA,EAKjC,YACmB,UACA,QACjB;AAFiB;AACA;AANnB,SAAQ,SAAgC;AACxC,SAAQ,WAA2C;AACnD,SAAS,aAAa,IAAI,gBAAgB;AAAA,EAKvC;AAAA,EAEH,YAAmC;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,eAA8B;AAC5B,WAAO,KAAK,QAAQ,aAAa;AAAA,EACnC;AAAA,EAEA,MAAM,KACJ,SACyB;AACzB,QAAI,CAAC,KAAK,UAAU,WAAW;AAC7B,YAAM;AAAA;AAAA,QAEJ;AAAA,QACA,EAAE,UAAU,UAAU,OAAO,MAAM,WAAW,MAAM;AAAA,MACtD;AAAA,IACF;AACA,WAAO,KAAK,IAAI,SAAS,MAAM,KAAK,SAAU,UAAU,OAAO,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,QACJ,SACyB;AACzB,UAAM,YACJ,KAAK,UAAU,iBAAiB,KAAK,UAAU;AACjD,QAAI,CAAC,WAAW;AACd,YAAM;AAAA;AAAA,QAEJ;AAAA,QACA,EAAE,UAAU,UAAU,OAAO,MAAM,WAAW,MAAM;AAAA,MACtD;AAAA,IACF;AACA,WAAO,KAAK,IAAI,SAAS,MAAM,UAAU,OAAO,CAAC;AAAA,EACnD;AAAA,EAEA,kBAAkB,QAA8B;AAC9C,SAAK,SAAS;AACd,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA,EAEA,MAAc,IACZ,SACA,IACyB;AACzB,QAAI,KAAK,SAAU,QAAO,KAAK;AAE/B,SAAK,YAAY,YAAY;AAC3B,UAAI;AACF,cAAM,OAAO,MAAM,GAAG;AACtB,YAAI,CAAC,MAAM,OAAO,OAAO,KAAK,cAAc,UAAU;AACpD,gBAAM;AAAA;AAAA,YAEJ;AAAA,YACA,EAAE,UAAU,YAAY,OAAO,MAAM,WAAW,KAAK;AAAA,UACvD;AAAA,QACF;AACA,aAAK,SAAS;AACd,aAAK,gBAAgB,IAAI;AACzB,aAAK,OAAO,MAAM,4BAA4B;AAAA,UAC5C,QAAQ,QAAQ;AAAA,UAChB,WAAW,KAAK;AAAA,QAClB,CAAC;AACD,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI,SAAS,OAAO,UAAU,YAAY,UAAU,MAAO,OAAM;AACjE,cAAM;AAAA;AAAA,UAEJ,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UACzC,EAAE,UAAU,YAAY,OAAO,MAAM,WAAW,MAAM,OAAO,MAAM;AAAA,QACrE;AAAA,MACF,UAAE;AACA,aAAK,WAAW;AAAA,MAClB;AAAA,IACF,GAAG;AAEH,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,gBAAgB,QAA8B;AACpD,QAAI,OAAO,YAAY;AACrB,WAAK,WAAW,OAAO,OAAO,UAAU;AACxC;AAAA,IACF;AACA,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,OAAO,GAAG;AAC9B,YAAM,SAAiC,CAAC;AACxC,UAAI,aAAa,QAAQ,CAAC,OAAO,QAAQ;AACvC,eAAO,GAAG,IAAI;AAAA,MAChB,CAAC;AACD,UAAI,OAAO,MAAO,QAAO,QAAQ,OAAO;AACxC,WAAK,WAAW,OAAO,MAAM;AAAA,IAC/B,QAAQ;AACN,UAAI,OAAO,OAAO;AAChB,aAAK,WAAW,OAAO,EAAE,OAAO,OAAO,MAAM,CAAC;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,SAAS;AACd,SAAK,WAAW;AAAA,EAClB;AACF;;;ACjGO,IAAM,iBAAN,MAAqB;AAAA,EAQ1B,YAA6B,SAAgC;AAAhC;AAP7B,SAAQ,QAA8C;AACtD,SAAQ,gBAAsD;AAC9D,SAAQ,WAAW;AACnB,SAAQ,sBAAsB;AAC9B,SAAQ,UAAU;AAClB,SAAQ,gBAAsC;AAAA,EAEgB;AAAA,EAE9D,MAAM,kBAAgC;AACpC,SAAK,SAAS,gBAAgB;AAAA,EAChC;AAAA,EAEA,aAAa,SAAwB,cAAoB;AACvD,QAAI,KAAK,WAAW,KAAK,QAAQ,YAAY,EAAG;AAChD,SAAK,gBAAgB;AACrB,QAAI,KAAK,cAAe;AACxB,SAAK,gBAAgB,WAAW,MAAM;AACpC,WAAK,gBAAgB;AACrB,YAAM,cAAc,KAAK,iBAAiB;AAC1C,WAAK,gBAAgB;AACrB,WAAK,KAAK,MAAM,WAAW;AAAA,IAC7B,GAAG,KAAK,QAAQ,UAAU;AAAA,EAC5B;AAAA,EAEA,OAAa;AACX,SAAK,UAAU;AACf,QAAI,KAAK,MAAO,cAAa,KAAK,KAAK;AACvC,QAAI,KAAK,cAAe,cAAa,KAAK,aAAa;AACvD,SAAK,QAAQ;AACb,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,SAAS,WAAyB;AACxC,QAAI,KAAK,MAAO,cAAa,KAAK,KAAK;AACvC,QAAI,KAAK,QAAS;AAClB,UAAM,QAAQ,KAAK;AAAA,MACjB;AAAA,MACA,YAAY,KAAK,IAAI,IAAI,KAAK,QAAQ;AAAA,IACxC;AACA,SAAK,QAAQ,WAAW,MAAM;AAC5B,WAAK,KAAK,MAAM,WAAW;AAAA,IAC7B,GAAG,KAAK;AAAA,EACV;AAAA,EAEA,MAAc,MAAM,QAAsC;AACxD,QAAI,KAAK,WAAW,KAAK,QAAQ,YAAY,KAAK,KAAK,UAAU;AAC/D,UAAI,KAAK,SAAU,MAAK,gBAAgB;AACxC;AAAA,IACF;AACA,SAAK,WAAW;AAChB,SAAK,QAAQ,aAAa;AAE1B,QAAI;AACF,YAAM,KAAK,QAAQ,YAAY,YAAY;AAAA,QACzC,QAAQ,WAAW,cAAc,aAAa;AAAA,QAC9C,SAAS,KAAK,QAAQ;AAAA,MACxB,CAAC;AAED,YAAM,SAAS,MAAM,KAAK,QAAQ,cAAc,QAAQ;AAAA,QACtD,SAAS,KAAK,QAAQ;AAAA,QACtB,QACE,WAAW,cACP,aACA,WAAW,WACT,WACA;AAAA,MACV,CAAC;AAED,WAAK,sBAAsB;AAC3B,WAAK,QAAQ,YAAY,OAAO,SAAS;AACzC,WAAK,SAAS,OAAO,SAAS;AAC9B,WAAK,QAAQ,OAAO,MAAM,2BAA2B,EAAE,OAAO,CAAC;AAAA,IACjE,SAAS,OAAO;AACd,WAAK,uBAAuB;AAC5B,YAAM,UAAU,oBAAoB,KAAK;AACzC,WAAK,QAAQ,OAAO,KAAK,2BAA2B;AAAA,QAClD;AAAA,QACA,SAAS,KAAK;AAAA,QACd;AAAA,MACF,CAAC;AAED,UAAI,KAAK,uBAAuB,KAAK,QAAQ,iBAAiB;AAC5D,aAAK,QAAQ,UAAU,OAAO;AAAA,MAChC,OAAO;AACL,cAAM,UACJ,KAAK,QAAQ,iBAAiB,KAAK;AACrC,aAAK,QAAQ,WAAW,MAAM;AAC5B,eAAK,KAAK,MAAM,MAAM;AAAA,QACxB,GAAG,OAAO;AAAA,MACZ;AAAA,IACF,UAAE;AACA,WAAK,WAAW;AAChB,UAAI,KAAK,iBAAiB,CAAC,KAAK,SAAS;AACvC,cAAM,UAAU,KAAK;AACrB,aAAK,gBAAgB;AACrB,aAAK,KAAK,MAAM,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,OAAwB;AACnD,MAAI,iBAAiB,SAAS,MAAM,QAAS,QAAO,MAAM;AAC1D,MACE,SACA,OAAO,UAAU,YACjB,aAAa,SACb,OAAQ,MAA+B,YAAY,YAClD,MAA8B,SAC/B;AACA,WAAQ,MAA8B;AAAA,EACxC;AACA,SAAO;AACT;;;AC7IO,IAAM,sCAAsC;AAiB5C,SAAS,gBACd,OACe;AACf,QAAM,EAAE,UAAU,SAAS,IAAI;AAC/B,MAAI;AACF,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,MAAM,SAAS,IAAI,SAAS,SAAS,CAAC;AAC5C,UAAI,OAAO,SAAS,GAAG,KAAK,OAAO,GAAG;AACpC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,MAAI,OAAO,SAAS,QAAQ,KAAK,WAAW,GAAG;AAC7C,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,aACd,OACA,mBAA2B,qCAClB;AACT,QAAM,OAAO,gBAAgB,KAAK;AAClC,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AACA,QAAM,MAAM,OAAO,MAAM;AACzB,SAAO,OAAO,KAAK,IAAI,GAAG,gBAAgB;AAC5C;AAeO,SAAS,eACd,OACA,SAKkB;AAClB,QAAM,YACJ,SAAS,oBAAoB;AAC/B,QAAM,aAAa,SAAS,qBAAqB;AACjD,QAAM,OAAO,gBAAgB,KAAK;AAElC,MAAI,SAAS,MAAM;AACjB,WAAO,EAAE,OAAO,OAAO,QAAQ,oBAAoB,MAAM,KAAK;AAAA,EAChE;AAEA,MAAI,aAAa,OAAO,SAAS,GAAG;AAClC,WAAO,EAAE,OAAO,OAAO,QAAQ,mBAAmB,KAAK;AAAA,EACzD;AAEA,QAAM,SAAS,KAAK,IAAI,GAAG,OAAO,UAAU;AAC5C,QAAM,cAAc;AACpB,SAAO,EAAE,OAAO,MAAM,KAAK;AAC7B;;;AChBA,IAAM,kBAAkB;AACxB,IAAM,uBAAuB,oBAAI,IAAI,CAAC,aAAa,aAAa,CAAC;AAOjE,IAAM,qBAAqB,uBAAO;AAAA,EAChC;AACF;AAGA,IAAM,qBAAqB,oBAAI,QAAsC;AAG9D,IAAM,yBAAyB;AAU/B,SAAS,mBACd,QACA,aAAqB,OAAO,aAAa,cACrC,SAAS,SACT,oBACK;AACT,MAAI;AACF,WAAO,gBAAgB,KAAK,IAAI,IAAI,QAAQ,UAAU,EAAE,QAAQ;AAAA,EAClE,QAAQ;AACN,WAAO,YAAY,KAAK,MAAM;AAAA,EAChC;AACF;AAEA,SAAS,oBAAoB,MAAuB;AAClD,SAAO,qBAAqB,IAAI,IAAI;AACtC;AAEA,SAAS,gBACP,UACA,QACsB;AACtB,MAAI,oBAAoB,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,EAAE,GAAG;AAC3E,uBAAmB,IAAI,UAAU,MAAM;AAAA,EACzC;AACA,SAAO;AACT;AAEA,SAAS,wBACP,QACkC;AAClC,SACE,OACA,kBAAkB;AACtB;AAOO,SAAS,wBACd,WACsB;AACtB,QAAM,WAAW;AACjB,QAAM,SAAS,mBAAmB,IAAI,QAAQ;AAC9C,MAAI,OAAQ,QAAO;AAEnB,QAAM,QAAQ,SAAS,cAAc;AACrC,MAAI,UAAuC;AAC3C,QAAM,OAAO,oBAAI,IAA0B;AAE3C,SAAO,WAAW,CAAC,KAAK,IAAI,OAAO,GAAG;AACpC,SAAK,IAAI,OAAO;AAChB,UAAM,OAAO,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAC/D,QAAI,oBAAoB,IAAI,GAAG;AAC7B,aAAO,gBAAgB,UAAU,OAAO;AAAA,IAC1C;AAGA,UAAM,UACJ,wBAAwB,OAAO;AACjC,QAAI,SAAS;AACX,gBAAU;AACV;AAAA,IACF;AAGA,UAAM,aAAa,OAAO,eAAe,QAAQ,SAAS,GACtD;AACJ,QACE,CAAC,cACD,eAAgB,UAChB,eAAgB,UAChB;AACA;AAAA,IACF;AACA,cAAU;AAAA,EACZ;AAGA,QAAM,WAAW,mBAAmB,IAAI,QAAQ;AAChD,SAAO,YAAY;AACrB;AAKO,SAAS,qBACd,QACA,OACA,UAAmC,CAAC,GACpC,aAAqB,OAAO,aAAa,cACrC,SAAS,SACT,oBACI;AACR,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,SAAS,IAAI,IAAI,QAAQ,UAAU;AACzC,QAAM,QAAQ,gBAAgB,KAAK,OAAO,QAAQ;AAElD,MAAI,SAAS,QAAQ,sBAAsB,QAAQ,SAAS;AAC1D,UAAM,WAAW,MAAM,SAAS;AAChC,WAAO,QAAQ,mBAAmB;AAAA,MAChC,SAAS,QAAQ;AAAA,MACjB,QAAQ,OAAO,SAAS;AAAA,MACxB,OAAO,SAAS;AAAA,MAChB,SAAS,SAAS;AAAA,MAClB,UAAU,SAAS;AAAA,MACnB,QAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,MAAM,UAAU,EAAG,QAAO,OAAO,SAAS;AAC/C,SAAO,MAAM,WAAW,QAAQ,UAAU;AAC5C;AAEA,SAAS,oBAAiC;AACxC,QAAM,MAAM,YAAY,IAAI;AAC5B,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS,EAAE,OAAO,KAAK,OAAO,GAAG,KAAK,EAAE;AAAA,IACxC,SAAS,EAAE,OAAO,GAAG,KAAK,EAAE;AAAA,IAC5B,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,EAAE;AAAA,EAC1C;AACF;AAEA,SAAS,uBACP,QACA,aACA,UACA,WACS;AACT,MAAI,WAAW,KAAK,WAAW,OAAO,WAAW,OAAO,WAAW,KAAK;AACtE,WAAO;AAAA,EACT;AACA,MAAI,WAAW,OAAO,WAAW,IAAK,QAAO;AAC7C,MAAI,aAAa,SAAS,WAAW,EAAG,QAAO;AAC/C,MAAI,oDAAoD,KAAK,QAAQ,GAAG;AACtE,WAAO;AAAA,EACT;AACA,MAAI,aAAa,uCAAuC,KAAK,SAAS,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAoBA,eAAe,wBACb,KACA,aACA,QACyB;AAIzB,QAAM,UAA8C,cAChD,EAAE,eAAe,UAAU,WAAW,IAAI,QAAQ,MAAM,IACxD;AAEJ,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC7B,aAAa;AAAA,MACb,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ,SAAS;AAAA,QACjB,MAAM,SAAS,cAAc,gBAAgB,SAAS,MAAM;AAAA,QAC5D,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,SAAS,YAAY;AACxC,UAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC;AACvD,QAAI,mBAAmB,KAAK,IAAI,GAAG;AACjC,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,KAAK,SAAS,OAAO;AAAA,IACvB;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN,UAAU;AAAA,MACZ;AAAA,IACF;AACA,UAAM,OACJ,iBAAiB,aAChB,iBAAiB,SAChB,qCAAqC,KAAK,MAAM,OAAO;AAC3D,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,MACE,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAC3C;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAGA,IAAM,oBAAoB;AAE1B,SAAS,mBAAmB,MAAuC;AACjE,MAAI,KAAK,eAAe,mBAAmB;AAEzC,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,iBACP,SACA,WACA,QACS;AACT,QAAM,MAAM,mBAAmB,OAAO,IAAI;AAC1C,MAAI,CAAC,KAAK;AACR,UAAMC,SAAQ,kBAAkB;AAChC,cAAU;AAAA,MACR;AAAA,QACE,MAAM;AAAA,QACN,MAAM,mBAAmB,iBAAiB,eAAe,OAAO,KAAK,UAAU;AAAA,MACjF;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACPA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,kBAAkB;AAChC,QAAM,MAAM,YAAY,IAAI;AAC5B,QAAM,QAAQ,QAAQ,MAAM,QAAQ;AACpC,QAAM,QAAQ,MAAM;AACpB,QAAM,SAAS,IAAI;AACnB,QAAM,QAAQ,IAAI;AAClB,YAAU;AAAA,IACR;AAAA,MACE,KAAK,OAAO;AAAA,MACZ,MAAM;AAAA,MACN,MAAM,OAAO,SAAS;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT;AACA,SAAO;AACT;AAqBA,eAAe,4BACb,SACA,WACA,MACA,QACA,OACA,WACuC;AACvC,QAAM,QAAQ,kBAAkB;AAChC,QAAM,eAAe,MAAM,UAAU,UAAU,KAAK,CAAC,OAAO;AAE5D,QAAM,cACJ,QAAQ,KAAK,QAAQ,KACrB,CAAC,MAAM,eACP,MAAM,gBAAgB,KAAK;AAE7B,MAAI,eAAe,KAAK,UAAU;AAChC,WACE,CAAC,MAAM,eACP,MAAM,gBAAgB,KAAK,oBAC3B,aAAa,GACb;AACA,YAAM,iBAAiB;AACvB,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,KAAK,UAAU;AAAA,UAC1C,QAAQ;AAAA,UACR,SAAS,EAAE,QAAQ,MAAM;AAAA,UACzB,aAAa;AAAA,UACb,OAAO;AAAA,UACP;AAAA,QACF,CAAC;AACD,YAAI,CAAC,UAAU,UAAU,EAAG,QAAO;AAEnC,cAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,cAAM,OAAO,MAAM,SAAS,YAAY;AACxC,YAAI,CAAC,UAAU,UAAU,EAAG,QAAO;AAEnC,cAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC;AAEvD,YACE,SAAS,MACT,CAAC,uBAAuB,SAAS,QAAQ,aAAa,IAAI,GAC1D;AACA,gBAAM,MAAM,mBAAmB,IAAI;AACnC,cAAI,CAAC,KAAK;AACR,sBAAU;AAAA,cACR;AAAA,gBACE,MAAM;AAAA,gBACN,MAAM,0BAA0B,KAAK,UAAU,gBAAgB,iBAAiB;AAAA,cAClF;AAAA,cACA,EAAE,GAAG,SAAS,KAAK,KAAK,SAAS;AAAA,cACjC;AAAA,cACA;AAAA,YACF;AACA,mBAAO;AAAA,UACT;AACA,gBAAM,MAAM,YAAY,IAAI;AAC5B,gBAAM,QAAQ,MAAM;AACpB,gBAAM,SAAS,IAAI;AACnB,gBAAM,QAAQ,IAAI;AAClB,oBAAU;AAAA,YACR;AAAA,cACE,KAAK,SAAS,OAAO,KAAK;AAAA,cAC1B,MAAM;AAAA,cACN,MAAM,SAAS;AAAA,YACjB;AAAA,YACA;AAAA,YACA,EAAE,GAAG,SAAS,KAAK,KAAK,SAAS;AAAA,YACjC;AAAA,UACF;AACA,iBAAO;AAAA,QACT;AAEA,YACE;AAAA,UACE,SAAS;AAAA,UACT;AAAA,UACA;AAAA,UACA,SAAS;AAAA,QACX,GACA;AACA,cACE,SAAS,WAAW,OACpB,aAAa,SAAS,WAAW,KACjC,8BAA8B,KAAK,IAAI,GACvC;AACA,kBAAM,cAAc;AACpB;AAAA,UACF;AACA;AAAA,QACF;AAEA,kBAAU;AAAA,UACR;AAAA,YACE,MAAM,SAAS;AAAA,YACf,MAAM,sBAAsB,SAAS,MAAM;AAAA,UAC7C;AAAA,UACA,EAAE,GAAG,SAAS,KAAK,KAAK,SAAS;AAAA,UACjC;AAAA,UACA;AAAA,QACF;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,YAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAGhE,iBAAO;AAAA,QACT;AACA,cAAM,cAAc;AACpB;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,UAAU,UAAU,EAAG,QAAO;AACnC,UAAM,cAAc;AAAA,EACtB;AAEA,MAAI,CAAC,UAAU,UAAU,EAAG,QAAO;AAInC,QAAM,cAAc,MAAM;AAAA,IACxB,KAAK;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,UAAU,UAAU,EAAG,QAAO;AAEnC,MAAI,YAAY,IAAI;AAClB;AAAA,MACE,EAAE,GAAG,SAAS,KAAK,KAAK,aAAa;AAAA,MACrC;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGA,MAAI,YAAY,WAAW,KAAK,OAAO,SAAS;AAC9C,WAAO;AAAA,EACT;AAEA,QAAM,cACJ,QAAQ,KAAK,WAAW,MACvB,YAAY,WAAW,OACtB,YAAY,WAAW;AAAA;AAAA,EAGvB,YAAY,QACZ,YAAY,WAAW;AAE3B,MAAI,eAAe,KAAK,aAAa;AACnC,UAAM,eAAe,MAAM;AAAA,MACzB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AACA,QAAI,CAAC,UAAU,UAAU,EAAG,QAAO;AAEnC,QAAI,aAAa,IAAI;AACnB;AAAA,QACE,EAAE,GAAG,SAAS,KAAK,KAAK,aAAa;AAAA,QACrC;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,IACT;AACA,QAAI,aAAa,WAAW,KAAK,OAAO,SAAS;AAC/C,aAAO;AAAA,IACT;AACA,QAAI,aAAa,QAAQ,aAAa,WAAW,GAAG;AAClD,aAAO;AAAA,IACT;AACA,cAAU;AAAA,MACR;AAAA,QACE,MAAM,aAAa;AAAA,QACnB,MAAM,aAAa;AAAA,MACrB;AAAA,MACA,EAAE,GAAG,SAAS,KAAK,KAAK,aAAa;AAAA,MACrC,aAAa;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,YAAY,QAAQ,YAAY,WAAW,GAAG;AAChD,WAAO;AAAA,EACT;AAEA,YAAU;AAAA,IACR;AAAA,MACE,MAAM,YAAY;AAAA,MAClB,MAAM,YAAY;AAAA,IACpB;AAAA,IACA,EAAE,GAAG,SAAS,KAAK,KAAK,aAAa;AAAA,IACrC,YAAY;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,uBACd,WACA,OACA,UAAmC,CAAC,GACd;AACtB,QAAM,WAAW;AACjB,QAAM,aAAa,wBAAwB,QAAQ;AACnD,kBAAgB,UAAU,UAAU;AAEpC,QAAM,mBACJ,OAAO,QAAQ,wBAAwB,YACvC,QAAQ,uBAAuB,IAC3B,QAAQ,sBACR;AAEN,QAAM,gBAAgB,EAAE,eAAe,GAAG,aAAa,MAAM;AAAA,EAE7D,MAAM,iBAAiB;AAAA,IASrB,YAAY,QAAgB;AAP5B,qBAAgC;AAEhC,WAAQ,WAAmC;AAE3C;AAAA,WAAQ,oBAAoB;AAC5B,WAAQ,sBAA6D;AAGnE,WAAK,QAAQ,IAAI,WAAW,MAAM;AAClC,WAAK,QAAQ,KAAK,MAAM;AAAA,IAC1B;AAAA,IAEQ,iBAAuB;AAC7B,YAAM,MAAM,KAAK;AACjB,WAAK,sBAAsB;AAC3B,WAAK,UAAU,MAAM;AACrB,WAAK,WAAW;AAChB,UAAI,KAAK,WAAW,KAAK,SAAS;AAChC,cAAM,QAAQ,kBAAkB;AAChC,cAAM,UAAU;AAChB,YAAI;AACF,cAAI,QAAQ,OAAO,KAAK,SAAS,IAAI;AAAA,QACvC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,IAEA,QAAc;AACZ,WAAK,qBAAqB;AAC1B,WAAK,eAAe;AACpB,WAAK,MAAM,MAAM;AAAA,IACnB;AAAA,IAEA,UAAgB;AACd,WAAK,qBAAqB;AAC1B,WAAK,eAAe;AACpB,WAAK,UAAU;AACf,WAAK,MAAM,QAAQ;AAAA,IACrB;AAAA,IAEA,KACE,SACA,QACA,WACM;AACN,WAAK,UAAU;AACf,UAAI,CAAC,QAAQ,KAAK;AAChB,aAAK,MAAM,KAAK,SAAS,QAAQ,SAAS;AAC1C;AAAA,MACF;AAEA,UAAI;AACF,cAAM,cAAc,QAAQ;AAC5B,cAAM,QAAQ,mBAAmB,WAAW;AAE5C,YAAI,CAAC,OAAO;AACV,cAAI,MAAM,UAAU,GAAG;AACrB,oBAAQ,MAAM,qBAAqB,aAAa,OAAO;AAAA,cACrD,GAAG;AAAA,cACH,oBAAoB;AAAA,YACtB,CAAC;AAAA,UACH;AACA,eAAK,MAAM,KAAK,SAAS,QAAQ,SAAS;AAC1C;AAAA,QACF;AAGA,cAAM,eAAe,qBAAqB,aAAa,OAAO;AAAA,UAC5D,GAAG;AAAA,UACH,oBAAoB;AAAA,QACtB,CAAC;AAED,cAAM,kBAAkB;AAAA,UACtB,QAAQ,sBAAsB,QAAQ;AAAA,QACxC;AACA,cAAM,WACJ,mBAAmB,CAAC,cAAc,cAC9B,qBAAqB,aAAa,OAAO,OAAO,IAChD;AAEN,cAAM,cAAc,QAAQ,oBAAoB,KAAK;AAGrD,YAAI,KAAK,YAAY,KAAK,qBAAqB;AAC7C,eAAK,qBAAqB;AAC1B,eAAK,eAAe;AAAA,QACtB;AAEA,cAAM,aAAa,EAAE,KAAK;AAC1B,aAAK,WAAW,IAAI,gBAAgB;AACpC,aAAK,sBAAsB;AAC3B,gBAAQ,eAAe;AACvB,cAAM,YACJ,OAAO,QAAQ,YAAY,YAAY,OAAO,UAAU,IACpD,OAAO,UACP;AACN,cAAM,QAAQ,WAAW,MAAM,KAAK,UAAU,MAAM,GAAG,SAAS;AAChE,cAAM,YAA8B;AAAA,UAClC,WAAW,MAAM,eAAe,KAAK;AAAA,QACvC;AAEA,aAAK;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,KAAK,SAAS;AAAA,UACd;AAAA,UACA;AAAA,QACF,EACG,KAAK,CAAC,WAAW;AAChB,cAAI,CAAC,UAAU,UAAU,EAAG;AAC5B,cAAI,WAAW,WAAW;AACxB,iBAAK,eAAe;AACpB;AAAA,UACF;AACA,eAAK,sBAAsB;AAC3B,cAAI,WAAW,WAAW;AAExB,oBAAQ,MAAM;AACd,iBAAK,MAAM,KAAK,SAAS,QAAQ,SAAS;AAAA,UAC5C;AAAA,QACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,cAAI,CAAC,UAAU,UAAU,EAAG;AAC5B,eAAK,sBAAsB;AAC3B,oBAAU;AAAA,YACR;AAAA,cACE,MAAM;AAAA,cACN,MACE,iBAAiB,QACb,MAAM,UACN;AAAA,YACR;AAAA,YACA;AAAA,YACA;AAAA,YACA,kBAAkB;AAAA,UACpB;AAAA,QACF,CAAC,EACA,QAAQ,MAAM;AACb,uBAAa,KAAK;AAAA,QACpB,CAAC;AACH;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,WAAK,MAAM,KAAK,SAAS,QAAQ,SAAS;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO,eAAe,kBAAkB,oBAAoB;AAAA,IAC1D,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AAED,SAAO;AACT;;;ACjvBA,SAAS,iBAAiB,MAAwB;AAChD,SAAO,SAAS,OAAO,SAAS;AAClC;AAaA,SAAS,iBAA0B;AACjC,MAAI,OAAO,cAAc,YAAa,QAAO;AAC7C,SAAO,mBAAmB,KAAK,UAAU,SAAS;AACpD;AAEO,IAAM,YAAN,MAAgB;AAAA,EAgBrB,YAA6B,SAA2B;AAA3B;AAf7B,SAAQ,MAAuC;AAC/C,SAAQ,YAAY;AACpB,SAAQ,cAA8B;AACtC,SAAQ,uBAAuB;AAC/B,SAAQ,qBAAqB;AAC7B,SAAQ,YAA+B,CAAC;AACxC,SAAQ,mBAAqC;AAC7C,SAAQ,aAAgC,CAAC;AACzC,SAAQ,qBAAyC;AACjD,SAAQ,cAAkC,CAAC;AAC3C,SAAQ,sBAAsB;AAC9B,SAAQ,yBAA8C;AACtD,SAAQ,uBAAuB;AAC/B,SAAQ,kBAAkB;AAAA,EAE+B;AAAA,EAEzD,MAAM,QAAuB;AAC3B,UAAM,EAAE,SAAS,aAAa,YAAY,OAAO,IAAI,KAAK;AAE1D,YAAQ,QAAQ;AAChB,QAAI,OAAO,WAAW,UAAU;AAC9B,cAAQ,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AAAA,IAClD;AAEA,UAAM,OAAO,MAAM,OAAO,QAAQ,GAAG;AAErC,QAAI,IAAI,YAAY,GAAG;AACrB,WAAK,cAAc;AACnB,WAAK,QAAQ,UAAU,gBAAgB,QAAQ;AAC/C,YAAM,KAAK,eAAe,KAAK,WAAW;AAC1C;AAAA,IACF;AAEA,QAAI,QAAQ,YAAY,+BAA+B,GAAG;AACxD,WAAK,cAAc;AACnB,WAAK,QAAQ,UAAU,gBAAgB,QAAQ;AAC/C,cAAQ,MAAM,KAAK,QAAQ,WAAW,WAAW,WAAW;AAC5D,WAAK,gBAAgB;AACrB,WAAK,qBAAqB;AAC1B,WAAK,QAAQ,UAAU,gBAAgB,OAAO;AAC9C,YAAM,KAAK,8BAA8B;AACzC;AAAA,IACF;AAEA,SAAK,cAAc;AACnB,SAAK,QAAQ,UAAU,gBAAgB,aAAa;AACpD,SAAK,QAAQ,UAAU;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,eACZ,KACA,aACe;AACf,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,KAAK;AAET,UAAM,SAAS,uBAAuB,KAAK,YAAY;AAAA,MACrD;AAAA,MACA;AAAA,MACA;AAAA,MACA,qBAAqB,KAAK,QAAQ;AAAA,IACpC,CAAC;AAID,UAAM,eAAe,UAAU,gBAAgB,CAAC,eAAe;AAC/D,QAAI,UAAU,gBAAgB,CAAC,cAAc;AAC3C,WAAK,QAAQ,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,MAAM,IAAI,IAAI;AAAA,MACjB;AAAA;AAAA,MAEA,gBAAgB,UAAU;AAAA,MAC1B,kBAAkB,UAAU;AAAA;AAAA;AAAA;AAAA,MAI5B,eAAe;AAAA,MACf,wBAAwB;AAAA,MACxB,oBAAoB;AAAA,MACpB,sBAAsB;AAAA,MACtB,oBAAoB;AAAA,MACpB,sBAAsB;AAAA,MACtB,YAAY;AAAA,MACZ;AAAA,IACF,CAAC;AAED,SAAK,IAAI,YAAY,OAAO;AAC5B,SAAK,IAAI,WAAW,WAAW,WAAW,WAAW,CAAC;AAEtD,SAAK,IAAI,GAAG,IAAI,OAAO,iBAAiB,CAAC,QAAQ,SAAS;AACxD,UAAI,KAAK,UAAW;AACpB,WAAK,aAAa,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,OAAO,WAAW;AAAA,QAC1D;AAAA,QACA,QAAQ,MAAM,UAAU;AAAA,QACxB,OAAO,MAAM,SAAS;AAAA,QACtB,SAAS,MAAM,WAAW;AAAA,QAC1B,OACE,MAAM,UAAU,QAAQ,MAAM,SAAS,IACnC,GAAG,MAAM,MAAM,MACf,SAAS,KAAK;AAAA,MACtB,EAAE;AACF,gBAAU,oBAAoB,KAAK,SAAS;AAC5C,WAAK,sBAAsB;AAC3B,WAAK,mBAAmB;AACxB,gBAAU,gBAAgB,OAAO;AAGjC,WAAK,KAAK,kBAAkB;AAAA,IAC9B,CAAC;AAED,SAAK,IAAI,GAAG,IAAI,OAAO,eAAe,MAAM;AAC1C,UAAI,KAAK,aAAa,KAAK,qBAAsB;AACjD,WAAK,KAAK,uBAAuB;AAAA,IACnC,CAAC;AAED,SAAK,IAAI,GAAG,IAAI,OAAO,yBAAyB,MAAM;AACpD,UAAI,KAAK,UAAW;AACpB,WAAK,sBAAsB;AAAA,IAC7B,CAAC;AAED,SAAK,IAAI,GAAG,IAAI,OAAO,sBAAsB,MAAM;AACjD,UAAI,KAAK,UAAW;AACpB,WAAK,mBAAmB;AAAA,IAC1B,CAAC;AAED,SAAK,IAAI,GAAG,IAAI,OAAO,OAAO,CAAC,QAAQ,SAAS;AAC9C,WAAK,eAAe,KAAK,IAAI;AAAA,IAC/B,CAAC;AAED,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,eACN,KACA,MAMM;AACN,QAAI,KAAK,UAAW;AACpB,UAAM,EAAE,WAAW,UAAU,IAAI,KAAK;AACtC,UAAM,SAAS,KAAK,UAAU;AAI9B,UAAM,cAAc,iBAAiB,MAAM;AAE3C,QAAI,KAAK,YAAY,IAAI,aAAa,gBAAgB;AACpD,UAAI,aAAa;AACf,kBAAU,uBAAuB,WAAW;AAC5C,YAAI,CAAC,KAAK,MAAO;AAAA,MACnB,WAAW,CAAC,KAAK,OAAO;AAItB,YAAI,CAAC,QAAQ;AACX;AAAA,QACF;AACA,kBAAU;AAAA,UACR,oCAAoC,MAAM;AAAA,QAC5C;AACA;AAAA,MACF,WAAW,CAAC,QAAQ;AAClB,kBAAU;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,OAAO;AACf,UACE,eACA,KAAK,SAAS,IAAI,WAAW,kBAC5B,KAAK,YAAY,IAAI,aAAa,mBACjC,KAAK,YAAY,IAAI,aAAa,mBACpC;AACA,kBAAU;AAAA,UACR,KAAK,YAAY,IAAI,aAAa,mBAC9B,gBACA;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,IAAI,WAAW,eAAe;AAC9C,WAAK,wBAAwB;AAC7B,UAAI,KAAK,wBAAwB,UAAU,oBAAoB;AAC7D,YAAI,aAAa;AACf,oBAAU,uBAAuB,eAAe;AAAA,QAClD;AACA,aAAK,KAAK,UAAU;AACpB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,IAAI,WAAW,aAAa;AAC5C,WAAK,sBAAsB;AAC3B,UAAI,KAAK,qBAAqB,UAAU,oBAAoB;AAC1D,kBAAU,eAAe,KAAK,WAAW,iBAAiB;AAC1D;AAAA,MACF;AAKA,UACE,KAAK,YAAY,IAAI,aAAa,uBAClC,KAAK,YAAY,IAAI,aAAa,mBAClC;AACA,aAAK,wBAAwB;AAAA,MAC/B;AAEA,UAAI,KAAK,uBAAuB,GAAG;AACjC,aAAK,KAAK,eAAe;AAAA,MAC3B;AACA,WAAK,KAAK,kBAAkB;AAC5B;AAAA,IACF;AAEA,cAAU,eAAe,KAAK,WAAW,iBAAiB;AAAA,EAC5D;AAAA;AAAA,EAGQ,0BAAgC;AACtC,QAAI,CAAC,KAAK,OAAO,KAAK,UAAU,WAAW,EAAG;AAC9C,QAAI;AACF,WAAK,IAAI,eAAe;AACxB,WAAK,IAAI,YAAY;AACrB,WAAK,IAAI,gBAAgB;AAAA,IAC3B,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,mBAAmB,KAAa,SAAmC;AACzE,QAAI,IAAI,KAAK,IAAI,GAAG,GAAG;AACvB,UAAM,WAAW,QAAQ;AACzB,QAAI,OAAO,SAAS,QAAQ,KAAK,WAAW,GAAG;AAE7C,UAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,WAAW,IAAI,CAAC;AAAA,IAC9C;AACA,QAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,YAAM,MAAM,QAAQ,SAAS,IAAI,QAAQ,SAAS,SAAS,CAAC;AAC5D,UAAI,OAAO,SAAS,GAAG,GAAG;AACxB,YAAI,KAAK,IAAI,GAAG,GAAG;AAAA,MACrB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,yBAAwC;AACpD,QAAI,KAAK,aAAa,KAAK,qBAAsB;AACjD,UAAM,EAAE,SAAS,cAAc,IAAI,KAAK;AACxC,SAAK,uBAAuB;AAE5B,QAAI,OAAO,kBAAkB,YAAY,iBAAiB,EAAG;AAE7D,UAAM,OAAO,MAAM;AACjB,UAAI,KAAK,UAAW;AACpB,UAAI;AACF,gBAAQ,cAAc,KAAK,mBAAmB,eAAe,OAAO;AAAA,MACtE,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,SAAS,KAAK,OAAO,SAAS,QAAQ,QAAQ,GAAG;AACpE,WAAK;AAAA,IACP,OAAO;AACL,cAAQ,iBAAiB,kBAAkB,MAAM,EAAE,MAAM,KAAK,CAAC;AAAA,IACjE;AAAA,EACF;AAAA,EAEA,MAAc,oBAAmC;AAC/C,QAAI,KAAK,aAAa,KAAK,gBAAiB;AAC5C,SAAK,kBAAkB;AACvB,UAAM,EAAE,SAAS,SAAS,IAAI,KAAK;AACnC,QAAI,CAAC,SAAU;AACf,QAAI;AACF,YAAM,QAAQ,KAAK;AAAA,IACrB,QAAQ;AACN,UAAI,CAAC,QAAQ,OAAO;AAClB,gBAAQ,QAAQ;AAChB,YAAI;AACF,gBAAM,QAAQ,KAAK;AAAA,QACrB,QAAQ;AACN,eAAK,QAAQ,OAAO,KAAK,kBAAkB;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gCAA+C;AAC3D,UAAM,KAAK,uBAAuB;AAClC,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAAA,EAEQ,kBAAwB;AAC9B,UAAM,EAAE,SAAS,UAAU,IAAI,KAAK;AACpC,YAAQ;AAAA,MAAiB;AAAA,MAAW,MAClC,UAAU,gBAAgB,SAAS;AAAA,IACrC;AACA,YAAQ,iBAAiB,SAAS,MAAM;AACtC,UAAI,CAAC,QAAQ,MAAO,WAAU,gBAAgB,QAAQ;AAAA,IACxD,CAAC;AACD,YAAQ;AAAA,MAAiB;AAAA,MAAW,MAClC,UAAU,gBAAgB,WAAW;AAAA,IACvC;AACA,YAAQ,iBAAiB,SAAS,MAAM;AACtC,gBAAU,gBAAgB,OAAO;AACjC,gBAAU,UAAU;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,mBAAyB;AACvB,QAAI,KAAK,gBAAgB,YAAY,KAAK,QAAQ,SAAS;AACzD,YAAM,OAAO,KAAK,QAAQ,QAAQ;AAClC,YAAM,YAAY,KAAK,QAAQ,QAAQ;AACvC,WAAK,QAAQ,QAAQ,MAAM,KAAK,QAAQ,WAAW;AAAA,QACjD,KAAK,QAAQ;AAAA,MACf;AACA,WAAK,QAAQ,QAAQ,cAAc;AACnC,UAAI,CAAC,UAAW,MAAK,KAAK,QAAQ,QAAQ,KAAK;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,uBAA6B;AAC3B,SAAK,uBAAuB;AAC5B,SAAK,KAAK,UAAU;AACpB,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,WAAW,WAAmC;AAC5C,SAAK,mBAAmB;AACxB,QAAI,CAAC,KAAK,IAAK;AACf,SAAK,IAAI,eAAe,cAAc,SAAS,KAAK;AACpD,SAAK,QAAQ,UAAU,2BAA2B,SAAS;AAAA,EAC7D;AAAA,EAEA,aAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,eAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,gBAAmC;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,wBAA4C;AAC1C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAAa,WAAqC;AAChD,QAAI,KAAK,UAAW;AACpB,SAAK,qBAAqB;AAC1B,SAAK,QAAQ,UAAU,6BAA6B,SAAS;AAE7D,QAAI,KAAK,gBAAgB,YAAY,KAAK,KAAK;AAC7C,WAAK,IAAI,kBAAkB,cAAc;AACzC,WAAK,IAAI,gBAAgB,cAAc,QAAQ,KAAK;AACpD;AAAA,IACF;AAEA,QAAI,KAAK,gBAAgB,YAAY,KAAK,QAAQ,SAAS;AACzD,YAAM,SAAS,KAAK,QAAQ,QAAQ;AACpC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,GAAG;AACzC,cAAM,QAAQ,OAAO,CAAC;AACtB,cAAM,OACJ,cAAc,SAAS,MAAM,YAAY,YAAY;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,iBAAqC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,yBAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAc,OAAqB;AACjC,QAAI,KAAK,UAAW;AACpB,QACE,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACP,KAAK,YAAY,SAAS,KAAK,SAAS,KAAK,YAAY,QAC1D;AACA;AAAA,IACF;AAEA,SAAK,sBAAsB;AAC3B,SAAK,QAAQ,UAAU,8BAA8B,KAAK;AAE1D,QAAI,KAAK,gBAAgB,YAAY,KAAK,KAAK;AAC7C,WAAK,IAAI,aAAa;AACtB;AAAA,IACF;AAEA,QAAI,KAAK,gBAAgB,YAAY,KAAK,QAAQ,SAAS;AACzD,YAAM,cACJ,KAAK,QAAQ,QAGb;AACF,UAAI,eAAe,YAAY,SAAS,GAAG;AACzC,iBAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,GAAG;AAC9C,sBAAY,CAAC,EAAG,UAAU,MAAM;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,iBAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,wBAA8B;AACpC,QAAI,CAAC,KAAK,IAAK;AACf,UAAM,UAA6B,KAAK,IAAI,kBAAkB,CAAC,GAAG;AAAA,MAChE,CAAC,OAAO,WAAW;AAAA,QACjB;AAAA,QACA,IAAI,OAAO,MAAM,MAAM,KAAK;AAAA,QAC5B,OAAO,MAAM,QAAQ,MAAM,QAAQ,aAAa,QAAQ,CAAC;AAAA,QACzD,UAAU,MAAM;AAAA,MAClB;AAAA,IACF;AACA,SAAK,aAAa;AAClB,SAAK,QAAQ,UAAU,qBAAqB,MAAM;AAAA,EACpD;AAAA,EAEQ,qBAA2B;AACjC,QAAI,CAAC,KAAK,IAAK;AACf,UAAM,UAA8B,KAAK,IAAI,eAAe,CAAC,GAAG;AAAA,MAC9D,CAAC,OAAO,WAAW;AAAA,QACjB;AAAA,QACA,IAAI,OAAO,MAAM,MAAM,KAAK;AAAA,QAC5B,OAAO,MAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAAA,QACrD,UAAU,MAAM;AAAA,MAClB;AAAA,IACF;AACA,SAAK,cAAc;AACnB,SAAK,QAAQ,UAAU,sBAAsB,MAAM;AACnD,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,sBAAsB;AAC3B,WAAK,QAAQ,UAAU,8BAA8B,CAAC;AAAA,IACxD;AAAA,EACF;AAAA,EAEQ,uBAA6B;AACnC,UAAM,EAAE,QAAQ,IAAI,KAAK;AACzB,UAAM,kBAAkB,MAAM;AAC5B,UAAI,KAAK,aAAa,KAAK,WAAW,SAAS,EAAG;AAClD,YAAM,OAAO,QAAQ;AACrB,YAAM,SAA4B,CAAC;AACnC,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,cAAM,QAAQ,KAAK,CAAC;AACpB,YAAI,MAAM,SAAS,eAAe,MAAM,SAAS,WAAY;AAC7D,eAAO,KAAK;AAAA,UACV,OAAO,OAAO;AAAA,UACd,IAAI,MAAM,MAAM,UAAU,OAAO,MAAM;AAAA,UACvC,OAAO,MAAM,SAAS,MAAM,YAAY,SAAS,OAAO,SAAS,CAAC;AAAA,UAClE,UAAU,MAAM,YAAY;AAAA,QAC9B,CAAC;AAAA,MACH;AACA,UAAI,OAAO,WAAW,EAAG;AACzB,WAAK,aAAa;AAClB,WAAK,QAAQ,UAAU,qBAAqB,MAAM;AAAA,IACpD;AAEA,UAAM,aAAa,QAAQ;AAU3B,eAAW,mBAAmB,YAAY,eAAe;AACzD,oBAAgB;AAChB,SAAK,yBAAyB,MAAM;AAClC,iBAAW,sBAAsB,YAAY,eAAe;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAW;AACpB,SAAK,YAAY;AACjB,SAAK,yBAAyB;AAC9B,SAAK,yBAAyB;AAC9B,SAAK,KAAK,QAAQ;AAClB,SAAK,MAAM;AACX,UAAM,EAAE,QAAQ,IAAI,KAAK;AACzB,YAAQ,gBAAgB,KAAK;AAC7B,YAAQ,KAAK;AAAA,EACf;AACF;;;AC7iBA,SAAS,aACP,WACA,UACuC;AACvC,MAAI,cAAc,QAAQ,aAAa,EAAG,QAAO;AACjD,QAAM,YAAY,YAAY,KAAK,IAAI;AACvC,MAAI,aAAa,EAAG,QAAO;AAC3B,MAAI,aAAa,SAAU,QAAO;AAClC,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,MAAI,OAAO,WAAW,eAAe,gBAAgB,QAAQ;AAC3D,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACpE;AAgDO,SAAS,kBACd,SACa;AAGb,0BAAwB;AAAA,IACtB,SAAS,QAAQ;AAAA,IACjB,WAAW,QAAQ;AAAA,IACnB,QAAQ,QAAQ;AAAA,IAChB,UAAU,QAAQ;AAAA,IAClB,OAAO,QAAQ;AAAA,IACf,WAAW,QAAQ;AAAA,IACnB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,OAAO,QAAQ;AAAA,IACf,eAAe,QAAQ;AAAA,EACzB,CAAC;AAED,MAAI,SAAS,kBAAkB;AAAA,IAC7B,QAAQ,QAAQ;AAAA,IAChB,UAAU,QAAQ;AAAA,IAClB,OAAO,QAAQ;AAAA,IACf,WAAW,QAAQ;AAAA,IACnB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,OAAO,QAAQ;AAAA,IACf,eAAe,QAAQ;AAAA,EACzB,CAAC;AAED,QAAM,SAAS,IAAI,aAAa;AAChC,QAAM,SAAS,IAAI,OAAO,OAAO,OAAO;AACxC,QAAM,oBAAoB,kBAAkB;AAE5C,MAAI,QAAqB;AACzB,MAAI,YAAY;AAChB,MAAI,YAAgC;AACpC,MAAI,UAAU,QAAQ,SAAS;AAC/B,MAAI,SAA2B;AAC/B,MAAI,iBAAwC;AAC5C,MAAI,eAAmC;AACvC,MAAI,eAAe;AACnB,MAAI,eAAoC;AAExC,QAAM,WAAW,CAAC,SAAsB;AACtC,QAAI,aAAa,SAAS,YAAa;AACvC,YAAQ;AACR,WAAO,KAAK,eAAe,EAAE,OAAO,KAAK,CAAC;AAAA,EAC5C;AAEA,QAAM,0BAA0B,CAAC,OAAyB;AACxD,mBAAe;AACf,UAAM,eAAe,MAAM;AACzB,UAAI,UAAW;AACf,aAAO,KAAK,cAAc;AAAA,QACxB,aAAa,GAAG;AAAA,QAChB,UAAU,OAAO,SAAS,GAAG,QAAQ,IAAI,GAAG,WAAW;AAAA,MACzD,CAAC;AAAA,IACH;AACA,UAAM,aAAa,MAAM;AACvB,UAAI,UAAW;AACf,UAAI,cAAc;AAClB,UAAI;AACF,YAAI,GAAG,SAAS,SAAS,GAAG;AAC1B,wBAAc,GAAG,SAAS,IAAI,GAAG,SAAS,SAAS,CAAC;AAAA,QACtD;AAAA,MACF,QAAQ;AACN,sBAAc;AAAA,MAChB;AACA,aAAO,KAAK,YAAY,EAAE,YAAY,CAAC;AAAA,IACzC;AAGA,UAAM,iBAAiB,MAAM;AAC3B,UAAI,UAAW;AACf,aAAO,KAAK,gBAAgB;AAAA,QAC1B,QAAQ,GAAG;AAAA,QACX,OAAO,GAAG;AAAA,MACZ,CAAC;AAAA,IACH;AACA,OAAG,iBAAiB,cAAc,YAAY;AAC9C,OAAG,iBAAiB,YAAY,UAAU;AAC1C,OAAG,iBAAiB,gBAAgB,cAAc;AAClD,mBAAe,MAAM;AACnB,SAAG,oBAAoB,cAAc,YAAY;AACjD,SAAG,oBAAoB,YAAY,UAAU;AAC7C,SAAG,oBAAoB,gBAAgB,cAAc;AAAA,IACvD;AAAA,EACF;AAEA,QAAM,cAAc,IAAI;AAAA,IACtB,QAAQ;AAAA,IACR,QAAQ,MAAM,yBAAyB;AAAA,IACvC;AAAA,IACA,CAAC,UAAU,OAAO,KAAK,eAAe,EAAE,WAAW,MAAM,UAAU,CAAC;AAAA,IACpE,CAAC,SAAS,cACR,OAAO,KAAK,aAAa,EAAE,SAAS,UAAU,CAAC;AAAA,EACnD;AAEA,QAAM,gBAAgB,IAAI,sBAAsB,QAAQ,UAAU,MAAM;AAExE,QAAM,qBAAqB,MAAwB;AACjD,QAAI,CAAC,SAAS;AACZ,YAAM;AAAA;AAAA,QAEJ;AAAA,QACA,EAAE,UAAU,UAAU,OAAO,MAAM,WAAW,MAAM;AAAA,MACtD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,YAA2B;AAC/C,QAAI,UAAW;AACf,aAAS,SAAS;AAClB,gBAAY;AAEZ,UAAM,UAAU,QAAQ,WAAW;AAEnC,QAAI;AACF,YAAM,YAAY,YAAY;AAAA,QAC5B,QAAQ;AAAA,QACR,SAAS,QAAQ;AAAA,MACnB,CAAC;AAED,UAAI;AACJ,UAAI;AAEJ,UAAI,QAAQ,WAAW;AACrB,cAAM,SAAS;AAAA,UACb,KAAK,QAAQ;AAAA,UACb,WAAW,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK;AAAA,UACvC,MAAM,oBAAoB,KAAK,QAAQ,SAAS;AAAA,QAClD;AACA,sBAAc,kBAAkB,MAAM;AACtC,sBAAc,OAAO;AACrB,oBAAY,OAAO;AACnB,uBAAe,QAAQ,OAAO,IAAI;AAAA,MACpC,OAAO;AACL,cAAM,SAAS,MAAM,cAAc,KAAK;AAAA,UACtC;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AACD,sBAAc,OAAO;AACrB,oBAAY,OAAO;AACnB,uBAAe,QAAQ,OAAO,IAAI;AAAA,MACpC;AAEA,YAAM,KAAK,mBAAmB;AAC9B,UAAI,cAAc;AAChB,WAAG,eAAe;AAAA,MACpB;AACA,8BAAwB,EAAE;AAC1B,cAAQ,QAAQ;AAChB,eAAS,IAAI,UAAU;AAAA,QACrB,SAAS;AAAA,QACT;AAAA,QACA,YAAY,cAAc;AAAA,QAC1B,UAAU,OAAO,OAAO;AAAA,QACxB,YAAY,OAAO,OAAO;AAAA,QAC1B,eAAe,OAAO,OAAO;AAAA,QAC7B,QAAQ,OAAO,OAAO;AAAA,QACtB,SAAS,QAAQ;AAAA,QACjB,oBAAoB,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMrC,mBACE,OAAO,UAAU,sBAChB,MAAM,YAAY,eAAe;AAAA,QACpC,qBAAqB,OAAO,UAAU;AAAA,QACtC,WAAW,OAAO,UAAU;AAAA,QAC5B;AAAA,QACA,WAAW;AAAA,UACT,eAAe,CAAC,MAAM;AACpB,qBAAS,CAAC;AACV,gBAAI,MAAM,QAAS,QAAO,KAAK,OAAO;AACtC,gBAAI,MAAM,WAAW;AACnB,qBAAO,KAAK,MAAM;AAClB,qBAAO,KAAK,SAAS;AAAA,YACvB;AACA,gBAAI,MAAM,SAAU,QAAO,KAAK,OAAO;AACvC,gBAAI,MAAM,YAAa,QAAO,KAAK,WAAW;AAC9C,gBAAI,MAAM,QAAS,QAAO,KAAK,OAAO;AAAA,UACxC;AAAA,UACA,cAAc,CAAC,YAAY;AACzB,wBAAY;AAAA;AAAA,cAEV;AAAA,cACA,EAAE,UAAU,YAAY,OAAO,MAAM,WAAW,KAAK;AAAA,YACvD;AACA,qBAAS,OAAO;AAChB,mBAAO,KAAK,SAAS;AAAA,cACnB,MAAM,UAAU;AAAA,cAChB,SAAS,UAAU;AAAA,cACnB,OAAO;AAAA,YACT,CAAC;AAAA,UACH;AAAA,UACA,sBAAsB,CAAC,WAAW;AAChC,4BAAgB;AAAA,cACd;AAAA,YACF;AAAA,UACF;AAAA,UACA,mBAAmB,MAAM;AAAA,UAEzB;AAAA,UACA,0BAA0B,CAAC,cAAc;AACvC,kBAAM,QAAQ,QACV,aAAa,EACd,KAAK,CAAC,MAAM,EAAE,UAAU,SAAS;AACpC,mBAAO,KAAK,iBAAiB;AAAA,cAC3B;AAAA,cACA,OAAO,OAAO,cAAc,WAAW,OAAO,QAAQ;AAAA,YACxD,CAAC;AAAA,UACH;AAAA,UACA,oBAAoB,CAAC,WAAW;AAC9B,mBAAO,KAAK,mBAAmB;AAAA,cAC7B;AAAA,cACA,WAAW,QAAQ,sBAAsB,KAAK;AAAA,YAChD,CAAC;AAAA,UACH;AAAA,UACA,4BAA4B,CAAC,cAAc;AACzC,mBAAO,KAAK,mBAAmB;AAAA,cAC7B,QAAQ,QAAQ,cAAc,KAAK,CAAC;AAAA,cACpC;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,qBAAqB,CAAC,WAAW;AAC/B,mBAAO,KAAK,oBAAoB;AAAA,cAC9B;AAAA,cACA,WAAW,QAAQ,uBAAuB,KAAK;AAAA,YACjD,CAAC;AAAA,UACH;AAAA,UACA,6BAA6B,CAAC,cAAc;AAC1C,mBAAO,KAAK,oBAAoB;AAAA,cAC9B,QAAQ,QAAQ,eAAe,KAAK,CAAC;AAAA,cACrC;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,SAAS,MAAM,OAAO,KAAK,OAAO;AAAA,QACpC;AAAA,MACF,CAAC;AAED,YAAM,OAAO,MAAM;AAInB,UAAI,CAAC,aAAa,SAAS;AACzB,eAAO,KAAK,gBAAgB;AAAA,UAC1B,QAAQ,QAAQ;AAAA,UAChB,OAAO,QAAQ;AAAA,QACjB,CAAC;AAAA,MACH;AAEA,UAAI,CAAC,QAAQ,aAAa,QAAQ,UAAU;AAC1C,wBAAgB,KAAK;AACrB,yBAAiB,IAAI,eAAe;AAAA,UAClC;AAAA,UACA;AAAA,UACA;AAAA,UACA,uBACE,QAAQ,SAAS,yBAAyB;AAAA,UAC5C,iBAAiB,QAAQ,SAAS,mBAAmB;AAAA,UACrD,gBAAgB,QAAQ,SAAS,kBAAkB;AAAA,UACnD,YAAY,QAAQ,SAAS,0BAA0B;AAAA,UACvD;AAAA,UACA,aAAa,MAAM;AAAA,UACnB,YAAY,MAAM,SAAS,UAAU;AAAA,UACrC,WAAW,CAAC,kBAAkB;AAC5B,oBAAQ,qBAAqB;AAC7B,gBAAI,CAAC,WAAW;AACd,oBAAMC,MAAK;AACX,kBAAIA,OAAM,CAACA,IAAG,UAAU,CAACA,IAAG,OAAO;AACjC,yBAAS,SAAS;AAAA,cACpB,OAAO;AACL,yBAAS,OAAO;AAAA,cAClB;AAAA,YACF;AACA,mBAAO,KAAK,gBAAgB,EAAE,WAAW,cAAc,CAAC;AACxD,mBAAO,KAAK,gBAAgB,EAAE,WAAW,cAAc,CAAC;AAAA,UAC1D;AAAA,UACA,SAAS,CAAC,YAAY;AACpB,wBAAY;AAAA;AAAA,cAEV;AAAA,cACA,EAAE,UAAU,QAAQ,OAAO,MAAM,WAAW,KAAK;AAAA,YACnD;AACA,qBAAS,OAAO;AAChB,mBAAO,KAAK,SAAS;AAAA,cACnB,MAAM,UAAU;AAAA,cAChB,SAAS,UAAU;AAAA,cACnB,OAAO;AAAA,YACT,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AACD,uBAAe,MAAM,SAAS;AAAA,MAChC;AAEA,cAAQ,WAAW,UAAU;AAAA,QAC3B,MAAM;AAAA,QACN,SAAS,EAAE,SAAS,kBAAkB;AAAA,MACxC,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,cACJ,SAAS,OAAO,UAAU,YAAY,UAAU,QAC3C,QACD;AAAA;AAAA,QAEE,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACzC,EAAE,UAAU,WAAW,OAAO,MAAM,WAAW,MAAM,OAAO,MAAM;AAAA,MACpE;AACN,kBAAY;AACZ,eAAS,OAAO;AAChB,aAAO,KAAK,SAAS;AAAA,QACnB,MAAM,YAAY;AAAA,QAClB,SAAS,YAAY;AAAA,QACrB,OAAO,YAAY;AAAA,MACrB,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAGA,MAAI,QAAQ,OAAO;AACjB,SAAK,cAAc,EAAE,MAAM,MAAM;AAAA,IAEjC,CAAC;AAAA,EACH;AAEA,QAAM,MAAmB;AAAA,IACvB,MAAM,OAAO;AACX,YAAM,mBAAmB,EAAE,KAAK;AAAA,IAClC;AAAA,IACA,QAAQ;AACN,yBAAmB,EAAE,MAAM;AAAA,IAC7B;AAAA,IACA,KAAK,MAAc;AACjB,YAAM,KAAK,mBAAmB;AAC9B,YAAM,WAAW,OAAO,SAAS,GAAG,QAAQ,IAAI,GAAG,WAAW;AAC9D,SAAG,cAAc,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,QAAQ;AAAA,IACvD;AAAA,IACA,WAAW;AACT,YAAM,KAAK,mBAAmB;AAC9B,aAAO,eAAe,EAAE;AAAA,IAC1B;AAAA,IACA,SAAS;AACP,aAAO;AAAA,IACT;AAAA,IACA,eAAe;AACb,UAAI,CAAC,gBAAgB,CAAC,SAAS;AAC7B,eAAO;AAAA,MACT;AACA,aAAO,aAAa,OAAO;AAAA,IAC7B;AAAA,IACA,iBAAiB;AACf,aAAO,SAAS,eAAe;AAAA,IACjC;AAAA,IACA,cAAc;AACZ,aAAO,SAAS,YAAY;AAAA,IAC9B;AAAA,IACA,UAAU,QAAgB;AACxB,YAAM,KAAK,mBAAmB;AAC9B,SAAG,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AAC3C,aAAO,KAAK,gBAAgB,EAAE,QAAQ,GAAG,QAAQ,OAAO,GAAG,MAAM,CAAC;AAAA,IACpE;AAAA,IACA,YAAY;AACV,aAAO,SAAS,UAAU;AAAA,IAC5B;AAAA,IACA,OAAO;AACL,YAAM,KAAK,mBAAmB;AAC9B,SAAG,QAAQ;AACX,aAAO,KAAK,gBAAgB,EAAE,QAAQ,GAAG,QAAQ,OAAO,KAAK,CAAC;AAAA,IAChE;AAAA,IACA,SAAS;AACP,YAAM,KAAK,mBAAmB;AAC9B,SAAG,QAAQ;AACX,aAAO,KAAK,gBAAgB,EAAE,QAAQ,GAAG,QAAQ,OAAO,MAAM,CAAC;AAAA,IACjE;AAAA,IACA,UAAU;AACR,aAAO,SAAS,SAAS;AAAA,IAC3B;AAAA,IACA,gBAAgB,MAAc;AAC5B,YAAM,KAAK,mBAAmB;AAE9B,SAAG,eAAe,eAAe,IAAI;AAAA,IACvC;AAAA,IACA,kBAAkB;AAChB,aAAO,SAAS,gBAAgB;AAAA,IAClC;AAAA,IACA,WAAW;AACT,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB;AAClB,YAAM,KAAK;AACX,UAAI,CAAC,GAAI,QAAO,CAAC;AACjB,YAAM,SAA0B,CAAC;AACjC,eAAS,IAAI,GAAG,IAAI,GAAG,SAAS,QAAQ,KAAK,GAAG;AAC9C,eAAO,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,CAAC,GAAG,KAAK,GAAG,SAAS,IAAI,CAAC,EAAE,CAAC;AAAA,MACtE;AACA,aAAO;AAAA,IACT;AAAA,IACA,aAAa;AACX,aAAO,QAAQ,WAAW,KAAK;AAAA,IACjC;AAAA,IACA,WAAW,WAAsC;AAC/C,UAAI,cAAc,QAAQ;AACxB,gBAAQ,WAAW,MAAM;AACzB;AAAA,MACF;AACA,UAAI,OAAO,cAAc,UAAU;AACjC,gBAAQ,WAAW,SAAS;AAC5B;AAAA,MACF;AACA,YAAM,QAAQ,QACV,aAAa,EACd,KAAK,CAAC,MAAM,EAAE,UAAU,aAAa,GAAG,EAAE,MAAM,QAAQ,SAAS;AACpE,UAAI,MAAO,SAAQ,WAAW,MAAM,KAAK;AAAA,IAC3C;AAAA,IACA,wBAAwB;AACtB,aAAO,QAAQ,aAAa,KAAK,CAAC;AAAA,IACpC;AAAA,IACA,gBAAgB;AACd,aAAO,QAAQ,cAAc,KAAK,CAAC;AAAA,IACrC;AAAA,IACA,uBAAuB;AACrB,aAAO,QAAQ,sBAAsB,KAAK;AAAA,IAC5C;AAAA,IACA,aAAa,WAA+B;AAC1C,cAAQ,aAAa,SAAS;AAAA,IAChC;AAAA,IACA,iBAAiB;AACf,aAAO,QAAQ,eAAe,KAAK,CAAC;AAAA,IACtC;AAAA,IACA,wBAAwB;AACtB,aAAO,QAAQ,uBAAuB,KAAK;AAAA,IAC7C;AAAA,IACA,cAAc,OAAe;AAC3B,cAAQ,cAAc,KAAK;AAAA,IAC7B;AAAA,IACA,MAAM,kBAAkB;AACtB,YAAM,SAAS,gBAAgB,SAAS,iBAAiB;AACzD,UAAI,UAAU,uBAAuB,QAAQ;AAC3C,cAAM,OAAO,kBAAkB;AAC/B,eAAO,KAAK,oBAAoB,EAAE,cAAc,KAAK,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,IACA,MAAM,iBAAiB;AACrB,UAAI,SAAS,mBAAmB;AAC9B,cAAM,SAAS,eAAe;AAC9B,eAAO,KAAK,oBAAoB,EAAE,cAAc,MAAM,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,IACA,eAAe;AACb,aAAO,QAAQ,SAAS,iBAAiB;AAAA,IAC3C;AAAA,IACA,qBAAqB,IAAwB;AAC3C,qBAAe;AAAA,IACjB;AAAA,IACA,MAAM,SAAS;AACb,sBAAgB,KAAK;AACrB,cAAQ,QAAQ;AAChB,YAAM,cAAc;AAAA,IACtB;AAAA,IACA,UAAU;AACR,UAAI,UAAW;AACf,kBAAY;AACZ,qBAAe;AACf,qBAAe;AACf,sBAAgB,KAAK;AACrB,uBAAiB;AACjB,cAAQ,QAAQ;AAChB,eAAS;AACT,kBAAY,QAAQ;AACpB,oBAAc,QAAQ;AACtB,eAAS,WAAW;AACpB,aAAO,KAAK,SAAS;AACrB,aAAO,UAAU;AACjB,cAAQ,WAAW,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAAA,IAC3D;AAAA,IACA,iBAAiB;AACf,YAAM,WAAW,IAAI,kBAAkB;AACvC,aAAO;AAAA,QACL,eAAe;AAAA,QACf,cAAc;AAAA,QACd,YAAY,QAAQ,eAAe,KAAK;AAAA,QACxC,SAAS,QAAQ,WAAW;AAAA,QAC5B,aAAa,IAAI,eAAe;AAAA,QAChC,UAAU,IAAI,YAAY;AAAA,QAC1B,aAAa,SAAS,SAAS,SAAS,SAAS,SAAS,CAAC,EAAG,MAAM;AAAA,QACpE,gBACE,IAAI,WAAW,MAAM,SACjB,SACA,QAAQ,aAAa,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,WAAW,CAAC,GAC3D,SAAS;AAAA,QACnB;AAAA,QACA,kBAAkB;AAAA,UAChB,YAAY,aAAa;AAAA,UACzB,QAAQ,MAAM,yBAAyB;AAAA,QACzC;AAAA,QACA,oBAAoB;AAAA,UAClB,cAAc,aAAa;AAAA,UAC3B,QAAQ,UAAU,yBAAyB;AAAA,QAC7C;AAAA,QACA,WAAW,WAAW,WAAW;AAAA,MACnC;AAAA,IACF;AAAA,IACA,YAAY;AACV,aAAO;AAAA,IACT;AAAA,IACA,aAAa,SAAS;AACpB,eAAS,kBAAkB;AAAA,QACzB,QAAQ,EAAE,GAAG,OAAO,QAAQ,GAAG,SAAS,OAAO;AAAA,QAC/C,UAAU,EAAE,GAAG,OAAO,UAAU,GAAG,SAAS,SAAS;AAAA,QACrD,OAAO,EAAE,GAAG,OAAO,OAAO,GAAG,SAAS,MAAM;AAAA,QAC5C,WAAW,EAAE,GAAG,OAAO,WAAW,GAAG,SAAS,UAAU;AAAA,QACxD,WAAW;AAAA,UACT,QAAQ;AAAA,UACR,KAAK,EAAE,GAAG,OAAO,UAAU,KAAK,GAAG,SAAS,WAAW,IAAI;AAAA,UAC3D,oBACE,SAAS,WAAW,sBACpB,OAAO,UAAU;AAAA,UACnB,mBACE,SAAS,WAAW,qBACpB,OAAO,UAAU,sBAChB,MAAM,YAAY,eAAe;AAAA,UACpC,qBACE,SAAS,WAAW,uBACpB,OAAO,UAAU;AAAA,QACrB;AAAA,QACA,SAAS,EAAE,GAAG,OAAO,SAAS,GAAG,SAAS,QAAQ;AAAA,QAClD,OAAO,EAAE,GAAG,OAAO,OAAO,GAAG,SAAS,MAAM;AAAA,QAC5C,eAAe;AAAA,UACb,GAAG,OAAO;AAAA,UACV,GAAG,SAAS;AAAA,QACd;AAAA,MACF,CAAC;AACD,aAAO,OAAO,OAAO,OAAO;AAAA,IAC9B;AAAA,IACA,IAAI,OAAO,GAAG,KAAK,MAAM;AAAA,IACzB,KAAK,OAAO,IAAI,KAAK,MAAM;AAAA,EAC7B;AAGA,EAAC,IAAmG,SAClG,OAAO,IAAsB,cAA4B;AACvD,cAAU;AACV,mBAAe,aAAa;AAC5B,UAAM,cAAc;AAAA,EACtB;AAEF,SAAO;AACT;","names":["PlayerErrorCode","isPlainObject","stats","el"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors/PlayerError.ts","../src/auth/AuthManager.ts","../src/config/defaults.ts","../src/events/EventEmitter.ts","../src/security/redaction.ts","../src/logging/Logger.ts","../src/auth/AuthParamsStore.ts","../src/playback/PlaybackSourceManager.ts","../src/playback/RefreshManager.ts","../src/playback/liveEdge.ts","../src/streaming/mediaUrl.ts","../src/streaming/authParamsLoader.ts","../src/streaming/HlsEngine.ts","../src/player/createVideoPlayer.ts"],"sourcesContent":["export { createVideoPlayer, type VideoPlayer } from \"./player/createVideoPlayer\";\nexport {\n DEFAULT_PLAYER_CONFIG,\n DEFAULT_PLAYER_BEHAVIOR,\n DEFAULT_CONTROLS,\n DEFAULT_THEME,\n DEFAULT_WATERMARK,\n PLAYBACK_RATES,\n PACKAGE_VERSION,\n mergePlayerConfig,\n themeToCssVars,\n assertNoSecretsInConfig,\n isPlainObject,\n SECRET_SCAN_MAX_DEPTH,\n} from \"./config/defaults\";\nexport {\n PlayerErrorCode,\n createPlayerError,\n redactSensitive,\n type PlayerError,\n} from \"./errors/PlayerError\";\nexport { AuthParamsStore } from \"./auth/AuthParamsStore\";\nexport { AuthManager } from \"./auth/AuthManager\";\nexport { PlaybackSourceManager } from \"./playback/PlaybackSourceManager\";\nexport { RefreshManager } from \"./playback/RefreshManager\";\nexport {\n rewriteHlsRequestUrl,\n createAuthParamsLoader,\n resolveBuiltinHlsLoader,\n isEncryptionKeyUrl,\n KEY_PROXY_MAX_FAILURES,\n type HlsModuleLike,\n type HlsLoaderConstructor,\n} from \"./streaming/authParamsLoader\";\nexport { isLivePlaylistUrl, isSameOriginHttpUrl } from \"./streaming/mediaUrl\";\nexport {\n DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS,\n getLiveEdgeTime,\n isAtLiveEdge,\n seekToLiveEdge,\n type LiveMediaSnapshot,\n type SeekToLiveResult,\n} from \"./playback/liveEdge\";\nexport { EventEmitter } from \"./events/EventEmitter\";\nexport { redactObject, redactValue } from \"./security/redaction\";\nexport type * from \"./types\";\n","export enum PlayerErrorCode {\n INVALID_CONFIGURATION = \"INVALID_CONFIGURATION\",\n AUTHENTICATION_FAILED = \"AUTHENTICATION_FAILED\",\n AUTH_TOKEN_REFRESH_FAILED = \"AUTH_TOKEN_REFRESH_FAILED\",\n TOKEN_EXPIRED = \"TOKEN_EXPIRED\",\n TOKEN_REFRESH_FAILED = \"TOKEN_REFRESH_FAILED\",\n SOURCE_RESOLUTION_FAILED = \"SOURCE_RESOLUTION_FAILED\",\n MANIFEST_LOAD_FAILED = \"MANIFEST_LOAD_FAILED\",\n SEGMENT_LOAD_FAILED = \"SEGMENT_LOAD_FAILED\",\n NETWORK_ERROR = \"NETWORK_ERROR\",\n PLAYBACK_ERROR = \"PLAYBACK_ERROR\",\n UNSUPPORTED_BROWSER = \"UNSUPPORTED_BROWSER\",\n AUTOPLAY_BLOCKED = \"AUTOPLAY_BLOCKED\",\n UNKNOWN = \"UNKNOWN\",\n}\n\nexport type PlayerError = {\n code: PlayerErrorCode;\n message: string;\n category: \"config\" | \"auth\" | \"network\" | \"playback\" | \"unknown\";\n fatal: boolean;\n retryable: boolean;\n timestamp: number;\n cause?: unknown;\n};\n\nexport function createPlayerError(\n code: PlayerErrorCode,\n message: string,\n options?: Partial<Omit<PlayerError, \"code\" | \"message\" | \"timestamp\">>,\n): PlayerError {\n return {\n code,\n message: redactSensitive(message),\n category: options?.category ?? \"unknown\",\n fatal: options?.fatal ?? true,\n retryable: options?.retryable ?? false,\n timestamp: Date.now(),\n cause: options?.cause,\n };\n}\n\nexport function redactSensitive(input: string): string {\n return input\n .replace(/(Bearer\\s+)[^\\s]+/gi, \"$1[REDACTED]\")\n .replace(/([?&](token|expires|signature|sig)=)[^&]+/gi, \"$1[REDACTED]\")\n .replace(/(Authorization:\\s*)[^\\s]+/gi, \"$1[REDACTED]\");\n}\n","import {\n createPlayerError,\n PlayerErrorCode,\n} from \"../errors/PlayerError\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n AuthConfig,\n AuthToken,\n AuthTokenProviderContext,\n} from \"../types\";\n\n/**\n * Manages provider auth-token lifecycle (independent from signed playback URL).\n * Single-flight refresh; never stores clientSecret.\n * Unauthorized recoveries are bounded to prevent infinite 401 → refresh loops.\n */\nexport class AuthManager {\n private token: AuthToken | null = null;\n private inFlight: Promise<AuthToken> | null = null;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private destroyed = false;\n /** Consecutive unauthorized refresh attempts (reset on success). */\n private unauthorizedAttempts = 0;\n private readonly maxUnauthorizedRetries: number;\n\n constructor(\n private readonly auth: AuthConfig | undefined,\n private readonly refreshBeforeExpiryMs: number,\n private readonly logger: Logger,\n private readonly onRefreshed?: (token: AuthToken) => void,\n private readonly onError?: (message: string, retryable: boolean) => void,\n maxUnauthorizedRetries = 1,\n ) {\n this.maxUnauthorizedRetries = Math.max(0, maxUnauthorizedRetries);\n }\n\n getAccessToken(): string | null {\n return this.token?.accessToken ?? null;\n }\n\n getExpiresAt(): number | null {\n return this.token?.expiresAt ?? null;\n }\n\n async ensureToken(\n context: AuthTokenProviderContext,\n ): Promise<AuthToken | null> {\n if (!this.auth?.getToken) return null;\n if (this.destroyed) return null;\n\n if (\n this.token &&\n context.reason !== \"unauthorized\" &&\n context.reason !== \"manual\" &&\n this.token.expiresAt - Date.now() > this.refreshBeforeExpiryMs\n ) {\n return this.token;\n }\n\n return this.refresh(context);\n }\n\n async refresh(context: AuthTokenProviderContext): Promise<AuthToken> {\n if (!this.auth?.getToken) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"auth.getToken is required for authenticated playback\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n\n if (context.reason === \"unauthorized\") {\n if (this.unauthorizedAttempts >= this.maxUnauthorizedRetries) {\n const message =\n \"Auth token refresh aborted: exceeded bounded unauthorized retry limit\";\n this.onError?.(message, false);\n throw createPlayerError(\n PlayerErrorCode.AUTH_TOKEN_REFRESH_FAILED,\n message,\n { category: \"auth\", fatal: true, retryable: false },\n );\n }\n this.unauthorizedAttempts += 1;\n }\n\n if (this.inFlight) return this.inFlight;\n\n this.inFlight = (async () => {\n try {\n const next = await this.auth!.getToken(context);\n if (\n !next?.accessToken ||\n typeof next.expiresAt !== \"number\" ||\n next.expiresAt <= 0\n ) {\n throw createPlayerError(\n PlayerErrorCode.AUTHENTICATION_FAILED,\n \"auth.getToken returned an invalid token payload\",\n { category: \"auth\", fatal: true, retryable: true },\n );\n }\n this.token = next;\n if (context.reason !== \"unauthorized\") {\n this.unauthorizedAttempts = 0;\n }\n this.scheduleProactiveRefresh();\n this.onRefreshed?.(next);\n this.logger.debug(\"Auth token refreshed\", {\n reason: context.reason,\n expiresAt: next.expiresAt,\n });\n return next;\n } catch (error) {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n (error as { code: string }).code ===\n PlayerErrorCode.AUTH_TOKEN_REFRESH_FAILED\n ) {\n throw error;\n }\n const message =\n error instanceof Error ? error.message : \"Auth token refresh failed\";\n const retryable = this.unauthorizedAttempts <= this.maxUnauthorizedRetries;\n this.onError?.(message, retryable);\n throw createPlayerError(\n PlayerErrorCode.AUTH_TOKEN_REFRESH_FAILED,\n message,\n { category: \"auth\", fatal: !retryable, retryable, cause: error },\n );\n } finally {\n this.inFlight = null;\n }\n })();\n\n return this.inFlight;\n }\n\n private scheduleProactiveRefresh(): void {\n if (this.timer) clearTimeout(this.timer);\n if (!this.token || this.destroyed) return;\n const delay = Math.max(\n 5_000,\n this.token.expiresAt - Date.now() - this.refreshBeforeExpiryMs,\n );\n this.timer = setTimeout(() => {\n void this.refresh({\n reason: \"expiring\",\n videoId: undefined,\n }).catch(() => {\n /* onError already notified */\n });\n }, delay);\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n this.token = null;\n this.inFlight = null;\n }\n}\n","import type {\n ControlsConfig,\n PlayerBehaviorConfig,\n PlayerConfig,\n ThemeConfig,\n WatermarkConfig,\n} from \"../types\";\n\nexport const PLAYBACK_RATES = [0.5, 0.75, 1, 1.25, 1.5, 2] as const;\n\nexport const PACKAGE_VERSION = \"3.0.3\";\n\nexport const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig> = {\n autoplay: true,\n startMuted: true,\n volume: 1,\n startPosition: 0,\n skipSeconds: 10,\n speedOptionCount: PLAYBACK_RATES.length,\n zoomEnabled: true,\n defaultZoom: 1,\n playbackRates: PLAYBACK_RATES,\n};\n\nexport const DEFAULT_CONTROLS: Required<ControlsConfig> = {\n enabled: true,\n showQuality: true,\n showSpeed: true,\n showCaptions: true,\n showAudio: true,\n showVolume: true,\n showFullscreen: true,\n showZoom: true,\n showSkip: true,\n showLive: true,\n seekCueDurationMs: 720,\n keyboardShortcuts: true,\n persistQualityPreference: false,\n};\n\nexport const DEFAULT_THEME: Required<ThemeConfig> = {\n playIconPreset: \"triangle\",\n playButtonBackground: \"#ffffff\",\n playButtonIconColor: \"#ffffff\",\n seekTrackColor: \"#334155\",\n seekProgressColor: \"#38bdf8\",\n seekBufferedColor: \"#64748b\",\n timeColor: \"#e2e8f0\",\n controlIconColor: \"#f1f5f9\",\n focusRingColor: \"#38bdf8\",\n spinnerColor: \"#38bdf8\",\n volumeIconColor: \"#f1f5f9\",\n volumeTrackColor: \"#334155\",\n volumeProgressColor: \"#38bdf8\",\n qualityOptionTextColor: \"#e2e8f0\",\n qualityOptionBackground: \"#020617\",\n qualityOptionActiveBackground: \"#0c4a6e\",\n qualityOptionActiveTextColor: \"#bae6fd\",\n speedOptionTextColor: \"#e2e8f0\",\n speedOptionBackground: \"#020617\",\n speedOptionActiveBackground: \"#0c4a6e\",\n speedOptionActiveTextColor: \"#bae6fd\",\n zoomIconColor: \"#f1f5f9\",\n skipIconColor: \"#f1f5f9\",\n skipCueBackground: \"#ffffff\",\n skipCueTextColor: \"#ffffff\",\n liveDotColor: \"#ef4444\",\n};\n\nexport const DEFAULT_WATERMARK: Required<WatermarkConfig> = {\n enabled: true,\n text: \"\",\n durationMs: 10_000,\n intervalMaxMs: 300_000,\n};\n\nexport const DEFAULT_PLAYER_CONFIG: PlayerConfig = {\n player: DEFAULT_PLAYER_BEHAVIOR,\n controls: DEFAULT_CONTROLS,\n theme: DEFAULT_THEME,\n watermark: DEFAULT_WATERMARK,\n streaming: {\n engine: \"hls\",\n hls: {\n enableWorker: true,\n // VOD + AES-128: LL mode causes ABR thrash → bufferAppendError on MSE.\n lowLatencyMode: false,\n backBufferLength: 90,\n fatalRecoveryLimit: 3,\n },\n },\n logging: { enabled: false, level: \"error\" },\n debug: { enabled: false, network: false, events: false, state: false },\n accessibility: { reducedMotion: false },\n};\n\nconst FORBIDDEN_SECRET_KEYS = [\n \"clientsecret\",\n \"apisecret\",\n \"privatekey\",\n \"video_api_secret\",\n \"basicauthpassword\",\n \"password\",\n] as const;\n\n/** Never descend into these — DOM hosts or credential callback bags. */\nconst SKIP_DEEP_SCAN_KEYS = new Set([\n \"mount\",\n \"auth\",\n \"playback\",\n \"gettoken\",\n \"getsource\",\n \"refreshsource\",\n \"keyproxyurlbuilder\",\n \"mediaproxyurlbuilder\",\n \"getkeyaccesstoken\",\n]);\n\n/** Hard cap so pathological graphs cannot blow the stack. */\nexport const SECRET_SCAN_MAX_DEPTH = 32;\n\n/**\n * True only for JSON-like plain objects (`{}` / `Object.create(null)`).\n * Excludes DOM nodes, class instances, arrays, dates, etc.\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n if (Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction normalizeConfigKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n}\n\nfunction isForbiddenSecretKey(key: string): boolean {\n const lower = normalizeConfigKey(key);\n return FORBIDDEN_SECRET_KEYS.some((k) => lower.includes(k));\n}\n\nfunction throwForbidden(path: string, key: string): never {\n throw new Error(\n `INVALID_CONFIGURATION: Forbidden secret key \"${path}${key}\" must never be passed to the browser SDK. Keep clientSecret on your server/BFF and use auth.getToken().`,\n );\n}\n\n/**\n * Scans plain config objects for forbidden secret key names.\n *\n * Enterprise guarantees:\n * - Never deep-walks DOM / host / class instances (plain-object only)\n * - Does not descend into `mount` / `auth` / `playback` (shallow key check only)\n * - Cycle-safe via WeakSet\n * - Depth-capped + iterative (no call-stack recursion)\n */\nexport function assertNoSecretsInConfig(raw: unknown): void {\n if (!isPlainObject(raw) && !Array.isArray(raw)) return;\n\n const seen = new WeakSet<object>();\n const stack: Array<{ value: unknown; path: string; depth: number }> = [\n { value: raw, path: \"\", depth: 0 },\n ];\n\n while (stack.length > 0) {\n const current = stack.pop()!;\n if (current.depth > SECRET_SCAN_MAX_DEPTH) continue;\n\n const { value, path, depth } = current;\n\n if (Array.isArray(value)) {\n if (seen.has(value)) continue;\n seen.add(value);\n for (let i = 0; i < value.length; i += 1) {\n const item = value[i];\n if (isPlainObject(item) || Array.isArray(item)) {\n stack.push({ value: item, path: `${path}[${i}]`, depth: depth + 1 });\n }\n }\n continue;\n }\n\n if (!isPlainObject(value)) continue;\n if (seen.has(value)) continue;\n seen.add(value);\n\n for (const [key, child] of Object.entries(value)) {\n const normalized = normalizeConfigKey(key);\n\n if (isForbiddenSecretKey(key)) {\n throwForbidden(path, key);\n }\n\n // mount: host node — never inspect further\n if (normalized === \"mount\") continue;\n\n // auth / playback / callback fields: shallow secret-key check only\n if (SKIP_DEEP_SCAN_KEYS.has(normalized)) {\n if (isPlainObject(child)) {\n for (const nestedKey of Object.keys(child)) {\n if (isForbiddenSecretKey(nestedKey)) {\n throwForbidden(`${path}${key}.`, nestedKey);\n }\n }\n }\n continue;\n }\n\n if (isPlainObject(child) || Array.isArray(child)) {\n stack.push({\n value: child,\n path: path ? `${path}${key}.` : `${key}.`,\n depth: depth + 1,\n });\n }\n }\n }\n}\n\nexport type PlayerConfigPartial = Partial<{\n player: Partial<PlayerBehaviorConfig>;\n controls: Partial<ControlsConfig>;\n theme: Partial<ThemeConfig>;\n watermark: Partial<WatermarkConfig>;\n streaming: {\n engine?: \"hls\";\n hls?: Partial<PlayerConfig[\"streaming\"][\"hls\"]>;\n mediaProxyUrlBuilder?: PlayerConfig[\"streaming\"][\"mediaProxyUrlBuilder\"];\n keyProxyUrlBuilder?: PlayerConfig[\"streaming\"][\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: PlayerConfig[\"streaming\"][\"getKeyAccessToken\"];\n keyProxyMaxFailures?: PlayerConfig[\"streaming\"][\"keyProxyMaxFailures\"];\n };\n logging: Partial<PlayerConfig[\"logging\"]>;\n debug: Partial<PlayerConfig[\"debug\"]>;\n accessibility: Partial<PlayerConfig[\"accessibility\"]>;\n}>;\n\nexport function mergePlayerConfig(partial?: PlayerConfigPartial): PlayerConfig {\n assertNoSecretsInConfig(partial);\n return {\n player: { ...DEFAULT_PLAYER_BEHAVIOR, ...partial?.player },\n controls: { ...DEFAULT_CONTROLS, ...partial?.controls },\n theme: { ...DEFAULT_THEME, ...partial?.theme },\n watermark: { ...DEFAULT_WATERMARK, ...partial?.watermark },\n streaming: {\n engine: \"hls\",\n hls: {\n ...DEFAULT_PLAYER_CONFIG.streaming.hls,\n ...partial?.streaming?.hls,\n },\n mediaProxyUrlBuilder: partial?.streaming?.mediaProxyUrlBuilder,\n keyProxyUrlBuilder: partial?.streaming?.keyProxyUrlBuilder,\n getKeyAccessToken: partial?.streaming?.getKeyAccessToken,\n keyProxyMaxFailures: partial?.streaming?.keyProxyMaxFailures,\n },\n logging: { ...DEFAULT_PLAYER_CONFIG.logging, ...partial?.logging },\n debug: { ...DEFAULT_PLAYER_CONFIG.debug, ...partial?.debug },\n accessibility: {\n ...DEFAULT_PLAYER_CONFIG.accessibility,\n ...partial?.accessibility,\n },\n };\n}\n\n/** Maps theme colors to CSS custom properties for UI adapters. */\nexport function themeToCssVars(\n theme: Required<ThemeConfig>,\n): Record<string, string> {\n return {\n \"--player-play-btn-bg\": theme.playButtonBackground,\n \"--player-play-btn-icon\": theme.playButtonIconColor,\n \"--player-seek-track\": theme.seekTrackColor,\n \"--player-seek-progress\": theme.seekProgressColor,\n \"--player-seek-buffered\": theme.seekBufferedColor,\n \"--player-time\": theme.timeColor,\n \"--player-control-icon\": theme.controlIconColor,\n \"--player-focus-ring\": theme.focusRingColor,\n \"--player-spinner\": theme.spinnerColor,\n \"--player-volume-icon\": theme.volumeIconColor,\n \"--player-volume-track\": theme.volumeTrackColor,\n \"--player-volume-progress\": theme.volumeProgressColor,\n \"--player-quality-text\": theme.qualityOptionTextColor,\n \"--player-quality-bg\": theme.qualityOptionBackground,\n \"--player-quality-active-bg\": theme.qualityOptionActiveBackground,\n \"--player-quality-active-text\": theme.qualityOptionActiveTextColor,\n \"--player-speed-text\": theme.speedOptionTextColor,\n \"--player-speed-bg\": theme.speedOptionBackground,\n \"--player-speed-active-bg\": theme.speedOptionActiveBackground,\n \"--player-speed-active-text\": theme.speedOptionActiveTextColor,\n \"--player-zoom-icon\": theme.zoomIconColor,\n \"--player-skip-icon\": theme.skipIconColor,\n \"--player-skip-cue-bg\": theme.skipCueBackground,\n \"--player-skip-cue-text\": theme.skipCueTextColor,\n \"--player-live-dot\": theme.liveDotColor,\n };\n}\n","import type { PlayerEventMap } from \"../types\";\n\ntype Handler<T> = T extends void ? () => void : (payload: T) => void;\n\nexport class EventEmitter {\n private listeners = new Map<keyof PlayerEventMap, Set<Function>>();\n\n on<K extends keyof PlayerEventMap>(\n event: K,\n handler: Handler<PlayerEventMap[K]>,\n ): () => void {\n let set = this.listeners.get(event);\n if (!set) {\n set = new Set();\n this.listeners.set(event, set);\n }\n set.add(handler);\n return () => this.off(event, handler);\n }\n\n off<K extends keyof PlayerEventMap>(\n event: K,\n handler: Handler<PlayerEventMap[K]>,\n ): void {\n this.listeners.get(event)?.delete(handler);\n }\n\n emit<K extends keyof PlayerEventMap>(\n event: K,\n ...args: PlayerEventMap[K] extends void ? [] : [PlayerEventMap[K]]\n ): void {\n const set = this.listeners.get(event);\n if (!set) return;\n for (const handler of set) {\n try {\n (handler as Function)(...args);\n } catch {\n // never let listener failures break the player\n }\n }\n }\n\n removeAll(): void {\n this.listeners.clear();\n }\n}\n","const SENSITIVE_KEYS =\n /^(authorization|cookie|set-cookie|x-api-key|token|accessToken|access_token|clientSecret|password)$/i;\n\nconst REDACT_MAX_DEPTH = 32;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n if (Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction redactStringUrl(value: string): string {\n if (!/^https?:\\/\\//i.test(value) || !/[?&](token|expires)=/i.test(value)) {\n return value;\n }\n try {\n const url = new URL(value);\n for (const param of [\"token\", \"expires\", \"signature\", \"sig\"]) {\n if (url.searchParams.has(param)) {\n url.searchParams.set(param, \"[REDACTED]\");\n }\n }\n return url.toString();\n } catch {\n return \"[REDACTED_URL]\";\n }\n}\n\nexport function redactValue(\n key: string,\n value: unknown,\n seen: WeakSet<object> = new WeakSet(),\n depth = 0,\n): unknown {\n if (SENSITIVE_KEYS.test(key)) return \"[REDACTED]\";\n if (typeof value === \"string\") return redactStringUrl(value);\n if (Array.isArray(value)) {\n if (depth >= REDACT_MAX_DEPTH || seen.has(value)) return \"[REDACTED_CYCLE]\";\n seen.add(value);\n return value.map((item, index) =>\n redactValue(String(index), item, seen, depth + 1),\n );\n }\n if (isPlainObject(value)) {\n return redactObject(value, seen, depth + 1);\n }\n return value;\n}\n\n/**\n * Redacts sensitive fields. Cycle-safe and depth-capped.\n * Only walks plain objects/arrays — never DOM / host graphs.\n */\nexport function redactObject(\n obj: Record<string, unknown>,\n seen: WeakSet<object> = new WeakSet(),\n depth = 0,\n): Record<string, unknown> {\n if (depth > REDACT_MAX_DEPTH) return { \"[REDACTED]\": \"max_depth\" };\n if (seen.has(obj)) return { \"[REDACTED]\": \"cycle\" };\n seen.add(obj);\n\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n out[key] = redactValue(key, value, seen, depth);\n }\n return out;\n}\n","import { redactObject } from \"../security/redaction\";\nimport type { LoggingConfig } from \"../types\";\n\nconst LEVELS = [\"silent\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"] as const;\n\nexport class Logger {\n constructor(private config: Required<LoggingConfig>) {}\n\n update(config: Partial<LoggingConfig>): void {\n this.config = { ...this.config, ...config } as Required<LoggingConfig>;\n }\n\n private shouldLog(level: (typeof LEVELS)[number]): boolean {\n if (!this.config.enabled || this.config.level === \"silent\") return false;\n return LEVELS.indexOf(level) <= LEVELS.indexOf(this.config.level);\n }\n\n private write(\n level: \"error\" | \"warn\" | \"info\" | \"debug\",\n message: string,\n details?: Record<string, unknown>,\n ): void {\n if (!this.shouldLog(level)) return;\n const payload = details ? redactObject(details) : undefined;\n const fn = console[level] ?? console.log;\n if (payload) fn(`[nsg-player] ${message}`, payload);\n else fn(`[nsg-player] ${message}`);\n }\n\n error(message: string, details?: Record<string, unknown>): void {\n this.write(\"error\", message, details);\n }\n\n warn(message: string, details?: Record<string, unknown>): void {\n this.write(\"warn\", message, details);\n }\n\n info(message: string, details?: Record<string, unknown>): void {\n this.write(\"info\", message, details);\n }\n\n debug(message: string, details?: Record<string, unknown>): void {\n this.write(\"debug\", message, details);\n }\n}\n","/**\n * Mutable store of the latest playback authorization query parameters.\n * Updated on renewal without recreating the HLS player.\n */\nexport class AuthParamsStore {\n private params: URLSearchParams;\n\n constructor(initial?: URLSearchParams | Record<string, string>) {\n if (initial instanceof URLSearchParams) {\n this.params = new URLSearchParams(initial);\n } else if (initial) {\n this.params = new URLSearchParams(initial);\n } else {\n this.params = new URLSearchParams();\n }\n }\n\n getSnapshot(): URLSearchParams {\n return new URLSearchParams(this.params);\n }\n\n toRecord(): Record<string, string> {\n const out: Record<string, string> = {};\n this.params.forEach((value, key) => {\n out[key] = value;\n });\n return out;\n }\n\n /** True when at least one auth query param is stored. */\n hasParams(): boolean {\n return [...this.params.keys()].length > 0;\n }\n\n toString(): string {\n return this.params.toString();\n }\n\n update(next: URLSearchParams | Record<string, string>): void {\n this.params =\n next instanceof URLSearchParams\n ? new URLSearchParams(next)\n : new URLSearchParams(next);\n }\n\n /**\n * Merges current auth params onto a target URL, preserving unrelated query keys.\n * Critical for child HLS playlists/segments that omit signed query params.\n */\n applyToUrl(rawUrl: string, baseOrigin?: string): string {\n const target = new URL(\n rawUrl,\n baseOrigin ??\n (typeof location !== \"undefined\" ? location.origin : \"http://localhost\"),\n );\n this.params.forEach((value, key) => {\n target.searchParams.set(key, value);\n });\n return target.toString();\n }\n}\n","import {\n createPlayerError,\n PlayerErrorCode,\n} from \"../errors/PlayerError\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n PlaybackCredentialConfig,\n PlaybackSource,\n PlaybackSourceContext,\n} from \"../types\";\nimport { AuthParamsStore } from \"../auth/AuthParamsStore\";\n\n/**\n * Resolves and refreshes signed playback sources via consumer callbacks.\n */\nexport class PlaybackSourceManager {\n private source: PlaybackSource | null = null;\n private inFlight: Promise<PlaybackSource> | null = null;\n readonly authParams = new AuthParamsStore();\n\n constructor(\n private readonly playback: PlaybackCredentialConfig | undefined,\n private readonly logger: Logger,\n ) {}\n\n getSource(): PlaybackSource | null {\n return this.source;\n }\n\n getExpiresAt(): number | null {\n return this.source?.expiresAt ?? null;\n }\n\n async load(\n context: PlaybackSourceContext,\n ): Promise<PlaybackSource> {\n if (!this.playback?.getSource) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"playback.getSource is required when not using sourceUrl\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n return this.run(context, () => this.playback!.getSource(context));\n }\n\n async refresh(\n context: PlaybackSourceContext,\n ): Promise<PlaybackSource> {\n const refresher =\n this.playback?.refreshSource ?? this.playback?.getSource;\n if (!refresher) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"playback.refreshSource or playback.getSource is required\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n return this.run(context, () => refresher(context));\n }\n\n applyDirectSource(source: PlaybackSource): void {\n this.source = source;\n this.applyAuthParams(source);\n }\n\n private async run(\n context: PlaybackSourceContext,\n fn: () => Promise<PlaybackSource>,\n ): Promise<PlaybackSource> {\n if (this.inFlight) return this.inFlight;\n\n this.inFlight = (async () => {\n try {\n const next = await fn();\n if (!next?.url || typeof next.expiresAt !== \"number\") {\n throw createPlayerError(\n PlayerErrorCode.SOURCE_RESOLUTION_FAILED,\n \"Playback source callback returned an invalid payload\",\n { category: \"playback\", fatal: true, retryable: true },\n );\n }\n this.source = next;\n this.applyAuthParams(next);\n this.logger.debug(\"Playback source resolved\", {\n reason: context.reason,\n expiresAt: next.expiresAt,\n });\n return next;\n } catch (error) {\n if (error && typeof error === \"object\" && \"code\" in error) throw error;\n throw createPlayerError(\n PlayerErrorCode.SOURCE_RESOLUTION_FAILED,\n error instanceof Error ? error.message : \"Source resolution failed\",\n { category: \"playback\", fatal: true, retryable: true, cause: error },\n );\n } finally {\n this.inFlight = null;\n }\n })();\n\n return this.inFlight;\n }\n\n private applyAuthParams(source: PlaybackSource): void {\n if (source.authParams) {\n this.authParams.update(source.authParams);\n return;\n }\n try {\n const url = new URL(source.url);\n const params: Record<string, string> = {};\n url.searchParams.forEach((value, key) => {\n params[key] = value;\n });\n if (source.token) params.token = source.token;\n this.authParams.update(params);\n } catch {\n if (source.token) {\n this.authParams.update({ token: source.token });\n }\n }\n }\n\n destroy(): void {\n this.source = null;\n this.inFlight = null;\n }\n}\n","import type { AuthManager } from \"../auth/AuthManager\";\nimport type { Logger } from \"../logging/Logger\";\nimport type { PlaybackSourceManager } from \"./PlaybackSourceManager\";\n\nexport type RefreshReason =\n | \"proactive\"\n | \"frag_error\"\n | \"level_error\"\n | \"key_error\"\n | \"fatal_network\"\n | \"manual\";\n\nexport type RefreshManagerOptions = {\n videoId: string;\n authManager: AuthManager;\n sourceManager: PlaybackSourceManager;\n refreshBeforeExpiryMs: number;\n renewMaxRetries: number;\n renewBackoffMs: number;\n coalesceMs: number;\n logger: Logger;\n isDestroyed: () => boolean;\n onRenewing?: () => void;\n onRenewed?: (expiresAt: number) => void;\n onFatal?: (message: string) => void;\n};\n\n/**\n * Schedules signed-URL renewal (playback clock) with single-flight + coalesce.\n * Ensures auth token is fresh before calling refreshSource.\n */\nexport class RefreshManager {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private coalesceTimer: ReturnType<typeof setTimeout> | null = null;\n private inFlight = false;\n private consecutiveFailures = 0;\n private stopped = false;\n private pendingReason: RefreshReason | null = null;\n\n constructor(private readonly options: RefreshManagerOptions) {}\n\n start(initialExpiresAt: number): void {\n this.schedule(initialExpiresAt);\n }\n\n requestRenew(reason: RefreshReason = \"frag_error\"): void {\n if (this.stopped || this.options.isDestroyed()) return;\n this.pendingReason = reason;\n if (this.coalesceTimer) return;\n this.coalesceTimer = setTimeout(() => {\n this.coalesceTimer = null;\n const reasonToUse = this.pendingReason ?? \"frag_error\";\n this.pendingReason = null;\n void this.renew(reasonToUse);\n }, this.options.coalesceMs);\n }\n\n stop(): void {\n this.stopped = true;\n if (this.timer) clearTimeout(this.timer);\n if (this.coalesceTimer) clearTimeout(this.coalesceTimer);\n this.timer = null;\n this.coalesceTimer = null;\n }\n\n private schedule(expiresAt: number): void {\n if (this.timer) clearTimeout(this.timer);\n if (this.stopped) return;\n const delay = Math.max(\n 5_000,\n expiresAt - Date.now() - this.options.refreshBeforeExpiryMs,\n );\n this.timer = setTimeout(() => {\n void this.renew(\"proactive\");\n }, delay);\n }\n\n private async renew(reason: RefreshReason): Promise<void> {\n if (this.stopped || this.options.isDestroyed() || this.inFlight) {\n if (this.inFlight) this.pendingReason = reason;\n return;\n }\n this.inFlight = true;\n this.options.onRenewing?.();\n\n try {\n await this.options.authManager.ensureToken({\n reason: reason === \"proactive\" ? \"expiring\" : \"unauthorized\",\n videoId: this.options.videoId,\n });\n\n const source = await this.options.sourceManager.refresh({\n videoId: this.options.videoId,\n reason:\n reason === \"proactive\"\n ? \"expiring\"\n : reason === \"manual\"\n ? \"manual\"\n : \"auth_error\",\n });\n\n this.consecutiveFailures = 0;\n this.options.onRenewed?.(source.expiresAt);\n this.schedule(source.expiresAt);\n this.options.logger.debug(\"Playback source renewed\", { reason });\n } catch (error) {\n this.consecutiveFailures += 1;\n const message = refreshErrorMessage(error);\n this.options.logger.warn(\"Playback refresh failed\", {\n reason,\n failure: this.consecutiveFailures,\n message,\n });\n\n if (this.consecutiveFailures >= this.options.renewMaxRetries) {\n this.options.onFatal?.(message);\n } else {\n const backoff =\n this.options.renewBackoffMs * this.consecutiveFailures;\n this.timer = setTimeout(() => {\n void this.renew(reason);\n }, backoff);\n }\n } finally {\n this.inFlight = false;\n if (this.pendingReason && !this.stopped) {\n const pending = this.pendingReason;\n this.pendingReason = null;\n void this.renew(pending);\n }\n }\n }\n}\n\nfunction refreshErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n if (\n error &&\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof (error as { message: unknown }).message === \"string\" &&\n (error as { message: string }).message\n ) {\n return (error as { message: string }).message;\n }\n return \"Playback refresh failed\";\n}\n","/**\n * Live-edge helpers for HLS DVR / live streams.\n * Uses HTMLMediaElement.seekable when available; falls back to duration.\n */\n\nexport const DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS = 3;\n\nexport type SeekableLike = {\n length: number;\n start: (index: number) => number;\n end: (index: number) => number;\n};\n\nexport type LiveMediaSnapshot = {\n currentTime: number;\n duration: number;\n seekable: SeekableLike;\n};\n\n/**\n * Returns the latest seekable end (live edge), or null when unknown.\n */\nexport function getLiveEdgeTime(\n media: Pick<LiveMediaSnapshot, \"duration\" | \"seekable\">,\n): number | null {\n const { seekable, duration } = media;\n try {\n if (seekable.length > 0) {\n const end = seekable.end(seekable.length - 1);\n if (Number.isFinite(end) && end >= 0) {\n return end;\n }\n }\n } catch {\n // Some browsers throw while seekable is updating mid-load.\n }\n\n if (Number.isFinite(duration) && duration > 0) {\n return duration;\n }\n\n return null;\n}\n\n/**\n * True when playback is within `toleranceSeconds` of the live edge.\n */\nexport function isAtLiveEdge(\n media: LiveMediaSnapshot,\n toleranceSeconds: number = DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS,\n): boolean {\n const edge = getLiveEdgeTime(media);\n if (edge === null) {\n return true;\n }\n const lag = edge - media.currentTime;\n return lag <= Math.max(0, toleranceSeconds);\n}\n\nexport type SeekToLiveResult =\n | { moved: true; edge: number }\n | { moved: false; reason: \"already_at_live\" | \"edge_unavailable\"; edge: number | null };\n\nexport type SeekableMediaElement = {\n currentTime: number;\n duration: number;\n seekable: SeekableLike;\n};\n\n/**\n * Seeks to the live edge. Returns whether the playhead moved.\n */\nexport function seekToLiveEdge(\n media: SeekableMediaElement,\n options?: {\n toleranceSeconds?: number;\n /** Leave a tiny buffer behind the absolute end for decoder stability. */\n edgeOffsetSeconds?: number;\n },\n): SeekToLiveResult {\n const tolerance =\n options?.toleranceSeconds ?? DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS;\n const edgeOffset = options?.edgeOffsetSeconds ?? 0.25;\n const edge = getLiveEdgeTime(media);\n\n if (edge === null) {\n return { moved: false, reason: \"edge_unavailable\", edge: null };\n }\n\n if (isAtLiveEdge(media, tolerance)) {\n return { moved: false, reason: \"already_at_live\", edge };\n }\n\n const target = Math.max(0, edge - edgeOffset);\n media.currentTime = target;\n return { moved: true, edge };\n}\n","const LIVE_PLAYLIST_PATH = /\\/(?:hls-web-live|live)\\//i;\n\n/**\n * True for legacy `/hls-web-live/` playlists and current `/live/` playlists.\n * A same-origin proxy URL is live when its `url` query points at one of those paths.\n */\nexport function isLivePlaylistUrl(value: string): boolean {\n if (LIVE_PLAYLIST_PATH.test(value)) return true;\n try {\n const parsed = new URL(value, \"http://localhost\");\n const inner = parsed.searchParams.get(\"url\");\n return Boolean(inner && LIVE_PLAYLIST_PATH.test(inner));\n } catch {\n return false;\n }\n}\n\nexport function isSameOriginHttpUrl(value: string, baseOrigin: string): boolean {\n try {\n return new URL(value, baseOrigin).origin === new URL(baseOrigin).origin;\n } catch {\n return false;\n }\n}\n","import type { AuthParamsStore } from \"../auth/AuthParamsStore\";\nimport type { StreamingConfig } from \"../types\";\nimport { isSameOriginHttpUrl } from \"./mediaUrl\";\n\n/**\n * Local loader types (structurally compatible with hls.js) so the public\n * `.d.ts` does not require a value import of optional peer `hls.js`.\n */\ntype HlsLoaderTiming = { start: number; first: number; end: number };\n\ntype LoaderStats = {\n aborted: boolean;\n loaded: number;\n retry: number;\n total: number;\n chunkCount: number;\n bwEstimate: number;\n loading: HlsLoaderTiming;\n parsing: { start: number; end: number };\n buffering: HlsLoaderTiming;\n};\n\ntype LoaderContext = {\n url: string;\n responseType?: string;\n rangeStart?: number;\n rangeEnd?: number;\n progressData?: boolean;\n [key: string]: unknown;\n};\n\ntype LoaderConfiguration = {\n timeout?: number;\n};\n\ntype LoaderCallbacks<TContext> = {\n onSuccess: (\n response: { url: string; data: ArrayBuffer | string; code?: number },\n stats: LoaderStats,\n context: TContext,\n networkDetails: unknown,\n ) => void;\n onError: (\n error: { code: number; text: string },\n context: TContext,\n networkDetails: unknown,\n stats: LoaderStats,\n ) => void;\n onTimeout?: (...args: unknown[]) => void;\n onAbort?: (...args: unknown[]) => void;\n onProgress?: (...args: unknown[]) => void;\n};\n\ntype HlsLoaderInstance = {\n stats: LoaderStats;\n context: LoaderContext | null;\n load(\n context: LoaderContext,\n config: LoaderConfiguration,\n callbacks: LoaderCallbacks<LoaderContext>,\n ): void;\n destroy(): void;\n abort(): void;\n};\n\n/** Constructor shape compatible with `Hls.DefaultConfig.loader`. */\nexport type HlsLoaderConstructor = new (config: object) => HlsLoaderInstance;\n\n/**\n * Opaque stand-in for `typeof import(\"hls.js\").default` used only inside\n * this module. Public APIs accept `object` so `.d.ts` never imports `hls.js`.\n */\ntype HlsClassLike = {\n DefaultConfig: {\n loader: HlsLoaderConstructor;\n };\n};\n\n/** Public alias — pass `hls.js` default export (typed as object at the boundary). */\nexport type HlsModuleLike = object;\n\nconst ENC_KEY_PATH_RE = /enc\\.key$/i;\nconst BUILTIN_LOADER_NAMES = new Set([\"XhrLoader\", \"FetchLoader\"]);\n\n/**\n * Composition wrappers (AuthParamsLoader) do not sit on XhrLoader's prototype\n * chain. Stash the resolved builtin so polluted DefaultConfig.loader can still\n * unwrap after HMR / repeated player mounts / nested createAuthParamsLoader.\n */\nconst BUILTIN_LOADER_REF = Symbol.for(\n \"@codenkay/video-nsgplayer-core/builtin-hls-loader\",\n);\n\n/** Per-hls.js-module cache of the first successfully resolved builtin loader. */\nconst builtinLoaderByHls = new WeakMap<object, HlsLoaderConstructor>();\n\n/** Max same-origin BFF key attempts before the session circuit opens. */\nexport const KEY_PROXY_MAX_FAILURES = 2;\n\nexport type AuthParamsLoaderOptions = {\n videoId?: string;\n mediaProxyUrlBuilder?: StreamingConfig[\"mediaProxyUrlBuilder\"];\n keyProxyUrlBuilder?: StreamingConfig[\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: StreamingConfig[\"getKeyAccessToken\"];\n /** Override max BFF key failures before permanent browser fallback (default 2). */\n keyProxyMaxFailures?: number;\n};\n\nexport function isEncryptionKeyUrl(\n rawUrl: string,\n baseOrigin: string = typeof location !== \"undefined\"\n ? location.origin\n : \"http://localhost\",\n): boolean {\n try {\n return ENC_KEY_PATH_RE.test(new URL(rawUrl, baseOrigin).pathname);\n } catch {\n return /enc\\.key/i.test(rawUrl);\n }\n}\n\nfunction isBuiltinLoaderName(name: string): boolean {\n return BUILTIN_LOADER_NAMES.has(name);\n}\n\nfunction rememberBuiltin(\n HlsClass: HlsClassLike,\n loader: HlsLoaderConstructor,\n): HlsLoaderConstructor {\n if (isBuiltinLoaderName(typeof loader.name === \"string\" ? loader.name : \"\")) {\n builtinLoaderByHls.set(HlsClass, loader);\n }\n return loader;\n}\n\nfunction getStashedBuiltinLoader(\n loader: HlsLoaderConstructor,\n): HlsLoaderConstructor | undefined {\n return (\n loader as unknown as Record<symbol, HlsLoaderConstructor | undefined>\n )[BUILTIN_LOADER_REF];\n}\n\n/**\n * Resolve the builtin loader from the **same** `hls.js` module instance the\n * engine loaded. Never statically import `XhrLoader` — that can pull a second\n * hls.js copy into the app bundle after npm pack/publish and break key loads.\n */\nexport function resolveBuiltinHlsLoader(\n HlsModule: HlsModuleLike,\n): HlsLoaderConstructor {\n const HlsClass = HlsModule as HlsClassLike;\n const cached = builtinLoaderByHls.get(HlsClass);\n if (cached) return cached;\n\n const start = HlsClass.DefaultConfig.loader as unknown as HlsLoaderConstructor;\n let current: HlsLoaderConstructor | null = start;\n const seen = new Set<HlsLoaderConstructor>();\n\n while (current && !seen.has(current)) {\n seen.add(current);\n const name = typeof current.name === \"string\" ? current.name : \"\";\n if (isBuiltinLoaderName(name)) {\n return rememberBuiltin(HlsClass, current);\n }\n\n // Composition wrapper: follow stashed builtin / next base.\n const stashed: HlsLoaderConstructor | undefined =\n getStashedBuiltinLoader(current);\n if (stashed) {\n current = stashed;\n continue;\n }\n\n // Inheritance wrapper: walk prototype chain.\n const parentCtor = Object.getPrototypeOf(current.prototype)\n ?.constructor as HlsLoaderConstructor | undefined;\n if (\n !parentCtor ||\n parentCtor === (Object as unknown as HlsLoaderConstructor) ||\n parentCtor === (Function as unknown as HlsLoaderConstructor)\n ) {\n break;\n }\n current = parentCtor;\n }\n\n // Last resort: cached from an earlier successful resolve on this Hls module.\n const fallback = builtinLoaderByHls.get(HlsClass);\n return fallback ?? start;\n}\n\n/**\n * Rewrites an HLS request URL so signed auth query params are present.\n */\nexport function rewriteHlsRequestUrl(\n rawUrl: string,\n store: AuthParamsStore,\n options: AuthParamsLoaderOptions = {},\n baseOrigin: string = typeof location !== \"undefined\"\n ? location.origin\n : \"http://localhost\",\n): string {\n if (!rawUrl) return rawUrl;\n\n const parsed = new URL(rawUrl, baseOrigin);\n const isKey = ENC_KEY_PATH_RE.test(parsed.pathname);\n\n if (isKey && options.keyProxyUrlBuilder && options.videoId) {\n const snapshot = store.toRecord();\n return options.keyProxyUrlBuilder({\n videoId: options.videoId,\n keyUrl: parsed.toString(),\n token: snapshot.token,\n expires: snapshot.expires,\n username: snapshot.username,\n mobile: snapshot.mobile,\n });\n }\n\n const withAuth = store.hasParams()\n ? store.applyToUrl(rawUrl, baseOrigin)\n : parsed.toString();\n return applyMediaProxy(withAuth, options, baseOrigin);\n}\n\n/**\n * Cross-origin playback URLs are handed to the host proxy. URLs already on\n * the page origin, including a proxy URL from an earlier rewrite, stay as-is\n * so playlist rewriting cannot nest `/api/media` inside itself.\n */\nfunction applyMediaProxy(\n url: string,\n options: AuthParamsLoaderOptions,\n baseOrigin: string,\n): string {\n if (!options.mediaProxyUrlBuilder) return url;\n if (isSameOriginHttpUrl(url, baseOrigin)) return url;\n return options.mediaProxyUrlBuilder({\n url,\n videoId: options.videoId,\n });\n}\n\nfunction createLoaderStats(): LoaderStats {\n const now = performance.now();\n return {\n aborted: false,\n loaded: 0,\n retry: 0,\n total: 0,\n chunkCount: 0,\n bwEstimate: 0,\n loading: { start: now, first: 0, end: 0 },\n parsing: { start: 0, end: 0 },\n buffering: { start: 0, first: 0, end: 0 },\n };\n}\n\nfunction isProxyUpstreamBlocked(\n status: number,\n contentType: string | null,\n bodyHead: string,\n errorText?: string,\n): boolean {\n if (status === 0 || status === 502 || status === 503 || status === 504) {\n return true;\n }\n if (status === 403 || status === 401) return true;\n if (contentType?.includes(\"text/html\")) return true;\n if (/<!DOCTYPE|<html|Just a moment|Cloudflare|blocked/i.test(bodyHead)) {\n return true;\n }\n if (errorText && /Cloudflare|HTML|DOCTYPE|blocked|502/i.test(errorText)) {\n return true;\n }\n return false;\n}\n\ntype KeyFetchResult =\n | {\n ok: true;\n data: ArrayBuffer;\n response: Response;\n url: string;\n }\n | {\n ok: false;\n status: number;\n text: string;\n cors: boolean;\n response: Response | null;\n };\n\n/**\n * Low-level key GET. Does not invoke hls callbacks (caller decides success/fallback).\n */\nasync function fetchEncryptionKeyBytes(\n url: string,\n accessToken: string | null | undefined,\n signal: AbortSignal,\n): Promise<KeyFetchResult> {\n // Query-only must stay a CORS \"simple\" request (no custom headers / no\n // Authorization) so CDN hosts that allow XHR but reject preflight still work.\n // Bearer is attached only when the caller explicitly requests it (401/403 path).\n const pageOrigin =\n typeof location !== \"undefined\" ? location.origin : \"http://localhost\";\n const sameOrigin = isSameOriginHttpUrl(url, pageOrigin);\n // Same-origin media stays on the site session. Do not attach a bearer:\n // the playback API credential is the query token, and a bearer here is\n // not the site password.\n const headers: Record<string, string> | undefined =\n !sameOrigin && accessToken\n ? { Authorization: `Bearer ${accessToken}`, Accept: \"*/*\" }\n : undefined;\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n ...(headers ? { headers } : {}),\n credentials: sameOrigin ? \"same-origin\" : \"omit\",\n cache: \"no-store\",\n signal,\n });\n\n if (!response.ok) {\n return {\n ok: false,\n status: response.status,\n text: response.statusText || `enc.key HTTP ${response.status}`,\n cors: false,\n response,\n };\n }\n\n const data = await response.arrayBuffer();\n const head = new TextDecoder().decode(data.slice(0, 32));\n if (/<!DOCTYPE|<html/i.test(head)) {\n return {\n ok: false,\n status: 403,\n text: \"enc.key returned HTML (CDN challenge/block), not an AES key\",\n cors: false,\n response,\n };\n }\n\n return {\n ok: true,\n data,\n response,\n url: response.url || url,\n };\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return {\n ok: false,\n status: 0,\n text: \"enc.key fetch aborted/timeout\",\n cors: false,\n response: null,\n };\n }\n const cors =\n error instanceof TypeError ||\n (error instanceof Error &&\n /Failed to fetch|NetworkError|CORS/i.test(error.message));\n return {\n ok: false,\n status: 0,\n text:\n error instanceof Error ? error.message : \"enc.key fetch failed\",\n cors,\n response: null,\n };\n }\n}\n\n/** AES-128 content keys are exactly 16 bytes; anything else decrypts to garbage MSE. */\nconst AES_128_KEY_BYTES = 16;\n\nfunction normalizeAes128Key(data: ArrayBuffer): ArrayBuffer | null {\n if (data.byteLength === AES_128_KEY_BYTES) {\n // Detach a clean copy so KeyLoader / worker transfers cannot alias a view.\n return data.slice(0);\n }\n return null;\n}\n\nfunction reportKeySuccess(\n context: LoaderContext,\n callbacks: LoaderCallbacks<LoaderContext>,\n result: Extract<KeyFetchResult, { ok: true }>,\n): boolean {\n const key = normalizeAes128Key(result.data);\n if (!key) {\n const stats = createLoaderStats();\n callbacks.onError(\n {\n code: 422,\n text: `enc.key must be ${AES_128_KEY_BYTES} bytes (got ${result.data.byteLength})`,\n },\n context,\n result.response,\n stats,\n );\n return false;\n }\n\n const stats = createLoaderStats();\n const end = performance.now();\n stats.loading.first = stats.loading.start;\n stats.loading.end = end;\n stats.loaded = key.byteLength;\n stats.total = key.byteLength;\n callbacks.onSuccess(\n {\n url: result.url,\n data: key,\n code: result.response.status,\n },\n stats,\n context,\n result.response,\n );\n return true;\n}\n\ntype KeyLoadPlan = {\n proxyUrl: string | null;\n signedKeyUrl: string;\n accessToken: string | null;\n maxProxyFailures: number;\n};\n\ntype KeyLoadLifecycle = {\n /** False when a newer key load superseded this one (intentional abort). */\n isCurrent: () => boolean;\n};\n\n/**\n * Enterprise AES key path:\n * 1. BFF — at most `maxProxyFailures`, then trip session circuit (no 9× 502 spam)\n * 2. Signed-query fetch **without** Authorization (same as working CDN path; no preflight)\n * 3. On 401/403 only — Bearer fetch (API-origin keys)\n * 4. Caller may still try hls XHR if fetch is CORS-blocked\n */\nasync function loadEncryptionKeyEnterprise(\n context: LoaderContext,\n callbacks: LoaderCallbacks<LoaderContext>,\n plan: KeyLoadPlan,\n signal: AbortSignal,\n state: { proxyFailures: number; circuitOpen: boolean },\n lifecycle: KeyLoadLifecycle,\n): Promise<\"ok\" | \"try_xhr\" | \"aborted\"> {\n const stats = createLoaderStats();\n const stillCurrent = () => lifecycle.isCurrent() && !signal.aborted;\n\n const canTryProxy =\n Boolean(plan.proxyUrl) &&\n !state.circuitOpen &&\n state.proxyFailures < plan.maxProxyFailures;\n\n if (canTryProxy && plan.proxyUrl) {\n while (\n !state.circuitOpen &&\n state.proxyFailures < plan.maxProxyFailures &&\n stillCurrent()\n ) {\n state.proxyFailures += 1;\n try {\n const response = await fetch(plan.proxyUrl, {\n method: \"GET\",\n headers: { Accept: \"*/*\" },\n credentials: \"same-origin\",\n cache: \"no-store\",\n signal,\n });\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n const contentType = response.headers.get(\"content-type\");\n const data = await response.arrayBuffer();\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n const head = new TextDecoder().decode(data.slice(0, 64));\n\n if (\n response.ok &&\n !isProxyUpstreamBlocked(response.status, contentType, head)\n ) {\n const key = normalizeAes128Key(data);\n if (!key) {\n callbacks.onError(\n {\n code: 422,\n text: `enc.key proxy returned ${data.byteLength} bytes (need ${AES_128_KEY_BYTES})`,\n },\n { ...context, url: plan.proxyUrl },\n response,\n stats,\n );\n return \"ok\";\n }\n const end = performance.now();\n stats.loading.end = end;\n stats.loaded = key.byteLength;\n stats.total = key.byteLength;\n callbacks.onSuccess(\n {\n url: response.url || plan.proxyUrl,\n data: key,\n code: response.status,\n },\n stats,\n { ...context, url: plan.proxyUrl },\n response,\n );\n return \"ok\";\n }\n\n if (\n isProxyUpstreamBlocked(\n response.status,\n contentType,\n head,\n response.statusText,\n )\n ) {\n if (\n response.status === 502 ||\n contentType?.includes(\"text/html\") ||\n /Cloudflare|DOCTYPE|blocked/i.test(head)\n ) {\n state.circuitOpen = true;\n break;\n }\n continue;\n }\n\n callbacks.onError(\n {\n code: response.status,\n text: `enc.key proxy HTTP ${response.status}`,\n },\n { ...context, url: plan.proxyUrl },\n response,\n stats,\n );\n return \"ok\";\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n // Superseded by a newer key load, or timeout of a stale generation —\n // never report status-0 to hls.js (false CORS fatal in HlsEngine).\n return \"aborted\";\n }\n state.circuitOpen = true;\n break;\n }\n }\n if (!lifecycle.isCurrent()) return \"aborted\";\n state.circuitOpen = true;\n }\n\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n // Query-only first (no Authorization → no CORS preflight). This is the path\n // that worked with local `file:` installs before Bearer-first broke pack/build.\n const queryResult = await fetchEncryptionKeyBytes(\n plan.signedKeyUrl,\n null,\n signal,\n );\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n if (queryResult.ok) {\n reportKeySuccess(\n { ...context, url: plan.signedKeyUrl },\n callbacks,\n queryResult,\n );\n return \"ok\";\n }\n\n // Aborted unsigned fetch — do not escalate; a newer load owns the key.\n if (queryResult.status === 0 && signal.aborted) {\n return \"aborted\";\n }\n\n const needsBearer =\n Boolean(plan.accessToken) &&\n (queryResult.status === 401 ||\n queryResult.status === 403 ||\n // Browser-direct: opaque CORS/network on unsigned GET — try Bearer once\n // Appextech allows ACAO + Authorization (AUTH_MODE=browser, no BFF).\n queryResult.cors ||\n queryResult.status === 0);\n\n if (needsBearer && plan.accessToken) {\n const bearerResult = await fetchEncryptionKeyBytes(\n plan.signedKeyUrl,\n plan.accessToken,\n signal,\n );\n if (!lifecycle.isCurrent()) return \"aborted\";\n\n if (bearerResult.ok) {\n reportKeySuccess(\n { ...context, url: plan.signedKeyUrl },\n callbacks,\n bearerResult,\n );\n return \"ok\";\n }\n if (bearerResult.status === 0 && signal.aborted) {\n return \"aborted\";\n }\n if (bearerResult.cors || bearerResult.status === 0) {\n return \"try_xhr\";\n }\n callbacks.onError(\n {\n code: bearerResult.status,\n text: bearerResult.text,\n },\n { ...context, url: plan.signedKeyUrl },\n bearerResult.response,\n stats,\n );\n return \"ok\";\n }\n\n if (queryResult.cors || queryResult.status === 0) {\n return \"try_xhr\";\n }\n\n callbacks.onError(\n {\n code: queryResult.status,\n text: queryResult.text,\n },\n { ...context, url: plan.signedKeyUrl },\n queryResult.response,\n stats,\n );\n return \"ok\";\n}\n\n/**\n * hls.js loader: auth query rewrite + enterprise AES key loading.\n */\nexport function createAuthParamsLoader(\n HlsModule: HlsModuleLike,\n store: AuthParamsStore,\n options: AuthParamsLoaderOptions = {},\n): HlsLoaderConstructor {\n const HlsClass = HlsModule as HlsClassLike;\n const BaseLoader = resolveBuiltinHlsLoader(HlsClass);\n rememberBuiltin(HlsClass, BaseLoader);\n\n const maxProxyFailures =\n typeof options.keyProxyMaxFailures === \"number\" &&\n options.keyProxyMaxFailures >= 0\n ? options.keyProxyMaxFailures\n : KEY_PROXY_MAX_FAILURES;\n\n const keyProxyState = { proxyFailures: 0, circuitOpen: false };\n\n class AuthParamsLoader {\n readonly stats: LoaderStats;\n context: LoaderContext | null = null;\n private readonly inner: HlsLoaderInstance;\n private keyAbort: AbortController | null = null;\n /** Bumps on each key load so superseded aborts never call onError. */\n private keyLoadGeneration = 0;\n private pendingKeyCallbacks: LoaderCallbacks<LoaderContext> | null = null;\n\n constructor(config: object) {\n this.inner = new BaseLoader(config);\n this.stats = this.inner.stats;\n }\n\n private finishKeyAbort(): void {\n const cbs = this.pendingKeyCallbacks;\n this.pendingKeyCallbacks = null;\n this.keyAbort?.abort();\n this.keyAbort = null;\n if (cbs?.onAbort && this.context) {\n const stats = createLoaderStats();\n stats.aborted = true;\n try {\n cbs.onAbort(stats, this.context, null);\n } catch {\n // KeyLoader abort handlers must not break loader teardown.\n }\n }\n }\n\n abort(): void {\n this.keyLoadGeneration += 1;\n this.finishKeyAbort();\n this.inner.abort();\n }\n\n destroy(): void {\n this.keyLoadGeneration += 1;\n this.finishKeyAbort();\n this.context = null;\n this.inner.destroy();\n }\n\n load(\n context: LoaderContext,\n config: LoaderConfiguration,\n callbacks: LoaderCallbacks<LoaderContext>,\n ): void {\n this.context = context;\n if (!context.url) {\n this.inner.load(context, config, callbacks);\n return;\n }\n\n try {\n const originalUrl = context.url;\n const isKey = isEncryptionKeyUrl(originalUrl);\n\n if (!isKey) {\n if (store.hasParams() || options.mediaProxyUrlBuilder) {\n context.url = rewriteHlsRequestUrl(originalUrl, store, {\n ...options,\n keyProxyUrlBuilder: undefined,\n });\n }\n this.inner.load(context, config, callbacks);\n return;\n }\n\n // Always apply signed query to the CDN key URL (never leave unsigned).\n const signedKeyUrl = rewriteHlsRequestUrl(originalUrl, store, {\n ...options,\n keyProxyUrlBuilder: undefined,\n });\n\n const proxyConfigured = Boolean(\n options.keyProxyUrlBuilder && options.videoId,\n );\n const proxyUrl =\n proxyConfigured && !keyProxyState.circuitOpen\n ? rewriteHlsRequestUrl(originalUrl, store, options)\n : null;\n\n const accessToken = options.getKeyAccessToken?.() ?? null;\n\n // Supersede any in-flight key load on this loader instance.\n if (this.keyAbort || this.pendingKeyCallbacks) {\n this.keyLoadGeneration += 1;\n this.finishKeyAbort();\n }\n\n const generation = ++this.keyLoadGeneration;\n this.keyAbort = new AbortController();\n this.pendingKeyCallbacks = callbacks;\n context.responseType = \"arraybuffer\";\n const timeoutMs =\n typeof config?.timeout === \"number\" && config.timeout > 0\n ? config.timeout\n : 20_000;\n const timer = setTimeout(() => this.keyAbort?.abort(), timeoutMs);\n const lifecycle: KeyLoadLifecycle = {\n isCurrent: () => generation === this.keyLoadGeneration,\n };\n\n void loadEncryptionKeyEnterprise(\n context,\n callbacks,\n {\n proxyUrl,\n signedKeyUrl,\n accessToken,\n maxProxyFailures,\n },\n this.keyAbort.signal,\n keyProxyState,\n lifecycle,\n )\n .then((result) => {\n if (!lifecycle.isCurrent()) return;\n if (result === \"aborted\") {\n this.finishKeyAbort();\n return;\n }\n this.pendingKeyCallbacks = null;\n if (result === \"try_xhr\") {\n // Fallback to same-module XhrLoader with signed query (no Bearer).\n context.url = signedKeyUrl;\n this.inner.load(context, config, callbacks);\n }\n })\n .catch((error: unknown) => {\n if (!lifecycle.isCurrent()) return;\n this.pendingKeyCallbacks = null;\n callbacks.onError(\n {\n code: 0,\n text:\n error instanceof Error\n ? error.message\n : \"enc.key load failed\",\n },\n context,\n null,\n createLoaderStats(),\n );\n })\n .finally(() => {\n clearTimeout(timer);\n });\n return;\n } catch {\n // Fall through to default loader.\n }\n\n this.inner.load(context, config, callbacks);\n }\n }\n\n Object.defineProperty(AuthParamsLoader, BUILTIN_LOADER_REF, {\n value: BaseLoader,\n enumerable: false,\n configurable: false,\n });\n\n return AuthParamsLoader;\n}\n","import type { AuthParamsStore } from \"../auth/AuthParamsStore\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n HlsQualityLevel,\n HlsSupportMode,\n PlayerAudioTrack,\n PlayerState,\n PlayerTextTrack,\n QualitySelection,\n StreamingConfig,\n TextTrackSelection,\n} from \"../types\";\nimport { createAuthParamsLoader, rewriteHlsRequestUrl } from \"./authParamsLoader\";\n\nexport type HlsEngineCallbacks = {\n onStateChange?: (state: PlayerState) => void;\n onSupportMode?: (mode: HlsSupportMode) => void;\n onFatalError?: (message: string) => void;\n onAuthRecoveryNeeded?: (reason: string) => void;\n onQualitiesChange?: (levels: HlsQualityLevel[]) => void;\n onQualitySelectionChange?: (selection: QualitySelection) => void;\n onTextTracksChange?: (tracks: PlayerTextTrack[]) => void;\n onTextTrackSelectionChange?: (selection: TextTrackSelection) => void;\n onAudioTracksChange?: (tracks: PlayerAudioTrack[]) => void;\n onAudioTrackSelectionChange?: (selection: number) => void;\n onEnded?: () => void;\n};\n\nexport type HlsEngineOptions = {\n videoEl: HTMLVideoElement;\n playbackUrl: string;\n authParams: AuthParamsStore;\n autoplay: boolean;\n startMuted: boolean;\n startPosition?: number;\n volume?: number;\n videoId?: string;\n mediaProxyUrlBuilder?: StreamingConfig[\"mediaProxyUrlBuilder\"];\n keyProxyUrlBuilder?: StreamingConfig[\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: StreamingConfig[\"getKeyAccessToken\"];\n keyProxyMaxFailures?: StreamingConfig[\"keyProxyMaxFailures\"];\n hlsConfig: {\n enableWorker: boolean;\n lowLatencyMode: boolean;\n backBufferLength: number;\n fatalRecoveryLimit: number;\n };\n logger: Logger;\n callbacks: HlsEngineCallbacks;\n};\n\nfunction isAuthHttpStatus(code: unknown): boolean {\n return code === 401 || code === 403;\n}\n\n/**\n * Dual-path HLS engine: hls.js when supported, otherwise native Safari HLS.\n *\n * Signed CDN playback requires auth query params on every HLS request\n * (playlists, segments, and AES `enc.key` on CDN hosts).\n *\n * Optional `streaming.mediaProxyUrlBuilder` sends playlists, segments, and\n * keys through a same-origin BFF. The playback API rejects the browser Origin.\n * Optional `streaming.keyProxyUrlBuilder` remains the enc.key path when set.\n * `streaming.getKeyAccessToken` attaches a bearer only to a cross-origin key\n * request after signed-query 401/403.\n */\nfunction isGeckoBrowser(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /firefox|gecko\\//i.test(navigator.userAgent);\n}\n\nexport class HlsEngine {\n private hls: import(\"hls.js\").default | null = null;\n private destroyed = false;\n private supportMode: HlsSupportMode = \"unsupported\";\n private networkRecoveryCount = 0;\n private mediaRecoveryCount = 0;\n private qualities: HlsQualityLevel[] = [];\n private qualitySelection: QualitySelection = \"auto\";\n private textTracks: PlayerTextTrack[] = [];\n private textTrackSelection: TextTrackSelection = \"off\";\n private audioTracks: PlayerAudioTrack[] = [];\n private audioTrackSelection = 0;\n private nativeTextTrackCleanup: (() => void) | null = null;\n private startPositionApplied = false;\n private autoplayApplied = false;\n\n constructor(private readonly options: HlsEngineOptions) {}\n\n async start(): Promise<void> {\n const { videoEl, playbackUrl, startMuted, volume } = this.options;\n\n videoEl.muted = startMuted;\n if (typeof volume === \"number\") {\n videoEl.volume = Math.min(1, Math.max(0, volume));\n }\n\n const Hls = (await import(\"hls.js\")).default;\n\n if (Hls.isSupported()) {\n this.supportMode = \"hls.js\";\n this.options.callbacks.onSupportMode?.(\"hls.js\");\n await this.startWithHlsJs(Hls, playbackUrl);\n return;\n }\n\n if (videoEl.canPlayType(\"application/vnd.apple.mpegurl\")) {\n this.supportMode = \"native\";\n this.options.callbacks.onSupportMode?.(\"native\");\n videoEl.src = this.playbackRequestUrl(playbackUrl);\n this.bindMediaEvents();\n this.bindNativeTextTracks();\n this.options.callbacks.onStateChange?.(\"ready\");\n await this.applyStartPositionAndAutoplay();\n return;\n }\n\n this.supportMode = \"unsupported\";\n this.options.callbacks.onSupportMode?.(\"unsupported\");\n this.options.callbacks.onFatalError?.(\n \"HLS is not supported in this browser\",\n );\n }\n\n private async startWithHlsJs(\n Hls: typeof import(\"hls.js\").default,\n playbackUrl: string,\n ): Promise<void> {\n const {\n videoEl,\n authParams,\n hlsConfig,\n callbacks,\n videoId,\n keyProxyUrlBuilder,\n getKeyAccessToken,\n } = this.options;\n\n const loader = createAuthParamsLoader(Hls, authParams, {\n videoId,\n mediaProxyUrlBuilder: this.options.mediaProxyUrlBuilder,\n keyProxyUrlBuilder,\n getKeyAccessToken,\n keyProxyMaxFailures: this.options.keyProxyMaxFailures,\n });\n\n // Firefox/Gecko + worker demux/decrypt is a frequent source of\n // bufferAppendError on AES-128 VOD; keep workers elsewhere.\n const enableWorker = hlsConfig.enableWorker && !isGeckoBrowser();\n if (hlsConfig.enableWorker && !enableWorker) {\n this.options.logger.warn(\n \"Disabling hls.js worker on Firefox to avoid MSE bufferAppendError\",\n );\n }\n\n this.hls = new Hls({\n enableWorker,\n // LL mode on short encrypted VOD drives aggressive ABR thrash → MSE errors.\n lowLatencyMode: hlsConfig.lowLatencyMode,\n backBufferLength: hlsConfig.backBufferLength,\n // Stabilize ABR: avoid first-frag-only bandwidth test that immediately\n // hops levels on single-segment Appextech VODs (HAR showed truncated\n // 720p body vs Content-Length during level switches).\n testBandwidth: false,\n abrEwmaDefaultEstimate: 500_000,\n abrBandWidthFactor: 0.8,\n abrBandWidthUpFactor: 0.5,\n maxStarvationDelay: 4,\n capLevelToPlayerSize: true,\n startLevel: -1,\n loader: loader as unknown as typeof Hls.DefaultConfig.loader,\n });\n\n this.hls.attachMedia(videoEl);\n this.hls.loadSource(this.playbackRequestUrl(playbackUrl));\n\n this.hls.on(Hls.Events.MANIFEST_PARSED, (_event, data) => {\n if (this.destroyed) return;\n this.qualities = (data.levels ?? []).map((level, index) => ({\n index,\n height: level.height ?? 0,\n width: level.width ?? 0,\n bitrate: level.bitrate ?? 0,\n label:\n level.height != null && level.height > 0\n ? `${level.height}p`\n : `Level ${index}`,\n }));\n callbacks.onQualitiesChange?.(this.qualities);\n this.syncHlsSubtitleTracks();\n this.syncHlsAudioTracks();\n callbacks.onStateChange?.(\"ready\");\n // Autoplay immediately; defer resume-seek until media is buffered so we\n // never seek past an empty/short buffer (common with wtime on 5s VODs).\n void this.applyAutoplayOnly();\n });\n\n this.hls.on(Hls.Events.FRAG_BUFFERED, () => {\n if (this.destroyed || this.startPositionApplied) return;\n void this.applyStartPositionOnly();\n });\n\n this.hls.on(Hls.Events.SUBTITLE_TRACKS_UPDATED, () => {\n if (this.destroyed) return;\n this.syncHlsSubtitleTracks();\n });\n\n this.hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, () => {\n if (this.destroyed) return;\n this.syncHlsAudioTracks();\n });\n\n this.hls.on(Hls.Events.ERROR, (_event, data) => {\n this.handleHlsError(Hls, data);\n });\n\n this.bindMediaEvents();\n }\n\n private handleHlsError(\n Hls: typeof import(\"hls.js\").default,\n data: {\n fatal: boolean;\n type: string;\n details: string;\n response?: { code?: number };\n },\n ): void {\n if (this.destroyed) return;\n const { callbacks, hlsConfig } = this.options;\n const status = data.response?.code;\n\n // Only treat real HTTP auth failures as credential expiry.\n // Status 0 / undefined is usually CORS/abort — renewing cannot fix that.\n const authFailure = isAuthHttpStatus(status);\n\n if (data.details === Hls.ErrorDetails.KEY_LOAD_ERROR) {\n if (authFailure) {\n callbacks.onAuthRecoveryNeeded?.(\"key_error\");\n if (!data.fatal) return;\n } else if (!data.fatal) {\n // Status 0 / missing is almost always an aborted superseded key load\n // during ABR — not CORS. Promoting it to fatal shows a false banner\n // even after /api/.../hls-key returned 200.\n if (!status) {\n return;\n }\n callbacks.onFatalError?.(\n `Encryption key load failed (HTTP ${status}).`,\n );\n return;\n } else if (!status) {\n callbacks.onFatalError?.(\n \"Encryption key load aborted or failed. Retry playback; if it persists, check the key proxy / CDN path.\",\n );\n return;\n }\n }\n\n if (!data.fatal) {\n if (\n authFailure &&\n data.type === Hls.ErrorTypes.NETWORK_ERROR &&\n (data.details === Hls.ErrorDetails.FRAG_LOAD_ERROR ||\n data.details === Hls.ErrorDetails.LEVEL_LOAD_ERROR)\n ) {\n callbacks.onAuthRecoveryNeeded?.(\n data.details === Hls.ErrorDetails.LEVEL_LOAD_ERROR\n ? \"level_error\"\n : \"frag_error\",\n );\n }\n return;\n }\n\n if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {\n this.networkRecoveryCount += 1;\n if (this.networkRecoveryCount <= hlsConfig.fatalRecoveryLimit) {\n if (authFailure) {\n callbacks.onAuthRecoveryNeeded?.(\"fatal_network\");\n }\n this.hls?.startLoad();\n return;\n }\n }\n\n if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {\n this.mediaRecoveryCount += 1;\n if (this.mediaRecoveryCount > hlsConfig.fatalRecoveryLimit) {\n callbacks.onFatalError?.(data.details || \"Fatal HLS error\");\n return;\n }\n\n // bufferAppendError: stop ABR thrash, optionally swap audio codec, then\n // recover MediaSource. Plain recoverMediaError alone re-triggers level\n // hopping on short multi-bitrate VOD (Firefox HAR pattern).\n if (\n data.details === Hls.ErrorDetails.BUFFER_APPEND_ERROR ||\n data.details === Hls.ErrorDetails.BUFFER_FULL_ERROR\n ) {\n this.lockPlaybackToSafeLevel();\n }\n\n if (this.mediaRecoveryCount === 2) {\n this.hls?.swapAudioCodec();\n }\n this.hls?.recoverMediaError();\n return;\n }\n\n callbacks.onFatalError?.(data.details || \"Fatal HLS error\");\n }\n\n /** Pin the next load to the lowest ladder rung after MSE append failures. */\n private lockPlaybackToSafeLevel(): void {\n if (!this.hls || this.qualities.length === 0) return;\n try {\n this.hls.currentLevel = 0;\n this.hls.loadLevel = 0;\n this.hls.nextLoadLevel = 0;\n } catch {\n // Ignore if levels are not ready yet.\n }\n }\n\n private clampStartPosition(raw: number, videoEl: HTMLVideoElement): number {\n let t = Math.max(0, raw);\n const duration = videoEl.duration;\n if (Number.isFinite(duration) && duration > 0) {\n // Leave a small epsilon so we never seek to/past EOS on short VOD.\n t = Math.min(t, Math.max(0, duration - 0.35));\n }\n if (videoEl.seekable.length > 0) {\n const end = videoEl.seekable.end(videoEl.seekable.length - 1);\n if (Number.isFinite(end)) {\n t = Math.min(t, end);\n }\n }\n return t;\n }\n\n private async applyStartPositionOnly(): Promise<void> {\n if (this.destroyed || this.startPositionApplied) return;\n const { videoEl, startPosition } = this.options;\n this.startPositionApplied = true;\n\n if (typeof startPosition !== \"number\" || startPosition <= 0) return;\n\n const seek = () => {\n if (this.destroyed) return;\n try {\n videoEl.currentTime = this.clampStartPosition(startPosition, videoEl);\n } catch {\n // Ignore seek before seekable ranges are ready.\n }\n };\n\n if (videoEl.seekable.length > 0 || Number.isFinite(videoEl.duration)) {\n seek();\n } else {\n videoEl.addEventListener(\"loadedmetadata\", seek, { once: true });\n }\n }\n\n private async applyAutoplayOnly(): Promise<void> {\n if (this.destroyed || this.autoplayApplied) return;\n this.autoplayApplied = true;\n const { videoEl, autoplay } = this.options;\n if (!autoplay) return;\n try {\n await videoEl.play();\n } catch {\n if (!videoEl.muted) {\n videoEl.muted = true;\n try {\n await videoEl.play();\n } catch {\n this.options.logger.warn(\"Autoplay blocked\");\n }\n }\n }\n }\n\n private async applyStartPositionAndAutoplay(): Promise<void> {\n await this.applyStartPositionOnly();\n await this.applyAutoplayOnly();\n }\n\n private bindMediaEvents(): void {\n const { videoEl, callbacks } = this.options;\n videoEl.addEventListener(\"playing\", () =>\n callbacks.onStateChange?.(\"playing\"),\n );\n videoEl.addEventListener(\"pause\", () => {\n if (!videoEl.ended) callbacks.onStateChange?.(\"paused\");\n });\n videoEl.addEventListener(\"waiting\", () =>\n callbacks.onStateChange?.(\"buffering\"),\n );\n videoEl.addEventListener(\"ended\", () => {\n callbacks.onStateChange?.(\"ended\");\n callbacks.onEnded?.();\n });\n }\n\n updateAuthParams(): void {\n if (this.supportMode === \"native\" && this.options.videoEl) {\n const time = this.options.videoEl.currentTime;\n const wasPaused = this.options.videoEl.paused;\n this.options.videoEl.src = this.playbackRequestUrl(this.options.playbackUrl);\n this.options.videoEl.currentTime = time;\n if (!wasPaused) void this.options.videoEl.play();\n }\n }\n\n private playbackRequestUrl(playbackUrl: string): string {\n return rewriteHlsRequestUrl(playbackUrl, this.options.authParams, {\n videoId: this.options.videoId,\n mediaProxyUrlBuilder: this.options.mediaProxyUrlBuilder,\n keyProxyUrlBuilder: this.options.keyProxyUrlBuilder,\n getKeyAccessToken: this.options.getKeyAccessToken,\n keyProxyMaxFailures: this.options.keyProxyMaxFailures,\n });\n }\n\n resumeAfterAuthRenew(): void {\n this.networkRecoveryCount = 0;\n this.hls?.startLoad();\n this.updateAuthParams();\n }\n\n setQuality(selection: QualitySelection): void {\n this.qualitySelection = selection;\n if (!this.hls) return;\n this.hls.currentLevel = selection === \"auto\" ? -1 : selection;\n this.options.callbacks.onQualitySelectionChange?.(selection);\n }\n\n getQuality(): QualitySelection {\n return this.qualitySelection;\n }\n\n getQualities(): HlsQualityLevel[] {\n return this.qualities;\n }\n\n getTextTracks(): PlayerTextTrack[] {\n return this.textTracks;\n }\n\n getTextTrackSelection(): TextTrackSelection {\n return this.textTrackSelection;\n }\n\n setTextTrack(selection: TextTrackSelection): void {\n if (this.destroyed) return;\n this.textTrackSelection = selection;\n this.options.callbacks.onTextTrackSelectionChange?.(selection);\n\n if (this.supportMode === \"hls.js\" && this.hls) {\n this.hls.subtitleDisplay = selection !== \"off\";\n this.hls.subtitleTrack = selection === \"off\" ? -1 : selection;\n return;\n }\n\n if (this.supportMode === \"native\" && this.options.videoEl) {\n const tracks = this.options.videoEl.textTracks;\n for (let i = 0; i < tracks.length; i += 1) {\n const track = tracks[i]!;\n track.mode =\n selection !== \"off\" && i === selection ? \"showing\" : \"disabled\";\n }\n }\n }\n\n getAudioTracks(): PlayerAudioTrack[] {\n return this.audioTracks;\n }\n\n getAudioTrackSelection(): number {\n return this.audioTrackSelection;\n }\n\n setAudioTrack(index: number): void {\n if (this.destroyed) return;\n if (\n !Number.isInteger(index) ||\n index < 0 ||\n (this.audioTracks.length > 0 && index >= this.audioTracks.length)\n ) {\n return;\n }\n\n this.audioTrackSelection = index;\n this.options.callbacks.onAudioTrackSelectionChange?.(index);\n\n if (this.supportMode === \"hls.js\" && this.hls) {\n this.hls.audioTrack = index;\n return;\n }\n\n if (this.supportMode === \"native\" && this.options.videoEl) {\n const audioTracks = (\n this.options.videoEl as HTMLVideoElement & {\n audioTracks?: { length: number; [i: number]: { enabled: boolean } };\n }\n ).audioTracks;\n if (audioTracks && audioTracks.length > 0) {\n for (let i = 0; i < audioTracks.length; i += 1) {\n audioTracks[i]!.enabled = i === index;\n }\n }\n }\n }\n\n getSupportMode(): HlsSupportMode {\n return this.supportMode;\n }\n\n private syncHlsSubtitleTracks(): void {\n if (!this.hls) return;\n const tracks: PlayerTextTrack[] = (this.hls.subtitleTracks ?? []).map(\n (track, index) => ({\n index,\n id: String(track.id ?? index),\n label: track.name || track.lang || `Subtitles ${index + 1}`,\n language: track.lang,\n }),\n );\n this.textTracks = tracks;\n this.options.callbacks.onTextTracksChange?.(tracks);\n }\n\n private syncHlsAudioTracks(): void {\n if (!this.hls) return;\n const tracks: PlayerAudioTrack[] = (this.hls.audioTracks ?? []).map(\n (track, index) => ({\n index,\n id: String(track.id ?? index),\n label: track.name || track.lang || `Audio ${index + 1}`,\n language: track.lang,\n }),\n );\n this.audioTracks = tracks;\n this.options.callbacks.onAudioTracksChange?.(tracks);\n if (tracks.length > 0) {\n this.audioTrackSelection = 0;\n this.options.callbacks.onAudioTrackSelectionChange?.(0);\n }\n }\n\n private bindNativeTextTracks(): void {\n const { videoEl } = this.options;\n const syncFromElement = () => {\n if (this.destroyed || this.textTracks.length > 0) return;\n const list = videoEl.textTracks;\n const tracks: PlayerTextTrack[] = [];\n for (let i = 0; i < list.length; i += 1) {\n const track = list[i]!;\n if (track.kind !== \"subtitles\" && track.kind !== \"captions\") continue;\n tracks.push({\n index: tracks.length,\n id: track.id || `native-${tracks.length}`,\n label: track.label || track.language || `Track ${tracks.length + 1}`,\n language: track.language || undefined,\n });\n }\n if (tracks.length === 0) return;\n this.textTracks = tracks;\n this.options.callbacks.onTextTracksChange?.(tracks);\n };\n\n const textTracks = videoEl.textTracks as TextTrackList & {\n addEventListener?: (\n type: string,\n listener: EventListenerOrEventListenerObject,\n ) => void;\n removeEventListener?: (\n type: string,\n listener: EventListenerOrEventListenerObject,\n ) => void;\n };\n textTracks.addEventListener?.(\"addtrack\", syncFromElement);\n syncFromElement();\n this.nativeTextTrackCleanup = () => {\n textTracks.removeEventListener?.(\"addtrack\", syncFromElement);\n };\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.nativeTextTrackCleanup?.();\n this.nativeTextTrackCleanup = null;\n this.hls?.destroy();\n this.hls = null;\n const { videoEl } = this.options;\n videoEl.removeAttribute(\"src\");\n videoEl.load();\n }\n}\n","import { AuthManager } from \"../auth/AuthManager\";\nimport {\n assertNoSecretsInConfig,\n mergePlayerConfig,\n PACKAGE_VERSION,\n} from \"../config/defaults\";\nimport {\n createPlayerError,\n PlayerErrorCode,\n type PlayerError,\n} from \"../errors/PlayerError\";\nimport { EventEmitter } from \"../events/EventEmitter\";\nimport { Logger } from \"../logging/Logger\";\nimport { PlaybackSourceManager } from \"../playback/PlaybackSourceManager\";\nimport { RefreshManager } from \"../playback/RefreshManager\";\nimport {\n isAtLiveEdge,\n seekToLiveEdge,\n type SeekToLiveResult,\n} from \"../playback/liveEdge\";\nimport { isLivePlaylistUrl } from \"../streaming/mediaUrl\";\nimport { HlsEngine } from \"../streaming/HlsEngine\";\nimport type {\n BufferedRange,\n CreateVideoPlayerOptions,\n PlayerAudioTrack,\n PlayerConfig,\n PlayerDiagnostics,\n PlayerState,\n PlayerTextTrack,\n QualitySelection,\n TextTrackSelection,\n} from \"../types\";\n\nfunction expiryStatus(\n expiresAt: number | null,\n safetyMs: number,\n): PlayerDiagnostics[\"authExpiryStatus\"] {\n if (expiresAt === null || expiresAt <= 0) return \"unknown\";\n const remaining = expiresAt - Date.now();\n if (remaining <= 0) return \"expired\";\n if (remaining <= safetyMs) return \"expiring_soon\";\n return \"valid\";\n}\n\nfunction generateSessionId(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `ps_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport type VideoPlayer = {\n play: () => Promise<void>;\n pause: () => void;\n seek: (time: number) => void;\n /** Jump to the latest live edge. No-op when already at live. */\n goToLive: () => SeekToLiveResult;\n isLive: () => boolean;\n isAtLiveEdge: () => boolean;\n getCurrentTime: () => number;\n getDuration: () => number;\n setVolume: (volume: number) => void;\n getVolume: () => number;\n mute: () => void;\n unmute: () => void;\n isMuted: () => boolean;\n setPlaybackRate: (rate: number) => void;\n getPlaybackRate: () => number;\n getState: () => PlayerState;\n getBufferedRanges: () => BufferedRange[];\n getQuality: () => QualitySelection;\n setQuality: (selection: QualitySelection | string) => void;\n getAvailableQualities: () => ReturnType<HlsEngine[\"getQualities\"]>;\n getTextTracks: () => PlayerTextTrack[];\n getSelectedTextTrack: () => TextTrackSelection;\n setTextTrack: (selection: TextTrackSelection) => void;\n getAudioTracks: () => PlayerAudioTrack[];\n getSelectedAudioTrack: () => number;\n setAudioTrack: (index: number) => void;\n enterFullscreen: () => Promise<void>;\n exitFullscreen: () => Promise<void>;\n isFullscreen: () => boolean;\n /** Attach fullscreen target container (host UI chrome). Zoom stays UI-only. */\n setFullscreenElement: (el: HTMLElement | null) => void;\n reload: () => Promise<void>;\n destroy: () => void;\n getDiagnostics: () => PlayerDiagnostics;\n getConfig: () => PlayerConfig;\n updateConfig: (partial: Parameters<typeof mergePlayerConfig>[0]) => void;\n on: EventEmitter[\"on\"];\n off: EventEmitter[\"off\"];\n};\n\n/**\n * Creates a framework-agnostic video player.\n * Never pass clientSecret — use auth.getToken / playback.getSource callbacks.\n */\nexport function createVideoPlayer(\n options: CreateVideoPlayerOptions,\n): VideoPlayer {\n // Scan only config-shaped fields — never deep-walk mount (HTMLVideoElement)\n // or credential callback objects (auth / playback).\n assertNoSecretsInConfig({\n videoId: options.videoId,\n sourceUrl: options.sourceUrl,\n player: options.player,\n controls: options.controls,\n theme: options.theme,\n watermark: options.watermark,\n streaming: options.streaming,\n logging: options.logging,\n debug: options.debug,\n accessibility: options.accessibility,\n });\n\n let config = mergePlayerConfig({\n player: options.player,\n controls: options.controls,\n theme: options.theme,\n watermark: options.watermark,\n streaming: options.streaming,\n logging: options.logging,\n debug: options.debug,\n accessibility: options.accessibility,\n });\n\n const events = new EventEmitter();\n const logger = new Logger(config.logging);\n const playbackSessionId = generateSessionId();\n\n let state: PlayerState = \"idle\";\n let destroyed = false;\n let lastError: PlayerError | null = null;\n let videoEl = options.mount ?? null;\n let engine: HlsEngine | null = null;\n let refreshManager: RefreshManager | null = null;\n let fullscreenEl: HTMLElement | null = null;\n let isLiveStream = false;\n let mediaCleanup: (() => void) | null = null;\n\n const setState = (next: PlayerState) => {\n if (destroyed && next !== \"destroyed\") return;\n state = next;\n events.emit(\"statechange\", { state: next });\n };\n\n const bindMediaProgressEvents = (el: HTMLVideoElement) => {\n mediaCleanup?.();\n const onTimeUpdate = () => {\n if (destroyed) return;\n events.emit(\"timeupdate\", {\n currentTime: el.currentTime,\n duration: Number.isFinite(el.duration) ? el.duration : 0,\n });\n };\n const onProgress = () => {\n if (destroyed) return;\n let bufferedEnd = 0;\n try {\n if (el.buffered.length > 0) {\n bufferedEnd = el.buffered.end(el.buffered.length - 1);\n }\n } catch {\n bufferedEnd = 0;\n }\n events.emit(\"progress\", { bufferedEnd });\n };\n // Keep control-bar mute icon in sync when the engine (or browser autoplay\n // policy) flips `video.muted` without going through player.mute()/unmute().\n const onVolumeChange = () => {\n if (destroyed) return;\n events.emit(\"volumechange\", {\n volume: el.volume,\n muted: el.muted,\n });\n };\n el.addEventListener(\"timeupdate\", onTimeUpdate);\n el.addEventListener(\"progress\", onProgress);\n el.addEventListener(\"volumechange\", onVolumeChange);\n mediaCleanup = () => {\n el.removeEventListener(\"timeupdate\", onTimeUpdate);\n el.removeEventListener(\"progress\", onProgress);\n el.removeEventListener(\"volumechange\", onVolumeChange);\n };\n };\n\n const authManager = new AuthManager(\n options.auth,\n options.auth?.refreshBeforeExpiryMs ?? 60_000,\n logger,\n (token) => events.emit(\"authrefresh\", { expiresAt: token.expiresAt }),\n (message, retryable) =>\n events.emit(\"autherror\", { message, retryable }),\n );\n\n const sourceManager = new PlaybackSourceManager(options.playback, logger);\n\n const ensureVideoElement = (): HTMLVideoElement => {\n if (!videoEl) {\n throw createPlayerError(\n PlayerErrorCode.INVALID_CONFIGURATION,\n \"A video element must be provided via mount before starting playback\",\n { category: \"config\", fatal: true, retryable: false },\n );\n }\n return videoEl;\n };\n\n const startPlayback = async (): Promise<void> => {\n if (destroyed) return;\n setState(\"loading\");\n lastError = null;\n\n const videoId = options.videoId ?? \"unknown\";\n\n try {\n await authManager.ensureToken({\n reason: \"initial\",\n videoId: options.videoId,\n });\n\n let playbackUrl: string;\n let expiresAt: number;\n\n if (options.sourceUrl) {\n const source = {\n url: options.sourceUrl,\n expiresAt: Date.now() + 24 * 60 * 60 * 1000,\n live: isLivePlaylistUrl(options.sourceUrl),\n };\n sourceManager.applyDirectSource(source);\n playbackUrl = source.url;\n expiresAt = source.expiresAt;\n isLiveStream = Boolean(source.live);\n } else {\n const source = await sourceManager.load({\n videoId,\n reason: \"initial\",\n });\n playbackUrl = source.url;\n expiresAt = source.expiresAt;\n isLiveStream = Boolean(source.live);\n }\n\n const el = ensureVideoElement();\n if (isLiveStream) {\n el.playbackRate = 1;\n }\n bindMediaProgressEvents(el);\n engine?.destroy();\n engine = new HlsEngine({\n videoEl: el,\n playbackUrl,\n authParams: sourceManager.authParams,\n autoplay: config.player.autoplay,\n startMuted: config.player.startMuted,\n startPosition: config.player.startPosition,\n volume: config.player.volume,\n videoId: options.videoId,\n mediaProxyUrlBuilder: config.streaming.mediaProxyUrlBuilder,\n keyProxyUrlBuilder: config.streaming.keyProxyUrlBuilder,\n // Enterprise AES key auth (see authParamsLoader):\n // 1) keyProxyUrlBuilder BFF — max 2 failures then circuit\n // 2) signed-query fetch (no Bearer / no CORS preflight)\n // 3) Bearer only on HTTP 401/403 when getKeyAccessToken is set\n // 4) signed-query XHR fallback if fetch is CORS-blocked\n getKeyAccessToken:\n config.streaming.getKeyAccessToken ??\n (() => authManager.getAccessToken()),\n keyProxyMaxFailures: config.streaming.keyProxyMaxFailures,\n hlsConfig: config.streaming.hls,\n logger,\n callbacks: {\n onStateChange: (s) => {\n setState(s);\n if (s === \"ready\") events.emit(\"ready\");\n if (s === \"playing\") {\n events.emit(\"play\");\n events.emit(\"playing\");\n }\n if (s === \"paused\") events.emit(\"pause\");\n if (s === \"buffering\") events.emit(\"buffering\");\n if (s === \"ended\") events.emit(\"ended\");\n },\n onFatalError: (message) => {\n lastError = createPlayerError(\n PlayerErrorCode.PLAYBACK_ERROR,\n message,\n { category: \"playback\", fatal: true, retryable: true },\n );\n setState(\"error\");\n events.emit(\"error\", {\n code: lastError.code,\n message: lastError.message,\n fatal: true,\n });\n },\n onAuthRecoveryNeeded: (reason) => {\n refreshManager?.requestRenew(\n reason as \"frag_error\" | \"level_error\" | \"key_error\" | \"fatal_network\",\n );\n },\n onQualitiesChange: () => {\n /* consumers poll getAvailableQualities */\n },\n onQualitySelectionChange: (selection) => {\n const level = engine\n ?.getQualities()\n .find((q) => q.index === selection);\n events.emit(\"qualitychange\", {\n selection,\n label: typeof selection === \"number\" ? level?.label : \"auto\",\n });\n },\n onTextTracksChange: (tracks) => {\n events.emit(\"texttrackchange\", {\n tracks,\n selection: engine?.getTextTrackSelection() ?? \"off\",\n });\n },\n onTextTrackSelectionChange: (selection) => {\n events.emit(\"texttrackchange\", {\n tracks: engine?.getTextTracks() ?? [],\n selection,\n });\n },\n onAudioTracksChange: (tracks) => {\n events.emit(\"audiotrackchange\", {\n tracks,\n selection: engine?.getAudioTrackSelection() ?? 0,\n });\n },\n onAudioTrackSelectionChange: (selection) => {\n events.emit(\"audiotrackchange\", {\n tracks: engine?.getAudioTracks() ?? [],\n selection,\n });\n },\n onEnded: () => events.emit(\"ended\"),\n },\n });\n\n await engine.start();\n\n // Emit after engine applies startMuted / volume so the UI does not keep a\n // stale unmuted icon when autoplay later force-mutes (Chrome policy).\n if (!destroyed && videoEl) {\n events.emit(\"volumechange\", {\n volume: videoEl.volume,\n muted: videoEl.muted,\n });\n }\n\n if (!options.sourceUrl && options.playback) {\n refreshManager?.stop();\n refreshManager = new RefreshManager({\n videoId,\n authManager,\n sourceManager,\n refreshBeforeExpiryMs:\n options.playback.refreshBeforeExpiryMs ?? 30_000,\n renewMaxRetries: options.playback.renewMaxRetries ?? 3,\n renewBackoffMs: options.playback.renewBackoffMs ?? 2_000,\n coalesceMs: options.playback.authRecoveryCoalesceMs ?? 1_000,\n logger,\n isDestroyed: () => destroyed,\n onRenewing: () => setState(\"renewing\"),\n onRenewed: (nextExpiresAt) => {\n engine?.resumeAfterAuthRenew();\n if (!destroyed) {\n const el = videoEl;\n if (el && !el.paused && !el.ended) {\n setState(\"playing\");\n } else {\n setState(\"ready\");\n }\n }\n events.emit(\"tokenrefresh\", { expiresAt: nextExpiresAt });\n events.emit(\"sourcechange\", { expiresAt: nextExpiresAt });\n },\n onFatal: (message) => {\n lastError = createPlayerError(\n PlayerErrorCode.TOKEN_REFRESH_FAILED,\n message,\n { category: \"auth\", fatal: true, retryable: true },\n );\n setState(\"error\");\n events.emit(\"error\", {\n code: lastError.code,\n message: lastError.message,\n fatal: true,\n });\n },\n });\n refreshManager.start(expiresAt);\n }\n\n options.analytics?.onEvent?.({\n type: \"PLAYER_INITIALIZED\",\n payload: { videoId, playbackSessionId },\n });\n } catch (error) {\n const playerError =\n error && typeof error === \"object\" && \"code\" in error\n ? (error as PlayerError)\n : createPlayerError(\n PlayerErrorCode.UNKNOWN,\n error instanceof Error ? error.message : \"Failed to start player\",\n { category: \"unknown\", fatal: true, retryable: true, cause: error },\n );\n lastError = playerError;\n setState(\"error\");\n events.emit(\"error\", {\n code: playerError.code,\n message: playerError.message,\n fatal: playerError.fatal,\n });\n throw playerError;\n }\n };\n\n // Auto-start when mount is provided\n if (options.mount) {\n void startPlayback().catch(() => {\n /* error already emitted */\n });\n }\n\n const api: VideoPlayer = {\n async play() {\n await ensureVideoElement().play();\n },\n pause() {\n ensureVideoElement().pause();\n },\n seek(time: number) {\n const el = ensureVideoElement();\n const duration = Number.isFinite(el.duration) ? el.duration : time;\n el.currentTime = Math.min(Math.max(0, time), duration);\n },\n goToLive() {\n const el = ensureVideoElement();\n return seekToLiveEdge(el);\n },\n isLive() {\n return isLiveStream;\n },\n isAtLiveEdge() {\n if (!isLiveStream || !videoEl) {\n return true;\n }\n return isAtLiveEdge(videoEl);\n },\n getCurrentTime() {\n return videoEl?.currentTime ?? 0;\n },\n getDuration() {\n return videoEl?.duration ?? 0;\n },\n setVolume(volume: number) {\n const el = ensureVideoElement();\n el.volume = Math.min(1, Math.max(0, volume));\n events.emit(\"volumechange\", { volume: el.volume, muted: el.muted });\n },\n getVolume() {\n return videoEl?.volume ?? 0;\n },\n mute() {\n const el = ensureVideoElement();\n el.muted = true;\n events.emit(\"volumechange\", { volume: el.volume, muted: true });\n },\n unmute() {\n const el = ensureVideoElement();\n el.muted = false;\n events.emit(\"volumechange\", { volume: el.volume, muted: false });\n },\n isMuted() {\n return videoEl?.muted ?? false;\n },\n setPlaybackRate(rate: number) {\n const el = ensureVideoElement();\n // Live streams always play at 1x — speed controls are hidden.\n el.playbackRate = isLiveStream ? 1 : rate;\n },\n getPlaybackRate() {\n return videoEl?.playbackRate ?? 1;\n },\n getState() {\n return state;\n },\n getBufferedRanges() {\n const el = videoEl;\n if (!el) return [];\n const ranges: BufferedRange[] = [];\n for (let i = 0; i < el.buffered.length; i += 1) {\n ranges.push({ start: el.buffered.start(i), end: el.buffered.end(i) });\n }\n return ranges;\n },\n getQuality() {\n return engine?.getQuality() ?? \"auto\";\n },\n setQuality(selection: QualitySelection | string) {\n if (selection === \"auto\") {\n engine?.setQuality(\"auto\");\n return;\n }\n if (typeof selection === \"number\") {\n engine?.setQuality(selection);\n return;\n }\n const match = engine\n ?.getQualities()\n .find((q) => q.label === selection || `${q.height}p` === selection);\n if (match) engine?.setQuality(match.index);\n },\n getAvailableQualities() {\n return engine?.getQualities() ?? [];\n },\n getTextTracks() {\n return engine?.getTextTracks() ?? [];\n },\n getSelectedTextTrack() {\n return engine?.getTextTrackSelection() ?? \"off\";\n },\n setTextTrack(selection: TextTrackSelection) {\n engine?.setTextTrack(selection);\n },\n getAudioTracks() {\n return engine?.getAudioTracks() ?? [];\n },\n getSelectedAudioTrack() {\n return engine?.getAudioTrackSelection() ?? 0;\n },\n setAudioTrack(index: number) {\n engine?.setAudioTrack(index);\n },\n async enterFullscreen() {\n const target = fullscreenEl ?? videoEl?.parentElement ?? videoEl;\n if (target && \"requestFullscreen\" in target) {\n await target.requestFullscreen();\n events.emit(\"fullscreenchange\", { isFullscreen: true });\n }\n },\n async exitFullscreen() {\n if (document.fullscreenElement) {\n await document.exitFullscreen();\n events.emit(\"fullscreenchange\", { isFullscreen: false });\n }\n },\n isFullscreen() {\n return Boolean(document.fullscreenElement);\n },\n setFullscreenElement(el: HTMLElement | null) {\n fullscreenEl = el;\n },\n async reload() {\n refreshManager?.stop();\n engine?.destroy();\n await startPlayback();\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\n mediaCleanup?.();\n mediaCleanup = null;\n refreshManager?.stop();\n refreshManager = null;\n engine?.destroy();\n engine = null;\n authManager.destroy();\n sourceManager.destroy();\n setState(\"destroyed\");\n events.emit(\"destroy\");\n events.removeAll();\n options.analytics?.onEvent?.({ type: \"PLAYER_DESTROYED\" });\n },\n getDiagnostics() {\n const buffered = api.getBufferedRanges();\n return {\n playerVersion: PACKAGE_VERSION,\n currentState: state,\n hlsSupport: engine?.getSupportMode() ?? \"unsupported\",\n videoId: options.videoId ?? null,\n currentTime: api.getCurrentTime(),\n duration: api.getDuration(),\n bufferedEnd: buffered.length ? buffered[buffered.length - 1]!.end : 0,\n currentQuality:\n api.getQuality() === \"auto\"\n ? \"auto\"\n : engine?.getQualities().find((q) => q.index === api.getQuality())\n ?.label ?? null,\n playbackSessionId,\n authExpiryStatus: expiryStatus(\n authManager.getExpiresAt(),\n options.auth?.refreshBeforeExpiryMs ?? 60_000,\n ),\n sourceExpiryStatus: expiryStatus(\n sourceManager.getExpiresAt(),\n options.playback?.refreshBeforeExpiryMs ?? 30_000,\n ),\n lastError: lastError?.message ?? null,\n };\n },\n getConfig() {\n return config;\n },\n updateConfig(partial) {\n config = mergePlayerConfig({\n player: { ...config.player, ...partial?.player },\n controls: { ...config.controls, ...partial?.controls },\n theme: { ...config.theme, ...partial?.theme },\n watermark: { ...config.watermark, ...partial?.watermark },\n streaming: {\n engine: \"hls\",\n hls: { ...config.streaming.hls, ...partial?.streaming?.hls },\n mediaProxyUrlBuilder:\n partial?.streaming?.mediaProxyUrlBuilder ??\n config.streaming.mediaProxyUrlBuilder,\n keyProxyUrlBuilder:\n partial?.streaming?.keyProxyUrlBuilder ??\n config.streaming.keyProxyUrlBuilder,\n getKeyAccessToken:\n partial?.streaming?.getKeyAccessToken ??\n config.streaming.getKeyAccessToken ??\n (() => authManager.getAccessToken()),\n keyProxyMaxFailures:\n partial?.streaming?.keyProxyMaxFailures ??\n config.streaming.keyProxyMaxFailures,\n },\n logging: { ...config.logging, ...partial?.logging },\n debug: { ...config.debug, ...partial?.debug },\n accessibility: {\n ...config.accessibility,\n ...partial?.accessibility,\n },\n });\n logger.update(config.logging);\n },\n on: events.on.bind(events),\n off: events.off.bind(events),\n };\n\n // Allow attaching mount after create\n (api as VideoPlayer & { attach: (el: HTMLVideoElement, container?: HTMLElement) => Promise<void> }).attach =\n async (el: HTMLVideoElement, container?: HTMLElement) => {\n videoEl = el;\n fullscreenEl = container ?? null;\n await startPlayback();\n };\n\n return api;\n}\n\nexport type { CreateVideoPlayerOptions };\n"],"mappings":"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","names":["PlayerErrorCode","isPlainObject","stats","el"]}