@codenkay/video-nsgplayer-core 0.1.2 → 0.1.5

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/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 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 = \"0.1.2\";\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};\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 lowLatencyMode: true,\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]);\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?: unknown;\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 },\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\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\") {\n if (/^https?:\\/\\//i.test(value) && /[?&](token|expires)=/i.test(value)) {\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 }\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\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 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 applyToUrl(rawUrl: string, baseOrigin?: string): string {\n const target = new URL(rawUrl, baseOrigin ?? (typeof location !== \"undefined\" ? location.origin : \"http://localhost\"));\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 =\n error instanceof Error ? error.message : \"Playback refresh failed\";\n this.options.logger.warn(\"Playback refresh failed\", {\n reason,\n failure: this.consecutiveFailures,\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","/**\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 { Logger } from \"../logging/Logger\";\nimport type {\n HlsQualityLevel,\n HlsSupportMode,\n PlayerState,\n QualitySelection,\n} from \"../types\";\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 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 hlsConfig: {\n enableWorker: boolean;\n lowLatencyMode: boolean;\n backBufferLength: number;\n fatalRecoveryLimit: number;\n };\n logger: Logger;\n callbacks: HlsEngineCallbacks;\n};\n\n/**\n * Dual-path HLS engine: hls.js when supported, otherwise native Safari HLS.\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\n constructor(private readonly options: HlsEngineOptions) {}\n\n async start(): Promise<void> {\n const { videoEl, playbackUrl, autoplay, startMuted, volume, startPosition } =\n this.options;\n\n videoEl.muted = startMuted;\n if (typeof volume === \"number\") videoEl.volume = Math.min(1, Math.max(0, volume));\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 } else 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.options.callbacks.onStateChange?.(\"ready\");\n } else {\n this.supportMode = \"unsupported\";\n this.options.callbacks.onSupportMode?.(\"unsupported\");\n this.options.callbacks.onFatalError?.(\"HLS is not supported in this browser\");\n return;\n }\n\n if (typeof startPosition === \"number\" && startPosition > 0) {\n videoEl.currentTime = startPosition;\n }\n\n if (autoplay) {\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\n private async startWithHlsJs(\n Hls: typeof import(\"hls.js\").default,\n playbackUrl: string,\n ): Promise<void> {\n const { videoEl, authParams, hlsConfig, callbacks } = this.options;\n\n this.hls = new Hls({\n enableWorker: hlsConfig.enableWorker,\n lowLatencyMode: hlsConfig.lowLatencyMode,\n backBufferLength: hlsConfig.backBufferLength,\n xhrSetup: (xhr, url) => {\n // Auth params are applied via loader URL rewriting below when possible.\n void xhr;\n void url;\n },\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 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 callbacks.onStateChange?.(\"ready\");\n });\n\n this.hls.on(Hls.Events.ERROR, (_event, data) => {\n if (!data.fatal) {\n if (\n data.type === Hls.ErrorTypes.NETWORK_ERROR &&\n (data.details === Hls.ErrorDetails.FRAG_LOAD_ERROR ||\n data.details === Hls.ErrorDetails.LEVEL_LOAD_ERROR ||\n data.details === Hls.ErrorDetails.KEY_LOAD_ERROR)\n ) {\n callbacks.onAuthRecoveryNeeded?.(\n data.details === Hls.ErrorDetails.KEY_LOAD_ERROR\n ? \"key_error\"\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 callbacks.onAuthRecoveryNeeded?.(\"fatal_network\");\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 this.hls?.recoverMediaError();\n return;\n }\n }\n\n callbacks.onFatalError?.(data.details || \"Fatal HLS error\");\n });\n\n this.bindMediaEvents();\n }\n\n private bindMediaEvents(): void {\n const { videoEl, callbacks } = this.options;\n videoEl.addEventListener(\"playing\", () => callbacks.onStateChange?.(\"playing\"));\n videoEl.addEventListener(\"pause\", () => {\n if (!videoEl.ended) callbacks.onStateChange?.(\"paused\");\n });\n videoEl.addEventListener(\"waiting\", () => callbacks.onStateChange?.(\"buffering\"));\n videoEl.addEventListener(\"ended\", () => {\n callbacks.onStateChange?.(\"ended\");\n callbacks.onEnded?.();\n });\n }\n\n updateAuthParams(): void {\n // AuthParamsStore is live; next segment/manifest requests should use updated params.\n // For hls.js we kick startLoad after reactive renew.\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.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 getSupportMode(): HlsSupportMode {\n return this.supportMode;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\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 PlayerConfig,\n PlayerDiagnostics,\n PlayerState,\n QualitySelection,\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 enterFullscreen: () => Promise<void>;\n exitFullscreen: () => Promise<void>;\n isFullscreen: () => boolean;\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\n const setState = (next: PlayerState) => {\n if (destroyed && next !== \"destroyed\") return;\n state = next;\n events.emit(\"statechange\", { state: next });\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 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 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 onEnded: () => events.emit(\"ended\"),\n },\n });\n\n await engine.start();\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 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 ensureVideoElement().playbackRate = 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 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 async reload() {\n refreshManager?.stop();\n engine?.destroy();\n await startPlayback();\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\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 },\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;;;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;AACrB;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,MACd,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;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;AAiBO,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,IACF;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;;;ACxRO,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;AAEO,SAAS,YACd,KACA,OACA,OAAwB,oBAAI,QAAQ,GACpC,QAAQ,GACC;AACT,MAAI,eAAe,KAAK,GAAG,EAAG,QAAO;AACrC,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,gBAAgB,KAAK,KAAK,KAAK,wBAAwB,KAAK,KAAK,GAAG;AACtE,UAAI;AACF,cAAM,MAAM,IAAI,IAAI,KAAK;AACzB,mBAAW,SAAS,CAAC,SAAS,WAAW,aAAa,KAAK,GAAG;AAC5D,cAAI,IAAI,aAAa,IAAI,KAAK,GAAG;AAC/B,gBAAI,aAAa,IAAI,OAAO,YAAY;AAAA,UAC1C;AAAA,QACF;AACA,eAAO,IAAI,SAAS;AAAA,MACtB,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,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;AAEO,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;;;AC1DA,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,EAEA,OAAO,MAAsD;AAC3D,SAAK,SACH,gBAAgB,kBACZ,IAAI,gBAAgB,IAAI,IACxB,IAAI,gBAAgB,IAAI;AAAA,EAChC;AAAA,EAEA,WAAW,QAAgB,YAA6B;AACtD,UAAM,SAAS,IAAI,IAAI,QAAQ,eAAe,OAAO,aAAa,cAAc,SAAS,SAAS,mBAAmB;AACrH,SAAK,OAAO,QAAQ,CAAC,OAAO,QAAQ;AAClC,aAAO,aAAa,IAAI,KAAK,KAAK;AAAA,IACpC,CAAC;AACD,WAAO,OAAO,SAAS;AAAA,EACzB;AACF;;;AC5BO,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,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,WAAK,QAAQ,OAAO,KAAK,2BAA2B;AAAA,QAClD;AAAA,QACA,SAAS,KAAK;AAAA,MAChB,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;;;AC/HO,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;;;ACxDO,IAAM,YAAN,MAAgB;AAAA,EASrB,YAA6B,SAA2B;AAA3B;AAR7B,SAAQ,MAAuC;AAC/C,SAAQ,YAAY;AACpB,SAAQ,cAA8B;AACtC,SAAQ,uBAAuB;AAC/B,SAAQ,qBAAqB;AAC7B,SAAQ,YAA+B,CAAC;AACxC,SAAQ,mBAAqC;AAAA,EAEY;AAAA,EAEzD,MAAM,QAAuB;AAC3B,UAAM,EAAE,SAAS,aAAa,UAAU,YAAY,QAAQ,cAAc,IACxE,KAAK;AAEP,YAAQ,QAAQ;AAChB,QAAI,OAAO,WAAW,SAAU,SAAQ,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AAEhF,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;AAAA,IAC5C,WAAW,QAAQ,YAAY,+BAA+B,GAAG;AAC/D,WAAK,cAAc;AACnB,WAAK,QAAQ,UAAU,gBAAgB,QAAQ;AAC/C,cAAQ,MAAM,KAAK,QAAQ,WAAW,WAAW,WAAW;AAC5D,WAAK,gBAAgB;AACrB,WAAK,QAAQ,UAAU,gBAAgB,OAAO;AAAA,IAChD,OAAO;AACL,WAAK,cAAc;AACnB,WAAK,QAAQ,UAAU,gBAAgB,aAAa;AACpD,WAAK,QAAQ,UAAU,eAAe,sCAAsC;AAC5E;AAAA,IACF;AAEA,QAAI,OAAO,kBAAkB,YAAY,gBAAgB,GAAG;AAC1D,cAAQ,cAAc;AAAA,IACxB;AAEA,QAAI,UAAU;AACZ,UAAI;AACF,cAAM,QAAQ,KAAK;AAAA,MACrB,QAAQ;AACN,YAAI,CAAC,QAAQ,OAAO;AAClB,kBAAQ,QAAQ;AAChB,cAAI;AACF,kBAAM,QAAQ,KAAK;AAAA,UACrB,QAAQ;AACN,iBAAK,QAAQ,OAAO,KAAK,kBAAkB;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,eACZ,KACA,aACe;AACf,UAAM,EAAE,SAAS,YAAY,WAAW,UAAU,IAAI,KAAK;AAE3D,SAAK,MAAM,IAAI,IAAI;AAAA,MACjB,cAAc,UAAU;AAAA,MACxB,gBAAgB,UAAU;AAAA,MAC1B,kBAAkB,UAAU;AAAA,MAC5B,UAAU,CAAC,KAAK,QAAQ;AAEtB,aAAK;AACL,aAAK;AAAA,MACP;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,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,gBAAU,gBAAgB,OAAO;AAAA,IACnC,CAAC;AAED,SAAK,IAAI,GAAG,IAAI,OAAO,OAAO,CAAC,QAAQ,SAAS;AAC9C,UAAI,CAAC,KAAK,OAAO;AACf,YACE,KAAK,SAAS,IAAI,WAAW,kBAC5B,KAAK,YAAY,IAAI,aAAa,mBACjC,KAAK,YAAY,IAAI,aAAa,oBAClC,KAAK,YAAY,IAAI,aAAa,iBACpC;AACA,oBAAU;AAAA,YACR,KAAK,YAAY,IAAI,aAAa,iBAC9B,cACA,KAAK,YAAY,IAAI,aAAa,mBAChC,gBACA;AAAA,UACR;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,KAAK,SAAS,IAAI,WAAW,eAAe;AAC9C,aAAK,wBAAwB;AAC7B,YAAI,KAAK,wBAAwB,UAAU,oBAAoB;AAC7D,oBAAU,uBAAuB,eAAe;AAChD,eAAK,KAAK,UAAU;AACpB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,KAAK,SAAS,IAAI,WAAW,aAAa;AAC5C,aAAK,sBAAsB;AAC3B,YAAI,KAAK,sBAAsB,UAAU,oBAAoB;AAC3D,eAAK,KAAK,kBAAkB;AAC5B;AAAA,QACF;AAAA,MACF;AAEA,gBAAU,eAAe,KAAK,WAAW,iBAAiB;AAAA,IAC5D,CAAC;AAED,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEQ,kBAAwB;AAC9B,UAAM,EAAE,SAAS,UAAU,IAAI,KAAK;AACpC,YAAQ,iBAAiB,WAAW,MAAM,UAAU,gBAAgB,SAAS,CAAC;AAC9E,YAAQ,iBAAiB,SAAS,MAAM;AACtC,UAAI,CAAC,QAAQ,MAAO,WAAU,gBAAgB,QAAQ;AAAA,IACxD,CAAC;AACD,YAAQ,iBAAiB,WAAW,MAAM,UAAU,gBAAgB,WAAW,CAAC;AAChF,YAAQ,iBAAiB,SAAS,MAAM;AACtC,gBAAU,gBAAgB,OAAO;AACjC,gBAAU,UAAU;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,mBAAyB;AAGvB,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,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,iBAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAW;AACpB,SAAK,YAAY;AACjB,SAAK,KAAK,QAAQ;AAClB,SAAK,MAAM;AACX,UAAM,EAAE,QAAQ,IAAI,KAAK;AACzB,YAAQ,gBAAgB,KAAK;AAC7B,YAAQ,KAAK;AAAA,EACf;AACF;;;AC5MA,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;AAwCO,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;AAEnB,QAAM,WAAW,CAAC,SAAsB;AACtC,QAAI,aAAa,SAAS,YAAa;AACvC,YAAQ;AACR,WAAO,KAAK,eAAe,EAAE,OAAO,KAAK,CAAC;AAAA,EAC5C;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,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,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,SAAS,MAAM,OAAO,KAAK,OAAO;AAAA,QACpC;AAAA,MACF,CAAC;AAED,YAAM,OAAO,MAAM;AAEnB,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,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,yBAAmB,EAAE,eAAe;AAAA,IACtC;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,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,MAAM,SAAS;AACb,sBAAgB,KAAK;AACrB,cAAQ,QAAQ;AAChB,YAAM,cAAc;AAAA,IACtB;AAAA,IACA,UAAU;AACR,UAAI,UAAW;AACf,kBAAY;AACZ,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,QAC7D;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"]}
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} 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 = \"0.1.5\";\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};\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 lowLatencyMode: true,\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 };\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 },\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\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\") {\n if (/^https?:\\/\\//i.test(value) && /[?&](token|expires)=/i.test(value)) {\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 }\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\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 =\n error instanceof Error ? error.message : \"Playback refresh failed\";\n this.options.logger.warn(\"Playback refresh failed\", {\n reason,\n failure: this.consecutiveFailures,\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","/**\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 Hls from \"hls.js\";\nimport type {\n LoaderCallbacks,\n LoaderConfiguration,\n LoaderContext,\n} from \"hls.js\";\nimport type { AuthParamsStore } from \"../auth/AuthParamsStore\";\nimport type { StreamingConfig } from \"../types\";\n\ntype HlsLoader = new (config: object) => {\n load(\n context: LoaderContext,\n config: LoaderConfiguration,\n callbacks: LoaderCallbacks<LoaderContext>,\n ): void;\n destroy(): void;\n};\n\nconst ENC_KEY_PATH_RE = /enc\\.key$/i;\n\nexport type AuthParamsLoaderOptions = {\n videoId?: string;\n keyProxyUrlBuilder?: StreamingConfig[\"keyProxyUrlBuilder\"];\n getKeyAccessToken?: StreamingConfig[\"getKeyAccessToken\"];\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\n/**\n * Rewrites an HLS request URL so signed auth query params are present.\n * Master playlists are signed on loadSource; child playlists / segments / keys\n * are relative and would otherwise be fetched unsigned → CDN 403.\n *\n * AES `enc.key` handling (pick one):\n * 1. `keyProxyUrlBuilder` — same-origin BFF (needs Cloudflare-allowlisted server IP)\n * 2. `getKeyAccessToken` — browser-direct CDN fetch with API Bearer header\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\n/**\n * hls.js loader that re-applies live AuthParamsStore credentials on every\n * manifest / level / fragment / key request.\n */\nexport function createAuthParamsLoader(\n HlsClass: typeof Hls,\n store: AuthParamsStore,\n options: AuthParamsLoaderOptions = {},\n): HlsLoader {\n const BaseLoader = HlsClass.DefaultConfig.loader as HlsLoader;\n\n return class AuthParamsLoader extends BaseLoader {\n load(\n context: LoaderContext,\n config: LoaderConfiguration,\n callbacks: LoaderCallbacks<LoaderContext>,\n ): void {\n if (context.url) {\n try {\n const originalUrl = context.url;\n const isKey = isEncryptionKeyUrl(originalUrl);\n context.url = rewriteHlsRequestUrl(originalUrl, store, options);\n\n // Browser-direct key path: attach Video API Bearer on enc.key XHR.\n // Skipped when keyProxyUrlBuilder rewrote the URL to a same-origin BFF.\n if (\n isKey &&\n !options.keyProxyUrlBuilder &&\n options.getKeyAccessToken\n ) {\n const accessToken = options.getKeyAccessToken();\n if (accessToken) {\n context.headers = {\n ...(context.headers ?? {}),\n Authorization: `Bearer ${accessToken}`,\n };\n }\n }\n } catch {\n // Leave context.url unchanged if parsing fails.\n }\n }\n super.load(context, config, callbacks);\n }\n };\n}\n","import type { AuthParamsStore } from \"../auth/AuthParamsStore\";\nimport type { Logger } from \"../logging/Logger\";\nimport type {\n HlsQualityLevel,\n HlsSupportMode,\n PlayerState,\n QualitySelection,\n StreamingConfig,\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 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 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 * Encrypted VOD also requires a same-origin `enc.key` proxy (Bearer + query)\n * via `streaming.keyProxyUrlBuilder` — browser CORS cannot fetch Video API keys.\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\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.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 });\n\n this.hls = new Hls({\n enableWorker: hlsConfig.enableWorker,\n lowLatencyMode: hlsConfig.lowLatencyMode,\n backBufferLength: hlsConfig.backBufferLength,\n loader: loader 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 callbacks.onStateChange?.(\"ready\");\n void this.applyStartPositionAndAutoplay();\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, keyProxyUrlBuilder, getKeyAccessToken } =\n this.options;\n const status = data.response?.code;\n\n if (\n data.details === Hls.ErrorDetails.KEY_LOAD_ERROR &&\n !keyProxyUrlBuilder &&\n !getKeyAccessToken\n ) {\n callbacks.onFatalError?.(\n \"Encryption key load failed. Configure streaming.getKeyAccessToken (browser Bearer) or streaming.keyProxyUrlBuilder (Cloudflare-allowlisted BFF) for Appextech AES-encrypted HLS.\",\n );\n return;\n }\n\n const authFailure =\n isAuthHttpStatus(status) ||\n (data.details === Hls.ErrorDetails.KEY_LOAD_ERROR &&\n (status === undefined || status === 0 || isAuthHttpStatus(status)));\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 data.details === Hls.ErrorDetails.KEY_LOAD_ERROR)\n ) {\n callbacks.onAuthRecoveryNeeded?.(\n data.details === Hls.ErrorDetails.KEY_LOAD_ERROR\n ? \"key_error\"\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 this.hls?.recoverMediaError();\n return;\n }\n }\n\n callbacks.onFatalError?.(data.details || \"Fatal HLS error\");\n }\n\n private async applyStartPositionAndAutoplay(): Promise<void> {\n if (this.destroyed) return;\n const { videoEl, autoplay, startPosition } = this.options;\n\n if (typeof startPosition === \"number\" && startPosition > 0) {\n const seek = () => {\n if (this.destroyed) return;\n try {\n videoEl.currentTime = startPosition;\n } catch {\n // Ignore seek before seekable ranges are ready.\n }\n };\n if (videoEl.seekable.length > 0) {\n seek();\n } else {\n videoEl.addEventListener(\"loadedmetadata\", seek, { once: true });\n }\n }\n\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 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 getSupportMode(): HlsSupportMode {\n return this.supportMode;\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\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 PlayerConfig,\n PlayerDiagnostics,\n PlayerState,\n QualitySelection,\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 enterFullscreen: () => Promise<void>;\n exitFullscreen: () => Promise<void>;\n isFullscreen: () => boolean;\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\n const setState = (next: PlayerState) => {\n if (destroyed && next !== \"destroyed\") return;\n state = next;\n events.emit(\"statechange\", { state: next });\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 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 getKeyAccessToken: config.streaming.getKeyAccessToken,\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 onEnded: () => events.emit(\"ended\"),\n },\n });\n\n await engine.start();\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 ensureVideoElement().playbackRate = 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 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 async reload() {\n refreshManager?.stop();\n engine?.destroy();\n await startPlayback();\n },\n destroy() {\n if (destroyed) return;\n destroyed = true;\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 },\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","el"]}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import Hls, { LoaderContext, LoaderConfiguration, LoaderCallbacks } from 'hls.js';
2
+
1
3
  /** Player lifecycle states. */
2
4
  type PlayerState = "idle" | "loading" | "ready" | "playing" | "paused" | "buffering" | "renewing" | "ended" | "error" | "destroyed";
3
5
  type HlsSupportMode = "hls.js" | "native" | "unsupported";
@@ -115,12 +117,24 @@ type StreamingConfig = {
115
117
  backBufferLength?: number;
116
118
  fatalRecoveryLimit?: number;
117
119
  };
120
+ /**
121
+ * Same-origin BFF proxy for `enc.key` (preferred in production when the
122
+ * server IP is allowlisted by the CDN / Cloudflare).
123
+ */
118
124
  keyProxyUrlBuilder?: (ctx: {
119
125
  videoId: string;
120
126
  keyUrl: string;
121
127
  token?: string;
122
128
  expires?: string;
129
+ username?: string;
130
+ mobile?: string;
123
131
  }) => string;
132
+ /**
133
+ * Browser-direct AES key auth: returns the Video API access token so hls.js
134
+ * can send `Authorization: Bearer …` on `enc.key` requests.
135
+ * Use when the BFF cannot reach Appextech (Cloudflare challenge on server IP).
136
+ */
137
+ getKeyAccessToken?: () => string | null | undefined;
124
138
  };
125
139
  type LoggingConfig = {
126
140
  enabled?: boolean;
@@ -166,6 +180,8 @@ type PlayerConfig = Required<{
166
180
  streaming: {
167
181
  engine: "hls";
168
182
  hls: Required<NonNullable<StreamingConfig["hls"]>>;
183
+ keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
184
+ getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
169
185
  };
170
186
  logging: Required<LoggingConfig>;
171
187
  debug: Required<DebugConfig>;
@@ -239,7 +255,7 @@ type PlayerEventMap = {
239
255
  };
240
256
 
241
257
  declare const PLAYBACK_RATES: readonly [0.5, 0.75, 1, 1.25, 1.5, 2];
242
- declare const PACKAGE_VERSION = "0.1.2";
258
+ declare const PACKAGE_VERSION = "0.1.5";
243
259
  declare const DEFAULT_PLAYER_BEHAVIOR: Required<PlayerBehaviorConfig>;
244
260
  declare const DEFAULT_CONTROLS: Required<ControlsConfig>;
245
261
  declare const DEFAULT_THEME: Required<ThemeConfig>;
@@ -270,7 +286,8 @@ type PlayerConfigPartial = Partial<{
270
286
  streaming: {
271
287
  engine?: "hls";
272
288
  hls?: Partial<PlayerConfig["streaming"]["hls"]>;
273
- keyProxyUrlBuilder?: unknown;
289
+ keyProxyUrlBuilder?: PlayerConfig["streaming"]["keyProxyUrlBuilder"];
290
+ getKeyAccessToken?: PlayerConfig["streaming"]["getKeyAccessToken"];
274
291
  };
275
292
  logging: Partial<PlayerConfig["logging"]>;
276
293
  debug: Partial<PlayerConfig["debug"]>;
@@ -343,7 +360,14 @@ declare class AuthParamsStore {
343
360
  constructor(initial?: URLSearchParams | Record<string, string>);
344
361
  getSnapshot(): URLSearchParams;
345
362
  toRecord(): Record<string, string>;
363
+ /** True when at least one auth query param is stored. */
364
+ hasParams(): boolean;
365
+ toString(): string;
346
366
  update(next: URLSearchParams | Record<string, string>): void;
367
+ /**
368
+ * Merges current auth params onto a target URL, preserving unrelated query keys.
369
+ * Critical for child HLS playlists/segments that omit signed query params.
370
+ */
347
371
  applyToUrl(rawUrl: string, baseOrigin?: string): string;
348
372
  }
349
373
 
@@ -376,6 +400,9 @@ type HlsEngineOptions = {
376
400
  startMuted: boolean;
377
401
  startPosition?: number;
378
402
  volume?: number;
403
+ videoId?: string;
404
+ keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
405
+ getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
379
406
  hlsConfig: {
380
407
  enableWorker: boolean;
381
408
  lowLatencyMode: boolean;
@@ -387,6 +414,10 @@ type HlsEngineOptions = {
387
414
  };
388
415
  /**
389
416
  * Dual-path HLS engine: hls.js when supported, otherwise native Safari HLS.
417
+ *
418
+ * Signed CDN playback requires auth query params on every HLS request.
419
+ * Encrypted VOD also requires a same-origin `enc.key` proxy (Bearer + query)
420
+ * via `streaming.keyProxyUrlBuilder` — browser CORS cannot fetch Video API keys.
390
421
  */
391
422
  declare class HlsEngine {
392
423
  private readonly options;
@@ -400,6 +431,8 @@ declare class HlsEngine {
400
431
  constructor(options: HlsEngineOptions);
401
432
  start(): Promise<void>;
402
433
  private startWithHlsJs;
434
+ private handleHlsError;
435
+ private applyStartPositionAndAutoplay;
403
436
  private bindMediaEvents;
404
437
  updateAuthParams(): void;
405
438
  resumeAfterAuthRenew(): void;
@@ -558,7 +591,32 @@ declare class RefreshManager {
558
591
  private renew;
559
592
  }
560
593
 
594
+ type HlsLoader = new (config: object) => {
595
+ load(context: LoaderContext, config: LoaderConfiguration, callbacks: LoaderCallbacks<LoaderContext>): void;
596
+ destroy(): void;
597
+ };
598
+ type AuthParamsLoaderOptions = {
599
+ videoId?: string;
600
+ keyProxyUrlBuilder?: StreamingConfig["keyProxyUrlBuilder"];
601
+ getKeyAccessToken?: StreamingConfig["getKeyAccessToken"];
602
+ };
603
+ /**
604
+ * Rewrites an HLS request URL so signed auth query params are present.
605
+ * Master playlists are signed on loadSource; child playlists / segments / keys
606
+ * are relative and would otherwise be fetched unsigned → CDN 403.
607
+ *
608
+ * AES `enc.key` handling (pick one):
609
+ * 1. `keyProxyUrlBuilder` — same-origin BFF (needs Cloudflare-allowlisted server IP)
610
+ * 2. `getKeyAccessToken` — browser-direct CDN fetch with API Bearer header
611
+ */
612
+ declare function rewriteHlsRequestUrl(rawUrl: string, store: AuthParamsStore, options?: AuthParamsLoaderOptions, baseOrigin?: string): string;
613
+ /**
614
+ * hls.js loader that re-applies live AuthParamsStore credentials on every
615
+ * manifest / level / fragment / key request.
616
+ */
617
+ declare function createAuthParamsLoader(HlsClass: typeof Hls, store: AuthParamsStore, options?: AuthParamsLoaderOptions): HlsLoader;
618
+
561
619
  declare function redactValue(key: string, value: unknown, seen?: WeakSet<object>, depth?: number): unknown;
562
620
  declare function redactObject(obj: Record<string, unknown>, seen?: WeakSet<object>, depth?: number): Record<string, unknown>;
563
621
 
564
- export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, seekToLiveEdge, themeToCssVars };
622
+ export { type AccessibilityConfig, type AnalyticsConfig, type AuthConfig, AuthManager, AuthParamsStore, type AuthToken, type AuthTokenProviderContext, type BufferedRange, type ControlsConfig, type CreateVideoPlayerOptions, DEFAULT_CONTROLS, DEFAULT_LIVE_EDGE_TOLERANCE_SECONDS, DEFAULT_PLAYER_BEHAVIOR, DEFAULT_PLAYER_CONFIG, DEFAULT_THEME, DEFAULT_WATERMARK, type DebugConfig, EventEmitter, type HlsQualityLevel, type HlsSupportMode, type LiveMediaSnapshot, type LoggingConfig, PACKAGE_VERSION, PLAYBACK_RATES, type PlayIconPreset, type PlaybackCredentialConfig, type PlaybackRate, type PlaybackSource, type PlaybackSourceContext, PlaybackSourceManager, type PlayerBehaviorConfig, type PlayerConfig, type PlayerDiagnostics, type PlayerError, PlayerErrorCode, type PlayerEventMap, type PlayerSkipSeconds, type PlayerState, type PlayerZoomLevel, type QualitySelection, RefreshManager, SECRET_SCAN_MAX_DEPTH, type SeekToLiveResult, type StreamingConfig, type ThemeConfig, type VideoPlayer, type WatermarkConfig, assertNoSecretsInConfig, createAuthParamsLoader, createPlayerError, createVideoPlayer, getLiveEdgeTime, isAtLiveEdge, isPlainObject, mergePlayerConfig, redactObject, redactSensitive, redactValue, rewriteHlsRequestUrl, seekToLiveEdge, themeToCssVars };