{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/AdConfigManager.cjs","../../src/player/AdConfigManager.ts","../../src/utils/vastEnvironmentSignals.ts","../../src/utils/vastMacros.ts","../../src/utils/devUrl.ts","../../src/utils/mqttConfig.ts","../../src/utils/mqttClient.ts","../../src/utils/tracking.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","__export","prototype","hasOwnProperty","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","AdConfigManager_exports","AdConfigManager","exports","AIRY_ANDROID_APP_ID","AIRY_WEBOS_APP_ID","AIRY_TIZEN_APP_ID","AIRY_ROKU_APP_ID","AIRY_DEFAULT_CONTENT_URL","CTV_SESSION_STORAGE_KEY","PLAYER_ID_STORAGE_KEY","LG_TEST_APP_ID","LG_TEST_APP_NAME","LG_TEST_CONTENT_URL","_lgTestDeviceId","getLgTestDeviceId","createUuid","isLgWebOS","navigator","test","userAgent","getDefaultAppId","ua","DEVICE_ID_STORAGE_KEYS","ANDROID_ID_TYPES","Set","resolveVastEnvironmentSignals","isCtv","platformLat","bridgeSignals","readNativeBridgeSignals","platformDevice","readPlatformNativeDeviceId","lg","deviceId","readStoredDeviceId","limitAdTracking","deviceIdType","readStoredString","inferDeviceIdType","readStoredLimitAdTracking","contentUrl","appId","appName","AIRY_APP_NAME","sessionId","getOrCreateCtvSessionId","deviceTypeHint","isEquivalentDeviceIdType","tagType","runtimeType","tag","toLowerCase","runtime","has","resolveNativeDeviceId","isMacroPlaceholder","isZeroedAdId","getOrCreateStoredUuid","storageKey","window","existing","readPersistentId","writePersistentId","id","readCookie","localStorage","setItem","writeCookie","PERSISTENT_ID_COOKIE_MAX_AGE","document","prefix","encodeURIComponent","parts","cookie","split","part","entry","trim","startsWith","decodeURIComponent","slice","length","bytes","crypto","randomUUID","Uint8Array","getRandomValues","seed","Date","now","Math","floor","performanceNow","i","random","hex","toString","padStart","performance","adinfo","webapis","tifa","getTIFA","lat","isLATEnabled","webOSDev","lgudid","LGUDID","roku","Roku","rida","getPublisherUniqueId","ZEROED_AD_ID_PATTERNS","t","candidates","__STORMCLOUD_CTV_AD_INFO__","__STORMCLOUD_CTV__","stormcloudCtv","AiryTV","Android","webOS","tizen","amazon","filter","Boolean","source","readBridgeValue","readBridgeBoolean","keys","result","normalized","normalizeBoolean","getItem","UNEXPANDED_MACRO_PATTERN","INVALID_VAST_PARAM_KEY","EXAMPLE_COM_URL","CTV_UNSUPPORTED_PARAMS","INLINE_DEVICE_MACRO_REPLACEMENTS","pattern","getValue","ctx","tagTypeValid","correlator","trimmed","generateCorrelator","buf","Uint32Array","String","Number","MAX_SAFE_INTEGER","expandInlineMacroPlaceholders","baseUrl","url","replace","applyDeviceIdentityParams","params","runtimeId","tagRdid","tagLat","latValue","set","tagRdidValid","delete","forEach","removeBrokenAppNameOrphans","toDelete","_value","suffix","push","normalizeVastTagUrl","anValue","orphanFragments","raw","URL","searchParams","reconstructed","join","_match","val","expandedUrl","applyVastMacros","streamCorrelator","podMinDurationMs","pod","max","round","podMaxDurationMs","podMaxAds","requestUrl","existingUrl","adWillPlayMuted","adWillAutoPlay","consent","gdpr","gdprConsent","usPrivacy","adTest","staleKeys","replaceCorrelatorFallback","correlatorRegex","sep","includes","PRIVATE_HOST_PATTERNS","host","rawUrl","hostname","endsWith","some","toDevSafeUrl","protocol","isLocalDevHost","cleanPath","pathname","DEFAULT_MQTT_CONFIG","enabled","brokerAddress","brokerPort","wsPort","username","password","topicPrefix","qos","mqttConfig","applyMQTTConfig","overrides","isMQTTEnabled","brokerUrl","buildPlayerTopic","licenseKey","channel","import_mqtt","require","LOG","KEEPALIVE_SECONDS","CONNECT_TIMEOUT_MS","RECONNECT_BASE_MS","RECONNECT_MAX_MS","MAX_RECONNECT_ATTEMPTS","COOLDOWN_MS","client","status","reconnectAttempts","reconnectTimer","stopped","clearReconnectTimer","clearTimeout","teardownClient","removeAllListeners","end","scheduleReconnect","console","warn","setTimeout","openConnection","delay","min","jitter","buildMQTTBrokerUrl","clientId","mqtt","connect","keepalive","clean","reconnectPeriod","connectTimeout","queueQoSZero","reschedulePings","timerVariant","err","on","info","message","initMQTTClient","ensureMQTTClient","publishMQTT","topic","payload","connected","publish","JSON","stringify","cachedBrowserId","buildAnalyticsContext","config","context","debugAdTiming","isLiveStream","inputStreamType","getClientInfo","screen","platform","vendor","maxTouchPoints","memory","deviceMemory","hardwareConcurrency","screenInfo","width","height","availWidth","availHeight","orientation","pixelDepth","type","brand","os","model","isSmartTV","isAndroid","isWebView","isWebApp","deviceType","webosMatch","match","tizenMatch","tvMatch"],"mappings":"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","sourcesContent":["\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n  for (var name in all)\n    __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n  if (from && typeof from === \"object\" || typeof from === \"function\") {\n    for (let key of __getOwnPropNames(from))\n      if (!__hasOwnProp.call(to, key) && key !== except)\n        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n  }\n  return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n  // If the importer is in node compatibility mode or this is not an ESM\n  // file that has been converted to a CommonJS file using a Babel-\n  // compatible transform (i.e. \"__esModule\" has not been set), then set\n  // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n  isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n  mod\n));\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/player/AdConfigManager.ts\nvar AdConfigManager_exports = {};\n__export(AdConfigManager_exports, {\n  AdConfigManager: () => AdConfigManager\n});\nmodule.exports = __toCommonJS(AdConfigManager_exports);\n\n// src/utils/vastEnvironmentSignals.ts\nvar AIRY_ANDROID_APP_ID = \"com.freeairytv.android\";\nvar AIRY_WEBOS_APP_ID = \"com.freeairytv.webos\";\nvar AIRY_TIZEN_APP_ID = \"com.freeairytv.samsung\";\nvar AIRY_ROKU_APP_ID = \"com.freeairytv.roku\";\nvar AIRY_APP_NAME = \"AiryTV Movies & TV\";\nvar AIRY_DEFAULT_CONTENT_URL = \"https://live.airy.tv\";\nvar CTV_SESSION_STORAGE_KEY = \"stormcloud.ctv.sid\";\nvar PLAYER_ID_STORAGE_KEY = \"stormcloud.player.id\";\nvar LG_TEST_APP_ID = \"com.hulu.plus\";\nvar LG_TEST_APP_NAME = \"Hulu\";\nvar LG_TEST_CONTENT_URL = \"https://www.hulu.com/live-tv\";\nvar _lgTestDeviceId;\nfunction getLgTestDeviceId() {\n  if (!_lgTestDeviceId) _lgTestDeviceId = createUuid();\n  return _lgTestDeviceId;\n}\nfunction isLgWebOS() {\n  if (typeof navigator === \"undefined\") return false;\n  return /Web0S|webOS|LG Browser|LGSTB|LGE/i.test(navigator.userAgent);\n}\nfunction getDefaultAppId() {\n  if (typeof navigator === \"undefined\") return AIRY_ANDROID_APP_ID;\n  const ua = navigator.userAgent;\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return AIRY_WEBOS_APP_ID;\n  if (/Tizen|Samsung/i.test(ua)) return AIRY_TIZEN_APP_ID;\n  if (/Roku/i.test(ua)) return AIRY_ROKU_APP_ID;\n  return AIRY_ANDROID_APP_ID;\n}\nvar DEVICE_ID_STORAGE_KEYS = [\n  \"rdid\",\n  \"ifa\",\n  \"advertisingId\",\n  \"advertising_id\",\n  \"deviceAdvertisingId\",\n  \"aaid\",\n  \"adid\",\n  \"rida\",\n  \"tifa\",\n  \"lgudid\"\n];\nvar ANDROID_ID_TYPES = /* @__PURE__ */ new Set([\"aaid\", \"adid\"]);\nfunction resolveVastEnvironmentSignals(isCtv) {\n  const bridgeSignals = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const lg = isCtv && isLgWebOS();\n  const deviceId = bridgeSignals.deviceId || readStoredDeviceId() || platformDevice.deviceId || (lg && platformDevice.limitAdTracking !== true ? getLgTestDeviceId() : void 0);\n  const deviceIdType = bridgeSignals.deviceIdType || readStoredString(\"deviceIdType\") || readStoredString(\"idtype\") || platformDevice.deviceIdType || inferDeviceIdType() || (lg ? \"lgudid\" : void 0);\n  const platformLat = bridgeSignals.deviceId ? bridgeSignals.limitAdTracking : platformDevice.limitAdTracking;\n  const limitAdTracking = deviceId != null ? platformLat ?? readStoredLimitAdTracking() ?? false : void 0;\n  if (isCtv) {\n    return {\n      isCtv: true,\n      contentUrl: bridgeSignals.contentUrl || readStoredString(\"contentUrl\") || (lg ? LG_TEST_CONTENT_URL : AIRY_DEFAULT_CONTENT_URL),\n      appId: bridgeSignals.appId || readStoredString(\"appId\") || readStoredString(\"msid\") || (lg ? LG_TEST_APP_ID : getDefaultAppId()),\n      appName: bridgeSignals.appName || readStoredString(\"appName\") || readStoredString(\"an\") || (lg ? LG_TEST_APP_NAME : AIRY_APP_NAME),\n      sessionId: getOrCreateCtvSessionId(),\n      ...deviceId ? { deviceId } : {},\n      ...deviceIdType ? { deviceIdType } : {},\n      ...limitAdTracking != null ? { limitAdTracking } : {},\n      deviceTypeHint: 5\n    };\n  }\n  return {\n    isCtv: false,\n    ...deviceId ? { deviceId } : {},\n    ...deviceIdType ? { deviceIdType } : {},\n    ...limitAdTracking != null ? { limitAdTracking } : {}\n  };\n}\nfunction inferDeviceIdType() {\n  if (typeof navigator === \"undefined\") {\n    return void 0;\n  }\n  const ua = navigator.userAgent;\n  if (/Roku/i.test(ua)) return \"rida\";\n  if (/Tizen|Samsung/i.test(ua)) return \"tifa\";\n  if (/AppleTV|Apple TV/i.test(ua)) return \"tvOS\";\n  if (/AFT|Fire TV|Amazon/i.test(ua)) return \"afai\";\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return \"lgudid\";\n  if (/Android|Google TV/i.test(ua)) return \"aaid\";\n  if (/iPhone|iPad|iPod/i.test(ua)) return \"idfa\";\n  return void 0;\n}\nfunction isEquivalentDeviceIdType(tagType, runtimeType) {\n  if (!tagType || !runtimeType) return false;\n  const tag = tagType.toLowerCase();\n  const runtime = runtimeType.toLowerCase();\n  if (tag === runtime) return true;\n  return ANDROID_ID_TYPES.has(tag) && ANDROID_ID_TYPES.has(runtime);\n}\nfunction resolveNativeDeviceId() {\n  const bridgeSignals = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const deviceId = bridgeSignals.deviceId || readStoredDeviceId() || platformDevice.deviceId;\n  if (!deviceId || isMacroPlaceholder(deviceId) || isZeroedAdId(deviceId)) {\n    return void 0;\n  }\n  return deviceId;\n}\nfunction getOrCreateStoredUuid(storageKey) {\n  if (typeof window === \"undefined\") {\n    return void 0;\n  }\n  const existing = readPersistentId(storageKey);\n  if (existing) {\n    writePersistentId(storageKey, existing);\n    return existing;\n  }\n  const id = createUuid();\n  writePersistentId(storageKey, id);\n  return id;\n}\nfunction getOrCreateCtvSessionId() {\n  const existing = readPersistentId(CTV_SESSION_STORAGE_KEY);\n  if (existing) {\n    writePersistentId(CTV_SESSION_STORAGE_KEY, existing);\n    return existing;\n  }\n  const sessionId = createUuid();\n  writePersistentId(CTV_SESSION_STORAGE_KEY, sessionId);\n  return sessionId;\n}\nfunction readPersistentId(storageKey) {\n  return readStoredString(storageKey) || readCookie(storageKey);\n}\nfunction writePersistentId(storageKey, value) {\n  try {\n    window.localStorage?.setItem(storageKey, value);\n  } catch {\n  }\n  writeCookie(storageKey, value);\n}\nvar PERSISTENT_ID_COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5;\nfunction readCookie(name) {\n  if (typeof document === \"undefined\") {\n    return void 0;\n  }\n  try {\n    const prefix = encodeURIComponent(name) + \"=\";\n    const parts = document.cookie ? document.cookie.split(\";\") : [];\n    for (const part of parts) {\n      const entry = part.trim();\n      if (entry.startsWith(prefix)) {\n        return decodeURIComponent(entry.slice(prefix.length)) || void 0;\n      }\n    }\n  } catch {\n  }\n  return void 0;\n}\nfunction writeCookie(name, value) {\n  if (typeof document === \"undefined\") {\n    return;\n  }\n  try {\n    document.cookie = encodeURIComponent(name) + \"=\" + encodeURIComponent(value) + \";path=/;max-age=\" + PERSISTENT_ID_COOKIE_MAX_AGE + \";SameSite=Lax\";\n  } catch {\n  }\n}\nfunction createUuid() {\n  if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n    return crypto.randomUUID();\n  }\n  const bytes = new Uint8Array(16);\n  if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n    crypto.getRandomValues(bytes);\n  } else {\n    let seed = Date.now() ^ Math.floor(performanceNow() * 1e3);\n    for (let i = 0; i < 16; i++) {\n      seed = seed * 1103515245 + 12345 & 2147483647;\n      bytes[i] = (seed ^ Math.floor(Math.random() * 256)) & 255;\n    }\n  }\n  bytes[6] = (bytes[6] ?? 0) & 15 | 64;\n  bytes[8] = (bytes[8] ?? 0) & 63 | 128;\n  let hex = \"\";\n  for (let i = 0; i < 16; i++) {\n    hex += (bytes[i] ?? 0).toString(16).padStart(2, \"0\");\n  }\n  return hex.slice(0, 8) + \"-\" + hex.slice(8, 12) + \"-\" + hex.slice(12, 16) + \"-\" + hex.slice(16, 20) + \"-\" + hex.slice(20, 32);\n}\nfunction performanceNow() {\n  try {\n    if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n      return performance.now();\n    }\n  } catch {\n  }\n  return 0;\n}\nfunction readPlatformNativeDeviceId() {\n  if (typeof window === \"undefined\") return {};\n  try {\n    const adinfo = window.webapis?.adinfo;\n    if (adinfo) {\n      const tifa = typeof adinfo.getTIFA === \"function\" ? adinfo.getTIFA() : adinfo.tifa;\n      if (typeof tifa === \"string\" && tifa && !isMacroPlaceholder(tifa)) {\n        const lat = typeof adinfo.isLATEnabled === \"function\" ? adinfo.isLATEnabled() : void 0;\n        return {\n          deviceId: tifa,\n          deviceIdType: \"tifa\",\n          ...typeof lat === \"boolean\" ? { limitAdTracking: lat } : {}\n        };\n      }\n    }\n  } catch {\n  }\n  try {\n    const webOSDev = window.webOSDev;\n    if (webOSDev) {\n      const lgudid = typeof webOSDev.LGUDID === \"function\" ? webOSDev.LGUDID() : webOSDev.lgudid ?? webOSDev.LGUDID;\n      if (typeof lgudid === \"string\" && lgudid) {\n        if (isZeroedAdId(lgudid)) {\n          return { deviceIdType: \"lgudid\", limitAdTracking: true };\n        }\n        if (!isMacroPlaceholder(lgudid)) {\n          return { deviceId: lgudid, deviceIdType: \"lgudid\", limitAdTracking: false };\n        }\n      }\n    }\n  } catch {\n  }\n  try {\n    const roku = window.Roku;\n    if (roku) {\n      const rida = typeof roku.getPublisherUniqueId === \"function\" ? roku.getPublisherUniqueId() : roku.rida;\n      if (typeof rida === \"string\" && rida && !isMacroPlaceholder(rida)) {\n        return { deviceId: rida, deviceIdType: \"rida\", limitAdTracking: false };\n      }\n    }\n  } catch {\n  }\n  return {};\n}\nvar ZEROED_AD_ID_PATTERNS = /* @__PURE__ */ new Set([\n  \"38400000-8cf0-11bd-b23e-10b96e40000d\",\n  \"00000000-0000-0000-0000-000000000000\"\n]);\nfunction isMacroPlaceholder(value) {\n  const t = value.trim();\n  return !t || /^(\\[[^\\]]*\\]|\\{[^}]*\\}|%%[^%]*%%)$/.test(t) || /^(unknown|null|undefined|none|n\\/a|\\$\\{[^}]+\\})$/i.test(t) || ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());\n}\nfunction isZeroedAdId(value) {\n  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());\n}\nfunction readNativeBridgeSignals() {\n  if (typeof window === \"undefined\") {\n    return {};\n  }\n  const candidates = [\n    window.__STORMCLOUD_CTV_AD_INFO__,\n    window.__STORMCLOUD_CTV__,\n    window.stormcloudCtv,\n    window.AiryTV,\n    window.Android,\n    window.webOS,\n    window.tizen,\n    window.amazon\n  ].filter(Boolean);\n  for (const source of candidates) {\n    const contentUrl = readBridgeValue(source, [\"contentUrl\", \"url\", \"videoUrl\", \"canonicalUrl\"]) || void 0;\n    const appId = readBridgeValue(source, [\"appId\", \"msid\", \"applicationId\", \"packageName\"]) || void 0;\n    const appName = readBridgeValue(source, [\"appName\", \"an\", \"applicationName\"]) || void 0;\n    const deviceId = readBridgeValue(source, [\n      \"rdid\",\n      \"ifa\",\n      \"advertisingId\",\n      \"adId\",\n      \"deviceId\",\n      \"lgudid\",\n      \"LGUDID\",\n      \"tifa\",\n      \"rida\",\n      \"afai\",\n      \"aaid\"\n    ]) || void 0;\n    if (!contentUrl && !deviceId && !appId && !appName) continue;\n    const deviceIdType = readBridgeValue(source, [\n      \"idtype\",\n      \"deviceIdType\",\n      \"advertisingIdType\",\n      \"idType\"\n    ]) || inferDeviceIdType();\n    const limitAdTracking = readBridgeBoolean(source, [\n      \"is_lat\",\n      \"limitAdTracking\",\n      \"limitedAdTracking\",\n      \"lat\"\n    ]);\n    return {\n      ...contentUrl ? { contentUrl } : {},\n      ...appId ? { appId } : {},\n      ...appName ? { appName } : {},\n      ...deviceId ? { deviceId } : {},\n      ...deviceId && deviceIdType ? { deviceIdType } : {},\n      ...deviceId && limitAdTracking != null ? { limitAdTracking } : {}\n    };\n  }\n  return {};\n}\nfunction readBridgeValue(source, keys) {\n  for (const key of keys) {\n    const value = source?.[key];\n    if (typeof value === \"string\" && value) {\n      return value;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = value.call(source);\n        if (typeof result === \"string\" && result) {\n          return result;\n        }\n      } catch {\n      }\n    }\n  }\n  return void 0;\n}\nfunction readBridgeBoolean(source, keys) {\n  for (const key of keys) {\n    const value = source?.[key];\n    const normalized = normalizeBoolean(value);\n    if (normalized != null) {\n      return normalized;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = normalizeBoolean(value.call(source));\n        if (result != null) {\n          return result;\n        }\n      } catch {\n      }\n    }\n  }\n  return void 0;\n}\nfunction readStoredDeviceId() {\n  for (const key of DEVICE_ID_STORAGE_KEYS) {\n    const value = readStoredString(key);\n    if (value) {\n      return value;\n    }\n  }\n  return void 0;\n}\nfunction readStoredString(key) {\n  if (typeof window === \"undefined\") {\n    return void 0;\n  }\n  try {\n    const value = window.localStorage?.getItem(key);\n    return value || void 0;\n  } catch {\n    return void 0;\n  }\n}\nfunction readStoredLimitAdTracking() {\n  return normalizeBoolean(\n    readStoredString(\"limitAdTracking\") || readStoredString(\"limitedAdTracking\") || readStoredString(\"is_lat\")\n  );\n}\nfunction normalizeBoolean(value) {\n  if (typeof value === \"boolean\") {\n    return value;\n  }\n  if (typeof value === \"number\") {\n    return value === 1;\n  }\n  if (typeof value === \"string\") {\n    const normalized = value.toLowerCase();\n    if (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\") {\n      return true;\n    }\n    if (normalized === \"0\" || normalized === \"false\" || normalized === \"no\") {\n      return false;\n    }\n  }\n  return void 0;\n}\n\n// src/utils/vastMacros.ts\nvar UNEXPANDED_MACRO_PATTERN = /^(\\[[^\\]]*\\]|\\{[^}]*\\}|%%[^%]*%%)$/;\nvar INVALID_VAST_PARAM_KEY = /^\\s|\\s$/;\nvar EXAMPLE_COM_URL = /example\\.com/i;\nvar CTV_UNSUPPORTED_PARAMS = [\n  \"description_url\",\n  \"tfcd\",\n  \"npa\",\n  \"min_ad_duration\",\n  \"max_ad_duration\",\n  \"unviewed_position_start\",\n  \"impl\",\n  \"vad_type\",\n  \"gdpr\",\n  \"gdpr_consent\",\n  \"us_privacy\"\n];\nvar INLINE_DEVICE_MACRO_REPLACEMENTS = [\n  { pattern: /\\[RDID\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[IFA\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[ADVERTISING[_-]?ID(?:ENTIFIER)?\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[DEVICE[_-]?ID\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[IDTYPE\\]/gi, getValue: (ctx) => ctx.deviceIdType },\n  { pattern: /\\{rdid\\}/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\{device[_-]?id\\}/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\{idtype\\}/gi, getValue: (ctx) => ctx.deviceIdType },\n  { pattern: /%%ADVERTISING_IDENTIFIER_PLAIN%%/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /%%ADVERTISING_ID_OPT_OUT%%/gi, getValue: (ctx) => ctx.limitAdTracking != null ? ctx.limitAdTracking ? \"1\" : \"0\" : void 0 },\n  { pattern: /%%ADVERTISING_ID_TYPE%%/gi, getValue: (ctx) => ctx.deviceIdType },\n  { pattern: /%%ADVERTISING_ID%%/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /%%LIMIT_AD_TRACKING%%/gi, getValue: (ctx) => ctx.limitAdTracking != null ? ctx.limitAdTracking ? \"1\" : \"0\" : void 0 },\n  { pattern: /%%MSID%%/gi, getValue: (ctx) => ctx.appId },\n  { pattern: /%%APP_NAME%%/gi, getValue: (ctx) => ctx.appName },\n  { pattern: /%%SESSION_ID%%/gi, getValue: (ctx) => ctx.sessionId },\n  { pattern: /%%CORRELATOR%%/gi, getValue: (ctx) => ctx.correlator }\n];\nfunction isMacroPlaceholder2(value) {\n  if (value == null) return true;\n  const trimmed = value.trim();\n  if (!trimmed) return true;\n  if (UNEXPANDED_MACRO_PATTERN.test(trimmed)) return true;\n  return /^(unknown|null|undefined|none|n\\/a|\\$\\{[^}]+\\})$/i.test(trimmed);\n}\nfunction generateCorrelator() {\n  if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n    try {\n      const buf = new Uint32Array(2);\n      crypto.getRandomValues(buf);\n      const value = (buf[0] ?? 0) * 2097152 + ((buf[1] ?? 0) & 2097151);\n      if (value > 0) {\n        return String(value);\n      }\n    } catch {\n    }\n  }\n  return String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1);\n}\nfunction expandInlineMacroPlaceholders(baseUrl, ctx) {\n  let url = baseUrl;\n  for (const { pattern, getValue } of INLINE_DEVICE_MACRO_REPLACEMENTS) {\n    const value = getValue(ctx);\n    if (value != null && value !== \"\") {\n      url = url.replace(pattern, encodeURIComponent(value));\n    }\n  }\n  return url;\n}\nfunction applyDeviceIdentityParams(params, ctx) {\n  const runtimeId = ctx.deviceId?.trim();\n  const runtimeType = ctx.deviceIdType?.trim() || inferDeviceIdType();\n  const tagRdid = params.get(\"rdid\");\n  const tagType = params.get(\"idtype\");\n  const tagLat = params.get(\"is_lat\");\n  const latValue = ctx.limitAdTracking != null ? ctx.limitAdTracking ? \"1\" : \"0\" : void 0;\n  if (runtimeId) {\n    params.set(\"rdid\", runtimeId);\n    params.set(\"idtype\", runtimeType || tagType || \"aaid\");\n    params.set(\"is_lat\", latValue ?? (isMacroPlaceholder2(tagLat) ? \"0\" : tagLat));\n    return;\n  }\n  const tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder2(tagRdid));\n  const tagTypeValid = Boolean(tagType && !isMacroPlaceholder2(tagType));\n  if (tagRdidValid && tagTypeValid && runtimeType && !isEquivalentDeviceIdType(tagType, runtimeType)) {\n    params.delete(\"rdid\");\n    params.delete(\"idtype\");\n    params.delete(\"is_lat\");\n    return;\n  }\n  if (tagRdidValid) {\n    if (isMacroPlaceholder2(tagType) && runtimeType) {\n      params.set(\"idtype\", runtimeType);\n    }\n    if (isMacroPlaceholder2(tagLat)) {\n      params.set(\"is_lat\", latValue ?? \"0\");\n    }\n    return;\n  }\n  params.delete(\"rdid\");\n  params.delete(\"idtype\");\n  params.delete(\"is_lat\");\n}\nfunction removeBrokenAppNameOrphans(params, appName) {\n  const toDelete = [];\n  params.forEach((_value, key) => {\n    if (!key || INVALID_VAST_PARAM_KEY.test(key)) {\n      toDelete.push(key);\n    }\n  });\n  if (appName && appName.includes(\"&\")) {\n    for (const suffix of appName.split(\"&\").slice(1)) {\n      const trimmed = suffix.replace(/^\\s+/, \"\");\n      if (!trimmed) continue;\n      toDelete.push(suffix, ` ${trimmed}`, trimmed);\n    }\n  }\n  for (const key of new Set(toDelete)) {\n    if (key) params.delete(key);\n  }\n}\nfunction normalizeVastTagUrl(raw) {\n  if (!raw) return raw;\n  try {\n    const url = new URL(raw);\n    const anValue = url.searchParams.get(\"an\");\n    if (anValue !== null) {\n      const orphanFragments = [];\n      url.searchParams.forEach((_value, key) => {\n        if (key && INVALID_VAST_PARAM_KEY.test(key)) {\n          orphanFragments.push(key.trim());\n        }\n      });\n      if (orphanFragments.length > 0) {\n        const reconstructed = [anValue.replace(/\\s+$/, \"\"), ...orphanFragments].filter(Boolean).join(\" & \");\n        url.searchParams.forEach((_value, key) => {\n          if (key && INVALID_VAST_PARAM_KEY.test(key)) {\n            url.searchParams.delete(key);\n          }\n        });\n        url.searchParams.set(\"an\", reconstructed);\n        return url.toString().replace(\n          /([?&]an=)([^&]*)/,\n          (_match, prefix, val) => prefix + val.replace(/\\+/g, \"%20\")\n        );\n      }\n    }\n    removeBrokenAppNameOrphans(url.searchParams);\n    return url.toString();\n  } catch {\n    return raw;\n  }\n}\nfunction applyVastMacros(baseUrl, ctx) {\n  const expandedUrl = expandInlineMacroPlaceholders(baseUrl, ctx);\n  let url;\n  try {\n    url = new URL(normalizeVastTagUrl(expandedUrl));\n  } catch {\n    return replaceCorrelatorFallback(expandedUrl, ctx.correlator);\n  }\n  const params = url.searchParams;\n  removeBrokenAppNameOrphans(params, ctx.appName);\n  params.set(\"correlator\", ctx.correlator);\n  params.set(\"scor\", ctx.streamCorrelator);\n  if (ctx.isCtv) {\n    for (const key of CTV_UNSUPPORTED_PARAMS) {\n      params.delete(key);\n    }\n  }\n  if (ctx.pod != null) {\n    params.set(\"pod\", String(ctx.pod));\n  }\n  params.delete(\"ppos\");\n  params.delete(\"lip\");\n  if (ctx.podMinDurationMs != null) {\n    params.set(\"pmnd\", String(Math.max(0, Math.round(ctx.podMinDurationMs))));\n  }\n  if (ctx.podMaxDurationMs != null) {\n    params.set(\"pmxd\", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));\n  }\n  if (ctx.podMaxAds != null) {\n    params.set(\"pmad\", String(Math.max(1, Math.round(ctx.podMaxAds))));\n  }\n  const requestUrl = ctx.contentUrl || ctx.pageUrl;\n  if (requestUrl) {\n    params.set(\"url\", requestUrl);\n    if (!ctx.isCtv) {\n      params.set(\"description_url\", requestUrl);\n    }\n  } else {\n    const existingUrl = params.get(\"url\") || \"\";\n    if (EXAMPLE_COM_URL.test(existingUrl)) {\n      params.delete(\"url\");\n      params.delete(\"description_url\");\n    }\n  }\n  if (ctx.adWillPlayMuted != null) {\n    params.set(\"vpmute\", ctx.adWillPlayMuted ? \"1\" : \"0\");\n  }\n  if (ctx.adWillAutoPlay != null) {\n    params.set(\"vpa\", ctx.adWillAutoPlay ? \"auto\" : \"click\");\n  }\n  if (ctx.appId) {\n    params.set(\"msid\", ctx.appId);\n  }\n  if (ctx.appName) {\n    removeBrokenAppNameOrphans(params, ctx.appName);\n    params.set(\"an\", ctx.appName);\n  }\n  if (ctx.sessionId) {\n    params.set(\"sid\", ctx.sessionId);\n  }\n  if (ctx.deviceTypeHint != null) {\n    params.set(\"dth\", String(ctx.deviceTypeHint));\n  } else if (ctx.isCtv) {\n    params.set(\"dth\", \"5\");\n  }\n  applyDeviceIdentityParams(params, ctx);\n  if (!ctx.isCtv) {\n    const consent = ctx.consent;\n    if (consent?.gdpr != null) {\n      params.set(\"gdpr\", consent.gdpr);\n    }\n    if (consent?.gdprConsent != null) {\n      params.set(\"gdpr_consent\", consent.gdprConsent);\n    }\n    if (consent?.usPrivacy != null) {\n      params.set(\"us_privacy\", consent.usPrivacy);\n    }\n  }\n  if (ctx.adTest) {\n    params.set(\"adtest\", \"on\");\n  }\n  const staleKeys = [];\n  params.forEach((value, key) => {\n    if (isMacroPlaceholder2(value)) {\n      staleKeys.push(key);\n    }\n  });\n  for (const key of staleKeys) {\n    params.delete(key);\n  }\n  removeBrokenAppNameOrphans(params, ctx.appName);\n  return url.toString();\n}\nfunction replaceCorrelatorFallback(baseUrl, correlator) {\n  const correlatorRegex = /([?&])correlator=([^&]*)/;\n  if (correlatorRegex.test(baseUrl)) {\n    return baseUrl.replace(correlatorRegex, `$1correlator=${correlator}`);\n  }\n  const sep = baseUrl.includes(\"?\") ? \"&\" : \"?\";\n  return `${baseUrl}${sep}correlator=${correlator}`;\n}\n\n// src/utils/devUrl.ts\nvar PRIVATE_HOST_PATTERNS = [\n  /^localhost$/i,\n  /^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/,\n  /^0\\.0\\.0\\.0$/,\n  /^::1$/,\n  /^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/,\n  /^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/,\n  /^172\\.(1[6-9]|2\\d|3[0-1])\\.\\d{1,3}\\.\\d{1,3}$/\n];\nfunction isLocalDevHost(hostname) {\n  const host = hostname.replace(/^\\[/, \"\").replace(/\\]$/, \"\").toLowerCase();\n  if (!host) return false;\n  if (host.endsWith(\".local\") || host.endsWith(\".localhost\")) return true;\n  return PRIVATE_HOST_PATTERNS.some((pattern) => pattern.test(host));\n}\nfunction toDevSafeUrl(rawUrl) {\n  if (!rawUrl) return rawUrl ?? \"\";\n  let url;\n  try {\n    url = new URL(rawUrl);\n  } catch {\n    return rawUrl;\n  }\n  if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n    return rawUrl;\n  }\n  if (!isLocalDevHost(url.hostname)) {\n    return rawUrl;\n  }\n  const cleanPath = url.pathname.replace(/\\/{2,}/g, \"/\") || \"/index.html\";\n  return `file://${cleanPath}`;\n}\n\n// src/utils/mqttConfig.ts\nvar DEFAULT_MQTT_CONFIG = {\n  enabled: true,\n  brokerAddress: \"vecbae77.ala.us-east-1.emqxsl.com\",\n  brokerPort: 8883,\n  wsPort: 8084,\n  username: \"for-sonifi\",\n  password: \"sonifi-mqtt\",\n  topicPrefix: \"adstorm/players\",\n  qos: 1\n};\nvar mqttConfig = { ...DEFAULT_MQTT_CONFIG };\nfunction applyMQTTConfig(overrides) {\n  Object.assign(mqttConfig, overrides);\n}\nfunction isMQTTEnabled() {\n  return mqttConfig.enabled;\n}\nfunction buildMQTTBrokerUrl() {\n  if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;\n  return `wss://${mqttConfig.brokerAddress}:${mqttConfig.wsPort}/mqtt`;\n}\nfunction buildPlayerTopic(licenseKey, channel) {\n  return `${mqttConfig.topicPrefix}/${licenseKey}/${channel}`;\n}\n\n// src/utils/mqttClient.ts\nvar import_mqtt = __toESM(require(\"mqtt\"), 1);\nvar LOG = \"[StormcloudVideoPlayer][MQTT]\";\nvar KEEPALIVE_SECONDS = 30;\nvar CONNECT_TIMEOUT_MS = 1e4;\nvar RECONNECT_BASE_MS = 5e3;\nvar RECONNECT_MAX_MS = 6e4;\nvar MAX_RECONNECT_ATTEMPTS = 8;\nvar COOLDOWN_MS = 10 * 6e4;\nvar client = null;\nvar status = \"disconnected\";\nvar reconnectAttempts = 0;\nvar reconnectTimer = null;\nvar stopped = false;\nfunction clearReconnectTimer() {\n  if (reconnectTimer) {\n    clearTimeout(reconnectTimer);\n    reconnectTimer = null;\n  }\n}\nfunction teardownClient() {\n  if (client) {\n    try {\n      client.removeAllListeners();\n      client.end(true);\n    } catch {\n    }\n    client = null;\n  }\n}\nfunction scheduleReconnect() {\n  if (stopped || !isMQTTEnabled() || reconnectTimer) return;\n  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n    console.warn(\n      `${LOG} giving up after ${reconnectAttempts} attempts; cooling down for ${COOLDOWN_MS / 6e4}m`\n    );\n    teardownClient();\n    status = \"disconnected\";\n    reconnectTimer = setTimeout(() => {\n      reconnectTimer = null;\n      reconnectAttempts = 0;\n      openConnection();\n    }, COOLDOWN_MS);\n    return;\n  }\n  const delay = Math.min(\n    RECONNECT_MAX_MS,\n    RECONNECT_BASE_MS * 2 ** reconnectAttempts\n  );\n  const jitter = Math.floor(Math.random() * 1e3);\n  reconnectAttempts += 1;\n  reconnectTimer = setTimeout(() => {\n    reconnectTimer = null;\n    openConnection();\n  }, delay + jitter);\n}\nfunction openConnection() {\n  if (stopped || !isMQTTEnabled()) return;\n  teardownClient();\n  const url = buildMQTTBrokerUrl();\n  status = \"connecting\";\n  const clientId = `stormcloud-vp-${Math.random().toString(36).slice(2, 9)}`;\n  try {\n    client = import_mqtt.default.connect(url, {\n      clientId,\n      username: mqttConfig.username,\n      password: mqttConfig.password,\n      keepalive: KEEPALIVE_SECONDS,\n      clean: true,\n      // Disable MQTT.js internal reconnect; we manage reconnection ourselves.\n      reconnectPeriod: 0,\n      connectTimeout: CONNECT_TIMEOUT_MS,\n      queueQoSZero: false,\n      reschedulePings: true,\n      // Root-cause fix for the Tizen 4.0 \"Keepalive timeout\" loop: MQTT.js's\n      // default timerVariant \"auto\" runs the keepalive interval inside a\n      // Blob-URL Web Worker (via worker-timers). On Samsung Tizen 4.0 (old\n      // WebKit) served from a file:// origin that worker can't tick reliably,\n      // so the keepalive counter trips onKeepaliveTimeout almost immediately\n      // after connect. Force the native setInterval timer instead; the main\n      // thread is free because video is decoded by the native AVPlay pipeline.\n      timerVariant: \"native\"\n    });\n  } catch (err) {\n    status = \"error\";\n    console.warn(`${LOG} connect() threw:`, err);\n    scheduleReconnect();\n    return;\n  }\n  client.on(\"connect\", () => {\n    status = \"connected\";\n    reconnectAttempts = 0;\n    clearReconnectTimer();\n    console.info(`${LOG} connected to ${url}`);\n  });\n  client.on(\"offline\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    console.warn(`${LOG} offline`);\n    scheduleReconnect();\n  });\n  client.on(\"error\", (err) => {\n    status = \"error\";\n    console.warn(`${LOG} error:`, err.message);\n    scheduleReconnect();\n  });\n  client.on(\"close\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    scheduleReconnect();\n  });\n}\nfunction initMQTTClient() {\n  if (client || !isMQTTEnabled()) return;\n  stopped = false;\n  reconnectAttempts = 0;\n  openConnection();\n}\nfunction ensureMQTTClient() {\n  if (isMQTTEnabled() && !client && !reconnectTimer) {\n    initMQTTClient();\n  }\n}\nfunction publishMQTT(topic, payload) {\n  if (!isMQTTEnabled()) {\n    return false;\n  }\n  ensureMQTTClient();\n  if (!client || !client.connected) {\n    return false;\n  }\n  try {\n    client.publish(topic, JSON.stringify(payload), { qos: mqttConfig.qos });\n    return true;\n  } catch (err) {\n    console.warn(`${LOG} publish failed on ${topic}:`, err);\n    return false;\n  }\n}\n\n// src/utils/tracking.ts\nvar cachedBrowserId = null;\nfunction buildAnalyticsContext(config) {\n  const context = {};\n  if (config.debugAdTiming) {\n    context.debugAdTiming = true;\n  }\n  if (config.isLiveStream !== void 0) {\n    context.inputStreamType = config.isLiveStream ? \"live\" : \"vod\";\n  }\n  return context;\n}\nfunction getClientInfo() {\n  const ua = navigator.userAgent;\n  const platform = navigator.platform;\n  const vendor = navigator.vendor || \"\";\n  const maxTouchPoints = navigator.maxTouchPoints || 0;\n  const memory = navigator.deviceMemory || null;\n  const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n  const screenInfo = {\n    width: screen?.width,\n    height: screen?.height,\n    availWidth: screen?.availWidth,\n    availHeight: screen?.availHeight,\n    orientation: screen?.orientation?.type || \"\",\n    pixelDepth: screen?.pixelDepth\n  };\n  let deviceType = \"desktop\";\n  let brand = \"Unknown\";\n  let os = \"Unknown\";\n  let model = \"\";\n  let isSmartTV = false;\n  let isAndroid = false;\n  let isWebView = false;\n  let isWebApp = false;\n  if (ua.includes(\"Web0S\")) {\n    brand = \"LG\";\n    os = \"webOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n    model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n  } else if (ua.includes(\"Tizen\")) {\n    brand = \"Samsung\";\n    os = \"Tizen\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n    const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n    model = tizenMatch ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim() : \"Tizen TV\";\n  } else if (ua.includes(\"Philips\")) {\n    brand = \"Philips\";\n    os = \"Saphi\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n    brand = \"Sharp\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Android\") && (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))) {\n    brand = \"Sony\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Android\") && (ua.includes(\"NetCast\") || ua.includes(\"LG\"))) {\n    brand = \"LG\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n    brand = \"Roku\";\n    os = \"Roku OS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"AppleTV\")) {\n    brand = \"Apple\";\n    os = \"tvOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  }\n  if (ua.includes(\"Android\")) {\n    isAndroid = true;\n    os = \"Android\";\n    deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n    if (ua.includes(\"Android\") && (maxTouchPoints === 0 || ua.includes(\"Google TV\") || ua.includes(\"XiaoMi\"))) {\n      deviceType = \"tv\";\n      isSmartTV = true;\n      brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n    }\n    const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n    if (androidModelMatch && androidModelMatch[1]) {\n      model = androidModelMatch[1];\n    }\n  }\n  if (/iPad|iPhone|iPod/.test(ua)) {\n    os = \"iOS\";\n    deviceType = \"mobile\";\n    brand = \"Apple\";\n    if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n      deviceType = \"tablet\";\n    }\n  }\n  if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n    if (ua.includes(\"Windows\")) {\n      os = \"Windows\";\n      deviceType = \"desktop\";\n    } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n      os = \"macOS\";\n      deviceType = \"desktop\";\n      if (maxTouchPoints > 1) deviceType = \"tablet\";\n    } else if (ua.includes(\"Linux\")) {\n      os = \"Linux\";\n      deviceType = \"desktop\";\n    }\n  }\n  if (brand === \"Unknown\") {\n    if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n    if (vendor.includes(\"Apple\")) brand = \"Apple\";\n    if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n  }\n  isWebView = /wv|WebView|Linux; U;/.test(ua);\n  if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n    isWebView = true;\n  }\n  isWebApp = window.matchMedia(\"(display-mode: standalone)\").matches || window.navigator.standalone === true || window.screen?.orientation?.angle !== void 0;\n  return {\n    brand,\n    os,\n    model: model || ua.substring(0, 50) + \"...\",\n    deviceType,\n    isSmartTV,\n    isAndroid,\n    isWebView,\n    isWebApp,\n    domain: window.location.hostname,\n    origin: window.location.origin,\n    path: window.location.pathname,\n    userAgent: ua,\n    vendor,\n    platform,\n    screen: screenInfo,\n    hardwareConcurrency,\n    deviceMemory: memory,\n    maxTouchPoints,\n    language: navigator.language,\n    languages: navigator.languages?.join(\",\") || \"\",\n    cookieEnabled: navigator.cookieEnabled,\n    doNotTrack: navigator.doNotTrack || \"\",\n    referrer: document.referrer,\n    visibilityState: document.visibilityState\n  };\n}\nasync function sha256Hex(input) {\n  if (typeof crypto !== \"undefined\" && crypto.subtle?.digest) {\n    try {\n      await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n      let encodedData;\n      if (typeof TextEncoder !== \"undefined\") {\n        encodedData = new TextEncoder().encode(input);\n      } else {\n        const utf8 = unescape(encodeURIComponent(input));\n        const buffer = new Uint8Array(utf8.length);\n        for (let i = 0; i < utf8.length; i++) {\n          buffer[i] = utf8.charCodeAt(i);\n        }\n        encodedData = buffer;\n      }\n      const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n      return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n    } catch {\n      console.warn(\n        \"[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash\"\n      );\n    }\n  }\n  let hash = 0;\n  for (let i = 0; i < input.length; i++) {\n    const char = input.charCodeAt(i);\n    hash = (hash << 5) - hash + char;\n    hash = hash & hash;\n  }\n  const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n  const timestamp = Date.now().toString(16).padStart(12, \"0\");\n  const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n  return (fallbackHash + timestamp + random).padEnd(64, \"0\");\n}\nfunction resolvePlayerIdentitySeed(clientInfo) {\n  const nativeDeviceId = resolveNativeDeviceId();\n  if (nativeDeviceId) {\n    return `device:${nativeDeviceId}`;\n  }\n  const persistedId = getOrCreateStoredUuid(PLAYER_ID_STORAGE_KEY);\n  if (persistedId) {\n    return `persisted:${persistedId}`;\n  }\n  return `fingerprint:${JSON.stringify(clientInfo)}`;\n}\nasync function getBrowserID(clientInfo) {\n  if (cachedBrowserId) {\n    return cachedBrowserId;\n  }\n  cachedBrowserId = await sha256Hex(resolvePlayerIdentitySeed(clientInfo));\n  return cachedBrowserId;\n}\nfunction canPublish(licenseKey) {\n  return Boolean(isMQTTEnabled() && licenseKey);\n}\nasync function buildPlayerMetricEvent(context = {}, flags = {}) {\n  const clientInfo = getClientInfo();\n  const debugAdTiming = !!context.debugAdTiming;\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] clientInfo: \", JSON.stringify(clientInfo, null, 2));\n  }\n  const playerId = await getBrowserID(clientInfo);\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] playerId: \", playerId);\n  }\n  const captureAt = flags.captureAt ?? (/* @__PURE__ */ new Date()).toISOString();\n  return {\n    player_id: playerId,\n    device_type: clientInfo.deviceType,\n    os: clientInfo.os.toLowerCase(),\n    ad_loaded: flags.adLoaded ?? false,\n    ad_detect: flags.adDetect ?? false,\n    capture_at: captureAt,\n    ...context.inputStreamType ? { input_stream_type: context.inputStreamType } : {}\n  };\n}\nfunction publishTracking(licenseKey, channel, body) {\n  ensureMQTTClient();\n  publishMQTT(buildPlayerTopic(licenseKey, channel), body);\n}\nasync function sendInitialTracking(licenseKey, context = {}) {\n  if (!canPublish(licenseKey)) return;\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      adLoaded: false,\n      adDetect: false\n    });\n    publishTracking(licenseKey, \"metrics\", {\n      events: [metricEvent]\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n      error\n    );\n  }\n}\nasync function sendHeartbeat(licenseKey, context = {}, flags = {}) {\n  if (!canPublish(licenseKey)) return;\n  try {\n    const heartbeatData = await buildPlayerMetricEvent(context, flags);\n    publishTracking(licenseKey, \"heartbeat\", heartbeatData);\n  } catch (error) {\n    console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n  }\n}\n\n// src/player/AdConfigManager.ts\nvar AdConfigManager = class {\n  constructor(config, video) {\n    this.vmapBreaks = [];\n    this.consumedVmapBreakIds = /* @__PURE__ */ new Set();\n    this.streamCorrelator = generateCorrelator();\n    this.viewCorrelator = generateCorrelator();\n    this.consentSignals = {};\n    this.podCounter = 0;\n    this.podAssignedByPrefetch = false;\n    this.lastHeartbeatTime = 0;\n    this.defaultPodMaxAds = 6;\n    this.defaultPodMaxDurationMs = 12e4;\n    this.config = config;\n    this.video = video;\n  }\n  get debug() {\n    return !!this.config.debugAdTiming;\n  }\n  isVmapEnabled() {\n    return !!(this.config.isVmap && this.config.vmapUrl?.trim());\n  }\n  async fetchAdConfiguration() {\n    if (this.isVmapEnabled()) {\n      await this.fetchAndParseVmap(this.config.vmapUrl);\n      if (this.debug) {\n        console.log(\"[StormcloudVideoPlayer] VMAP mode enabled\");\n      }\n      return;\n    }\n    const vastMode = this.config.vastMode || \"default\";\n    if (this.debug) {\n      console.log(\"[StormcloudVideoPlayer] VAST mode:\", vastMode);\n    }\n    if (vastMode === \"adstorm\") {\n      if (!this.config.licenseKey) {\n        if (this.debug) {\n          console.warn(\n            \"[StormcloudVideoPlayer] AdStorm mode requires a license key\"\n          );\n        }\n        return;\n      }\n      const vastEndpoint = `https://adstorm.co/api-adstorm-dev/adstorm/vast/${this.config.licenseKey}`;\n      this.apiVastTagUrl = vastEndpoint;\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Using AdStorm VAST endpoint (adstorm mode):\",\n          vastEndpoint\n        );\n      }\n      return;\n    }\n    if (this.config.vastTagUrl) {\n      this.apiVastTagUrl = normalizeVastTagUrl(this.config.vastTagUrl);\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Using custom VAST tag URL:\",\n          this.apiVastTagUrl\n        );\n      }\n      return;\n    }\n    const apiUrl = \"https://adstorm.co/api-adstorm-dev/adstorm/ads/web\";\n    if (this.debug) {\n      console.log(\n        \"[StormcloudVideoPlayer] Fetching ad configuration from:\",\n        apiUrl\n      );\n    }\n    const headers = {};\n    if (this.config.licenseKey) {\n      headers[\"Authorization\"] = `Bearer ${this.config.licenseKey}`;\n    }\n    const response = await fetch(apiUrl, { headers });\n    if (!response.ok) {\n      if (this.debug) {\n        console.warn(\n          `[StormcloudVideoPlayer] Failed to fetch ad configuration: ${response.status}`\n        );\n      }\n      return;\n    }\n    const data = await response.json();\n    this.applyMqttConfigFromResponse(data);\n    const imaPayload = data.response?.ima?.[\"publisherdesk.ima\"]?.payload;\n    if (imaPayload) {\n      let decodedPayload = imaPayload;\n      try {\n        decodedPayload = decodeURIComponent(imaPayload);\n      } catch {\n        console.warn(\"[StormcloudVideoPlayer] imaPayload was not URI-encoded; using as-is:\", imaPayload);\n      }\n      console.log(\"[StormcloudVideoPlayer] Raw VAST tag URL (from API):\", decodedPayload);\n      this.apiVastTagUrl = normalizeVastTagUrl(decodedPayload);\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Normalized VAST tag URL:\",\n          this.apiVastTagUrl\n        );\n      }\n    } else {\n      if (this.debug) {\n        console.warn(\n          \"[StormcloudVideoPlayer] No VAST tag URL found in /ads/web response\"\n        );\n      }\n    }\n    const numberAds = data.response?.options?.vast?.cue_tones?.number_ads;\n    if (numberAds != null && numberAds > 0) {\n      this.apiNumberAds = numberAds;\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Number of ads per break from API:\",\n          this.apiNumberAds\n        );\n      }\n    }\n  }\n  applyMqttConfigFromResponse(data) {\n    const mqttConfig2 = data.response?.mqtt_config;\n    if (!mqttConfig2 || typeof mqttConfig2 !== \"object\") {\n      return;\n    }\n    applyMQTTConfig(mqttConfig2);\n    if (this.debug) {\n      console.log(\n        \"[StormcloudVideoPlayer] Applied MQTT config from /ads/web:\",\n        mqttConfig2\n      );\n    }\n  }\n  async fetchAndParseVmap(vmapUrl) {\n    if (!vmapUrl.trim()) {\n      return;\n    }\n    try {\n      const response = await fetch(vmapUrl);\n      if (!response.ok) {\n        throw new Error(`Failed to fetch VMAP (${response.status})`);\n      }\n      const vmapXml = await response.text();\n      this.vmapBreaks = this.parseVmapToBreaks(vmapXml);\n      this.consumedVmapBreakIds.clear();\n      if (this.debug) {\n        console.log(\n          `[StormcloudVideoPlayer] Loaded ${this.vmapBreaks.length} VMAP ad break(s) from:`,\n          vmapUrl\n        );\n      }\n    } catch (error) {\n      this.vmapBreaks = [];\n      this.consumedVmapBreakIds.clear();\n      if (this.debug) {\n        console.warn(\"[StormcloudVideoPlayer] Failed to load VMAP:\", error);\n      }\n    }\n  }\n  parseVmapToBreaks(vmapXml) {\n    if (typeof DOMParser === \"undefined\") {\n      return [];\n    }\n    const doc = new DOMParser().parseFromString(vmapXml, \"application/xml\");\n    if (doc.querySelector(\"parsererror\")) {\n      if (this.debug) {\n        console.warn(\"[StormcloudVideoPlayer] Invalid VMAP XML received\");\n      }\n      return [];\n    }\n    const VMAP_NS = \"http://www.iab.net/videosuite/vmap\";\n    let adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, \"AdBreak\"));\n    if (adBreakNodes.length === 0) {\n      adBreakNodes = Array.from(\n        doc.querySelectorAll(\"AdBreak, vmap\\\\:AdBreak\")\n      );\n    }\n    if (adBreakNodes.length === 0) {\n      adBreakNodes = Array.from(doc.getElementsByTagName(\"*\")).filter(\n        (el) => el.localName === \"AdBreak\"\n      );\n    }\n    const parsed = [];\n    adBreakNodes.forEach((node, index) => {\n      const timeOffsetRaw = (node.getAttribute(\"timeOffset\") || \"\").trim();\n      const startTimeMs = this.parseVmapTimeOffsetToMs(timeOffsetRaw);\n      if (startTimeMs == null) {\n        return;\n      }\n      let adTagNode = node.getElementsByTagNameNS(VMAP_NS, \"AdTagURI\")[0];\n      if (!adTagNode) {\n        adTagNode = node.querySelector(\"AdTagURI, vmap\\\\:AdTagURI\") ?? void 0;\n      }\n      const adTagUrl = (adTagNode?.textContent || \"\").trim();\n      if (!adTagUrl) {\n        return;\n      }\n      const breakId = node.getAttribute(\"breakId\") || `vmap-break-${index}-${timeOffsetRaw || \"unknown\"}`;\n      parsed.push({\n        id: breakId,\n        startTimeMs,\n        vastTagUrl: adTagUrl\n      });\n    });\n    parsed.sort((a, b) => {\n      const aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;\n      const bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;\n      return aStart - bStart;\n    });\n    return parsed;\n  }\n  parseVmapTimeOffsetToMs(timeOffset) {\n    if (!timeOffset) {\n      return void 0;\n    }\n    const normalized = timeOffset.trim().toLowerCase();\n    if (normalized === \"start\") {\n      return 0;\n    }\n    if (normalized === \"end\") {\n      return -1;\n    }\n    const hms = timeOffset.match(\n      /^(\\d{1,2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,3}))?$/\n    );\n    if (hms) {\n      const [, hh, mm, ss, ms = \"0\"] = hms;\n      const hours = Number(hh);\n      const minutes = Number(mm);\n      const seconds = Number(ss);\n      const millis = Number(ms.padEnd(3, \"0\").slice(0, 3));\n      return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;\n    }\n    const percent = timeOffset.match(/^(\\d+(?:\\.\\d+)?)%$/);\n    if (percent) {\n      const ratio = Number(percent[1]) / 100;\n      const durationSec = this.video.duration;\n      if (Number.isFinite(durationSec) && durationSec > 0) {\n        return Math.floor(durationSec * 1e3 * ratio);\n      }\n      return void 0;\n    }\n    return void 0;\n  }\n  getAdBreakKey(adBreak) {\n    if (adBreak.id) {\n      return adBreak.id;\n    }\n    return `${adBreak.startTimeMs}-${adBreak.vastTagUrl || \"\"}`;\n  }\n  resolveBreakStartMs(adBreak) {\n    if (adBreak.startTimeMs >= 0) {\n      return adBreak.startTimeMs;\n    }\n    if (adBreak.startTimeMs === -1) {\n      const durationSec = this.video.duration;\n      if (Number.isFinite(durationSec) && durationSec > 0) {\n        return Math.floor(durationSec * 1e3);\n      }\n    }\n    return void 0;\n  }\n  findCurrentOrNextBreak(nowMs) {\n    const schedule = this.vmapBreaks;\n    let candidate;\n    const tol = this.config.driftToleranceMs ?? 1e3;\n    for (const b of schedule) {\n      if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {\n        continue;\n      }\n      const breakStartMs = this.resolveBreakStartMs(b);\n      if (breakStartMs == null) {\n        continue;\n      }\n      if (breakStartMs <= nowMs + tol && (candidate == null || breakStartMs > (this.resolveBreakStartMs(candidate) ?? 0))) {\n        candidate = b;\n      }\n    }\n    return candidate;\n  }\n  findBreakForTime(nowMs) {\n    const schedule = this.vmapBreaks;\n    for (const b of schedule) {\n      if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {\n        continue;\n      }\n      const breakStartMs = this.resolveBreakStartMs(b);\n      if (breakStartMs == null) {\n        continue;\n      }\n      if (b.durationMs) {\n        const end = breakStartMs + b.durationMs;\n        if (nowMs >= breakStartMs && nowMs < end) {\n          return b;\n        }\n        continue;\n      }\n      if (nowMs >= breakStartMs) {\n        return b;\n      }\n    }\n    return void 0;\n  }\n  selectVastTagsForBreak(b) {\n    if (!b || !b.vastTagUrl) return void 0;\n    if (b.vastTagUrl.includes(\",\")) {\n      return b.vastTagUrl.split(\",\").map((s) => s.trim()).filter((s) => s.length > 0);\n    }\n    return [b.vastTagUrl];\n  }\n  beginNewAdPod() {\n    this.podCounter++;\n  }\n  resolvePodParams(breakDurationMs) {\n    const maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs != null && this.config.podMaxDurationMs > 0 ? this.config.podMaxDurationMs : this.defaultPodMaxDurationMs;\n    const maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;\n    const minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;\n    return { maxAds, minDurationMs, maxDurationMs };\n  }\n  generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {\n    const adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;\n    const envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);\n    const urlWithMacros = applyVastMacros(baseUrl, {\n      correlator: this.viewCorrelator,\n      streamCorrelator: this.streamCorrelator,\n      pod: this.podCounter > 0 ? this.podCounter : void 0,\n      podMaxAds: podParams.maxAds,\n      podMinDurationMs: podParams.minDurationMs,\n      podMaxDurationMs: podParams.maxDurationMs,\n      isCtv: envSignals.isCtv,\n      contentUrl: envSignals.contentUrl,\n      pageUrl: !envSignals.isCtv && typeof window !== \"undefined\" ? toDevSafeUrl(window.location.href) : void 0,\n      adWillPlayMuted,\n      adWillAutoPlay: !!this.config.autoplay,\n      appId: envSignals.appId,\n      appName: envSignals.appName,\n      sessionId: envSignals.sessionId,\n      deviceId: envSignals.deviceId,\n      deviceIdType: envSignals.deviceIdType,\n      limitAdTracking: envSignals.limitAdTracking,\n      deviceTypeHint: envSignals.deviceTypeHint,\n      adTest: this.config.adTest,\n      consent: this.consentSignals\n    });\n    const finalUrl = palNonce.injectNonce(urlWithMacros);\n    console.log(\n      `[StormcloudVideoPlayer] Resolved optimized-pod request URL (pod=${this.podCounter}, pmad=${podParams.maxAds}, pmnd=${podParams.minDurationMs}, pmxd=${podParams.maxDurationMs ?? \"?\"}):`,\n      finalUrl\n    );\n    return finalUrl;\n  }\n  // --- Tracking ---\n  initializeTracking() {\n    sendInitialTracking(this.config.licenseKey, buildAnalyticsContext(this.config)).then(() => {\n      this.heartbeatInterval = window.setInterval(() => {\n        this.sendHeartbeatIfNeeded();\n      }, 5e3);\n    }).catch((error) => {\n      if (this.debug) {\n        console.warn(\n          \"[StormcloudVideoPlayer] Failed to send initial tracking:\",\n          error\n        );\n      }\n      this.heartbeatInterval = window.setInterval(() => {\n        this.sendHeartbeatIfNeeded();\n      }, 5e3);\n    });\n  }\n  sendHeartbeatIfNeeded() {\n    const now = Date.now();\n    if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 3e4) {\n      this.lastHeartbeatTime = now;\n      sendHeartbeat(this.config.licenseKey, buildAnalyticsContext(this.config)).catch((error) => {\n        if (this.debug) {\n          console.warn(\n            \"[StormcloudVideoPlayer] Failed to send heartbeat:\",\n            error\n          );\n        }\n      });\n    }\n  }\n  destroyTracking() {\n    if (this.heartbeatInterval) {\n      clearInterval(this.heartbeatInterval);\n      this.heartbeatInterval = void 0;\n    }\n  }\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n  AdConfigManager\n});\n","import type {\n  StormcloudVideoPlayerConfig,\n  AdBreak,\n  StormcloudApiResponse,\n  AdController,\n} from \"../types\";\nimport type { PalNonceManager } from \"../sdk/pal\";\nimport { applyVastMacros, generateCorrelator, normalizeVastTagUrl } from \"../utils/vastMacros\";\nimport type { VastConsentSignals } from \"../utils/vastMacros\";\nimport { resolveVastEnvironmentSignals } from \"../utils/vastEnvironmentSignals\";\nimport { toDevSafeUrl } from \"../utils/devUrl\";\nimport {\n  buildAnalyticsContext,\n  sendHeartbeat,\n  sendInitialTracking,\n} from \"../utils/tracking\";\nimport { applyMQTTConfig } from \"../utils/mqttConfig\";\n\nexport class AdConfigManager {\n  vmapBreaks: AdBreak[] = [];\n  consumedVmapBreakIds: Set<string> = new Set();\n  apiVastTagUrl: string | undefined;\n  apiNumberAds: number | undefined;\n  readonly streamCorrelator: string = generateCorrelator();\n  readonly viewCorrelator: string = generateCorrelator();\n  consentSignals: VastConsentSignals = {};\n  podCounter: number = 0;\n  podAssignedByPrefetch: boolean = false;\n\n  private lastHeartbeatTime: number = 0;\n  private heartbeatInterval: number | undefined;\n\n  private config: StormcloudVideoPlayerConfig;\n  private video: HTMLVideoElement;\n\n  constructor(config: StormcloudVideoPlayerConfig, video: HTMLVideoElement) {\n    this.config = config;\n    this.video = video;\n  }\n\n  get debug(): boolean {\n    return !!this.config.debugAdTiming;\n  }\n\n  isVmapEnabled(): boolean {\n    return !!(this.config.isVmap && this.config.vmapUrl?.trim());\n  }\n\n  async fetchAdConfiguration(): Promise<void> {\n    if (this.isVmapEnabled()) {\n      await this.fetchAndParseVmap(this.config.vmapUrl!);\n      if (this.debug) {\n        console.log(\"[StormcloudVideoPlayer] VMAP mode enabled\");\n      }\n      return;\n    }\n\n    const vastMode = this.config.vastMode || \"default\";\n\n    if (this.debug) {\n      console.log(\"[StormcloudVideoPlayer] VAST mode:\", vastMode);\n    }\n\n    if (vastMode === \"adstorm\") {\n      if (!this.config.licenseKey) {\n        if (this.debug) {\n          console.warn(\n            \"[StormcloudVideoPlayer] AdStorm mode requires a license key\"\n          );\n        }\n        return;\n      }\n\n      const vastEndpoint = `https://adstorm.co/api-adstorm-dev/adstorm/vast/${this.config.licenseKey}`;\n      this.apiVastTagUrl = vastEndpoint;\n\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Using AdStorm VAST endpoint (adstorm mode):\",\n          vastEndpoint\n        );\n      }\n      return;\n    }\n\n    if (this.config.vastTagUrl) {\n      this.apiVastTagUrl = normalizeVastTagUrl(this.config.vastTagUrl);\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Using custom VAST tag URL:\",\n          this.apiVastTagUrl\n        );\n      }\n      return;\n    }\n\n    const apiUrl = \"https://adstorm.co/api-adstorm-dev/adstorm/ads/web\";\n\n    if (this.debug) {\n      console.log(\n        \"[StormcloudVideoPlayer] Fetching ad configuration from:\",\n        apiUrl\n      );\n    }\n\n    const headers: Record<string, string> = {};\n    if (this.config.licenseKey) {\n      headers[\"Authorization\"] = `Bearer ${this.config.licenseKey}`;\n    }\n\n    const response = await fetch(apiUrl, { headers });\n    if (!response.ok) {\n      if (this.debug) {\n        console.warn(\n          `[StormcloudVideoPlayer] Failed to fetch ad configuration: ${response.status}`\n        );\n      }\n      return;\n    }\n\n    const data: StormcloudApiResponse = await response.json();\n\n    this.applyMqttConfigFromResponse(data);\n\n    const imaPayload = data.response?.ima?.[\"publisherdesk.ima\"]?.payload;\n    if (imaPayload) {\n      let decodedPayload = imaPayload;\n      try {\n        decodedPayload = decodeURIComponent(imaPayload);\n      } catch {\n        console.warn(\"[StormcloudVideoPlayer] imaPayload was not URI-encoded; using as-is:\", imaPayload);\n      }\n      console.log(\"[StormcloudVideoPlayer] Raw VAST tag URL (from API):\", decodedPayload);\n      this.apiVastTagUrl = normalizeVastTagUrl(decodedPayload);\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Normalized VAST tag URL:\",\n          this.apiVastTagUrl\n        );\n      }\n    } else {\n      if (this.debug) {\n        console.warn(\n          \"[StormcloudVideoPlayer] No VAST tag URL found in /ads/web response\"\n        );\n      }\n    }\n\n    const numberAds = data.response?.options?.vast?.cue_tones?.number_ads;\n    if (numberAds != null && numberAds > 0) {\n      this.apiNumberAds = numberAds;\n      if (this.debug) {\n        console.log(\n          \"[StormcloudVideoPlayer] Number of ads per break from API:\",\n          this.apiNumberAds\n        );\n      }\n    }\n  }\n\n  private applyMqttConfigFromResponse(data: StormcloudApiResponse): void {\n    const mqttConfig = data.response?.mqtt_config;\n    if (!mqttConfig || typeof mqttConfig !== \"object\") {\n      return;\n    }\n\n    applyMQTTConfig(mqttConfig);\n\n    if (this.debug) {\n      console.log(\n        \"[StormcloudVideoPlayer] Applied MQTT config from /ads/web:\",\n        mqttConfig\n      );\n    }\n  }\n\n  private async fetchAndParseVmap(vmapUrl: string): Promise<void> {\n    if (!vmapUrl.trim()) {\n      return;\n    }\n\n    try {\n      const response = await fetch(vmapUrl);\n      if (!response.ok) {\n        throw new Error(`Failed to fetch VMAP (${response.status})`);\n      }\n\n      const vmapXml = await response.text();\n      this.vmapBreaks = this.parseVmapToBreaks(vmapXml);\n      this.consumedVmapBreakIds.clear();\n\n      if (this.debug) {\n        console.log(\n          `[StormcloudVideoPlayer] Loaded ${this.vmapBreaks.length} VMAP ad break(s) from:`,\n          vmapUrl\n        );\n      }\n    } catch (error) {\n      this.vmapBreaks = [];\n      this.consumedVmapBreakIds.clear();\n      if (this.debug) {\n        console.warn(\"[StormcloudVideoPlayer] Failed to load VMAP:\", error);\n      }\n    }\n  }\n\n  private parseVmapToBreaks(vmapXml: string): AdBreak[] {\n    if (typeof DOMParser === \"undefined\") {\n      return [];\n    }\n\n    const doc = new DOMParser().parseFromString(vmapXml, \"application/xml\");\n    if (doc.querySelector(\"parsererror\")) {\n      if (this.debug) {\n        console.warn(\"[StormcloudVideoPlayer] Invalid VMAP XML received\");\n      }\n      return [];\n    }\n\n    const VMAP_NS = \"http://www.iab.net/videosuite/vmap\";\n    let adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, \"AdBreak\"));\n    if (adBreakNodes.length === 0) {\n      adBreakNodes = Array.from(\n        doc.querySelectorAll(\"AdBreak, vmap\\\\:AdBreak\")\n      );\n    }\n    if (adBreakNodes.length === 0) {\n      adBreakNodes = Array.from(doc.getElementsByTagName(\"*\")).filter(\n        (el) => el.localName === \"AdBreak\"\n      );\n    }\n    const parsed: AdBreak[] = [];\n\n    adBreakNodes.forEach((node, index) => {\n      const timeOffsetRaw = (node.getAttribute(\"timeOffset\") || \"\").trim();\n      const startTimeMs = this.parseVmapTimeOffsetToMs(timeOffsetRaw);\n      if (startTimeMs == null) {\n        return;\n      }\n\n      let adTagNode = node.getElementsByTagNameNS(VMAP_NS, \"AdTagURI\")[0];\n      if (!adTagNode) {\n        adTagNode =\n          (node.querySelector(\"AdTagURI, vmap\\\\:AdTagURI\") as Element | null) ??\n          undefined;\n      }\n      const adTagUrl = (adTagNode?.textContent || \"\").trim();\n      if (!adTagUrl) {\n        return;\n      }\n\n      const breakId =\n        node.getAttribute(\"breakId\") ||\n        `vmap-break-${index}-${timeOffsetRaw || \"unknown\"}`;\n      parsed.push({\n        id: breakId,\n        startTimeMs,\n        vastTagUrl: adTagUrl,\n      });\n    });\n\n    parsed.sort((a, b) => {\n      const aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;\n      const bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;\n      return aStart - bStart;\n    });\n\n    return parsed;\n  }\n\n  private parseVmapTimeOffsetToMs(timeOffset: string): number | undefined {\n    if (!timeOffset) {\n      return undefined;\n    }\n\n    const normalized = timeOffset.trim().toLowerCase();\n    if (normalized === \"start\") {\n      return 0;\n    }\n\n    if (normalized === \"end\") {\n      return -1;\n    }\n\n    const hms = timeOffset.match(\n      /^(\\d{1,2}):(\\d{2}):(\\d{2})(?:\\.(\\d{1,3}))?$/\n    );\n    if (hms) {\n      const [, hh, mm, ss, ms = \"0\"] = hms;\n      const hours = Number(hh);\n      const minutes = Number(mm);\n      const seconds = Number(ss);\n      const millis = Number(ms.padEnd(3, \"0\").slice(0, 3));\n      return ((hours * 3600 + minutes * 60 + seconds) * 1000) + millis;\n    }\n\n    const percent = timeOffset.match(/^(\\d+(?:\\.\\d+)?)%$/);\n    if (percent) {\n      const ratio = Number(percent[1]) / 100;\n      const durationSec = this.video.duration;\n      if (Number.isFinite(durationSec) && durationSec > 0) {\n        return Math.floor(durationSec * 1000 * ratio);\n      }\n      return undefined;\n    }\n\n    return undefined;\n  }\n\n  getAdBreakKey(adBreak: AdBreak): string {\n    if (adBreak.id) {\n      return adBreak.id;\n    }\n    return `${adBreak.startTimeMs}-${adBreak.vastTagUrl || \"\"}`;\n  }\n\n  resolveBreakStartMs(adBreak: AdBreak): number | undefined {\n    if (adBreak.startTimeMs >= 0) {\n      return adBreak.startTimeMs;\n    }\n\n    if (adBreak.startTimeMs === -1) {\n      const durationSec = this.video.duration;\n      if (Number.isFinite(durationSec) && durationSec > 0) {\n        return Math.floor(durationSec * 1000);\n      }\n    }\n\n    return undefined;\n  }\n\n  findCurrentOrNextBreak(nowMs: number): AdBreak | undefined {\n    const schedule: AdBreak[] = this.vmapBreaks;\n    let candidate: AdBreak | undefined;\n    const tol = this.config.driftToleranceMs ?? 1000;\n    for (const b of schedule) {\n      if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {\n        continue;\n      }\n      const breakStartMs = this.resolveBreakStartMs(b);\n      if (breakStartMs == null) {\n        continue;\n      }\n      if (\n        breakStartMs <= nowMs + tol &&\n        (candidate == null ||\n          breakStartMs > (this.resolveBreakStartMs(candidate) ?? 0))\n      ) {\n        candidate = b;\n      }\n    }\n    return candidate;\n  }\n\n  findBreakForTime(nowMs: number): AdBreak | undefined {\n    const schedule: AdBreak[] = this.vmapBreaks;\n    for (const b of schedule) {\n      if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {\n        continue;\n      }\n      const breakStartMs = this.resolveBreakStartMs(b);\n      if (breakStartMs == null) {\n        continue;\n      }\n\n      if (b.durationMs) {\n        const end = breakStartMs + b.durationMs;\n        if (nowMs >= breakStartMs && nowMs < end) {\n          return b;\n        }\n        continue;\n      }\n\n      if (nowMs >= breakStartMs) {\n        return b;\n      }\n    }\n    return undefined;\n  }\n\n  selectVastTagsForBreak(b?: AdBreak): string[] | undefined {\n    if (!b || !b.vastTagUrl) return undefined;\n    if (b.vastTagUrl.includes(\",\")) {\n      return b.vastTagUrl\n        .split(\",\")\n        .map((s) => s.trim())\n        .filter((s) => s.length > 0);\n    }\n    return [b.vastTagUrl];\n  }\n\n  beginNewAdPod(): void {\n    this.podCounter++;\n  }\n\n  private readonly defaultPodMaxAds: number = 6;\n  private readonly defaultPodMaxDurationMs: number = 120000;\n\n  resolvePodParams(breakDurationMs?: number): {\n    maxAds: number;\n    minDurationMs: number;\n    maxDurationMs: number;\n  } {\n    const maxDurationMs =\n      breakDurationMs != null && breakDurationMs > 0\n        ? breakDurationMs\n        : this.config.podMaxDurationMs != null && this.config.podMaxDurationMs > 0\n          ? this.config.podMaxDurationMs\n          : this.defaultPodMaxDurationMs;\n\n    const maxAds =\n      this.config.podMaxAds && this.config.podMaxAds > 0\n        ? this.config.podMaxAds\n        : this.apiNumberAds && this.apiNumberAds > 0\n          ? this.apiNumberAds\n          : this.defaultPodMaxAds;\n\n    const minDurationMs =\n      this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;\n\n    return { maxAds, minDurationMs, maxDurationMs };\n  }\n\n  generatePodVastUrl(\n    baseUrl: string,\n    podParams: { maxAds: number; minDurationMs: number; maxDurationMs: number },\n    adPlayer: AdController,\n    palNonce: PalNonceManager,\n    inAdBreak: boolean\n  ): string {\n    const adWillPlayMuted = inAdBreak\n      ? adPlayer.getOriginalMutedState()\n      : this.video.muted;\n    const envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);\n\n    const urlWithMacros = applyVastMacros(baseUrl, {\n      correlator: this.viewCorrelator,\n      streamCorrelator: this.streamCorrelator,\n      pod: this.podCounter > 0 ? this.podCounter : undefined,\n      podMaxAds: podParams.maxAds,\n      podMinDurationMs: podParams.minDurationMs,\n      podMaxDurationMs: podParams.maxDurationMs,\n      isCtv: envSignals.isCtv,\n      contentUrl: envSignals.contentUrl,\n      pageUrl:\n        !envSignals.isCtv && typeof window !== \"undefined\"\n          ? toDevSafeUrl(window.location.href)\n          : undefined,\n      adWillPlayMuted,\n      adWillAutoPlay: !!this.config.autoplay,\n      appId: envSignals.appId,\n      appName: envSignals.appName,\n      sessionId: envSignals.sessionId,\n      deviceId: envSignals.deviceId,\n      deviceIdType: envSignals.deviceIdType,\n      limitAdTracking: envSignals.limitAdTracking,\n      deviceTypeHint: envSignals.deviceTypeHint,\n      adTest: this.config.adTest,\n      consent: this.consentSignals,\n    });\n\n    const finalUrl = palNonce.injectNonce(urlWithMacros);\n    console.log(\n      `[StormcloudVideoPlayer] Resolved optimized-pod request URL (pod=${this.podCounter}, pmad=${podParams.maxAds}, pmnd=${podParams.minDurationMs}, pmxd=${podParams.maxDurationMs ?? \"?\"}):`,\n      finalUrl\n    );\n    return finalUrl;\n  }\n\n  // --- Tracking ---\n\n  initializeTracking(): void {\n    sendInitialTracking(this.config.licenseKey, buildAnalyticsContext(this.config))\n      .then(() => {\n        this.heartbeatInterval = window.setInterval(() => {\n          this.sendHeartbeatIfNeeded();\n        }, 5000);\n      })\n      .catch((error) => {\n        if (this.debug) {\n          console.warn(\n            \"[StormcloudVideoPlayer] Failed to send initial tracking:\",\n            error\n          );\n        }\n        this.heartbeatInterval = window.setInterval(() => {\n          this.sendHeartbeatIfNeeded();\n        }, 5000);\n      });\n  }\n\n  private sendHeartbeatIfNeeded(): void {\n    const now = Date.now();\n    if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 30000) {\n      this.lastHeartbeatTime = now;\n      sendHeartbeat(this.config.licenseKey, buildAnalyticsContext(this.config)).catch((error) => {\n        if (this.debug) {\n          console.warn(\n            \"[StormcloudVideoPlayer] Failed to send heartbeat:\",\n            error\n          );\n        }\n      });\n    }\n  }\n\n  destroyTracking(): void {\n    if (this.heartbeatInterval) {\n      clearInterval(this.heartbeatInterval);\n      this.heartbeatInterval = undefined;\n    }\n  }\n}\n","export interface VastEnvironmentSignals {\n  isCtv: boolean;\n  contentUrl?: string;\n  appId?: string;\n  appName?: string;\n  sessionId?: string;\n  deviceId?: string;\n  deviceIdType?: string;\n  limitAdTracking?: boolean;\n  deviceTypeHint?: number;\n}\n\nconst AIRY_ANDROID_APP_ID = \"com.freeairytv.android\";\nconst AIRY_WEBOS_APP_ID    = \"com.freeairytv.webos\";\nconst AIRY_TIZEN_APP_ID    = \"com.freeairytv.samsung\";\nconst AIRY_ROKU_APP_ID     = \"com.freeairytv.roku\";\nconst AIRY_APP_NAME = \"AiryTV Movies & TV\";\nconst AIRY_DEFAULT_CONTENT_URL = \"https://live.airy.tv\";\nconst CTV_SESSION_STORAGE_KEY = \"stormcloud.ctv.sid\";\nexport const PLAYER_ID_STORAGE_KEY = \"stormcloud.player.id\";\n\nconst LG_TEST_APP_ID      = \"com.hulu.plus\";\nconst LG_TEST_APP_NAME    = \"Hulu\";\nconst LG_TEST_CONTENT_URL = \"https://www.hulu.com/live-tv\";\n\nlet _lgTestDeviceId: string | undefined;\nfunction getLgTestDeviceId(): string {\n  if (!_lgTestDeviceId) _lgTestDeviceId = createUuid();\n  return _lgTestDeviceId;\n}\n\nfunction isLgWebOS(): boolean {\n  if (typeof navigator === \"undefined\") return false;\n  return /Web0S|webOS|LG Browser|LGSTB|LGE/i.test(navigator.userAgent);\n}\n\nfunction getDefaultAppId(): string {\n  if (typeof navigator === \"undefined\") return AIRY_ANDROID_APP_ID;\n  const ua = navigator.userAgent;\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return AIRY_WEBOS_APP_ID;\n  if (/Tizen|Samsung/i.test(ua))                       return AIRY_TIZEN_APP_ID;\n  if (/Roku/i.test(ua))                                return AIRY_ROKU_APP_ID;\n  return AIRY_ANDROID_APP_ID;\n}\n\nconst DEVICE_ID_STORAGE_KEYS = [\n  \"rdid\",\n  \"ifa\",\n  \"advertisingId\",\n  \"advertising_id\",\n  \"deviceAdvertisingId\",\n  \"aaid\",\n  \"adid\",\n  \"rida\",\n  \"tifa\",\n  \"lgudid\",\n];\n\nconst ANDROID_ID_TYPES = new Set([\"aaid\", \"adid\"]);\n\nexport function resolveVastEnvironmentSignals(isCtv: boolean): VastEnvironmentSignals {\n  const bridgeSignals  = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const lg = isCtv && isLgWebOS();\n\n  const deviceId =\n    bridgeSignals.deviceId  ||\n    readStoredDeviceId()    ||\n    platformDevice.deviceId ||\n    (lg && platformDevice.limitAdTracking !== true ? getLgTestDeviceId() : undefined);\n  const deviceIdType =\n    bridgeSignals.deviceIdType  ||\n    readStoredString(\"deviceIdType\") ||\n    readStoredString(\"idtype\") ||\n    platformDevice.deviceIdType ||\n    inferDeviceIdType() ||\n    (lg ? \"lgudid\" : undefined);\n  const platformLat = bridgeSignals.deviceId\n    ? bridgeSignals.limitAdTracking\n    : platformDevice.limitAdTracking;\n  const limitAdTracking =\n    deviceId != null\n      ? platformLat ?? readStoredLimitAdTracking() ?? false\n      : undefined;\n\n  if (isCtv) {\n    return {\n      isCtv: true,\n      contentUrl:\n        bridgeSignals.contentUrl ||\n        readStoredString(\"contentUrl\") ||\n        (lg ? LG_TEST_CONTENT_URL : AIRY_DEFAULT_CONTENT_URL),\n      appId:\n        bridgeSignals.appId ||\n        readStoredString(\"appId\") ||\n        readStoredString(\"msid\") ||\n        (lg ? LG_TEST_APP_ID : getDefaultAppId()),\n      appName:\n        bridgeSignals.appName ||\n        readStoredString(\"appName\") ||\n        readStoredString(\"an\") ||\n        (lg ? LG_TEST_APP_NAME : AIRY_APP_NAME),\n      sessionId: getOrCreateCtvSessionId(),\n      ...(deviceId ? { deviceId } : {}),\n      ...(deviceIdType ? { deviceIdType } : {}),\n      ...(limitAdTracking != null ? { limitAdTracking } : {}),\n      deviceTypeHint: 5,\n    };\n  }\n\n  return {\n    isCtv: false,\n    ...(deviceId ? { deviceId } : {}),\n    ...(deviceIdType ? { deviceIdType } : {}),\n    ...(limitAdTracking != null ? { limitAdTracking } : {}),\n  };\n}\n\nexport function inferDeviceIdType(): string | undefined {\n  if (typeof navigator === \"undefined\") {\n    return undefined;\n  }\n\n  const ua = navigator.userAgent;\n  if (/Roku/i.test(ua)) return \"rida\";\n  if (/Tizen|Samsung/i.test(ua)) return \"tifa\";\n  if (/AppleTV|Apple TV/i.test(ua)) return \"tvOS\";\n  if (/AFT|Fire TV|Amazon/i.test(ua)) return \"afai\";\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return \"lgudid\";\n  if (/Android|Google TV/i.test(ua)) return \"aaid\";\n  if (/iPhone|iPad|iPod/i.test(ua)) return \"idfa\";\n  return undefined;\n}\n\nexport function isEquivalentDeviceIdType(\n  tagType: string | undefined,\n  runtimeType: string | undefined\n): boolean {\n  if (!tagType || !runtimeType) return false;\n  const tag = tagType.toLowerCase();\n  const runtime = runtimeType.toLowerCase();\n  if (tag === runtime) return true;\n  return ANDROID_ID_TYPES.has(tag) && ANDROID_ID_TYPES.has(runtime);\n}\n\nexport function resolveNativeDeviceId(): string | undefined {\n  const bridgeSignals = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const deviceId =\n    bridgeSignals.deviceId ||\n    readStoredDeviceId() ||\n    platformDevice.deviceId;\n\n  if (!deviceId || isMacroPlaceholder(deviceId) || isZeroedAdId(deviceId)) {\n    return undefined;\n  }\n\n  return deviceId;\n}\n\nexport function getOrCreateStoredUuid(storageKey: string): string | undefined {\n  if (typeof window === \"undefined\") {\n    return undefined;\n  }\n\n  const existing = readPersistentId(storageKey);\n  if (existing) {\n    writePersistentId(storageKey, existing);\n    return existing;\n  }\n\n  const id = createUuid();\n  writePersistentId(storageKey, id);\n  return id;\n}\n\nfunction getOrCreateCtvSessionId(): string {\n  const existing = readPersistentId(CTV_SESSION_STORAGE_KEY);\n  if (existing) {\n    writePersistentId(CTV_SESSION_STORAGE_KEY, existing);\n    return existing;\n  }\n\n  const sessionId = createUuid();\n  writePersistentId(CTV_SESSION_STORAGE_KEY, sessionId);\n  return sessionId;\n}\n\nfunction readPersistentId(storageKey: string): string | undefined {\n  return readStoredString(storageKey) || readCookie(storageKey);\n}\n\nfunction writePersistentId(storageKey: string, value: string): void {\n  try {\n    window.localStorage?.setItem(storageKey, value);\n  } catch {}\n  writeCookie(storageKey, value);\n}\n\nconst PERSISTENT_ID_COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5; // ~5 years\n\nfunction readCookie(name: string): string | undefined {\n  if (typeof document === \"undefined\") {\n    return undefined;\n  }\n\n  try {\n    const prefix = encodeURIComponent(name) + \"=\";\n    const parts = document.cookie ? document.cookie.split(\";\") : [];\n    for (const part of parts) {\n      const entry = part.trim();\n      if (entry.startsWith(prefix)) {\n        return decodeURIComponent(entry.slice(prefix.length)) || undefined;\n      }\n    }\n  } catch {}\n\n  return undefined;\n}\n\nfunction writeCookie(name: string, value: string): void {\n  if (typeof document === \"undefined\") {\n    return;\n  }\n\n  try {\n    document.cookie =\n      encodeURIComponent(name) +\n      \"=\" +\n      encodeURIComponent(value) +\n      \";path=/;max-age=\" +\n      PERSISTENT_ID_COOKIE_MAX_AGE +\n      \";SameSite=Lax\";\n  } catch {}\n}\n\nfunction createUuid(): string {\n  if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n    return crypto.randomUUID();\n  }\n\n  const bytes = new Uint8Array(16);\n  if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n    crypto.getRandomValues(bytes);\n  } else {\n    let seed = Date.now() ^ Math.floor(performanceNow() * 1e3);\n    for (let i = 0; i < 16; i++) {\n      seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n      bytes[i] = (seed ^ Math.floor(Math.random() * 256)) & 0xff;\n    }\n  }\n\n  bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n  bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n\n  let hex = \"\";\n  for (let i = 0; i < 16; i++) {\n    hex += (bytes[i] ?? 0).toString(16).padStart(2, \"0\");\n  }\n\n  return (\n    hex.slice(0, 8) +\n    \"-\" +\n    hex.slice(8, 12) +\n    \"-\" +\n    hex.slice(12, 16) +\n    \"-\" +\n    hex.slice(16, 20) +\n    \"-\" +\n    hex.slice(20, 32)\n  );\n}\n\nfunction performanceNow(): number {\n  try {\n    if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n      return performance.now();\n    }\n  } catch {}\n  return 0;\n}\n\nfunction readPlatformNativeDeviceId(): {\n  deviceId?: string;\n  deviceIdType?: string;\n  limitAdTracking?: boolean;\n} {\n  if (typeof window === \"undefined\") return {};\n\n  try {\n    const adinfo = (window as any).webapis?.adinfo;\n    if (adinfo) {\n      const tifa: unknown =\n        typeof adinfo.getTIFA === \"function\" ? adinfo.getTIFA() : adinfo.tifa;\n      if (typeof tifa === \"string\" && tifa && !isMacroPlaceholder(tifa)) {\n        const lat: unknown =\n          typeof adinfo.isLATEnabled === \"function\"\n            ? adinfo.isLATEnabled()\n            : undefined;\n        return {\n          deviceId: tifa,\n          deviceIdType: \"tifa\",\n          ...(typeof lat === \"boolean\" ? { limitAdTracking: lat } : {}),\n        };\n      }\n    }\n  } catch {}\n\n  try {\n    const webOSDev = (window as any).webOSDev;\n    if (webOSDev) {\n      const lgudid: unknown =\n        typeof webOSDev.LGUDID === \"function\"\n          ? webOSDev.LGUDID()\n          : webOSDev.lgudid ?? webOSDev.LGUDID;\n      if (typeof lgudid === \"string\" && lgudid) {\n        if (isZeroedAdId(lgudid)) {\n          return { deviceIdType: \"lgudid\", limitAdTracking: true };\n        }\n        if (!isMacroPlaceholder(lgudid)) {\n          return { deviceId: lgudid, deviceIdType: \"lgudid\", limitAdTracking: false };\n        }\n      }\n    }\n  } catch {}\n\n  try {\n    const roku = (window as any).Roku;\n    if (roku) {\n      const rida: unknown =\n        typeof roku.getPublisherUniqueId === \"function\"\n          ? roku.getPublisherUniqueId()\n          : roku.rida;\n      if (typeof rida === \"string\" && rida && !isMacroPlaceholder(rida)) {\n        return { deviceId: rida, deviceIdType: \"rida\", limitAdTracking: false };\n      }\n    }\n  } catch {}\n\n  return {};\n}\n\nconst ZEROED_AD_ID_PATTERNS: ReadonlySet<string> = new Set([\n  \"38400000-8cf0-11bd-b23e-10b96e40000d\",\n  \"00000000-0000-0000-0000-000000000000\",\n]);\n\nfunction isMacroPlaceholder(value: string): boolean {\n  const t = value.trim();\n  return !t ||\n    /^(\\[[^\\]]*\\]|\\{[^}]*\\}|%%[^%]*%%)$/.test(t) ||\n    /^(unknown|null|undefined|none|n\\/a|\\$\\{[^}]+\\})$/i.test(t) ||\n    ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());\n}\n\nfunction isZeroedAdId(value: string): boolean {\n  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());\n}\n\nfunction readNativeBridgeSignals(): {\n  contentUrl?: string;\n  appId?: string;\n  appName?: string;\n  deviceId?: string;\n  deviceIdType?: string;\n  limitAdTracking?: boolean;\n} {\n  if (typeof window === \"undefined\") {\n    return {};\n  }\n\n  const candidates = [\n    (window as any).__STORMCLOUD_CTV_AD_INFO__,\n    (window as any).__STORMCLOUD_CTV__,\n    (window as any).stormcloudCtv,\n    (window as any).AiryTV,\n    (window as any).Android,\n    (window as any).webOS,\n    (window as any).tizen,\n    (window as any).amazon,\n  ].filter(Boolean);\n\n  for (const source of candidates) {\n    const contentUrl =\n      readBridgeValue(source, [\"contentUrl\", \"url\", \"videoUrl\", \"canonicalUrl\"]) ||\n      undefined;\n    const appId =\n      readBridgeValue(source, [\"appId\", \"msid\", \"applicationId\", \"packageName\"]) ||\n      undefined;\n    const appName =\n      readBridgeValue(source, [\"appName\", \"an\", \"applicationName\"]) || undefined;\n    const deviceId =\n      readBridgeValue(source, [\n        \"rdid\",\n        \"ifa\",\n        \"advertisingId\",\n        \"adId\",\n        \"deviceId\",\n        \"lgudid\",\n        \"LGUDID\",\n        \"tifa\",\n        \"rida\",\n        \"afai\",\n        \"aaid\",\n      ]) || undefined;\n\n    if (!contentUrl && !deviceId && !appId && !appName) continue;\n\n    const deviceIdType =\n      readBridgeValue(source, [\n        \"idtype\",\n        \"deviceIdType\",\n        \"advertisingIdType\",\n        \"idType\",\n      ]) || inferDeviceIdType();\n    const limitAdTracking = readBridgeBoolean(source, [\n      \"is_lat\",\n      \"limitAdTracking\",\n      \"limitedAdTracking\",\n      \"lat\",\n    ]);\n\n    return {\n      ...(contentUrl ? { contentUrl } : {}),\n      ...(appId ? { appId } : {}),\n      ...(appName ? { appName } : {}),\n      ...(deviceId ? { deviceId } : {}),\n      ...(deviceId && deviceIdType ? { deviceIdType } : {}),\n      ...(deviceId && limitAdTracking != null ? { limitAdTracking } : {}),\n    };\n  }\n\n  return {};\n}\n\nfunction readBridgeValue(source: any, keys: string[]): string | undefined {\n  for (const key of keys) {\n    const value = source?.[key];\n    if (typeof value === \"string\" && value) {\n      return value;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = value.call(source);\n        if (typeof result === \"string\" && result) {\n          return result;\n        }\n      } catch {}\n    }\n  }\n  return undefined;\n}\n\nfunction readBridgeBoolean(source: any, keys: string[]): boolean | undefined {\n  for (const key of keys) {\n    const value = source?.[key];\n    const normalized = normalizeBoolean(value);\n    if (normalized != null) {\n      return normalized;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = normalizeBoolean(value.call(source));\n        if (result != null) {\n          return result;\n        }\n      } catch {}\n    }\n  }\n  return undefined;\n}\n\nfunction readStoredDeviceId(): string | undefined {\n  for (const key of DEVICE_ID_STORAGE_KEYS) {\n    const value = readStoredString(key);\n    if (value) {\n      return value;\n    }\n  }\n  return undefined;\n}\n\nfunction readStoredString(key: string): string | undefined {\n  if (typeof window === \"undefined\") {\n    return undefined;\n  }\n\n  try {\n    const value = window.localStorage?.getItem(key);\n    return value || undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction readStoredLimitAdTracking(): boolean | undefined {\n  return normalizeBoolean(\n    readStoredString(\"limitAdTracking\") ||\n      readStoredString(\"limitedAdTracking\") ||\n      readStoredString(\"is_lat\")\n  );\n}\n\nfunction normalizeBoolean(value: unknown): boolean | undefined {\n  if (typeof value === \"boolean\") {\n    return value;\n  }\n  if (typeof value === \"number\") {\n    return value === 1;\n  }\n  if (typeof value === \"string\") {\n    const normalized = value.toLowerCase();\n    if (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\") {\n      return true;\n    }\n    if (normalized === \"0\" || normalized === \"false\" || normalized === \"no\") {\n      return false;\n    }\n  }\n  return undefined;\n}\n","import {\n  inferDeviceIdType,\n  isEquivalentDeviceIdType,\n} from \"./vastEnvironmentSignals\";\n\nexport interface VastConsentSignals {\n  gdpr?: string | undefined;\n  gdprConsent?: string | undefined;\n  usPrivacy?: string | undefined;\n}\n\nexport interface VastMacroContext {\n  correlator: string;\n  streamCorrelator: string;\n  pod?: number | undefined;\n  podMaxAds?: number | undefined;\n  podMinDurationMs?: number | undefined;\n  podMaxDurationMs?: number | undefined;\n  isCtv?: boolean | undefined;\n  contentUrl?: string | undefined;\n  pageUrl?: string | undefined;\n  adWillPlayMuted?: boolean | undefined;\n  adWillAutoPlay?: boolean | undefined;\n  appId?: string | undefined;\n  appName?: string | undefined;\n  sessionId?: string | undefined;\n  deviceId?: string | undefined;\n  deviceIdType?: string | undefined;\n  limitAdTracking?: boolean | undefined;\n  deviceTypeHint?: number | undefined;\n  adTest?: boolean | undefined;\n  consent?: VastConsentSignals | undefined;\n}\n\nconst UNEXPANDED_MACRO_PATTERN = /^(\\[[^\\]]*\\]|\\{[^}]*\\}|%%[^%]*%%)$/;\nconst INVALID_VAST_PARAM_KEY = /^\\s|\\s$/;\nconst EXAMPLE_COM_URL = /example\\.com/i;\nconst CTV_UNSUPPORTED_PARAMS = [\n  \"description_url\",\n  \"tfcd\",\n  \"npa\",\n  \"min_ad_duration\",\n  \"max_ad_duration\",\n  \"unviewed_position_start\",\n  \"impl\",\n  \"vad_type\",\n  \"gdpr\",\n  \"gdpr_consent\",\n  \"us_privacy\",\n];\n\nconst INLINE_DEVICE_MACRO_REPLACEMENTS: Array<{\n  pattern: RegExp;\n  getValue: (ctx: VastMacroContext) => string | undefined;\n}> = [\n  { pattern: /\\[RDID\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[IFA\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[ADVERTISING[_-]?ID(?:ENTIFIER)?\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[DEVICE[_-]?ID\\]/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\[IDTYPE\\]/gi, getValue: (ctx) => ctx.deviceIdType },\n  { pattern: /\\{rdid\\}/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\{device[_-]?id\\}/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /\\{idtype\\}/gi, getValue: (ctx) => ctx.deviceIdType },\n  { pattern: /%%ADVERTISING_IDENTIFIER_PLAIN%%/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /%%ADVERTISING_ID_OPT_OUT%%/gi, getValue: (ctx) =>\n      ctx.limitAdTracking != null ? (ctx.limitAdTracking ? \"1\" : \"0\") : undefined },\n  { pattern: /%%ADVERTISING_ID_TYPE%%/gi, getValue: (ctx) => ctx.deviceIdType },\n  { pattern: /%%ADVERTISING_ID%%/gi, getValue: (ctx) => ctx.deviceId },\n  { pattern: /%%LIMIT_AD_TRACKING%%/gi, getValue: (ctx) =>\n      ctx.limitAdTracking != null ? (ctx.limitAdTracking ? \"1\" : \"0\") : undefined },\n  { pattern: /%%MSID%%/gi, getValue: (ctx) => ctx.appId },\n  { pattern: /%%APP_NAME%%/gi, getValue: (ctx) => ctx.appName },\n  { pattern: /%%SESSION_ID%%/gi, getValue: (ctx) => ctx.sessionId },\n  { pattern: /%%CORRELATOR%%/gi, getValue: (ctx) => ctx.correlator },\n];\n\nexport function isMacroPlaceholder(value: string | null | undefined): boolean {\n  if (value == null) return true;\n  const trimmed = value.trim();\n  if (!trimmed) return true;\n  if (UNEXPANDED_MACRO_PATTERN.test(trimmed)) return true;\n  return /^(unknown|null|undefined|none|n\\/a|\\$\\{[^}]+\\})$/i.test(trimmed);\n}\n\nexport function generateCorrelator(): string {\n  if (typeof crypto !== \"undefined\" && crypto.getRandomValues) {\n    try {\n      const buf = new Uint32Array(2);\n      crypto.getRandomValues(buf);\n      const value = (buf[0] ?? 0) * 0x200000 + ((buf[1] ?? 0) & 0x1fffff);\n      if (value > 0) {\n        return String(value);\n      }\n    } catch {\n    }\n  }\n  return String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1);\n}\n\nfunction expandInlineMacroPlaceholders(baseUrl: string, ctx: VastMacroContext): string {\n  let url = baseUrl;\n  for (const { pattern, getValue } of INLINE_DEVICE_MACRO_REPLACEMENTS) {\n    const value = getValue(ctx);\n    if (value != null && value !== \"\") {\n      url = url.replace(pattern, encodeURIComponent(value));\n    }\n  }\n  return url;\n}\n\nfunction applyDeviceIdentityParams(\n  params: URLSearchParams,\n  ctx: VastMacroContext\n): void {\n  const runtimeId = ctx.deviceId?.trim();\n  const runtimeType = ctx.deviceIdType?.trim() || inferDeviceIdType();\n  const tagRdid = params.get(\"rdid\");\n  const tagType = params.get(\"idtype\");\n  const tagLat = params.get(\"is_lat\");\n  const latValue =\n    ctx.limitAdTracking != null ? (ctx.limitAdTracking ? \"1\" : \"0\") : undefined;\n\n  if (runtimeId) {\n    params.set(\"rdid\", runtimeId);\n    params.set(\"idtype\", runtimeType || tagType || \"aaid\");\n    params.set(\"is_lat\", latValue ?? (isMacroPlaceholder(tagLat) ? \"0\" : tagLat!));\n    return;\n  }\n\n  const tagRdidValid = Boolean(tagRdid && !isMacroPlaceholder(tagRdid));\n  const tagTypeValid = Boolean(tagType && !isMacroPlaceholder(tagType));\n\n  if (\n    tagRdidValid &&\n    tagTypeValid &&\n    runtimeType &&\n    !isEquivalentDeviceIdType(tagType!, runtimeType)\n  ) {\n    params.delete(\"rdid\");\n    params.delete(\"idtype\");\n    params.delete(\"is_lat\");\n    return;\n  }\n\n  if (tagRdidValid) {\n    if (isMacroPlaceholder(tagType) && runtimeType) {\n      params.set(\"idtype\", runtimeType);\n    }\n    if (isMacroPlaceholder(tagLat)) {\n      params.set(\"is_lat\", latValue ?? \"0\");\n    }\n    return;\n  }\n\n  params.delete(\"rdid\");\n  params.delete(\"idtype\");\n  params.delete(\"is_lat\");\n}\n\nfunction removeBrokenAppNameOrphans(\n  params: URLSearchParams,\n  appName?: string\n): void {\n  const toDelete: string[] = [];\n\n  params.forEach((_value, key) => {\n    if (!key || INVALID_VAST_PARAM_KEY.test(key)) {\n      toDelete.push(key);\n    }\n  });\n\n  if (appName && appName.includes(\"&\")) {\n    for (const suffix of appName.split(\"&\").slice(1)) {\n      const trimmed = suffix.replace(/^\\s+/, \"\");\n      if (!trimmed) continue;\n      toDelete.push(suffix, ` ${trimmed}`, trimmed);\n    }\n  }\n\n  for (const key of new Set(toDelete)) {\n    if (key) params.delete(key);\n  }\n}\n\nexport function normalizeVastTagUrl(raw: string): string {\n  if (!raw) return raw;\n\n  try {\n    const url = new URL(raw);\n\n    const anValue = url.searchParams.get(\"an\");\n    if (anValue !== null) {\n      const orphanFragments: string[] = [];\n      url.searchParams.forEach((_value, key) => {\n        if (key && INVALID_VAST_PARAM_KEY.test(key)) {\n          orphanFragments.push(key.trim());\n        }\n      });\n      if (orphanFragments.length > 0) {\n        const reconstructed = [anValue.replace(/\\s+$/, \"\"), ...orphanFragments]\n          .filter(Boolean)\n          .join(\" & \");\n\n        url.searchParams.forEach((_value, key) => {\n          if (key && INVALID_VAST_PARAM_KEY.test(key)) {\n            url.searchParams.delete(key);\n          }\n        });\n        url.searchParams.set(\"an\", reconstructed);\n\n        return url.toString().replace(\n          /([?&]an=)([^&]*)/,\n          (_match, prefix, val) => prefix + val.replace(/\\+/g, \"%20\")\n        );\n      }\n    }\n\n    removeBrokenAppNameOrphans(url.searchParams);\n    return url.toString();\n  } catch {\n    return raw;\n  }\n}\n\nexport function applyVastMacros(\n  baseUrl: string,\n  ctx: VastMacroContext\n): string {\n  const expandedUrl = expandInlineMacroPlaceholders(baseUrl, ctx);\n  let url: URL;\n  try {\n    url = new URL(normalizeVastTagUrl(expandedUrl));\n  } catch {\n    return replaceCorrelatorFallback(expandedUrl, ctx.correlator);\n  }\n\n  const params = url.searchParams;\n\n  removeBrokenAppNameOrphans(params, ctx.appName);\n\n  params.set(\"correlator\", ctx.correlator);\n  params.set(\"scor\", ctx.streamCorrelator);\n  if (ctx.isCtv) {\n    for (const key of CTV_UNSUPPORTED_PARAMS) {\n      params.delete(key);\n    }\n  }\n\n  if (ctx.pod != null) {\n    params.set(\"pod\", String(ctx.pod));\n  }\n\n  params.delete(\"ppos\");\n  params.delete(\"lip\");\n  if (ctx.podMinDurationMs != null) {\n    params.set(\"pmnd\", String(Math.max(0, Math.round(ctx.podMinDurationMs))));\n  }\n  if (ctx.podMaxDurationMs != null) {\n    params.set(\"pmxd\", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));\n  }\n  if (ctx.podMaxAds != null) {\n    params.set(\"pmad\", String(Math.max(1, Math.round(ctx.podMaxAds))));\n  }\n\n  const requestUrl = ctx.contentUrl || ctx.pageUrl;\n  if (requestUrl) {\n    params.set(\"url\", requestUrl);\n    if (!ctx.isCtv) {\n      params.set(\"description_url\", requestUrl);\n    }\n  } else {\n    const existingUrl = params.get(\"url\") || \"\";\n    if (EXAMPLE_COM_URL.test(existingUrl)) {\n      params.delete(\"url\");\n      params.delete(\"description_url\");\n    }\n  }\n\n  if (ctx.adWillPlayMuted != null) {\n    params.set(\"vpmute\", ctx.adWillPlayMuted ? \"1\" : \"0\");\n  }\n  if (ctx.adWillAutoPlay != null) {\n    params.set(\"vpa\", ctx.adWillAutoPlay ? \"auto\" : \"click\");\n  }\n\n  if (ctx.appId) {\n    params.set(\"msid\", ctx.appId);\n  }\n  if (ctx.appName) {\n    removeBrokenAppNameOrphans(params, ctx.appName);\n    params.set(\"an\", ctx.appName);\n  }\n  if (ctx.sessionId) {\n    params.set(\"sid\", ctx.sessionId);\n  }\n  if (ctx.deviceTypeHint != null) {\n    params.set(\"dth\", String(ctx.deviceTypeHint));\n  } else if (ctx.isCtv) {\n    params.set(\"dth\", \"5\");\n  }\n\n  applyDeviceIdentityParams(params, ctx);\n\n  if (!ctx.isCtv) {\n    const consent = ctx.consent;\n    if (consent?.gdpr != null) {\n      params.set(\"gdpr\", consent.gdpr);\n    }\n    if (consent?.gdprConsent != null) {\n      params.set(\"gdpr_consent\", consent.gdprConsent);\n    }\n    if (consent?.usPrivacy != null) {\n      params.set(\"us_privacy\", consent.usPrivacy);\n    }\n  }\n\n  if (ctx.adTest) {\n    params.set(\"adtest\", \"on\");\n  }\n\n  const staleKeys: string[] = [];\n  params.forEach((value, key) => {\n    if (isMacroPlaceholder(value)) {\n      staleKeys.push(key);\n    }\n  });\n  for (const key of staleKeys) {\n    params.delete(key);\n  }\n\n  removeBrokenAppNameOrphans(params, ctx.appName);\n\n  return url.toString();\n}\n\nfunction replaceCorrelatorFallback(baseUrl: string, correlator: string): string {\n  const correlatorRegex = /([?&])correlator=([^&]*)/;\n  if (correlatorRegex.test(baseUrl)) {\n    return baseUrl.replace(correlatorRegex, `$1correlator=${correlator}`);\n  }\n  const sep = baseUrl.includes(\"?\") ? \"&\" : \"?\";\n  return `${baseUrl}${sep}correlator=${correlator}`;\n}\n\nexport function fetchConsentSignals(\n  timeoutMs: number = 1500\n): Promise<VastConsentSignals> {\n  const signals: VastConsentSignals = {};\n  if (typeof window === \"undefined\") {\n    return Promise.resolve(signals);\n  }\n\n  const tasks: Promise<void>[] = [];\n\n  const tcfApi = (window as any).__tcfapi;\n  if (typeof tcfApi === \"function\") {\n    tasks.push(\n      new Promise<void>((resolve) => {\n        let settled = false;\n        try {\n          tcfApi(\"addEventListener\", 2, (tcData: any, success: boolean) => {\n            if (settled) return;\n            if (\n              success &&\n              tcData &&\n              (tcData.eventStatus === \"tcloaded\" ||\n                tcData.eventStatus === \"useractioncomplete\")\n            ) {\n              settled = true;\n              signals.gdpr = tcData.gdprApplies ? \"1\" : \"0\";\n              if (typeof tcData.tcString === \"string\" && tcData.tcString) {\n                signals.gdprConsent = tcData.tcString;\n              }\n              try {\n                tcfApi(\"removeEventListener\", 2, () => {}, tcData.listenerId);\n              } catch {}\n              resolve();\n            }\n          });\n        } catch {\n          resolve();\n        }\n        setTimeout(() => {\n          if (!settled) {\n            settled = true;\n            resolve();\n          }\n        }, timeoutMs);\n      })\n    );\n  }\n\n  const uspApi = (window as any).__uspapi;\n  if (typeof uspApi === \"function\") {\n    tasks.push(\n      new Promise<void>((resolve) => {\n        try {\n          uspApi(\"getUSPData\", 1, (data: any, success: boolean) => {\n            if (success && typeof data?.uspString === \"string\" && data.uspString) {\n              signals.usPrivacy = data.uspString;\n            }\n            resolve();\n          });\n        } catch {\n          resolve();\n        }\n        setTimeout(resolve, timeoutMs);\n      })\n    );\n  }\n\n  if (tasks.length === 0) {\n    return Promise.resolve(signals);\n  }\n\n  return Promise.all(tasks).then(() => signals);\n}\n","const PRIVATE_HOST_PATTERNS: RegExp[] = [\n  /^localhost$/i,\n  /^127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/,\n  /^0\\.0\\.0\\.0$/,\n  /^::1$/,\n  /^10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/,\n  /^192\\.168\\.\\d{1,3}\\.\\d{1,3}$/,\n  /^172\\.(1[6-9]|2\\d|3[0-1])\\.\\d{1,3}\\.\\d{1,3}$/,\n];\n\nexport function isLocalDevHost(hostname: string): boolean {\n  const host = hostname.replace(/^\\[/, \"\").replace(/\\]$/, \"\").toLowerCase();\n  if (!host) return false;\n  if (host.endsWith(\".local\") || host.endsWith(\".localhost\")) return true;\n  return PRIVATE_HOST_PATTERNS.some((pattern) => pattern.test(host));\n}\n\nexport function toDevSafeUrl(rawUrl: string | undefined): string {\n  if (!rawUrl) return rawUrl ?? \"\";\n\n  let url: URL;\n  try {\n    url = new URL(rawUrl);\n  } catch {\n    return rawUrl;\n  }\n\n  if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n    return rawUrl;\n  }\n\n  if (!isLocalDevHost(url.hostname)) {\n    return rawUrl;\n  }\n\n  const cleanPath = url.pathname.replace(/\\/{2,}/g, \"/\") || \"/index.html\";\n  return `file://${cleanPath}`;\n}\n","export const MQTT_CA_CERT_FILE = \"src/certs/emqxsl-ca.crt\";\n\nexport type MQTTConfig = {\n  enabled: boolean;\n  brokerAddress: string;\n  brokerPort: number;\n  wsPort: number;\n  username: string;\n  password: string;\n  topicPrefix: string;\n  qos: 0 | 1 | 2;\n  brokerUrl?: string;\n};\n\nexport const DEFAULT_MQTT_CONFIG: MQTTConfig = {\n  enabled: true,\n  brokerAddress: \"vecbae77.ala.us-east-1.emqxsl.com\",\n  brokerPort: 8883,\n  wsPort: 8084,\n  username: \"for-sonifi\",\n  password: \"sonifi-mqtt\",\n  topicPrefix: \"adstorm/players\",\n  qos: 1,\n};\n\nexport const mqttConfig: MQTTConfig = { ...DEFAULT_MQTT_CONFIG };\n\nexport function applyMQTTConfig(overrides: Partial<MQTTConfig>): void {\n  Object.assign(mqttConfig, overrides);\n}\n\nexport function isMQTTEnabled(): boolean {\n  return mqttConfig.enabled;\n}\n\nexport function buildMQTTBrokerUrl(): string {\n  if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;\n  return `wss://${mqttConfig.brokerAddress}:${mqttConfig.wsPort}/mqtt`;\n}\n\nexport function buildPlayerTopic(\n  licenseKey: string,\n  channel: \"metrics\" | \"impressions\" | \"heartbeat\"\n): string {\n  return `${mqttConfig.topicPrefix}/${licenseKey}/${channel}`;\n}\n","import mqtt from \"mqtt\";\nimport type { MqttClient } from \"mqtt\";\nimport {\n  applyMQTTConfig,\n  buildMQTTBrokerUrl,\n  isMQTTEnabled,\n  mqttConfig,\n} from \"./mqttConfig\";\nimport type { MQTTConfig } from \"./mqttConfig\";\n\nconst LOG = \"[StormcloudVideoPlayer][MQTT]\";\n\nconst KEEPALIVE_SECONDS = 30;\nconst CONNECT_TIMEOUT_MS = 10_000;\n\nconst RECONNECT_BASE_MS = 5_000;\nconst RECONNECT_MAX_MS = 60_000;\nconst MAX_RECONNECT_ATTEMPTS = 8;\nconst COOLDOWN_MS = 10 * 60_000;\n\nexport type MQTTStatus = \"disconnected\" | \"connecting\" | \"connected\" | \"error\";\n\nlet client: MqttClient | null = null;\nlet status: MQTTStatus = \"disconnected\";\nlet reconnectAttempts = 0;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet stopped = false;\n\nexport function getMQTTStatus(): MQTTStatus {\n  return status;\n}\n\nexport function isMQTTConnected(): boolean {\n  return status === \"connected\" && client !== null && client.connected;\n}\n\nexport function isMQTTConfigured(): boolean {\n  return isMQTTEnabled();\n}\n\nexport function configureMQTT(overrides: Partial<MQTTConfig>): void {\n  applyMQTTConfig(overrides);\n  disconnectMQTT();\n}\n\nfunction clearReconnectTimer(): void {\n  if (reconnectTimer) {\n    clearTimeout(reconnectTimer);\n    reconnectTimer = null;\n  }\n}\n\nfunction teardownClient(): void {\n  if (client) {\n    try {\n      client.removeAllListeners();\n      client.end(true);\n    } catch {\n      // ignore teardown errors\n    }\n    client = null;\n  }\n}\n\nfunction scheduleReconnect(): void {\n  if (stopped || !isMQTTEnabled() || reconnectTimer) return;\n\n  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n    console.warn(\n      `${LOG} giving up after ${reconnectAttempts} attempts; cooling down for ${\n        COOLDOWN_MS / 60_000\n      }m`\n    );\n    teardownClient();\n    status = \"disconnected\";\n    reconnectTimer = setTimeout(() => {\n      reconnectTimer = null;\n      reconnectAttempts = 0;\n      openConnection();\n    }, COOLDOWN_MS);\n    return;\n  }\n\n  const delay = Math.min(\n    RECONNECT_MAX_MS,\n    RECONNECT_BASE_MS * 2 ** reconnectAttempts\n  );\n  const jitter = Math.floor(Math.random() * 1_000);\n  reconnectAttempts += 1;\n\n  reconnectTimer = setTimeout(() => {\n    reconnectTimer = null;\n    openConnection();\n  }, delay + jitter);\n}\n\nfunction openConnection(): void {\n  if (stopped || !isMQTTEnabled()) return;\n\n  teardownClient();\n\n  const url = buildMQTTBrokerUrl();\n  status = \"connecting\";\n\n  const clientId = `stormcloud-vp-${Math.random().toString(36).slice(2, 9)}`;\n\n  try {\n    client = mqtt.connect(url, {\n      clientId,\n      username: mqttConfig.username,\n      password: mqttConfig.password,\n      keepalive: KEEPALIVE_SECONDS,\n      clean: true,\n      // Disable MQTT.js internal reconnect; we manage reconnection ourselves.\n      reconnectPeriod: 0,\n      connectTimeout: CONNECT_TIMEOUT_MS,\n      queueQoSZero: false,\n      reschedulePings: true,\n      // Root-cause fix for the Tizen 4.0 \"Keepalive timeout\" loop: MQTT.js's\n      // default timerVariant \"auto\" runs the keepalive interval inside a\n      // Blob-URL Web Worker (via worker-timers). On Samsung Tizen 4.0 (old\n      // WebKit) served from a file:// origin that worker can't tick reliably,\n      // so the keepalive counter trips onKeepaliveTimeout almost immediately\n      // after connect. Force the native setInterval timer instead; the main\n      // thread is free because video is decoded by the native AVPlay pipeline.\n      timerVariant: \"native\",\n    });\n  } catch (err) {\n    status = \"error\";\n    console.warn(`${LOG} connect() threw:`, err);\n    scheduleReconnect();\n    return;\n  }\n\n  client.on(\"connect\", () => {\n    status = \"connected\";\n    reconnectAttempts = 0;\n    clearReconnectTimer();\n    console.info(`${LOG} connected to ${url}`);\n  });\n\n  client.on(\"offline\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    console.warn(`${LOG} offline`);\n    scheduleReconnect();\n  });\n\n  client.on(\"error\", (err) => {\n    status = \"error\";\n    console.warn(`${LOG} error:`, err.message);\n    scheduleReconnect();\n  });\n\n  client.on(\"close\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    scheduleReconnect();\n  });\n}\n\nexport function initMQTTClient(): void {\n  if (client || !isMQTTEnabled()) return;\n  stopped = false;\n  reconnectAttempts = 0;\n  openConnection();\n}\n\nexport function ensureMQTTClient(): void {\n  if (isMQTTEnabled() && !client && !reconnectTimer) {\n    initMQTTClient();\n  }\n}\n\nexport function publishMQTT(\n  topic: string,\n  payload: Record<string, unknown>\n): boolean {\n  if (!isMQTTEnabled()) {\n    return false;\n  }\n\n  ensureMQTTClient();\n\n  if (!client || !client.connected) {\n    return false;\n  }\n\n  try {\n    client.publish(topic, JSON.stringify(payload), { qos: mqttConfig.qos });\n    return true;\n  } catch (err) {\n    console.warn(`${LOG} publish failed on ${topic}:`, err);\n    return false;\n  }\n}\n\nexport function disconnectMQTT(): void {\n  stopped = true;\n  clearReconnectTimer();\n  teardownClient();\n  reconnectAttempts = 0;\n  status = \"disconnected\";\n}\n","import type {\n  ClientInfo,\n  AdDetectInfo,\n  AdLoadedInfo,\n  AdImpressionInfo,\n  PlayerAnalyticsContext,\n  StormcloudVideoPlayerConfig,\n} from \"../types\";\n\nimport { buildPlayerTopic, isMQTTEnabled } from \"./mqttConfig\";\nimport { ensureMQTTClient, publishMQTT } from \"./mqttClient\";\nimport {\n  getOrCreateStoredUuid,\n  PLAYER_ID_STORAGE_KEY,\n  resolveNativeDeviceId,\n} from \"./vastEnvironmentSignals\";\n\nlet cachedBrowserId: string | null = null;\n\nexport function buildAnalyticsContext(\n  config: Pick<StormcloudVideoPlayerConfig, \"debugAdTiming\" | \"isLiveStream\">\n): PlayerAnalyticsContext {\n  const context: PlayerAnalyticsContext = {};\n  if (config.debugAdTiming) {\n    context.debugAdTiming = true;\n  }\n  if (config.isLiveStream !== undefined) {\n    context.inputStreamType = config.isLiveStream ? \"live\" : \"vod\";\n  }\n  return context;\n}\n\nexport function getClientInfo(): ClientInfo {\n  const ua = navigator.userAgent;\n  const platform = navigator.platform;\n  const vendor = navigator.vendor || \"\";\n  const maxTouchPoints = navigator.maxTouchPoints || 0;\n  const memory = (navigator as any).deviceMemory || null;\n  const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n\n  const screenInfo = {\n    width: screen?.width,\n    height: screen?.height,\n    availWidth: screen?.availWidth,\n    availHeight: screen?.availHeight,\n    orientation: (screen?.orientation as any)?.type || \"\",\n    pixelDepth: screen?.pixelDepth,\n  };\n\n  let deviceType: \"tv\" | \"mobile\" | \"tablet\" | \"desktop\" = \"desktop\";\n  let brand = \"Unknown\";\n  let os = \"Unknown\";\n  let model = \"\";\n  let isSmartTV = false;\n  let isAndroid = false;\n  let isWebView = false;\n  let isWebApp = false;\n\n  if (ua.includes(\"Web0S\")) {\n    brand = \"LG\";\n    os = \"webOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n    model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n  } else if (ua.includes(\"Tizen\")) {\n    brand = \"Samsung\";\n    os = \"Tizen\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n    const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n    model = tizenMatch\n      ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim()\n      : \"Tizen TV\";\n  } else if (ua.includes(\"Philips\")) {\n    brand = \"Philips\";\n    os = \"Saphi\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n    brand = \"Sharp\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (\n    ua.includes(\"Android\") &&\n    (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))\n  ) {\n    brand = \"Sony\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (\n    ua.includes(\"Android\") &&\n    (ua.includes(\"NetCast\") || ua.includes(\"LG\"))\n  ) {\n    brand = \"LG\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n    brand = \"Roku\";\n    os = \"Roku OS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"AppleTV\")) {\n    brand = \"Apple\";\n    os = \"tvOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  }\n\n  if (ua.includes(\"Android\")) {\n    isAndroid = true;\n    os = \"Android\";\n    deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n\n    if (\n      ua.includes(\"Android\") &&\n      (maxTouchPoints === 0 ||\n        ua.includes(\"Google TV\") ||\n        ua.includes(\"XiaoMi\"))\n    ) {\n      deviceType = \"tv\";\n      isSmartTV = true;\n      brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n    }\n\n    const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n    if (androidModelMatch && androidModelMatch[1]) {\n      model = androidModelMatch[1];\n    }\n  }\n\n  if (/iPad|iPhone|iPod/.test(ua)) {\n    os = \"iOS\";\n    deviceType = \"mobile\";\n    brand = \"Apple\";\n    if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n      deviceType = \"tablet\";\n    }\n  }\n\n  if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n    if (ua.includes(\"Windows\")) {\n      os = \"Windows\";\n      deviceType = \"desktop\";\n    } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n      os = \"macOS\";\n      deviceType = \"desktop\";\n      if (maxTouchPoints > 1) deviceType = \"tablet\";\n    } else if (ua.includes(\"Linux\")) {\n      os = \"Linux\";\n      deviceType = \"desktop\";\n    }\n  }\n\n  if (brand === \"Unknown\") {\n    if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n    if (vendor.includes(\"Apple\")) brand = \"Apple\";\n    if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n  }\n\n  isWebView = /wv|WebView|Linux; U;/.test(ua);\n\n  if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n    isWebView = true;\n  }\n\n  isWebApp =\n    window.matchMedia(\"(display-mode: standalone)\").matches ||\n    (window.navigator as any).standalone === true ||\n    window.screen?.orientation?.angle !== undefined;\n\n  return {\n    brand,\n    os,\n    model: model || ua.substring(0, 50) + \"...\",\n    deviceType,\n    isSmartTV,\n    isAndroid,\n    isWebView,\n    isWebApp,\n    domain: window.location.hostname,\n    origin: window.location.origin,\n    path: window.location.pathname,\n    userAgent: ua,\n    vendor,\n    platform,\n    screen: screenInfo,\n    hardwareConcurrency,\n    deviceMemory: memory,\n    maxTouchPoints,\n    language: navigator.language,\n    languages: navigator.languages?.join(\",\") || \"\",\n    cookieEnabled: navigator.cookieEnabled,\n    doNotTrack: navigator.doNotTrack || \"\",\n    referrer: document.referrer,\n    visibilityState: document.visibilityState,\n  };\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n  if (typeof crypto !== \"undefined\" && crypto.subtle?.digest) {\n    try {\n      await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n\n      let encodedData: BufferSource;\n      if (typeof TextEncoder !== \"undefined\") {\n        encodedData = new TextEncoder().encode(input);\n      } else {\n        const utf8 = unescape(encodeURIComponent(input));\n        const buffer = new Uint8Array(utf8.length);\n        for (let i = 0; i < utf8.length; i++) {\n          buffer[i] = utf8.charCodeAt(i);\n        }\n        encodedData = buffer;\n      }\n\n      const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n      return Array.from(new Uint8Array(hashBuffer))\n        .map((b) => b.toString(16).padStart(2, \"0\"))\n        .join(\"\");\n    } catch {\n      console.warn(\n        \"[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash\"\n      );\n    }\n  }\n\n  let hash = 0;\n  for (let i = 0; i < input.length; i++) {\n    const char = input.charCodeAt(i);\n    hash = (hash << 5) - hash + char;\n    hash = hash & hash;\n  }\n\n  const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n  const timestamp = Date.now().toString(16).padStart(12, \"0\");\n  const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n\n  return (fallbackHash + timestamp + random).padEnd(64, \"0\");\n}\n\nfunction resolvePlayerIdentitySeed(clientInfo: ClientInfo): string {\n  const nativeDeviceId = resolveNativeDeviceId();\n  if (nativeDeviceId) {\n    return `device:${nativeDeviceId}`;\n  }\n\n  const persistedId = getOrCreateStoredUuid(PLAYER_ID_STORAGE_KEY);\n  if (persistedId) {\n    return `persisted:${persistedId}`;\n  }\n\n  return `fingerprint:${JSON.stringify(clientInfo)}`;\n}\n\nexport async function getBrowserID(clientInfo: ClientInfo): Promise<string> {\n  if (cachedBrowserId) {\n    return cachedBrowserId;\n  }\n\n  cachedBrowserId = await sha256Hex(resolvePlayerIdentitySeed(clientInfo));\n  return cachedBrowserId;\n}\n\ntype PlayerMetricFlags = {\n  adLoaded?: boolean;\n  adDetect?: boolean;\n  captureAt?: string;\n};\n\nfunction canPublish(licenseKey: string | undefined): licenseKey is string {\n  return Boolean(isMQTTEnabled() && licenseKey);\n}\n\nasync function buildPlayerMetricEvent(\n  context: PlayerAnalyticsContext = {},\n  flags: PlayerMetricFlags = {}\n): Promise<Record<string, unknown>> {\n  const clientInfo = getClientInfo();\n\n  const debugAdTiming = !!context.debugAdTiming;\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] clientInfo: \", JSON.stringify(clientInfo, null, 2));\n  }\n\n  const playerId = await getBrowserID(clientInfo);\n\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] playerId: \", playerId);\n  }\n\n  const captureAt = flags.captureAt ?? new Date().toISOString();\n\n  return {\n    player_id: playerId,\n    device_type: clientInfo.deviceType,\n    os: clientInfo.os.toLowerCase(),\n    ad_loaded: flags.adLoaded ?? false,\n    ad_detect: flags.adDetect ?? false,\n    capture_at: captureAt,\n    ...(context.inputStreamType\n      ? { input_stream_type: context.inputStreamType }\n      : {}),\n  };\n}\n\nfunction publishTracking(\n  licenseKey: string,\n  channel: \"metrics\" | \"impressions\" | \"heartbeat\",\n  body: Record<string, unknown>\n): void {\n  ensureMQTTClient();\n  publishMQTT(buildPlayerTopic(licenseKey, channel), body);\n}\n\nexport async function sendInitialTracking(\n  licenseKey?: string,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  if (!canPublish(licenseKey)) return;\n\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      adLoaded: false,\n      adDetect: false,\n    });\n\n    publishTracking(licenseKey, \"metrics\", {\n      events: [metricEvent],\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n      error\n    );\n  }\n}\n\nexport async function sendAdDetectTracking(\n  licenseKey: string | undefined,\n  adDetectInfo: AdDetectInfo,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  try {\n    await sendHeartbeat(licenseKey, context, {\n      adDetect: true,\n      captureAt: adDetectInfo.timestamp,\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad detect tracking:\",\n      error\n    );\n  }\n}\n\nexport async function sendAdLoadedTracking(\n  licenseKey: string | undefined,\n  adLoadedInfo: AdLoadedInfo,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  try {\n    await sendHeartbeat(licenseKey, context, {\n      adLoaded: true,\n      captureAt: adLoadedInfo.timestamp,\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n      error\n    );\n  }\n}\n\nexport async function sendAdImpressionTracking(\n  licenseKey: string | undefined,\n  adImpressionInfo: AdImpressionInfo,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  if (!canPublish(licenseKey)) return;\n\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      captureAt: adImpressionInfo.timestamp,\n    });\n\n    publishTracking(licenseKey, \"heartbeat\", metricEvent);\n    publishTracking(licenseKey, \"impressions\", {\n      events: [\n        {\n          player_id: metricEvent.player_id,\n          ad_played_count: 1,\n          ad_url: adImpressionInfo.adUrl,\n          capture_at: adImpressionInfo.timestamp,\n        },\n      ],\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n      error\n    );\n  }\n}\n\nexport async function sendHeartbeat(\n  licenseKey?: string,\n  context: PlayerAnalyticsContext = {},\n  flags: PlayerMetricFlags = {}\n): Promise<void> {\n  if (!canPublish(licenseKey)) return;\n\n  try {\n    const heartbeatData = await buildPlayerMetricEvent(context, flags);\n    publishTracking(licenseKey, \"heartbeat\", heartbeatData);\n  } catch (error) {\n    console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n  }\n}\n"]}