stormcloud-video-player 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/stormcloud-vp.min.js +1 -1
- package/lib/index.cjs +370 -447
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +355 -267
- package/lib/index.d.ts +355 -267
- package/lib/index.js +329 -406
- package/lib/index.js.map +1 -1
- package/lib/player/StormcloudVideoPlayer.cjs +96 -178
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/players/FilePlayer.cjs +99 -116
- package/lib/players/FilePlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +148 -230
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.d.cts +1 -1
- package/lib/players/index.cjs +227 -309
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +17 -9
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.d.cts +1 -1
- package/lib/sdk/ima.cjs +28 -20
- package/lib/sdk/ima.cjs.map +1 -1
- package/lib/sdk/ima.d.cts +1 -1
- package/lib/sdk/prebid.cjs +27 -85
- package/lib/sdk/prebid.cjs.map +1 -1
- package/lib/sdk/prebid.d.cts +6 -3
- package/lib/sdk/prebidController.cjs +35 -108
- package/lib/sdk/prebidController.cjs.map +1 -1
- package/lib/sdk/prebidController.d.cts +3 -2
- package/lib/sdk/vastParser.cjs +19 -11
- package/lib/sdk/vastParser.cjs.map +1 -1
- package/lib/{types-g2d4Akez.d.cts → types-CRi_KrjM.d.cts} +1 -45
- package/lib/ui/StormcloudVideoPlayer.cjs +190 -267
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
- package/lib/utils/browserCompat.cjs +11 -11
- package/lib/utils/browserCompat.cjs.map +1 -1
- package/lib/utils/polyfills.cjs +13 -13
- package/lib/utils/polyfills.cjs.map +1 -1
- package/lib/utils/tracking.cjs +19 -11
- package/lib/utils/tracking.cjs.map +1 -1
- package/lib/utils/tracking.d.cts +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/ubuntu24/Dev/stormcloud-vp/lib/sdk/prebidController.cjs","../../src/sdk/prebidController.ts","../../src/sdk/vastParser.ts","../../src/sdk/prebid.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","hasOwnProperty","prototype","name","all","target","get","enumerable","__copyProps","desc","to","from","except","key","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","prebidController_exports","__export","createPrebidController","module","exports","isHlsType","type","includes","isMp4Type","parseVastXml","xmlString","filter","logPrefix","xmlDoc","parser","DOMParser","parseFromString","parserError","querySelector","console","textContent","error","adElement","warn","adId","getAttribute","title","isNoAdAvailable","toLowerCase","durationText","durationParts","split","duration","parseInt","Math","round","parseFloat","mediaFileElements","querySelectorAll","mediaFiles","log","length","forEach","mf","index","url","trim","width","height","substring","isHls","isMp4","accepted","bitrateAttr","bitrateValue","bitrate","sort","a","b","aIsMp4","bIsMp4","impression","start","complete","mute","unmute","resume","clickThrough","firstQuartile","midpoint","thirdQuartile","pause","fullscreen","exitFullscreen","skip","el","trackingUrls","push","event","eventKey","id","fetchAndParseVastAd","vastTagUrl","response","vastXml","mode","credentials","Accept","referrerPolicy","ok","Error","statusText","text","fireTrackingPixels","urls","sessionId","licenseKey","trackingUrl","img","Image","src","DEFAULT_TIMEOUT_MS","AUCTION_PATH","createPrebidManager","config","initialized","serverUrl","debug","args","resolveServerUrl","replace","extUrl","ortbRequest","ext","prebid","server","externalurl","buildRequest","req","JSON","parse","stringify","Date","now","random","toString","slice","cache","vastxml","targeting","includewinners","includebidderkeys","device","navigator","ua","userAgent","language","window","w","screen","innerWidth","h","innerHeight","site","page","location","href","domain","hostname","parseResponse","data","bids","seatbids","seatbid","currency","cur","seat","bidArray","bid","cacheUrl","adm","bidResponse","bidder","cpm","price","crid","impId","impid","creativeId","vastUrl","adomain","extractVastUrl","winner","cpmFloor","toFixed","blob","Blob"],"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/sdk/prebidController.ts\nvar prebidController_exports = {};\n__export(prebidController_exports, {\n createPrebidController: () => createPrebidController\n});\nmodule.exports = __toCommonJS(prebidController_exports);\n\n// src/sdk/vastParser.ts\nfunction isHlsType(type) {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\nfunction isMp4Type(type) {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\nfunction parseVastXml(xmlString, filter = \"all\", logPrefix = \"[VastParser]\") {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const isNoAdAvailable = adId === \"empty\" || title.toLowerCase().includes(\"no ad available\") || title.toLowerCase() === \"no ad available\";\n const durationText = xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + Math.round(parseFloat(durationParts[2] || \"0\"));\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0\n });\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: []\n };\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = xmlDoc.querySelector(\"ClickThrough\")?.textContent?.trim();\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\nasync function fetchAndParseVastAd(vastTagUrl, filter = \"all\", logPrefix = \"[VastParser]\") {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\"\n },\n referrerPolicy: \"no-referrer-when-downgrade\"\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2e3)\n );\n return parseVastXml(vastXml, filter, logPrefix);\n}\nfunction createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n}\nfunction fireTrackingPixels(urls, sessionId, licenseKey, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n if (licenseKey) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}license_key=${licenseKey}`;\n }\n const img = new Image(1, 1);\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n\n// src/sdk/prebid.ts\nvar DEFAULT_TIMEOUT_MS = 3e3;\nvar AUCTION_PATH = \"/openrtb2/auction\";\nfunction createPrebidManager(config) {\n let initialized = false;\n let serverUrl = \"\";\n const debug = config.debug ?? false;\n function log(...args) {\n if (debug) {\n console.log(\"[Prebid]\", ...args);\n }\n }\n function warn(...args) {\n console.warn(\"[Prebid]\", ...args);\n }\n function resolveServerUrl() {\n if (config.serverUrl) {\n return config.serverUrl.replace(/\\/$/, \"\");\n }\n const extUrl = config.ortbRequest?.ext?.prebid?.server?.externalurl;\n if (typeof extUrl === \"string\" && extUrl.length > 0) {\n return extUrl.replace(/\\/$/, \"\");\n }\n throw new Error(\n \"Prebid Server URL not configured. Provide serverUrl in PrebidConfig or ext.prebid.server.externalurl in the OpenRTB request.\"\n );\n }\n function buildRequest() {\n const req = JSON.parse(JSON.stringify(config.ortbRequest));\n req.id = `${req.id || \"prebid\"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n if (!req.ext) req.ext = {};\n if (!req.ext.prebid) req.ext.prebid = {};\n if (!req.ext.prebid.cache) req.ext.prebid.cache = {};\n if (!req.ext.prebid.cache.vastxml) req.ext.prebid.cache.vastxml = {};\n if (!req.ext.prebid.targeting) {\n req.ext.prebid.targeting = {\n includewinners: true,\n includebidderkeys: false\n };\n }\n if (!req.device) req.device = {};\n if (typeof navigator !== \"undefined\") {\n if (!req.device.ua) req.device.ua = navigator.userAgent;\n if (!req.device.language) {\n req.device.language = (navigator.language || \"\").split(\"-\")[0] || \"en\";\n }\n }\n if (typeof window !== \"undefined\") {\n if (!req.device.w) req.device.w = window.screen?.width || window.innerWidth;\n if (!req.device.h) req.device.h = window.screen?.height || window.innerHeight;\n }\n if (!req.site) req.site = {};\n if (typeof window !== \"undefined\") {\n if (!req.site.page) req.site.page = window.location.href;\n if (!req.site.domain) req.site.domain = window.location.hostname;\n }\n return req;\n }\n function parseResponse(data) {\n const bids = [];\n const seatbids = data?.seatbid || [];\n const currency = data?.cur || \"USD\";\n for (const seatbid of seatbids) {\n const seat = seatbid.seat || \"unknown\";\n const bidArray = seatbid.bid || [];\n for (const bid of bidArray) {\n const cacheUrl = bid.ext?.prebid?.cache?.vastXml?.url;\n const vastXml = bid.adm || void 0;\n const bidResponse = {\n bidder: seat,\n cpm: bid.price || 0,\n width: bid.w || 0,\n height: bid.h || 0,\n adId: bid.id || \"\",\n impId: bid.impid || \"\",\n creativeId: bid.crid || \"\",\n currency\n };\n if (cacheUrl) bidResponse.vastUrl = cacheUrl;\n if (vastXml) bidResponse.vastXml = vastXml;\n if (bid.adomain) bidResponse.adomain = bid.adomain;\n bids.push(bidResponse);\n }\n }\n bids.sort((a, b) => b.cpm - a.cpm);\n return bids;\n }\n function extractVastUrl(bids) {\n if (bids.length === 0) return null;\n const winner = bids[0];\n const cpmFloor = config.cpmFloor ?? 0;\n if (cpmFloor > 0 && winner.cpm < cpmFloor) {\n log(\n `Winning bid $${winner.cpm.toFixed(2)} below CPM floor $${cpmFloor.toFixed(2)}, rejecting`\n );\n return null;\n }\n if (winner.vastUrl) {\n log(\n `Using cached VAST URL from ${winner.bidder} ($${winner.cpm.toFixed(2)} ${winner.currency})`\n );\n return winner.vastUrl;\n }\n if (winner.vastXml) {\n log(\n `Creating blob URL from VAST XML (${winner.bidder}, $${winner.cpm.toFixed(2)})`\n );\n try {\n const blob = new Blob([winner.vastXml], { type: \"text/xml\" });\n return URL.createObjectURL(blob);\n } catch (error) {\n warn(\"Failed to create blob URL from VAST XML:\", error);\n }\n }\n return null;\n }\n async function initialize() {\n if (initialized) return;\n serverUrl = resolveServerUrl();\n if (!config.ortbRequest?.imp || config.ortbRequest.imp.length === 0) {\n throw new Error(\"No impressions (imp) defined in the OpenRTB request.\");\n }\n initialized = true;\n log(\"Initialized with server:\", serverUrl);\n log(\n \"Bidders:\",\n config.ortbRequest.imp.map((imp) => {\n const bidders = imp.ext?.prebid?.bidder;\n return bidders ? Object.keys(bidders).join(\", \") : \"none\";\n }).join(\"; \")\n );\n }\n async function requestBids() {\n if (!initialized) {\n throw new Error(\"Prebid not initialized. Call initialize() first.\");\n }\n const auctionUrl = `${serverUrl}${AUCTION_PATH}`;\n const request = buildRequest();\n const timeout = config.timeout ?? config.ortbRequest.tmax ?? DEFAULT_TIMEOUT_MS;\n log(\"Sending auction request to:\", auctionUrl);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => {\n controller?.abort();\n }, timeout + 2e3);\n try {\n const fetchOptions = {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request)\n };\n if (controller) {\n fetchOptions.signal = controller.signal;\n }\n const response = await fetch(auctionUrl, fetchOptions);\n clearTimeout(timeoutId);\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `Prebid Server returned HTTP ${response.status}: ${body.slice(0, 200)}`\n );\n }\n const data = await response.json();\n if (debug && data?.ext?.responsetimemillis) {\n log(\"Bidder response times:\", data.ext.responsetimemillis);\n }\n if (debug && data?.ext?.errors) {\n warn(\"Auction errors:\", data.ext.errors);\n }\n const bids = parseResponse(data);\n log(`Received ${bids.length} bid(s)`);\n if (debug) {\n for (const b of bids) {\n log(\n ` ${b.bidder}: $${b.cpm.toFixed(2)} ${b.currency} ${b.width}x${b.height}` + (b.vastUrl ? \" [cached VAST]\" : \"\") + (b.vastXml && !b.vastUrl ? \" [VAST XML]\" : \"\")\n );\n }\n }\n return bids;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`Auction request timed out after ${timeout + 2e3}ms`);\n return [];\n }\n throw error;\n }\n }\n async function getVastUrl() {\n try {\n const bids = await requestBids();\n return extractVastUrl(bids);\n } catch (error) {\n warn(\"Failed to get VAST URL:\", error);\n return null;\n }\n }\n function destroy() {\n initialized = false;\n serverUrl = \"\";\n log(\"Destroyed\");\n }\n return {\n initialize,\n requestBids,\n getVastUrl,\n destroy,\n get isInitialized() {\n return initialized;\n }\n };\n}\n\n// src/sdk/prebidController.ts\nvar import_hls = __toESM(require(\"hls.js\"), 1);\nvar LOG = \"[PrebidController]\";\nfunction createPrebidController(contentVideo, prebidConfig, options) {\n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = /* @__PURE__ */ new Map();\n const licenseKey = options?.licenseKey;\n const mainHlsInstance = options?.mainHlsInstance;\n let adVideoElement;\n let adHls;\n let adContainerEl;\n let currentAd;\n let sessionId;\n let destroyed = false;\n let trackingFired = createEmptyTrackingState();\n const prebidDebug = prebidConfig.debug ?? false;\n const prebidManager = createPrebidManager({\n ...prebidConfig,\n debug: prebidDebug\n });\n let prebidInitialized = false;\n function emit(event, payload) {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`${LOG} Error in event listener for ${event}:`, error);\n }\n }\n }\n function generateSessionId() {\n return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n function fireTrackingPixels2(urls) {\n fireTrackingPixels(urls, sessionId, licenseKey, LOG);\n }\n function getMainStreamQuality() {\n if (!mainHlsInstance || !mainHlsInstance.levels) {\n return null;\n }\n const currentLevel = mainHlsInstance.currentLevel;\n if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {\n const autoLevel = mainHlsInstance.loadLevel;\n if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {\n const level2 = mainHlsInstance.levels[autoLevel];\n return {\n width: level2.width || 1920,\n height: level2.height || 1080,\n bitrate: level2.bitrate || 5e6\n };\n }\n return null;\n }\n const level = mainHlsInstance.levels[currentLevel];\n return {\n width: level.width || 1920,\n height: level.height || 1080,\n bitrate: level.bitrate || 5e6\n };\n }\n function selectBestMediaFile(mediaFiles) {\n if (mediaFiles.length === 0) {\n throw new Error(\"No media files available\");\n }\n const firstFile = mediaFiles[0];\n if (!firstFile) {\n throw new Error(\"No media files available\");\n }\n if (mediaFiles.length === 1) {\n return firstFile;\n }\n const mainQuality = getMainStreamQuality();\n if (!mainQuality) {\n console.log(`${LOG} No main stream quality info, using first media file`);\n return firstFile;\n }\n console.log(`${LOG} Main stream quality:`, mainQuality);\n const scoredFiles = mediaFiles.map((file) => {\n const widthDiff = Math.abs(file.width - mainQuality.width);\n const heightDiff = Math.abs(file.height - mainQuality.height);\n const resolutionDiff = widthDiff + heightDiff;\n const fileBitrate = (file.bitrate || 5e3) * 1e3;\n const bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);\n const score = resolutionDiff * 2 + bitrateDiff / 1e3;\n return { file, score, resolutionDiff, bitrateDiff };\n });\n scoredFiles.sort((a, b) => a.score - b.score);\n const bestMatch = scoredFiles[0];\n if (!bestMatch) {\n console.log(`${LOG} No best match found, using first media file`);\n return firstFile;\n }\n console.log(`${LOG} Selected media file:`, {\n url: bestMatch.file.url,\n resolution: `${bestMatch.file.width}x${bestMatch.file.height}`,\n bitrate: bestMatch.file.bitrate,\n score: bestMatch.score\n });\n return bestMatch.file;\n }\n function isHlsMediaFile(file) {\n return file.type === \"application/x-mpegURL\" || file.type.includes(\"m3u8\");\n }\n function createAdVideoElement() {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.playsInline = true;\n video.muted = false;\n video.volume = 1;\n console.log(`${LOG} Created ad video element with volume ${video.volume}`);\n return video;\n }\n function setupAdEventListeners() {\n if (!adVideoElement || !currentAd) return;\n adVideoElement.addEventListener(\"timeupdate\", () => {\n if (!currentAd || !adVideoElement) return;\n const progress = adVideoElement.currentTime / currentAd.duration;\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);\n }\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels2(currentAd.trackingUrls.midpoint);\n }\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);\n }\n });\n adVideoElement.addEventListener(\"playing\", () => {\n if (!currentAd || trackingFired.start) return;\n trackingFired.start = true;\n fireTrackingPixels2(currentAd.trackingUrls.start);\n console.log(`${LOG} Ad started playing`);\n });\n adVideoElement.addEventListener(\"ended\", () => {\n if (!currentAd || trackingFired.complete) return;\n trackingFired.complete = true;\n fireTrackingPixels2(currentAd.trackingUrls.complete);\n console.log(`${LOG} Ad completed`);\n handleAdComplete();\n });\n adVideoElement.addEventListener(\"error\", (e) => {\n console.error(`${LOG} Ad video error:`, e);\n if (currentAd) {\n fireTrackingPixels2(currentAd.trackingUrls.error);\n }\n handleAdError();\n });\n adVideoElement.addEventListener(\"volumechange\", () => {\n if (!currentAd) return;\n if (adVideoElement.muted) {\n fireTrackingPixels2(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels2(currentAd.trackingUrls.unmute);\n }\n });\n adVideoElement.addEventListener(\"pause\", () => {\n if (currentAd && !adVideoElement.ended) {\n fireTrackingPixels2(currentAd.trackingUrls.pause);\n }\n });\n adVideoElement.addEventListener(\"play\", () => {\n if (currentAd && adVideoElement.currentTime > 0) {\n fireTrackingPixels2(currentAd.trackingUrls.resume);\n }\n });\n }\n function setAdPlayingFlag(isPlaying) {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n function handleAdComplete() {\n console.log(`${LOG} Handling ad completion`);\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback`\n );\n contentVideo.play().catch(() => {\n });\n } else {\n console.log(`${LOG} Content video already playing in live mode`);\n }\n }\n emit(\"content_resume\");\n }\n function handleAdError() {\n console.log(`${LOG} Handling ad error`);\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n emit(\"ad_error\");\n }\n async function ensurePrebidInitialized() {\n if (prebidInitialized) return;\n if (prebidConfig.enabled === false) {\n throw new Error(\"Prebid is disabled in config\");\n }\n if (!prebidConfig.ortbRequest?.imp?.length) {\n throw new Error(\"No impressions configured in ortbRequest\");\n }\n await prebidManager.initialize();\n prebidInitialized = true;\n console.log(`${LOG} Prebid Server manager initialized`);\n }\n async function runPrebidAuction() {\n await ensurePrebidInitialized();\n const bids = await prebidManager.requestBids();\n if (bids.length === 0) {\n console.warn(`${LOG} No bids received from Prebid Server`);\n return null;\n }\n const cpmFloor = prebidConfig.cpmFloor ?? 0;\n const winner = bids[0];\n if (cpmFloor > 0 && winner.cpm < cpmFloor) {\n console.log(\n `${LOG} Winning bid $${winner.cpm.toFixed(2)} below CPM floor $${cpmFloor.toFixed(2)}, rejecting`\n );\n return null;\n }\n console.log(\n `${LOG} Winning bid: ${winner.bidder} $${winner.cpm.toFixed(2)} ${winner.currency}`\n );\n if (winner.vastXml) {\n console.log(`${LOG} Parsing VAST XML from bid response (inline)`);\n return parseVastXml(winner.vastXml, \"mp4-first\", LOG);\n }\n if (winner.vastUrl) {\n console.log(`${LOG} Fetching VAST from cached URL: ${winner.vastUrl}`);\n return fetchAndParseVastAd(winner.vastUrl, \"mp4-first\", LOG);\n }\n console.warn(`${LOG} Winning bid has no VAST URL or XML`);\n return null;\n }\n function startPlayback(mediaFile) {\n if (!adVideoElement) return;\n if (isHlsMediaFile(mediaFile)) {\n startHlsPlayback(mediaFile);\n } else {\n startNativePlayback(mediaFile);\n }\n }\n function startNativePlayback(mediaFile) {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting native MP4 playback: ${mediaFile.url}`);\n adVideoElement.src = mediaFile.url;\n adVideoElement.load();\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native ad playback:`, error);\n handleAdError();\n });\n }\n function startHlsPlayback(mediaFile) {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting HLS playback: ${mediaFile.url}`);\n if (import_hls.default.isSupported()) {\n if (adHls) {\n adHls.destroy();\n }\n adHls = new import_hls.default({\n enableWorker: true,\n lowLatencyMode: false\n });\n adHls.loadSource(mediaFile.url);\n adHls.attachMedia(adVideoElement);\n adHls.on(import_hls.default.Events.MANIFEST_PARSED, () => {\n console.log(`${LOG} HLS manifest parsed, starting playback`);\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting HLS ad playback:`, error);\n handleAdError();\n });\n });\n adHls.on(import_hls.default.Events.ERROR, (_event, data) => {\n console.error(`${LOG} HLS error:`, data);\n if (data.fatal) {\n handleAdError();\n }\n });\n } else if (adVideoElement.canPlayType(\"application/vnd.apple.mpegurl\")) {\n adVideoElement.src = mediaFile.url;\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native HLS ad playback:`, error);\n handleAdError();\n });\n } else {\n console.error(`${LOG} HLS not supported on this platform`);\n handleAdError();\n }\n }\n return {\n initialize() {\n console.log(`${LOG} Initializing`);\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n },\n async requestAds(vastTagUrl) {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n console.log(`${LOG} requestAds called:`, vastTagUrl || \"(empty - will run Prebid auction)\");\n if (adPlaying) {\n console.warn(`${LOG} Cannot request new ads while an ad is playing`);\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n try {\n sessionId = generateSessionId();\n let ad;\n if (vastTagUrl && vastTagUrl.length > 0) {\n console.log(`${LOG} Fetching VAST from provided URL`);\n ad = await fetchAndParseVastAd(vastTagUrl, \"mp4-first\", LOG);\n } else {\n console.log(`${LOG} Running Prebid Server auction`);\n ad = await runPrebidAuction();\n }\n if (!ad) {\n console.warn(`${LOG} No ads available`);\n emit(\"ad_error\");\n return Promise.reject(new Error(\"No ads available\"));\n }\n currentAd = ad;\n console.log(\n `${LOG} Ad parsed: ${ad.title}, duration: ${ad.duration}s, mediaFiles: ${ad.mediaFiles.length}`\n );\n fireTrackingPixels2(ad.trackingUrls.impression);\n trackingFired.impression = true;\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error requesting ads:`, error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n async play() {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n if (!currentAd) {\n console.warn(`${LOG} Cannot play: No ad loaded`);\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n console.log(`${LOG} Starting ad playback`);\n try {\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n setupAdEventListeners();\n }\n trackingFired = {\n ...createEmptyTrackingState(),\n impression: trackingFired.impression\n };\n const contentVolume = contentVideo.volume;\n originalVolume = Math.max(\n 0,\n Math.min(1, contentVolume || originalVolume)\n );\n if (!options?.continueLiveStreamDuringAds) {\n contentVideo.pause();\n console.log(`${LOG} Content paused (VOD mode)`);\n } else {\n console.log(`${LOG} Content continues (Live mode)`);\n }\n console.log(`${LOG} FORCE MUTING main video`);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n adPlaying = true;\n setAdPlayingFlag(true);\n if (adVideoElement) {\n const adVolume = originalMutedState ? 0 : originalVolume;\n adVideoElement.volume = Math.max(0, Math.min(1, adVolume));\n adVideoElement.muted = false;\n console.log(\n `${LOG} Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}`\n );\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n emit(\"content_pause\");\n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available for ad\");\n }\n console.log(`${LOG} Loading ad from: ${mediaFile.url}`);\n startPlayback(mediaFile);\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error playing ad:`, error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && !adVideoElement.paused) {\n adVideoElement.pause();\n }\n } catch (error) {\n console.warn(`${LOG} Error pausing ad:`, error);\n }\n },\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && adVideoElement.paused) {\n adVideoElement.play().catch(() => {\n });\n }\n } catch (error) {\n console.warn(`${LOG} Error resuming ad:`, error);\n }\n },\n async stop() {\n console.log(`${LOG} Stopping ad`);\n adPlaying = false;\n setAdPlayingFlag(false);\n const previousMutedState = contentVideo.muted;\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n console.log(\n `${LOG} Restored mute state on stop: ${previousMutedState} -> ${originalMutedState}`\n );\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback on stop`\n );\n contentVideo.play().catch(() => {\n });\n }\n }\n if (adHls) {\n adHls.destroy();\n adHls = void 0;\n }\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n }\n currentAd = void 0;\n },\n destroy() {\n console.log(`${LOG} Destroying`);\n destroyed = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n if (adHls) {\n adHls.destroy();\n adHls = void 0;\n }\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n adVideoElement.remove();\n adVideoElement = void 0;\n }\n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n adContainerEl = void 0;\n currentAd = void 0;\n listeners.clear();\n prebidManager.destroy();\n prebidInitialized = false;\n },\n isAdPlaying() {\n return adPlaying;\n },\n resize(width, height) {\n console.log(`${LOG} Resizing to ${width}x${height}`);\n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n on(event, listener) {\n if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());\n listeners.get(event).add(listener);\n },\n off(event, listener) {\n listeners.get(event)?.delete(listener);\n },\n updateOriginalMutedState(muted, volume) {\n const nextVolume = typeof volume === \"number\" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;\n console.log(\n `${LOG} updateOriginalMutedState: { muted: ${originalMutedState} -> ${muted}, volume: ${originalVolume} -> ${nextVolume} }`\n );\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n getOriginalMutedState() {\n return originalMutedState;\n },\n getOriginalVolume() {\n return originalVolume;\n },\n setAdVolume(volume) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n }\n },\n getAdVolume() {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n showPlaceholder() {\n contentVideo.style.opacity = \"0\";\n contentVideo.style.visibility = \"hidden\";\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n if (!adPlaying) {\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n }\n }\n };\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createPrebidController\n});\n","import type { ImaController, PrebidConfig } from \"../types\";\nimport type { VastAd, VastMediaFile } from \"./vastParser\";\nimport {\n parseVastXml,\n fetchAndParseVastAd,\n fireTrackingPixels as fireTrackingPixelsShared,\n createEmptyTrackingState,\n} from \"./vastParser\";\nimport { createPrebidManager } from \"./prebid\";\nimport Hls from \"hls.js\";\n\nconst LOG = \"[PrebidController]\";\n\nexport interface PrebidControllerOptions {\n continueLiveStreamDuringAds?: boolean;\n licenseKey?: string;\n mainHlsInstance?: Hls;\n}\n\nexport function createPrebidController(\n contentVideo: HTMLVideoElement,\n prebidConfig: PrebidConfig,\n options?: PrebidControllerOptions\n): ImaController {\n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = new Map<string, Set<(payload?: any) => void>>();\n const licenseKey = options?.licenseKey;\n const mainHlsInstance = options?.mainHlsInstance;\n\n let adVideoElement: HTMLVideoElement | undefined;\n let adHls: Hls | undefined;\n let adContainerEl: HTMLDivElement | undefined;\n let currentAd: VastAd | undefined;\n let sessionId: string | undefined;\n let destroyed = false;\n let trackingFired = createEmptyTrackingState();\n\n const prebidDebug = prebidConfig.debug ?? false;\n const prebidManager = createPrebidManager({\n ...prebidConfig,\n debug: prebidDebug,\n });\n let prebidInitialized = false;\n\n function emit(event: string, payload?: any): void {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`${LOG} Error in event listener for ${event}:`, error);\n }\n }\n }\n\n function generateSessionId(): string {\n return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n function fireTrackingPixels(urls: string[]): void {\n fireTrackingPixelsShared(urls, sessionId, licenseKey, LOG);\n }\n\n function getMainStreamQuality(): {\n width: number;\n height: number;\n bitrate: number;\n } | null {\n if (!mainHlsInstance || !mainHlsInstance.levels) {\n return null;\n }\n\n const currentLevel = mainHlsInstance.currentLevel;\n if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {\n const autoLevel = mainHlsInstance.loadLevel;\n if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {\n const level = mainHlsInstance.levels[autoLevel];\n return {\n width: level.width || 1920,\n height: level.height || 1080,\n bitrate: level.bitrate || 5000000,\n };\n }\n return null;\n }\n\n const level = mainHlsInstance.levels[currentLevel];\n return {\n width: level.width || 1920,\n height: level.height || 1080,\n bitrate: level.bitrate || 5000000,\n };\n }\n\n function selectBestMediaFile(mediaFiles: VastMediaFile[]): VastMediaFile {\n if (mediaFiles.length === 0) {\n throw new Error(\"No media files available\");\n }\n\n const firstFile = mediaFiles[0];\n if (!firstFile) {\n throw new Error(\"No media files available\");\n }\n\n if (mediaFiles.length === 1) {\n return firstFile;\n }\n\n const mainQuality = getMainStreamQuality();\n if (!mainQuality) {\n console.log(`${LOG} No main stream quality info, using first media file`);\n return firstFile;\n }\n\n console.log(`${LOG} Main stream quality:`, mainQuality);\n\n const scoredFiles = mediaFiles.map((file) => {\n const widthDiff = Math.abs(file.width - mainQuality.width);\n const heightDiff = Math.abs(file.height - mainQuality.height);\n const resolutionDiff = widthDiff + heightDiff;\n\n const fileBitrate = (file.bitrate || 5000) * 1000;\n const bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);\n\n const score = resolutionDiff * 2 + bitrateDiff / 1000;\n\n return { file, score, resolutionDiff, bitrateDiff };\n });\n\n scoredFiles.sort((a, b) => a.score - b.score);\n\n const bestMatch = scoredFiles[0];\n if (!bestMatch) {\n console.log(`${LOG} No best match found, using first media file`);\n return firstFile;\n }\n\n console.log(`${LOG} Selected media file:`, {\n url: bestMatch.file.url,\n resolution: `${bestMatch.file.width}x${bestMatch.file.height}`,\n bitrate: bestMatch.file.bitrate,\n score: bestMatch.score,\n });\n\n return bestMatch.file;\n }\n\n function isHlsMediaFile(file: VastMediaFile): boolean {\n return (\n file.type === \"application/x-mpegURL\" || file.type.includes(\"m3u8\")\n );\n }\n\n function createAdVideoElement(): HTMLVideoElement {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.playsInline = true;\n video.muted = false;\n video.volume = 1.0;\n console.log(`${LOG} Created ad video element with volume ${video.volume}`);\n return video;\n }\n\n function setupAdEventListeners(): void {\n if (!adVideoElement || !currentAd) return;\n\n adVideoElement.addEventListener(\"timeupdate\", () => {\n if (!currentAd || !adVideoElement) return;\n\n const progress = adVideoElement.currentTime / currentAd.duration;\n\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.firstQuartile);\n }\n\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels(currentAd.trackingUrls.midpoint);\n }\n\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);\n }\n });\n\n adVideoElement.addEventListener(\"playing\", () => {\n if (!currentAd || trackingFired.start) return;\n trackingFired.start = true;\n fireTrackingPixels(currentAd.trackingUrls.start);\n console.log(`${LOG} Ad started playing`);\n });\n\n adVideoElement.addEventListener(\"ended\", () => {\n if (!currentAd || trackingFired.complete) return;\n trackingFired.complete = true;\n fireTrackingPixels(currentAd.trackingUrls.complete);\n console.log(`${LOG} Ad completed`);\n handleAdComplete();\n });\n\n adVideoElement.addEventListener(\"error\", (e) => {\n console.error(`${LOG} Ad video error:`, e);\n if (currentAd) {\n fireTrackingPixels(currentAd.trackingUrls.error);\n }\n handleAdError();\n });\n\n adVideoElement.addEventListener(\"volumechange\", () => {\n if (!currentAd) return;\n if (adVideoElement!.muted) {\n fireTrackingPixels(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels(currentAd.trackingUrls.unmute);\n }\n });\n\n adVideoElement.addEventListener(\"pause\", () => {\n if (currentAd && !adVideoElement!.ended) {\n fireTrackingPixels(currentAd.trackingUrls.pause);\n }\n });\n\n adVideoElement.addEventListener(\"play\", () => {\n if (currentAd && adVideoElement!.currentTime > 0) {\n fireTrackingPixels(currentAd.trackingUrls.resume);\n }\n });\n }\n\n function setAdPlayingFlag(isPlaying: boolean): void {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n\n function handleAdComplete(): void {\n console.log(`${LOG} Handling ad completion`);\n adPlaying = false;\n setAdPlayingFlag(false);\n\n contentVideo.muted = true;\n contentVideo.volume = 0;\n\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback`\n );\n contentVideo.play().catch(() => {});\n } else {\n console.log(`${LOG} Content video already playing in live mode`);\n }\n }\n\n emit(\"content_resume\");\n }\n\n function handleAdError(): void {\n console.log(`${LOG} Handling ad error`);\n adPlaying = false;\n setAdPlayingFlag(false);\n\n contentVideo.muted = true;\n contentVideo.volume = 0;\n\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n emit(\"ad_error\");\n }\n\n async function ensurePrebidInitialized(): Promise<void> {\n if (prebidInitialized) return;\n\n if (prebidConfig.enabled === false) {\n throw new Error(\"Prebid is disabled in config\");\n }\n\n if (!prebidConfig.ortbRequest?.imp?.length) {\n throw new Error(\"No impressions configured in ortbRequest\");\n }\n\n await prebidManager.initialize();\n prebidInitialized = true;\n console.log(`${LOG} Prebid Server manager initialized`);\n }\n\n async function runPrebidAuction(): Promise<VastAd | null> {\n await ensurePrebidInitialized();\n\n const bids = await prebidManager.requestBids();\n if (bids.length === 0) {\n console.warn(`${LOG} No bids received from Prebid Server`);\n return null;\n }\n\n const cpmFloor = prebidConfig.cpmFloor ?? 0;\n const winner = bids[0]!;\n\n if (cpmFloor > 0 && winner.cpm < cpmFloor) {\n console.log(\n `${LOG} Winning bid $${winner.cpm.toFixed(2)} below CPM floor $${cpmFloor.toFixed(2)}, rejecting`\n );\n return null;\n }\n\n console.log(\n `${LOG} Winning bid: ${winner.bidder} $${winner.cpm.toFixed(2)} ${winner.currency}`\n );\n\n if (winner.vastXml) {\n console.log(`${LOG} Parsing VAST XML from bid response (inline)`);\n return parseVastXml(winner.vastXml, \"mp4-first\", LOG);\n }\n\n if (winner.vastUrl) {\n console.log(`${LOG} Fetching VAST from cached URL: ${winner.vastUrl}`);\n return fetchAndParseVastAd(winner.vastUrl, \"mp4-first\", LOG);\n }\n\n console.warn(`${LOG} Winning bid has no VAST URL or XML`);\n return null;\n }\n\n function startPlayback(mediaFile: VastMediaFile): void {\n if (!adVideoElement) return;\n\n if (isHlsMediaFile(mediaFile)) {\n startHlsPlayback(mediaFile);\n } else {\n startNativePlayback(mediaFile);\n }\n }\n\n function startNativePlayback(mediaFile: VastMediaFile): void {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting native MP4 playback: ${mediaFile.url}`);\n\n adVideoElement.src = mediaFile.url;\n adVideoElement.load();\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native ad playback:`, error);\n handleAdError();\n });\n }\n\n function startHlsPlayback(mediaFile: VastMediaFile): void {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting HLS playback: ${mediaFile.url}`);\n\n if (Hls.isSupported()) {\n if (adHls) {\n adHls.destroy();\n }\n\n adHls = new Hls({\n enableWorker: true,\n lowLatencyMode: false,\n });\n\n adHls.loadSource(mediaFile.url);\n adHls.attachMedia(adVideoElement);\n\n adHls.on(Hls.Events.MANIFEST_PARSED, () => {\n console.log(`${LOG} HLS manifest parsed, starting playback`);\n adVideoElement!.play().catch((error) => {\n console.error(`${LOG} Error starting HLS ad playback:`, error);\n handleAdError();\n });\n });\n\n adHls.on(Hls.Events.ERROR, (_event, data) => {\n console.error(`${LOG} HLS error:`, data);\n if (data.fatal) {\n handleAdError();\n }\n });\n } else if (\n adVideoElement.canPlayType(\"application/vnd.apple.mpegurl\")\n ) {\n adVideoElement.src = mediaFile.url;\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native HLS ad playback:`, error);\n handleAdError();\n });\n } else {\n console.error(`${LOG} HLS not supported on this platform`);\n handleAdError();\n }\n }\n\n return {\n initialize() {\n console.log(`${LOG} Initializing`);\n\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n },\n\n async requestAds(vastTagUrl: string) {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n\n console.log(`${LOG} requestAds called:`, vastTagUrl || \"(empty - will run Prebid auction)\");\n\n if (adPlaying) {\n console.warn(`${LOG} Cannot request new ads while an ad is playing`);\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n\n try {\n sessionId = generateSessionId();\n let ad: VastAd | null;\n\n if (vastTagUrl && vastTagUrl.length > 0) {\n console.log(`${LOG} Fetching VAST from provided URL`);\n ad = await fetchAndParseVastAd(vastTagUrl, \"mp4-first\", LOG);\n } else {\n console.log(`${LOG} Running Prebid Server auction`);\n ad = await runPrebidAuction();\n }\n\n if (!ad) {\n console.warn(`${LOG} No ads available`);\n emit(\"ad_error\");\n return Promise.reject(new Error(\"No ads available\"));\n }\n\n currentAd = ad;\n console.log(\n `${LOG} Ad parsed: ${ad.title}, duration: ${ad.duration}s, mediaFiles: ${ad.mediaFiles.length}`\n );\n\n fireTrackingPixels(ad.trackingUrls.impression);\n trackingFired.impression = true;\n\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error requesting ads:`, error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n\n async play() {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n\n if (!currentAd) {\n console.warn(`${LOG} Cannot play: No ad loaded`);\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n\n console.log(`${LOG} Starting ad playback`);\n\n try {\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n setupAdEventListeners();\n }\n\n trackingFired = {\n ...createEmptyTrackingState(),\n impression: trackingFired.impression,\n };\n\n const contentVolume = contentVideo.volume;\n originalVolume = Math.max(\n 0,\n Math.min(1, contentVolume || originalVolume)\n );\n\n if (!options?.continueLiveStreamDuringAds) {\n contentVideo.pause();\n console.log(`${LOG} Content paused (VOD mode)`);\n } else {\n console.log(`${LOG} Content continues (Live mode)`);\n }\n\n console.log(`${LOG} FORCE MUTING main video`);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n adPlaying = true;\n setAdPlayingFlag(true);\n\n if (adVideoElement) {\n const adVolume = originalMutedState ? 0 : originalVolume;\n adVideoElement.volume = Math.max(0, Math.min(1, adVolume));\n adVideoElement.muted = false;\n console.log(\n `${LOG} Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}`\n );\n }\n\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n\n emit(\"content_pause\");\n\n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available for ad\");\n }\n\n console.log(`${LOG} Loading ad from: ${mediaFile.url}`);\n startPlayback(mediaFile);\n\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error playing ad:`, error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && !adVideoElement.paused) {\n adVideoElement.pause();\n }\n } catch (error) {\n console.warn(`${LOG} Error pausing ad:`, error);\n }\n },\n\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && adVideoElement.paused) {\n adVideoElement.play().catch(() => {});\n }\n } catch (error) {\n console.warn(`${LOG} Error resuming ad:`, error);\n }\n },\n\n async stop() {\n console.log(`${LOG} Stopping ad`);\n adPlaying = false;\n setAdPlayingFlag(false);\n\n const previousMutedState = contentVideo.muted;\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n console.log(\n `${LOG} Restored mute state on stop: ${previousMutedState} -> ${originalMutedState}`\n );\n\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback on stop`\n );\n contentVideo.play().catch(() => {});\n }\n }\n\n if (adHls) {\n adHls.destroy();\n adHls = undefined;\n }\n\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n }\n\n currentAd = undefined;\n },\n\n destroy() {\n console.log(`${LOG} Destroying`);\n destroyed = true;\n\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n\n if (adHls) {\n adHls.destroy();\n adHls = undefined;\n }\n\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n adVideoElement.remove();\n adVideoElement = undefined;\n }\n\n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n\n adContainerEl = undefined;\n currentAd = undefined;\n listeners.clear();\n\n prebidManager.destroy();\n prebidInitialized = false;\n },\n\n isAdPlaying() {\n return adPlaying;\n },\n\n resize(width: number, height: number) {\n console.log(`${LOG} Resizing to ${width}x${height}`);\n\n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n\n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n\n on(event: string, listener: (payload?: any) => void) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(listener);\n },\n\n off(event: string, listener: (payload?: any) => void) {\n listeners.get(event)?.delete(listener);\n },\n\n updateOriginalMutedState(muted: boolean, volume?: number) {\n const nextVolume =\n typeof volume === \"number\" && !Number.isNaN(volume)\n ? Math.max(0, Math.min(1, volume))\n : originalVolume;\n console.log(\n `${LOG} updateOriginalMutedState: { muted: ${originalMutedState} -> ${muted}, volume: ${originalVolume} -> ${nextVolume} }`\n );\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n\n getOriginalMutedState() {\n return originalMutedState;\n },\n\n getOriginalVolume() {\n return originalVolume;\n },\n\n setAdVolume(volume: number) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n }\n },\n\n getAdVolume(): number {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n\n showPlaceholder() {\n contentVideo.style.opacity = \"0\";\n contentVideo.style.visibility = \"hidden\";\n\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n if (!adPlaying) {\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n }\n },\n };\n}\n","export interface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nexport interface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n fullscreen: string[];\n exitFullscreen: string[];\n skip: string[];\n error: string[];\n}\n\nexport interface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport type MediaFileFilter = \"hls-only\" | \"mp4-first\" | \"all\";\n\nfunction isHlsType(type: string): boolean {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\n\nfunction isMp4Type(type: string): boolean {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\n\nexport function parseVastXml(\n xmlString: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): VastAd | null {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n\n const isNoAdAvailable =\n adId === \"empty\" ||\n title.toLowerCase().includes(\"no ad available\") ||\n title.toLowerCase() === \"no ad available\";\n\n const durationText =\n xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n Math.round(parseFloat(durationParts[2] || \"0\"));\n\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : undefined;\n\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : undefined,\n });\n\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n\n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: [],\n };\n\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n\n const clickThrough = xmlDoc\n .querySelector(\"ClickThrough\")\n ?.textContent?.trim();\n\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\nexport async function fetchAndParseVastAd(\n vastTagUrl: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): Promise<VastAd | null> {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2000)\n );\n\n return parseVastXml(vastXml, filter, logPrefix);\n}\n\nexport function createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n licenseKey?: string,\n logPrefix = \"[VastParser]\"\n): void {\n if (!urls || urls.length === 0) return;\n\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n\n if (sessionId) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }session_id=${sessionId}`;\n }\n\n if (licenseKey) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }license_key=${licenseKey}`;\n }\n\n const img = new Image(1, 1);\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n","import type {\n PrebidConfig,\n PrebidBidResponse,\n PrebidManager,\n} from \"../types\";\n\nconst DEFAULT_TIMEOUT_MS = 3000;\nconst AUCTION_PATH = \"/openrtb2/auction\";\n\nexport function createPrebidManager(config: PrebidConfig): PrebidManager {\n let initialized = false;\n let serverUrl = \"\";\n const debug = config.debug ?? false;\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[Prebid]\", ...args);\n }\n }\n\n function warn(...args: any[]): void {\n console.warn(\"[Prebid]\", ...args);\n }\n\n function resolveServerUrl(): string {\n if (config.serverUrl) {\n return config.serverUrl.replace(/\\/$/, \"\");\n }\n\n const extUrl =\n config.ortbRequest?.ext?.prebid?.server?.externalurl;\n if (typeof extUrl === \"string\" && extUrl.length > 0) {\n return extUrl.replace(/\\/$/, \"\");\n }\n\n throw new Error(\n \"Prebid Server URL not configured. Provide serverUrl in PrebidConfig or ext.prebid.server.externalurl in the OpenRTB request.\"\n );\n }\n\n function buildRequest(): Record<string, any> {\n const req = JSON.parse(JSON.stringify(config.ortbRequest));\n\n req.id =\n `${req.id || \"prebid\"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n if (!req.ext) req.ext = {};\n if (!req.ext.prebid) req.ext.prebid = {};\n if (!req.ext.prebid.cache) req.ext.prebid.cache = {};\n if (!req.ext.prebid.cache.vastxml) req.ext.prebid.cache.vastxml = {};\n if (!req.ext.prebid.targeting) {\n req.ext.prebid.targeting = {\n includewinners: true,\n includebidderkeys: false,\n };\n }\n\n if (!req.device) req.device = {};\n if (typeof navigator !== \"undefined\") {\n if (!req.device.ua) req.device.ua = navigator.userAgent;\n if (!req.device.language) {\n req.device.language =\n (navigator.language || \"\").split(\"-\")[0] || \"en\";\n }\n }\n if (typeof window !== \"undefined\") {\n if (!req.device.w) req.device.w = window.screen?.width || window.innerWidth;\n if (!req.device.h) req.device.h = window.screen?.height || window.innerHeight;\n }\n\n if (!req.site) req.site = {};\n if (typeof window !== \"undefined\") {\n if (!req.site.page) req.site.page = window.location.href;\n if (!req.site.domain) req.site.domain = window.location.hostname;\n }\n\n return req;\n }\n\n function parseResponse(data: any): PrebidBidResponse[] {\n const bids: PrebidBidResponse[] = [];\n const seatbids: any[] = data?.seatbid || [];\n const currency: string = data?.cur || \"USD\";\n\n for (const seatbid of seatbids) {\n const seat: string = seatbid.seat || \"unknown\";\n const bidArray: any[] = seatbid.bid || [];\n\n for (const bid of bidArray) {\n const cacheUrl: string | undefined =\n bid.ext?.prebid?.cache?.vastXml?.url;\n const vastXml: string | undefined = bid.adm || undefined;\n\n const bidResponse: PrebidBidResponse = {\n bidder: seat,\n cpm: bid.price || 0,\n width: bid.w || 0,\n height: bid.h || 0,\n adId: bid.id || \"\",\n impId: bid.impid || \"\",\n creativeId: bid.crid || \"\",\n currency,\n };\n if (cacheUrl) bidResponse.vastUrl = cacheUrl;\n if (vastXml) bidResponse.vastXml = vastXml;\n if (bid.adomain) bidResponse.adomain = bid.adomain;\n\n bids.push(bidResponse);\n }\n }\n\n bids.sort((a, b) => b.cpm - a.cpm);\n return bids;\n }\n\n function extractVastUrl(bids: PrebidBidResponse[]): string | null {\n if (bids.length === 0) return null;\n\n const winner = bids[0]!;\n\n const cpmFloor = config.cpmFloor ?? 0;\n if (cpmFloor > 0 && winner.cpm < cpmFloor) {\n log(\n `Winning bid $${winner.cpm.toFixed(2)} below CPM floor $${cpmFloor.toFixed(2)}, rejecting`\n );\n return null;\n }\n\n if (winner.vastUrl) {\n log(\n `Using cached VAST URL from ${winner.bidder} ($${winner.cpm.toFixed(2)} ${winner.currency})`\n );\n return winner.vastUrl;\n }\n\n if (winner.vastXml) {\n log(\n `Creating blob URL from VAST XML (${winner.bidder}, $${winner.cpm.toFixed(2)})`\n );\n try {\n const blob = new Blob([winner.vastXml], { type: \"text/xml\" });\n return URL.createObjectURL(blob);\n } catch (error) {\n warn(\"Failed to create blob URL from VAST XML:\", error);\n }\n }\n\n return null;\n }\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n\n serverUrl = resolveServerUrl();\n\n if (\n !config.ortbRequest?.imp ||\n config.ortbRequest.imp.length === 0\n ) {\n throw new Error(\"No impressions (imp) defined in the OpenRTB request.\");\n }\n\n initialized = true;\n log(\"Initialized with server:\", serverUrl);\n log(\n \"Bidders:\",\n config.ortbRequest.imp\n .map((imp) => {\n const bidders = imp.ext?.prebid?.bidder;\n return bidders ? Object.keys(bidders).join(\", \") : \"none\";\n })\n .join(\"; \")\n );\n }\n\n async function requestBids(): Promise<PrebidBidResponse[]> {\n if (!initialized) {\n throw new Error(\"Prebid not initialized. Call initialize() first.\");\n }\n\n const auctionUrl = `${serverUrl}${AUCTION_PATH}`;\n const request = buildRequest();\n const timeout = config.timeout ?? config.ortbRequest.tmax ?? DEFAULT_TIMEOUT_MS;\n\n log(\"Sending auction request to:\", auctionUrl);\n\n const controller =\n typeof AbortController !== \"undefined\"\n ? new AbortController()\n : null;\n const timeoutId = setTimeout(() => {\n controller?.abort();\n }, timeout + 2000);\n\n try {\n const fetchOptions: RequestInit = {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n };\n if (controller) {\n fetchOptions.signal = controller.signal;\n }\n\n const response = await fetch(auctionUrl, fetchOptions);\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `Prebid Server returned HTTP ${response.status}: ${body.slice(0, 200)}`\n );\n }\n\n const data = await response.json();\n\n if (debug && data?.ext?.responsetimemillis) {\n log(\"Bidder response times:\", data.ext.responsetimemillis);\n }\n if (debug && data?.ext?.errors) {\n warn(\"Auction errors:\", data.ext.errors);\n }\n\n const bids = parseResponse(data);\n log(`Received ${bids.length} bid(s)`);\n\n if (debug) {\n for (const b of bids) {\n log(\n ` ${b.bidder}: $${b.cpm.toFixed(2)} ${b.currency}` +\n ` ${b.width}x${b.height}` +\n (b.vastUrl ? \" [cached VAST]\" : \"\") +\n (b.vastXml && !b.vastUrl ? \" [VAST XML]\" : \"\")\n );\n }\n }\n\n return bids;\n } catch (error: any) {\n clearTimeout(timeoutId);\n\n if (error?.name === \"AbortError\") {\n warn(`Auction request timed out after ${timeout + 2000}ms`);\n return [];\n }\n\n throw error;\n }\n }\n\n async function getVastUrl(): Promise<string | null> {\n try {\n const bids = await requestBids();\n return extractVastUrl(bids);\n } catch (error) {\n warn(\"Failed to get VAST URL:\", error);\n return null;\n }\n }\n\n function destroy(): void {\n initialized = false;\n serverUrl = \"\";\n log(\"Destroyed\");\n }\n\n return {\n initialize,\n requestBids,\n getVastUrl,\n destroy,\n get isInitialized() {\n return initialized;\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/prebidController.cjs","../../src/sdk/prebidController.ts","../../src/sdk/vastParser.ts","../../src/sdk/prebid.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","prebidController_exports","createPrebidController","exports","isHlsType","type","includes","isMp4Type","parseVastXml","xmlString","filter","logPrefix","xmlDoc","parser","DOMParser","parseFromString","parserError","querySelector","console","error","textContent","adElement","isMp4","durationText","mediaFileElements","url","bitrateAttr","mf","getAttribute","warn","adId","title","durationParts","split","duration","parseInt","Math","round","parseFloat","querySelectorAll","mediaFiles","log","length","index","forEach","trim","width","height","isHls","accepted","bitrateValue","push","substring","aIsMp4","a","thirdQuartile","el","sort","b","bIsMp4","isNoAdAvailable","trackingUrls","impression","start","firstQuartile","midpoint","mute","unmute","pause","resume","exitFullscreen","skip","event","eventKey","clickThrough","id","fetchAndParseVastAd","vastTagUrl","response","vastXml","mode","credentials","headers","Accept","referrerPolicy","ok","Error","statusText","text","createEmptyTrackingState","complete","fireTrackingPixels","urls","sessionId","licenseKey","trackingUrl","img","Image","src","DEFAULT_TIMEOUT_MS","AUCTION_URL","createPrebidManager","options","initialized","debug","args","parseResponse","data","bids","seatbids","seatbid","currency","cur","seat","bidArray","bid","cacheUrl","ext","prebid","cache","adm","bidResponse","bidder","cpm","price","w","h","impId","impid","creativeId","crid","vastUrl","adomain"],"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/sdk/prebidController.ts\nvar prebidController_exports = {};\n__export(prebidController_exports, {\n createPrebidController: () => createPrebidController\n});\nmodule.exports = __toCommonJS(prebidController_exports);\n\n// src/sdk/vastParser.ts\nfunction isHlsType(type) {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\nfunction isMp4Type(type) {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\nfunction parseVastXml(xmlString, filter = \"all\", logPrefix = \"[VastParser]\") {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const isNoAdAvailable = adId === \"empty\" || title.toLowerCase().includes(\"no ad available\") || title.toLowerCase() === \"no ad available\";\n const durationText = xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + Math.round(parseFloat(durationParts[2] || \"0\"));\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0\n });\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: []\n };\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = xmlDoc.querySelector(\"ClickThrough\")?.textContent?.trim();\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\nasync function fetchAndParseVastAd(vastTagUrl, filter = \"all\", logPrefix = \"[VastParser]\") {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\"\n },\n referrerPolicy: \"no-referrer-when-downgrade\"\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2e3)\n );\n return parseVastXml(vastXml, filter, logPrefix);\n}\nfunction createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n}\nfunction fireTrackingPixels(urls, sessionId, licenseKey, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n if (licenseKey) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}license_key=${licenseKey}`;\n }\n const img = new Image(1, 1);\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n\n// src/sdk/prebid.ts\nvar DEFAULT_TIMEOUT_MS = 3e3;\nvar AUCTION_URL = \"https://sspproxy.adstorm.co/openrtb2/auction/adstorm\";\nfunction createPrebidManager(options = {}) {\n let initialized = false;\n const debug = options.debug ?? false;\n function log(...args) {\n if (debug) {\n console.log(\"[Prebid]\", ...args);\n }\n }\n function warn(...args) {\n console.warn(\"[Prebid]\", ...args);\n }\n function parseResponse(data) {\n const bids = [];\n const seatbids = data?.seatbid || [];\n const currency = data?.cur || \"USD\";\n for (const seatbid of seatbids) {\n const seat = seatbid.seat || \"unknown\";\n const bidArray = seatbid.bid || [];\n for (const bid of bidArray) {\n const cacheUrl = bid.ext?.prebid?.cache?.vastXml?.url;\n const vastXml = bid.adm || void 0;\n const bidResponse = {\n bidder: seat,\n cpm: bid.price || 0,\n width: bid.w || 0,\n height: bid.h || 0,\n adId: bid.id || \"\",\n impId: bid.impid || \"\",\n creativeId: bid.crid || \"\",\n currency\n };\n if (cacheUrl) bidResponse.vastUrl = cacheUrl;\n if (vastXml) bidResponse.vastXml = vastXml;\n if (bid.adomain) bidResponse.adomain = bid.adomain;\n bids.push(bidResponse);\n }\n }\n bids.sort((a, b) => b.cpm - a.cpm);\n return bids;\n }\n function extractVastUrl(bids) {\n if (bids.length === 0) return null;\n const winner = bids[0];\n if (winner.vastUrl) {\n log(\n `Using cached VAST URL from ${winner.bidder} ($${winner.cpm.toFixed(2)} ${winner.currency})`\n );\n return winner.vastUrl;\n }\n if (winner.vastXml) {\n log(\n `Creating blob URL from VAST XML (${winner.bidder}, $${winner.cpm.toFixed(2)})`\n );\n try {\n const blob = new Blob([winner.vastXml], { type: \"text/xml\" });\n return URL.createObjectURL(blob);\n } catch (error) {\n warn(\"Failed to create blob URL from VAST XML:\", error);\n }\n }\n return null;\n }\n async function initialize() {\n if (initialized) return;\n initialized = true;\n log(\"Initialized, auction URL:\", AUCTION_URL);\n }\n async function requestBids() {\n if (!initialized) {\n throw new Error(\"Prebid not initialized. Call initialize() first.\");\n }\n const timeout = DEFAULT_TIMEOUT_MS;\n log(\"Fetching auction response from:\", AUCTION_URL);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => {\n controller?.abort();\n }, timeout + 2e3);\n try {\n const fetchOptions = {\n method: \"POST\"\n };\n if (controller) {\n fetchOptions.signal = controller.signal;\n }\n const response = await fetch(AUCTION_URL, fetchOptions);\n clearTimeout(timeoutId);\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `Prebid Server returned HTTP ${response.status}: ${body.slice(0, 200)}`\n );\n }\n const data = await response.json();\n if (debug && data?.ext?.responsetimemillis) {\n log(\"Bidder response times:\", data.ext.responsetimemillis);\n }\n if (debug && data?.ext?.errors) {\n warn(\"Auction errors:\", data.ext.errors);\n }\n const bids = parseResponse(data);\n log(`Received ${bids.length} bid(s)`);\n if (debug) {\n for (const b of bids) {\n log(\n ` ${b.bidder}: $${b.cpm.toFixed(2)} ${b.currency} ${b.width}x${b.height}` + (b.vastUrl ? \" [cached VAST]\" : \"\") + (b.vastXml && !b.vastUrl ? \" [VAST XML]\" : \"\")\n );\n }\n }\n return bids;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`Auction request timed out after ${timeout + 2e3}ms`);\n return [];\n }\n throw error;\n }\n }\n async function getVastUrl() {\n try {\n const bids = await requestBids();\n return extractVastUrl(bids);\n } catch (error) {\n warn(\"Failed to get VAST URL:\", error);\n return null;\n }\n }\n function destroy() {\n initialized = false;\n log(\"Destroyed\");\n }\n return {\n initialize,\n requestBids,\n getVastUrl,\n destroy,\n get isInitialized() {\n return initialized;\n }\n };\n}\n\n// src/sdk/prebidController.ts\nvar import_hls = __toESM(require(\"hls.js\"), 1);\nvar LOG = \"[PrebidController]\";\nfunction createPrebidController(contentVideo, options) {\n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = /* @__PURE__ */ new Map();\n const licenseKey = options?.licenseKey;\n const mainHlsInstance = options?.mainHlsInstance;\n let adVideoElement;\n let adHls;\n let adContainerEl;\n let currentAd;\n let sessionId;\n let destroyed = false;\n let trackingFired = createEmptyTrackingState();\n const prebidManager = createPrebidManager(\n options?.debug !== void 0 ? { debug: options.debug } : {}\n );\n let prebidInitialized = false;\n function emit(event, payload) {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`${LOG} Error in event listener for ${event}:`, error);\n }\n }\n }\n function generateSessionId() {\n return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n function fireTrackingPixels2(urls) {\n fireTrackingPixels(urls, sessionId, licenseKey, LOG);\n }\n function getMainStreamQuality() {\n if (!mainHlsInstance || !mainHlsInstance.levels) {\n return null;\n }\n const currentLevel = mainHlsInstance.currentLevel;\n if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {\n const autoLevel = mainHlsInstance.loadLevel;\n if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {\n const level2 = mainHlsInstance.levels[autoLevel];\n return {\n width: level2.width || 1920,\n height: level2.height || 1080,\n bitrate: level2.bitrate || 5e6\n };\n }\n return null;\n }\n const level = mainHlsInstance.levels[currentLevel];\n return {\n width: level.width || 1920,\n height: level.height || 1080,\n bitrate: level.bitrate || 5e6\n };\n }\n function selectBestMediaFile(mediaFiles) {\n if (mediaFiles.length === 0) {\n throw new Error(\"No media files available\");\n }\n const firstFile = mediaFiles[0];\n if (!firstFile) {\n throw new Error(\"No media files available\");\n }\n if (mediaFiles.length === 1) {\n return firstFile;\n }\n const mainQuality = getMainStreamQuality();\n if (!mainQuality) {\n console.log(`${LOG} No main stream quality info, using first media file`);\n return firstFile;\n }\n console.log(`${LOG} Main stream quality:`, mainQuality);\n const scoredFiles = mediaFiles.map((file) => {\n const widthDiff = Math.abs(file.width - mainQuality.width);\n const heightDiff = Math.abs(file.height - mainQuality.height);\n const resolutionDiff = widthDiff + heightDiff;\n const fileBitrate = (file.bitrate || 5e3) * 1e3;\n const bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);\n const score = resolutionDiff * 2 + bitrateDiff / 1e3;\n return { file, score, resolutionDiff, bitrateDiff };\n });\n scoredFiles.sort((a, b) => a.score - b.score);\n const bestMatch = scoredFiles[0];\n if (!bestMatch) {\n console.log(`${LOG} No best match found, using first media file`);\n return firstFile;\n }\n console.log(`${LOG} Selected media file:`, {\n url: bestMatch.file.url,\n resolution: `${bestMatch.file.width}x${bestMatch.file.height}`,\n bitrate: bestMatch.file.bitrate,\n score: bestMatch.score\n });\n return bestMatch.file;\n }\n function isHlsMediaFile(file) {\n return file.type === \"application/x-mpegURL\" || file.type.includes(\"m3u8\");\n }\n function createAdVideoElement() {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.playsInline = true;\n video.muted = false;\n video.volume = 1;\n console.log(`${LOG} Created ad video element with volume ${video.volume}`);\n return video;\n }\n function setupAdEventListeners() {\n if (!adVideoElement || !currentAd) return;\n adVideoElement.addEventListener(\"timeupdate\", () => {\n if (!currentAd || !adVideoElement) return;\n const progress = adVideoElement.currentTime / currentAd.duration;\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.firstQuartile);\n }\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels2(currentAd.trackingUrls.midpoint);\n }\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels2(currentAd.trackingUrls.thirdQuartile);\n }\n });\n adVideoElement.addEventListener(\"playing\", () => {\n if (!currentAd || trackingFired.start) return;\n trackingFired.start = true;\n fireTrackingPixels2(currentAd.trackingUrls.start);\n console.log(`${LOG} Ad started playing`);\n });\n adVideoElement.addEventListener(\"ended\", () => {\n if (!currentAd || trackingFired.complete) return;\n trackingFired.complete = true;\n fireTrackingPixels2(currentAd.trackingUrls.complete);\n console.log(`${LOG} Ad completed`);\n handleAdComplete();\n });\n adVideoElement.addEventListener(\"error\", (e) => {\n console.error(`${LOG} Ad video error:`, e);\n if (currentAd) {\n fireTrackingPixels2(currentAd.trackingUrls.error);\n }\n handleAdError();\n });\n adVideoElement.addEventListener(\"volumechange\", () => {\n if (!currentAd) return;\n if (adVideoElement.muted) {\n fireTrackingPixels2(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels2(currentAd.trackingUrls.unmute);\n }\n });\n adVideoElement.addEventListener(\"pause\", () => {\n if (currentAd && !adVideoElement.ended) {\n fireTrackingPixels2(currentAd.trackingUrls.pause);\n }\n });\n adVideoElement.addEventListener(\"play\", () => {\n if (currentAd && adVideoElement.currentTime > 0) {\n fireTrackingPixels2(currentAd.trackingUrls.resume);\n }\n });\n }\n function setAdPlayingFlag(isPlaying) {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n function handleAdComplete() {\n console.log(`${LOG} Handling ad completion`);\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback`\n );\n contentVideo.play().catch(() => {\n });\n } else {\n console.log(`${LOG} Content video already playing in live mode`);\n }\n }\n emit(\"content_resume\");\n }\n function handleAdError() {\n console.log(`${LOG} Handling ad error`);\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n emit(\"ad_error\");\n }\n async function ensurePrebidInitialized() {\n if (prebidInitialized) return;\n await prebidManager.initialize();\n prebidInitialized = true;\n console.log(`${LOG} Prebid Server manager initialized`);\n }\n async function runPrebidAuction() {\n await ensurePrebidInitialized();\n const bids = await prebidManager.requestBids();\n if (bids.length === 0) {\n console.warn(`${LOG} No bids received from Prebid Server`);\n return null;\n }\n const winner = bids[0];\n console.log(\n `${LOG} Winning bid: ${winner.bidder} $${winner.cpm.toFixed(2)} ${winner.currency}`\n );\n if (winner.vastXml) {\n console.log(`${LOG} Parsing VAST XML from bid response (inline)`);\n return parseVastXml(winner.vastXml, \"mp4-first\", LOG);\n }\n if (winner.vastUrl) {\n console.log(`${LOG} Fetching VAST from cached URL: ${winner.vastUrl}`);\n return fetchAndParseVastAd(winner.vastUrl, \"mp4-first\", LOG);\n }\n console.warn(`${LOG} Winning bid has no VAST URL or XML`);\n return null;\n }\n function startPlayback(mediaFile) {\n if (!adVideoElement) return;\n if (isHlsMediaFile(mediaFile)) {\n startHlsPlayback(mediaFile);\n } else {\n startNativePlayback(mediaFile);\n }\n }\n function startNativePlayback(mediaFile) {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting native MP4 playback: ${mediaFile.url}`);\n adVideoElement.src = mediaFile.url;\n adVideoElement.load();\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native ad playback:`, error);\n handleAdError();\n });\n }\n function startHlsPlayback(mediaFile) {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting HLS playback: ${mediaFile.url}`);\n if (import_hls.default.isSupported()) {\n if (adHls) {\n adHls.destroy();\n }\n adHls = new import_hls.default({\n enableWorker: true,\n lowLatencyMode: false\n });\n adHls.loadSource(mediaFile.url);\n adHls.attachMedia(adVideoElement);\n adHls.on(import_hls.default.Events.MANIFEST_PARSED, () => {\n console.log(`${LOG} HLS manifest parsed, starting playback`);\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting HLS ad playback:`, error);\n handleAdError();\n });\n });\n adHls.on(import_hls.default.Events.ERROR, (_event, data) => {\n console.error(`${LOG} HLS error:`, data);\n if (data.fatal) {\n handleAdError();\n }\n });\n } else if (adVideoElement.canPlayType(\"application/vnd.apple.mpegurl\")) {\n adVideoElement.src = mediaFile.url;\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native HLS ad playback:`, error);\n handleAdError();\n });\n } else {\n console.error(`${LOG} HLS not supported on this platform`);\n handleAdError();\n }\n }\n return {\n initialize() {\n console.log(`${LOG} Initializing`);\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n },\n async requestAds(vastTagUrl) {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n console.log(`${LOG} requestAds called:`, vastTagUrl || \"(empty - will run Prebid auction)\");\n if (adPlaying) {\n console.warn(`${LOG} Cannot request new ads while an ad is playing`);\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n try {\n sessionId = generateSessionId();\n let ad;\n if (vastTagUrl && vastTagUrl.length > 0) {\n console.log(`${LOG} Fetching VAST from provided URL`);\n ad = await fetchAndParseVastAd(vastTagUrl, \"mp4-first\", LOG);\n } else {\n console.log(`${LOG} Running Prebid Server auction`);\n ad = await runPrebidAuction();\n }\n if (!ad) {\n console.warn(`${LOG} No ads available`);\n emit(\"ad_error\");\n return Promise.reject(new Error(\"No ads available\"));\n }\n currentAd = ad;\n console.log(\n `${LOG} Ad parsed: ${ad.title}, duration: ${ad.duration}s, mediaFiles: ${ad.mediaFiles.length}`\n );\n fireTrackingPixels2(ad.trackingUrls.impression);\n trackingFired.impression = true;\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error requesting ads:`, error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n async play() {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n if (!currentAd) {\n console.warn(`${LOG} Cannot play: No ad loaded`);\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n console.log(`${LOG} Starting ad playback`);\n try {\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n setupAdEventListeners();\n }\n trackingFired = {\n ...createEmptyTrackingState(),\n impression: trackingFired.impression\n };\n const contentVolume = contentVideo.volume;\n originalVolume = Math.max(\n 0,\n Math.min(1, contentVolume || originalVolume)\n );\n if (!options?.continueLiveStreamDuringAds) {\n contentVideo.pause();\n console.log(`${LOG} Content paused (VOD mode)`);\n } else {\n console.log(`${LOG} Content continues (Live mode)`);\n }\n console.log(`${LOG} FORCE MUTING main video`);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n adPlaying = true;\n setAdPlayingFlag(true);\n if (adVideoElement) {\n const adVolume = originalMutedState ? 0 : originalVolume;\n adVideoElement.volume = Math.max(0, Math.min(1, adVolume));\n adVideoElement.muted = false;\n console.log(\n `${LOG} Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}`\n );\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n emit(\"content_pause\");\n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available for ad\");\n }\n console.log(`${LOG} Loading ad from: ${mediaFile.url}`);\n startPlayback(mediaFile);\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error playing ad:`, error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && !adVideoElement.paused) {\n adVideoElement.pause();\n }\n } catch (error) {\n console.warn(`${LOG} Error pausing ad:`, error);\n }\n },\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && adVideoElement.paused) {\n adVideoElement.play().catch(() => {\n });\n }\n } catch (error) {\n console.warn(`${LOG} Error resuming ad:`, error);\n }\n },\n async stop() {\n console.log(`${LOG} Stopping ad`);\n adPlaying = false;\n setAdPlayingFlag(false);\n const previousMutedState = contentVideo.muted;\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n console.log(\n `${LOG} Restored mute state on stop: ${previousMutedState} -> ${originalMutedState}`\n );\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback on stop`\n );\n contentVideo.play().catch(() => {\n });\n }\n }\n if (adHls) {\n adHls.destroy();\n adHls = void 0;\n }\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n }\n currentAd = void 0;\n },\n destroy() {\n console.log(`${LOG} Destroying`);\n destroyed = true;\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n if (adHls) {\n adHls.destroy();\n adHls = void 0;\n }\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n adVideoElement.remove();\n adVideoElement = void 0;\n }\n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n adContainerEl = void 0;\n currentAd = void 0;\n listeners.clear();\n prebidManager.destroy();\n prebidInitialized = false;\n },\n isAdPlaying() {\n return adPlaying;\n },\n resize(width, height) {\n console.log(`${LOG} Resizing to ${width}x${height}`);\n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n on(event, listener) {\n if (!listeners.has(event)) listeners.set(event, /* @__PURE__ */ new Set());\n listeners.get(event).add(listener);\n },\n off(event, listener) {\n listeners.get(event)?.delete(listener);\n },\n updateOriginalMutedState(muted, volume) {\n const nextVolume = typeof volume === \"number\" && !Number.isNaN(volume) ? Math.max(0, Math.min(1, volume)) : originalVolume;\n console.log(\n `${LOG} updateOriginalMutedState: { muted: ${originalMutedState} -> ${muted}, volume: ${originalVolume} -> ${nextVolume} }`\n );\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n getOriginalMutedState() {\n return originalMutedState;\n },\n getOriginalVolume() {\n return originalVolume;\n },\n setAdVolume(volume) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n }\n },\n getAdVolume() {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n showPlaceholder() {\n contentVideo.style.opacity = \"0\";\n contentVideo.style.visibility = \"hidden\";\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n if (!adPlaying) {\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n }\n }\n };\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createPrebidController\n});\n","import type { ImaController } from \"../types\";\nimport type { VastAd, VastMediaFile } from \"./vastParser\";\nimport {\n parseVastXml,\n fetchAndParseVastAd,\n fireTrackingPixels as fireTrackingPixelsShared,\n createEmptyTrackingState,\n} from \"./vastParser\";\nimport { createPrebidManager } from \"./prebid\";\nimport Hls from \"hls.js\";\n\nconst LOG = \"[PrebidController]\";\n\nexport interface PrebidControllerOptions {\n continueLiveStreamDuringAds?: boolean;\n licenseKey?: string;\n mainHlsInstance?: Hls;\n debug?: boolean;\n}\n\nexport function createPrebidController(\n contentVideo: HTMLVideoElement,\n options?: PrebidControllerOptions\n): ImaController {\n let adPlaying = false;\n let originalMutedState = false;\n let originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));\n const listeners = new Map<string, Set<(payload?: any) => void>>();\n const licenseKey = options?.licenseKey;\n const mainHlsInstance = options?.mainHlsInstance;\n\n let adVideoElement: HTMLVideoElement | undefined;\n let adHls: Hls | undefined;\n let adContainerEl: HTMLDivElement | undefined;\n let currentAd: VastAd | undefined;\n let sessionId: string | undefined;\n let destroyed = false;\n let trackingFired = createEmptyTrackingState();\n\n const prebidManager = createPrebidManager(\n options?.debug !== undefined ? { debug: options.debug } : {}\n );\n let prebidInitialized = false;\n\n function emit(event: string, payload?: any): void {\n const set = listeners.get(event);\n if (!set) return;\n for (const fn of Array.from(set)) {\n try {\n fn(payload);\n } catch (error) {\n console.warn(`${LOG} Error in event listener for ${event}:`, error);\n }\n }\n }\n\n function generateSessionId(): string {\n return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n function fireTrackingPixels(urls: string[]): void {\n fireTrackingPixelsShared(urls, sessionId, licenseKey, LOG);\n }\n\n function getMainStreamQuality(): {\n width: number;\n height: number;\n bitrate: number;\n } | null {\n if (!mainHlsInstance || !mainHlsInstance.levels) {\n return null;\n }\n\n const currentLevel = mainHlsInstance.currentLevel;\n if (currentLevel === -1 || !mainHlsInstance.levels[currentLevel]) {\n const autoLevel = mainHlsInstance.loadLevel;\n if (autoLevel !== -1 && mainHlsInstance.levels[autoLevel]) {\n const level = mainHlsInstance.levels[autoLevel];\n return {\n width: level.width || 1920,\n height: level.height || 1080,\n bitrate: level.bitrate || 5000000,\n };\n }\n return null;\n }\n\n const level = mainHlsInstance.levels[currentLevel];\n return {\n width: level.width || 1920,\n height: level.height || 1080,\n bitrate: level.bitrate || 5000000,\n };\n }\n\n function selectBestMediaFile(mediaFiles: VastMediaFile[]): VastMediaFile {\n if (mediaFiles.length === 0) {\n throw new Error(\"No media files available\");\n }\n\n const firstFile = mediaFiles[0];\n if (!firstFile) {\n throw new Error(\"No media files available\");\n }\n\n if (mediaFiles.length === 1) {\n return firstFile;\n }\n\n const mainQuality = getMainStreamQuality();\n if (!mainQuality) {\n console.log(`${LOG} No main stream quality info, using first media file`);\n return firstFile;\n }\n\n console.log(`${LOG} Main stream quality:`, mainQuality);\n\n const scoredFiles = mediaFiles.map((file) => {\n const widthDiff = Math.abs(file.width - mainQuality.width);\n const heightDiff = Math.abs(file.height - mainQuality.height);\n const resolutionDiff = widthDiff + heightDiff;\n\n const fileBitrate = (file.bitrate || 5000) * 1000;\n const bitrateDiff = Math.abs(fileBitrate - mainQuality.bitrate);\n\n const score = resolutionDiff * 2 + bitrateDiff / 1000;\n\n return { file, score, resolutionDiff, bitrateDiff };\n });\n\n scoredFiles.sort((a, b) => a.score - b.score);\n\n const bestMatch = scoredFiles[0];\n if (!bestMatch) {\n console.log(`${LOG} No best match found, using first media file`);\n return firstFile;\n }\n\n console.log(`${LOG} Selected media file:`, {\n url: bestMatch.file.url,\n resolution: `${bestMatch.file.width}x${bestMatch.file.height}`,\n bitrate: bestMatch.file.bitrate,\n score: bestMatch.score,\n });\n\n return bestMatch.file;\n }\n\n function isHlsMediaFile(file: VastMediaFile): boolean {\n return (\n file.type === \"application/x-mpegURL\" || file.type.includes(\"m3u8\")\n );\n }\n\n function createAdVideoElement(): HTMLVideoElement {\n const video = document.createElement(\"video\");\n video.style.position = \"absolute\";\n video.style.left = \"0\";\n video.style.top = \"0\";\n video.style.width = \"100%\";\n video.style.height = \"100%\";\n video.style.objectFit = \"contain\";\n video.style.backgroundColor = \"#000\";\n video.playsInline = true;\n video.muted = false;\n video.volume = 1.0;\n console.log(`${LOG} Created ad video element with volume ${video.volume}`);\n return video;\n }\n\n function setupAdEventListeners(): void {\n if (!adVideoElement || !currentAd) return;\n\n adVideoElement.addEventListener(\"timeupdate\", () => {\n if (!currentAd || !adVideoElement) return;\n\n const progress = adVideoElement.currentTime / currentAd.duration;\n\n if (progress >= 0.25 && !trackingFired.firstQuartile) {\n trackingFired.firstQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.firstQuartile);\n }\n\n if (progress >= 0.5 && !trackingFired.midpoint) {\n trackingFired.midpoint = true;\n fireTrackingPixels(currentAd.trackingUrls.midpoint);\n }\n\n if (progress >= 0.75 && !trackingFired.thirdQuartile) {\n trackingFired.thirdQuartile = true;\n fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);\n }\n });\n\n adVideoElement.addEventListener(\"playing\", () => {\n if (!currentAd || trackingFired.start) return;\n trackingFired.start = true;\n fireTrackingPixels(currentAd.trackingUrls.start);\n console.log(`${LOG} Ad started playing`);\n });\n\n adVideoElement.addEventListener(\"ended\", () => {\n if (!currentAd || trackingFired.complete) return;\n trackingFired.complete = true;\n fireTrackingPixels(currentAd.trackingUrls.complete);\n console.log(`${LOG} Ad completed`);\n handleAdComplete();\n });\n\n adVideoElement.addEventListener(\"error\", (e) => {\n console.error(`${LOG} Ad video error:`, e);\n if (currentAd) {\n fireTrackingPixels(currentAd.trackingUrls.error);\n }\n handleAdError();\n });\n\n adVideoElement.addEventListener(\"volumechange\", () => {\n if (!currentAd) return;\n if (adVideoElement!.muted) {\n fireTrackingPixels(currentAd.trackingUrls.mute);\n } else {\n fireTrackingPixels(currentAd.trackingUrls.unmute);\n }\n });\n\n adVideoElement.addEventListener(\"pause\", () => {\n if (currentAd && !adVideoElement!.ended) {\n fireTrackingPixels(currentAd.trackingUrls.pause);\n }\n });\n\n adVideoElement.addEventListener(\"play\", () => {\n if (currentAd && adVideoElement!.currentTime > 0) {\n fireTrackingPixels(currentAd.trackingUrls.resume);\n }\n });\n }\n\n function setAdPlayingFlag(isPlaying: boolean): void {\n if (isPlaying) {\n contentVideo.dataset.stormcloudAdPlaying = \"true\";\n } else {\n delete contentVideo.dataset.stormcloudAdPlaying;\n }\n }\n\n function handleAdComplete(): void {\n console.log(`${LOG} Handling ad completion`);\n adPlaying = false;\n setAdPlayingFlag(false);\n\n contentVideo.muted = true;\n contentVideo.volume = 0;\n\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback`\n );\n contentVideo.play().catch(() => {});\n } else {\n console.log(`${LOG} Content video already playing in live mode`);\n }\n }\n\n emit(\"content_resume\");\n }\n\n function handleAdError(): void {\n console.log(`${LOG} Handling ad error`);\n adPlaying = false;\n setAdPlayingFlag(false);\n\n contentVideo.muted = true;\n contentVideo.volume = 0;\n\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n emit(\"ad_error\");\n }\n\n async function ensurePrebidInitialized(): Promise<void> {\n if (prebidInitialized) return;\n await prebidManager.initialize();\n prebidInitialized = true;\n console.log(`${LOG} Prebid Server manager initialized`);\n }\n\n async function runPrebidAuction(): Promise<VastAd | null> {\n await ensurePrebidInitialized();\n\n const bids = await prebidManager.requestBids();\n if (bids.length === 0) {\n console.warn(`${LOG} No bids received from Prebid Server`);\n return null;\n }\n\n const winner = bids[0]!;\n\n console.log(\n `${LOG} Winning bid: ${winner.bidder} $${winner.cpm.toFixed(2)} ${winner.currency}`\n );\n\n if (winner.vastXml) {\n console.log(`${LOG} Parsing VAST XML from bid response (inline)`);\n return parseVastXml(winner.vastXml, \"mp4-first\", LOG);\n }\n\n if (winner.vastUrl) {\n console.log(`${LOG} Fetching VAST from cached URL: ${winner.vastUrl}`);\n return fetchAndParseVastAd(winner.vastUrl, \"mp4-first\", LOG);\n }\n\n console.warn(`${LOG} Winning bid has no VAST URL or XML`);\n return null;\n }\n\n function startPlayback(mediaFile: VastMediaFile): void {\n if (!adVideoElement) return;\n\n if (isHlsMediaFile(mediaFile)) {\n startHlsPlayback(mediaFile);\n } else {\n startNativePlayback(mediaFile);\n }\n }\n\n function startNativePlayback(mediaFile: VastMediaFile): void {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting native MP4 playback: ${mediaFile.url}`);\n\n adVideoElement.src = mediaFile.url;\n adVideoElement.load();\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native ad playback:`, error);\n handleAdError();\n });\n }\n\n function startHlsPlayback(mediaFile: VastMediaFile): void {\n if (!adVideoElement) return;\n console.log(`${LOG} Starting HLS playback: ${mediaFile.url}`);\n\n if (Hls.isSupported()) {\n if (adHls) {\n adHls.destroy();\n }\n\n adHls = new Hls({\n enableWorker: true,\n lowLatencyMode: false,\n });\n\n adHls.loadSource(mediaFile.url);\n adHls.attachMedia(adVideoElement);\n\n adHls.on(Hls.Events.MANIFEST_PARSED, () => {\n console.log(`${LOG} HLS manifest parsed, starting playback`);\n adVideoElement!.play().catch((error) => {\n console.error(`${LOG} Error starting HLS ad playback:`, error);\n handleAdError();\n });\n });\n\n adHls.on(Hls.Events.ERROR, (_event, data) => {\n console.error(`${LOG} HLS error:`, data);\n if (data.fatal) {\n handleAdError();\n }\n });\n } else if (\n adVideoElement.canPlayType(\"application/vnd.apple.mpegurl\")\n ) {\n adVideoElement.src = mediaFile.url;\n adVideoElement.play().catch((error) => {\n console.error(`${LOG} Error starting native HLS ad playback:`, error);\n handleAdError();\n });\n } else {\n console.error(`${LOG} HLS not supported on this platform`);\n handleAdError();\n }\n }\n\n return {\n initialize() {\n console.log(`${LOG} Initializing`);\n\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n },\n\n async requestAds(vastTagUrl: string) {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n\n console.log(`${LOG} requestAds called:`, vastTagUrl || \"(empty - will run Prebid auction)\");\n\n if (adPlaying) {\n console.warn(`${LOG} Cannot request new ads while an ad is playing`);\n return Promise.reject(new Error(\"Ad already playing\"));\n }\n\n try {\n sessionId = generateSessionId();\n let ad: VastAd | null;\n\n if (vastTagUrl && vastTagUrl.length > 0) {\n console.log(`${LOG} Fetching VAST from provided URL`);\n ad = await fetchAndParseVastAd(vastTagUrl, \"mp4-first\", LOG);\n } else {\n console.log(`${LOG} Running Prebid Server auction`);\n ad = await runPrebidAuction();\n }\n\n if (!ad) {\n console.warn(`${LOG} No ads available`);\n emit(\"ad_error\");\n return Promise.reject(new Error(\"No ads available\"));\n }\n\n currentAd = ad;\n console.log(\n `${LOG} Ad parsed: ${ad.title}, duration: ${ad.duration}s, mediaFiles: ${ad.mediaFiles.length}`\n );\n\n fireTrackingPixels(ad.trackingUrls.impression);\n trackingFired.impression = true;\n\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error requesting ads:`, error);\n emit(\"ad_error\");\n return Promise.reject(error);\n }\n },\n\n async play() {\n if (destroyed) {\n return Promise.reject(new Error(\"Controller has been destroyed\"));\n }\n\n if (!currentAd) {\n console.warn(`${LOG} Cannot play: No ad loaded`);\n return Promise.reject(new Error(\"No ad loaded\"));\n }\n\n console.log(`${LOG} Starting ad playback`);\n\n try {\n if (!adVideoElement) {\n adVideoElement = createAdVideoElement();\n adContainerEl?.appendChild(adVideoElement);\n setupAdEventListeners();\n }\n\n trackingFired = {\n ...createEmptyTrackingState(),\n impression: trackingFired.impression,\n };\n\n const contentVolume = contentVideo.volume;\n originalVolume = Math.max(\n 0,\n Math.min(1, contentVolume || originalVolume)\n );\n\n if (!options?.continueLiveStreamDuringAds) {\n contentVideo.pause();\n console.log(`${LOG} Content paused (VOD mode)`);\n } else {\n console.log(`${LOG} Content continues (Live mode)`);\n }\n\n console.log(`${LOG} FORCE MUTING main video`);\n contentVideo.muted = true;\n contentVideo.volume = 0;\n adPlaying = true;\n setAdPlayingFlag(true);\n\n if (adVideoElement) {\n const adVolume = originalMutedState ? 0 : originalVolume;\n adVideoElement.volume = Math.max(0, Math.min(1, adVolume));\n adVideoElement.muted = false;\n console.log(\n `${LOG} Set ad video volume to ${adVideoElement.volume}, muted: ${adVideoElement.muted}`\n );\n }\n\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n\n emit(\"content_pause\");\n\n const mediaFile = selectBestMediaFile(currentAd.mediaFiles);\n if (!mediaFile) {\n throw new Error(\"No media file available for ad\");\n }\n\n console.log(`${LOG} Loading ad from: ${mediaFile.url}`);\n startPlayback(mediaFile);\n\n return Promise.resolve();\n } catch (error) {\n console.error(`${LOG} Error playing ad:`, error);\n handleAdError();\n return Promise.reject(error);\n }\n },\n\n pause() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && !adVideoElement.paused) {\n adVideoElement.pause();\n }\n } catch (error) {\n console.warn(`${LOG} Error pausing ad:`, error);\n }\n },\n\n resume() {\n if (!adPlaying || !adVideoElement) return;\n try {\n if (adVideoElement && adVideoElement.paused) {\n adVideoElement.play().catch(() => {});\n }\n } catch (error) {\n console.warn(`${LOG} Error resuming ad:`, error);\n }\n },\n\n async stop() {\n console.log(`${LOG} Stopping ad`);\n adPlaying = false;\n setAdPlayingFlag(false);\n\n const previousMutedState = contentVideo.muted;\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n console.log(\n `${LOG} Restored mute state on stop: ${previousMutedState} -> ${originalMutedState}`\n );\n\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n\n if (options?.continueLiveStreamDuringAds) {\n if (contentVideo.paused) {\n console.log(\n `${LOG} Content video paused in live mode, resuming playback on stop`\n );\n contentVideo.play().catch(() => {});\n }\n }\n\n if (adHls) {\n adHls.destroy();\n adHls = undefined;\n }\n\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n }\n\n currentAd = undefined;\n },\n\n destroy() {\n console.log(`${LOG} Destroying`);\n destroyed = true;\n\n adPlaying = false;\n setAdPlayingFlag(false);\n contentVideo.muted = originalMutedState;\n contentVideo.volume = originalMutedState ? 0 : originalVolume;\n\n if (adHls) {\n adHls.destroy();\n adHls = undefined;\n }\n\n if (adVideoElement) {\n adVideoElement.pause();\n adVideoElement.src = \"\";\n adVideoElement.remove();\n adVideoElement = undefined;\n }\n\n if (adContainerEl?.parentElement) {\n adContainerEl.parentElement.removeChild(adContainerEl);\n }\n\n adContainerEl = undefined;\n currentAd = undefined;\n listeners.clear();\n\n prebidManager.destroy();\n prebidInitialized = false;\n },\n\n isAdPlaying() {\n return adPlaying;\n },\n\n resize(width: number, height: number) {\n console.log(`${LOG} Resizing to ${width}x${height}`);\n\n if (adContainerEl) {\n adContainerEl.style.width = `${width}px`;\n adContainerEl.style.height = `${height}px`;\n }\n\n if (adVideoElement) {\n adVideoElement.style.width = `${width}px`;\n adVideoElement.style.height = `${height}px`;\n }\n },\n\n on(event: string, listener: (payload?: any) => void) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(listener);\n },\n\n off(event: string, listener: (payload?: any) => void) {\n listeners.get(event)?.delete(listener);\n },\n\n updateOriginalMutedState(muted: boolean, volume?: number) {\n const nextVolume =\n typeof volume === \"number\" && !Number.isNaN(volume)\n ? Math.max(0, Math.min(1, volume))\n : originalVolume;\n console.log(\n `${LOG} updateOriginalMutedState: { muted: ${originalMutedState} -> ${muted}, volume: ${originalVolume} -> ${nextVolume} }`\n );\n originalMutedState = muted;\n originalVolume = nextVolume;\n },\n\n getOriginalMutedState() {\n return originalMutedState;\n },\n\n getOriginalVolume() {\n return originalVolume;\n },\n\n setAdVolume(volume: number) {\n if (adVideoElement && adPlaying) {\n adVideoElement.volume = Math.max(0, Math.min(1, volume));\n }\n },\n\n getAdVolume(): number {\n if (adVideoElement && adPlaying) {\n return adVideoElement.volume;\n }\n return 1;\n },\n\n showPlaceholder() {\n contentVideo.style.opacity = \"0\";\n contentVideo.style.visibility = \"hidden\";\n\n if (!adContainerEl) {\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.left = \"0\";\n container.style.top = \"0\";\n container.style.right = \"0\";\n container.style.bottom = \"0\";\n container.style.display = \"none\";\n container.style.alignItems = \"center\";\n container.style.justifyContent = \"center\";\n container.style.pointerEvents = \"none\";\n container.style.zIndex = \"10\";\n container.style.backgroundColor = \"#000\";\n\n contentVideo.parentElement?.appendChild(container);\n adContainerEl = container;\n }\n\n if (adContainerEl) {\n adContainerEl.style.display = \"flex\";\n adContainerEl.style.pointerEvents = \"auto\";\n }\n },\n\n hidePlaceholder() {\n if (adContainerEl) {\n adContainerEl.style.display = \"none\";\n adContainerEl.style.pointerEvents = \"none\";\n }\n\n if (!adPlaying) {\n contentVideo.style.visibility = \"visible\";\n contentVideo.style.opacity = \"1\";\n }\n },\n };\n}\n","export interface VastMediaFile {\n url: string;\n type: string;\n width: number;\n height: number;\n bitrate?: number | undefined;\n}\n\nexport interface VastTrackingUrls {\n impression: string[];\n start: string[];\n firstQuartile: string[];\n midpoint: string[];\n thirdQuartile: string[];\n complete: string[];\n mute: string[];\n unmute: string[];\n pause: string[];\n resume: string[];\n fullscreen: string[];\n exitFullscreen: string[];\n skip: string[];\n error: string[];\n}\n\nexport interface VastAd {\n id: string;\n title: string;\n duration: number;\n mediaFiles: VastMediaFile[];\n trackingUrls: VastTrackingUrls;\n clickThrough?: string | undefined;\n}\n\nexport type MediaFileFilter = \"hls-only\" | \"mp4-first\" | \"all\";\n\nfunction isHlsType(type: string): boolean {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\n\nfunction isMp4Type(type: string): boolean {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\n\nexport function parseVastXml(\n xmlString: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): VastAd | null {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n\n const isNoAdAvailable =\n adId === \"empty\" ||\n title.toLowerCase().includes(\"no ad available\") ||\n title.toLowerCase() === \"no ad available\";\n\n const durationText =\n xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration =\n parseInt(durationParts[0] || \"0\", 10) * 3600 +\n parseInt(durationParts[1] || \"0\", 10) * 60 +\n Math.round(parseFloat(durationParts[2] || \"0\"));\n\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles: VastMediaFile[] = [];\n\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : undefined;\n\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : undefined,\n });\n\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n\n const trackingUrls: VastTrackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: [],\n };\n\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event as keyof VastTrackingUrls;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n\n const clickThrough = xmlDoc\n .querySelector(\"ClickThrough\")\n ?.textContent?.trim();\n\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough,\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\n\nexport async function fetchAndParseVastAd(\n vastTagUrl: string,\n filter: MediaFileFilter = \"all\",\n logPrefix = \"[VastParser]\"\n): Promise<VastAd | null> {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\",\n },\n referrerPolicy: \"no-referrer-when-downgrade\",\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2000)\n );\n\n return parseVastXml(vastXml, filter, logPrefix);\n}\n\nexport function createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false,\n };\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: string,\n licenseKey?: string,\n logPrefix = \"[VastParser]\"\n): void {\n if (!urls || urls.length === 0) return;\n\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n\n if (sessionId) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }session_id=${sessionId}`;\n }\n\n if (licenseKey) {\n trackingUrl = `${trackingUrl}${\n trackingUrl.includes(\"?\") ? \"&\" : \"?\"\n }license_key=${licenseKey}`;\n }\n\n const img = new Image(1, 1);\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n","import type { PrebidBidResponse, PrebidManager } from \"../types\";\n\nconst DEFAULT_TIMEOUT_MS = 3000;\nconst AUCTION_URL = \"https://sspproxy.adstorm.co/openrtb2/auction/adstorm\";\n\nexport interface PrebidManagerOptions {\n debug?: boolean;\n}\n\nexport function createPrebidManager(\n options: PrebidManagerOptions = {}\n): PrebidManager {\n let initialized = false;\n const debug = options.debug ?? false;\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[Prebid]\", ...args);\n }\n }\n\n function warn(...args: any[]): void {\n console.warn(\"[Prebid]\", ...args);\n }\n\n function parseResponse(data: any): PrebidBidResponse[] {\n const bids: PrebidBidResponse[] = [];\n const seatbids: any[] = data?.seatbid || [];\n const currency: string = data?.cur || \"USD\";\n\n for (const seatbid of seatbids) {\n const seat: string = seatbid.seat || \"unknown\";\n const bidArray: any[] = seatbid.bid || [];\n\n for (const bid of bidArray) {\n const cacheUrl: string | undefined =\n bid.ext?.prebid?.cache?.vastXml?.url;\n const vastXml: string | undefined = bid.adm || undefined;\n\n const bidResponse: PrebidBidResponse = {\n bidder: seat,\n cpm: bid.price || 0,\n width: bid.w || 0,\n height: bid.h || 0,\n adId: bid.id || \"\",\n impId: bid.impid || \"\",\n creativeId: bid.crid || \"\",\n currency,\n };\n if (cacheUrl) bidResponse.vastUrl = cacheUrl;\n if (vastXml) bidResponse.vastXml = vastXml;\n if (bid.adomain) bidResponse.adomain = bid.adomain;\n\n bids.push(bidResponse);\n }\n }\n\n bids.sort((a, b) => b.cpm - a.cpm);\n return bids;\n }\n\n function extractVastUrl(bids: PrebidBidResponse[]): string | null {\n if (bids.length === 0) return null;\n\n const winner = bids[0]!;\n\n if (winner.vastUrl) {\n log(\n `Using cached VAST URL from ${winner.bidder} ($${winner.cpm.toFixed(2)} ${winner.currency})`\n );\n return winner.vastUrl;\n }\n\n if (winner.vastXml) {\n log(\n `Creating blob URL from VAST XML (${winner.bidder}, $${winner.cpm.toFixed(2)})`\n );\n try {\n const blob = new Blob([winner.vastXml], { type: \"text/xml\" });\n return URL.createObjectURL(blob);\n } catch (error) {\n warn(\"Failed to create blob URL from VAST XML:\", error);\n }\n }\n\n return null;\n }\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n initialized = true;\n log(\"Initialized, auction URL:\", AUCTION_URL);\n }\n\n async function requestBids(): Promise<PrebidBidResponse[]> {\n if (!initialized) {\n throw new Error(\"Prebid not initialized. Call initialize() first.\");\n }\n\n const timeout = DEFAULT_TIMEOUT_MS;\n\n log(\"Fetching auction response from:\", AUCTION_URL);\n\n const controller =\n typeof AbortController !== \"undefined\"\n ? new AbortController()\n : null;\n const timeoutId = setTimeout(() => {\n controller?.abort();\n }, timeout + 2000);\n\n try {\n const fetchOptions: RequestInit = {\n method: \"POST\",\n };\n if (controller) {\n fetchOptions.signal = controller.signal;\n }\n\n const response = await fetch(AUCTION_URL, fetchOptions);\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `Prebid Server returned HTTP ${response.status}: ${body.slice(0, 200)}`\n );\n }\n\n const data = await response.json();\n\n if (debug && data?.ext?.responsetimemillis) {\n log(\"Bidder response times:\", data.ext.responsetimemillis);\n }\n if (debug && data?.ext?.errors) {\n warn(\"Auction errors:\", data.ext.errors);\n }\n\n const bids = parseResponse(data);\n log(`Received ${bids.length} bid(s)`);\n\n if (debug) {\n for (const b of bids) {\n log(\n ` ${b.bidder}: $${b.cpm.toFixed(2)} ${b.currency}` +\n ` ${b.width}x${b.height}` +\n (b.vastUrl ? \" [cached VAST]\" : \"\") +\n (b.vastXml && !b.vastUrl ? \" [VAST XML]\" : \"\")\n );\n }\n }\n\n return bids;\n } catch (error: any) {\n clearTimeout(timeoutId);\n\n if (error?.name === \"AbortError\") {\n warn(`Auction request timed out after ${timeout + 2000}ms`);\n return [];\n }\n\n throw error;\n }\n }\n\n async function getVastUrl(): Promise<string | null> {\n try {\n const bids = await requestBids();\n return extractVastUrl(bids);\n } catch (error) {\n warn(\"Failed to get VAST URL:\", error);\n return null;\n }\n }\n\n function destroy(): void {\n initialized = false;\n log(\"Destroyed\");\n }\n\n return {\n initialize,\n requestBids,\n getVastUrl,\n destroy,\n get isInitialized() {\n return initialized;\n },\n };\n}\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { I as ImaController } from '../types-CRi_KrjM.cjs';
|
|
2
2
|
import Hls from 'hls.js';
|
|
3
3
|
|
|
4
4
|
interface PrebidControllerOptions {
|
|
5
5
|
continueLiveStreamDuringAds?: boolean;
|
|
6
6
|
licenseKey?: string;
|
|
7
7
|
mainHlsInstance?: Hls;
|
|
8
|
+
debug?: boolean;
|
|
8
9
|
}
|
|
9
|
-
declare function createPrebidController(contentVideo: HTMLVideoElement,
|
|
10
|
+
declare function createPrebidController(contentVideo: HTMLVideoElement, options?: PrebidControllerOptions): ImaController;
|
|
10
11
|
|
|
11
12
|
export { type PrebidControllerOptions, createPrebidController };
|
package/lib/sdk/vastParser.cjs
CHANGED
|
@@ -41,9 +41,17 @@ function _ts_generator(thisArg, body) {
|
|
|
41
41
|
},
|
|
42
42
|
trys: [],
|
|
43
43
|
ops: []
|
|
44
|
-
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
45
|
-
return
|
|
46
|
-
|
|
44
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
45
|
+
return d(g, "next", {
|
|
46
|
+
value: verb(0)
|
|
47
|
+
}), d(g, "throw", {
|
|
48
|
+
value: verb(1)
|
|
49
|
+
}), d(g, "return", {
|
|
50
|
+
value: verb(2)
|
|
51
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
52
|
+
value: function() {
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
47
55
|
}), g;
|
|
48
56
|
function verb(n) {
|
|
49
57
|
return function(v) {
|
|
@@ -127,20 +135,20 @@ var __defProp = Object.defineProperty;
|
|
|
127
135
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
128
136
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
129
137
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
130
|
-
var __export = function(target, all) {
|
|
138
|
+
var __export = function __export(target, all) {
|
|
131
139
|
for(var name in all)__defProp(target, name, {
|
|
132
140
|
get: all[name],
|
|
133
141
|
enumerable: true
|
|
134
142
|
});
|
|
135
143
|
};
|
|
136
|
-
var __copyProps = function(to, from, except, desc) {
|
|
144
|
+
var __copyProps = function __copyProps(to, from, except, desc) {
|
|
137
145
|
if (from && (typeof from === "undefined" ? "undefined" : _type_of(from)) === "object" || typeof from === "function") {
|
|
138
146
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
139
147
|
try {
|
|
140
148
|
var _loop = function() {
|
|
141
149
|
var key = _step.value;
|
|
142
150
|
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
143
|
-
get: function() {
|
|
151
|
+
get: function get() {
|
|
144
152
|
return from[key];
|
|
145
153
|
},
|
|
146
154
|
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
@@ -164,7 +172,7 @@ var __copyProps = function(to, from, except, desc) {
|
|
|
164
172
|
}
|
|
165
173
|
return to;
|
|
166
174
|
};
|
|
167
|
-
var __toCommonJS = function(mod) {
|
|
175
|
+
var __toCommonJS = function __toCommonJS(mod) {
|
|
168
176
|
return __copyProps(__defProp({}, "__esModule", {
|
|
169
177
|
value: true
|
|
170
178
|
}), mod);
|
|
@@ -172,16 +180,16 @@ var __toCommonJS = function(mod) {
|
|
|
172
180
|
// src/sdk/vastParser.ts
|
|
173
181
|
var vastParser_exports = {};
|
|
174
182
|
__export(vastParser_exports, {
|
|
175
|
-
createEmptyTrackingState: function() {
|
|
183
|
+
createEmptyTrackingState: function createEmptyTrackingState1() {
|
|
176
184
|
return createEmptyTrackingState;
|
|
177
185
|
},
|
|
178
|
-
fetchAndParseVastAd: function() {
|
|
186
|
+
fetchAndParseVastAd: function fetchAndParseVastAd1() {
|
|
179
187
|
return fetchAndParseVastAd;
|
|
180
188
|
},
|
|
181
|
-
fireTrackingPixels: function() {
|
|
189
|
+
fireTrackingPixels: function fireTrackingPixels1() {
|
|
182
190
|
return fireTrackingPixels;
|
|
183
191
|
},
|
|
184
|
-
parseVastXml: function() {
|
|
192
|
+
parseVastXml: function parseVastXml1() {
|
|
185
193
|
return parseVastXml;
|
|
186
194
|
}
|
|
187
195
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/ubuntu24/Dev/stormcloud-vp/lib/sdk/vastParser.cjs"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/vastParser.cjs"],"names":["key"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wEAWaA,UAAAA,gBAAAA,CAAJ","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\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 __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/sdk/vastParser.ts\nvar vastParser_exports = {};\n__export(vastParser_exports, {\n createEmptyTrackingState: () => createEmptyTrackingState,\n fetchAndParseVastAd: () => fetchAndParseVastAd,\n fireTrackingPixels: () => fireTrackingPixels,\n parseVastXml: () => parseVastXml\n});\nmodule.exports = __toCommonJS(vastParser_exports);\nfunction isHlsType(type) {\n return type === \"application/x-mpegURL\" || type.includes(\"m3u8\");\n}\nfunction isMp4Type(type) {\n return type === \"video/mp4\" || type.includes(\"mp4\");\n}\nfunction parseVastXml(xmlString, filter = \"all\", logPrefix = \"[VastParser]\") {\n try {\n const parser = new DOMParser();\n const xmlDoc = parser.parseFromString(xmlString, \"text/xml\");\n const parserError = xmlDoc.querySelector(\"parsererror\");\n if (parserError) {\n console.error(\n `${logPrefix} XML parsing error (malformed VAST XML):`,\n parserError.textContent\n );\n return null;\n }\n const adElement = xmlDoc.querySelector(\"Ad\");\n if (!adElement) {\n console.warn(`${logPrefix} No Ad element found in VAST XML`);\n return null;\n }\n const adId = adElement.getAttribute(\"id\") || \"unknown\";\n const title = xmlDoc.querySelector(\"AdTitle\")?.textContent || \"Ad\";\n const isNoAdAvailable = adId === \"empty\" || title.toLowerCase().includes(\"no ad available\") || title.toLowerCase() === \"no ad available\";\n const durationText = xmlDoc.querySelector(\"Duration\")?.textContent || \"00:00:30\";\n const durationParts = durationText.split(\":\");\n const duration = parseInt(durationParts[0] || \"0\", 10) * 3600 + parseInt(durationParts[1] || \"0\", 10) * 60 + Math.round(parseFloat(durationParts[2] || \"0\"));\n const mediaFileElements = xmlDoc.querySelectorAll(\"MediaFile\");\n const mediaFiles = [];\n console.log(\n `${logPrefix} Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`\n );\n mediaFileElements.forEach((mf, index) => {\n const type = mf.getAttribute(\"type\") || \"\";\n const url = mf.textContent?.trim() || \"\";\n const width = mf.getAttribute(\"width\") || \"\";\n const height = mf.getAttribute(\"height\") || \"\";\n console.log(\n `${logPrefix} MediaFile ${index}: type=\"${type}\", url=\"${url.substring(0, 80)}...\", width=\"${width}\", height=\"${height}\"`\n );\n if (!url) {\n console.warn(`${logPrefix} MediaFile ${index} has empty URL`);\n return;\n }\n const isHls = isHlsType(type);\n const isMp4 = isMp4Type(type);\n let accepted = false;\n if (filter === \"hls-only\") {\n accepted = isHls;\n } else if (filter === \"mp4-first\") {\n accepted = isMp4 || isHls;\n } else {\n accepted = true;\n }\n if (!accepted) {\n console.log(\n `${logPrefix} MediaFile ${index} ignored (type=\"${type}\" not accepted by filter \"${filter}\")`\n );\n return;\n }\n const bitrateAttr = mf.getAttribute(\"bitrate\");\n const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;\n mediaFiles.push({\n url,\n type,\n width: parseInt(width || \"1920\", 10),\n height: parseInt(height || \"1080\", 10),\n bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0\n });\n console.log(`${logPrefix} Added MediaFile: type=\"${type}\" url=\"${url.substring(0, 80)}...\"`);\n });\n if (filter === \"mp4-first\" && mediaFiles.length > 1) {\n mediaFiles.sort((a, b) => {\n const aIsMp4 = isMp4Type(a.type) ? 0 : 1;\n const bIsMp4 = isMp4Type(b.type) ? 0 : 1;\n return aIsMp4 - bIsMp4;\n });\n }\n if (mediaFiles.length === 0) {\n if (isNoAdAvailable) {\n console.warn(\n `${logPrefix} No ads available (VAST response indicates no ads)`\n );\n } else {\n console.warn(`${logPrefix} No compatible media files found in VAST XML`);\n }\n return null;\n }\n const trackingUrls = {\n impression: [],\n start: [],\n firstQuartile: [],\n midpoint: [],\n thirdQuartile: [],\n complete: [],\n mute: [],\n unmute: [],\n pause: [],\n resume: [],\n fullscreen: [],\n exitFullscreen: [],\n skip: [],\n error: []\n };\n xmlDoc.querySelectorAll(\"Impression\").forEach((el) => {\n const url = el.textContent?.trim();\n if (url) trackingUrls.impression.push(url);\n });\n xmlDoc.querySelectorAll(\"Tracking\").forEach((el) => {\n const event = el.getAttribute(\"event\");\n const url = el.textContent?.trim();\n if (event && url) {\n const eventKey = event;\n if (trackingUrls[eventKey]) {\n trackingUrls[eventKey].push(url);\n }\n }\n });\n const clickThrough = xmlDoc.querySelector(\"ClickThrough\")?.textContent?.trim();\n return {\n id: adId,\n title,\n duration,\n mediaFiles,\n trackingUrls,\n clickThrough\n };\n } catch (error) {\n console.error(`${logPrefix} Error parsing VAST XML:`, error);\n return null;\n }\n}\nasync function fetchAndParseVastAd(vastTagUrl, filter = \"all\", logPrefix = \"[VastParser]\") {\n const response = await fetch(vastTagUrl, {\n mode: \"cors\",\n credentials: \"include\",\n headers: {\n Accept: \"application/xml, text/xml, */*\"\n },\n referrerPolicy: \"no-referrer-when-downgrade\"\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch VAST: ${response.statusText}`);\n }\n const vastXml = await response.text();\n console.log(`${logPrefix} VAST XML received`);\n console.log(\n `${logPrefix} VAST XML content (first 2000 chars):`,\n vastXml.substring(0, 2e3)\n );\n return parseVastXml(vastXml, filter, logPrefix);\n}\nfunction createEmptyTrackingState() {\n return {\n impression: false,\n start: false,\n firstQuartile: false,\n midpoint: false,\n thirdQuartile: false,\n complete: false\n };\n}\nfunction fireTrackingPixels(urls, sessionId, licenseKey, logPrefix = \"[VastParser]\") {\n if (!urls || urls.length === 0) return;\n urls.forEach((url) => {\n try {\n let trackingUrl = url;\n if (sessionId) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}session_id=${sessionId}`;\n }\n if (licenseKey) {\n trackingUrl = `${trackingUrl}${trackingUrl.includes(\"?\") ? \"&\" : \"?\"}license_key=${licenseKey}`;\n }\n const img = new Image(1, 1);\n img.src = trackingUrl;\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createEmptyTrackingState,\n fetchAndParseVastAd,\n fireTrackingPixels,\n parseVastXml\n});\n"]}
|