stormcloud-video-player 0.6.9 → 0.6.11

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.
@@ -361,7 +361,8 @@ function parseVastXml(xmlString) {
361
361
  }
362
362
  }
363
363
  // src/sdk/vastManager.ts
364
- var VAST_TAG_URL = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
364
+ var VAST_TAG_URL_FALLBACK = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
365
+ var ADSTORM_API_URL = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
365
366
  var DEFAULT_TIMEOUT_MS = 5e3;
366
367
  var MAX_RETRIES = 3;
367
368
  var RETRY_BACKOFF_MS = 1500;
@@ -369,6 +370,7 @@ function createVastManager() {
369
370
  var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
370
371
  var _options_debug;
371
372
  var initialized = false;
373
+ var vastTagUrl = VAST_TAG_URL_FALLBACK;
372
374
  var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
373
375
  function log() {
374
376
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
@@ -390,17 +392,97 @@ function createVastManager() {
390
392
  "[VastManager]"
391
393
  ].concat(_to_consumable_array(args)));
392
394
  }
395
+ function fetchVastUrlFromApi() {
396
+ return _async_to_generator(function() {
397
+ var apiUrl, _data_response_ima_publisherdeskima, _data_response_ima, _data_response, res, data, payload, err;
398
+ return _ts_generator(this, function(_state) {
399
+ switch(_state.label){
400
+ case 0:
401
+ apiUrl = options.adstormApiUrl || ADSTORM_API_URL;
402
+ _state.label = 1;
403
+ case 1:
404
+ _state.trys.push([
405
+ 1,
406
+ 4,
407
+ ,
408
+ 5
409
+ ]);
410
+ return [
411
+ 4,
412
+ fetch(apiUrl, {
413
+ method: "GET",
414
+ headers: {
415
+ Authorization: "Bearer ".concat(options.licenseKey),
416
+ Accept: "application/json"
417
+ }
418
+ })
419
+ ];
420
+ case 2:
421
+ res = _state.sent();
422
+ if (!res.ok) {
423
+ warn("Failed to fetch VAST URL from API (HTTP ".concat(res.status, "), using fallback"));
424
+ return [
425
+ 2
426
+ ];
427
+ }
428
+ return [
429
+ 4,
430
+ res.json()
431
+ ];
432
+ case 3:
433
+ data = _state.sent();
434
+ payload = data === null || data === void 0 ? void 0 : (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
435
+ if (payload) {
436
+ vastTagUrl = payload;
437
+ log("VAST tag URL fetched from API:", vastTagUrl.split("?")[0]);
438
+ } else {
439
+ log("API response had no VAST payload, using fallback URL");
440
+ }
441
+ return [
442
+ 3,
443
+ 5
444
+ ];
445
+ case 4:
446
+ err = _state.sent();
447
+ warn("Error fetching VAST URL from API, using fallback:", err);
448
+ return [
449
+ 3,
450
+ 5
451
+ ];
452
+ case 5:
453
+ return [
454
+ 2
455
+ ];
456
+ }
457
+ });
458
+ })();
459
+ }
393
460
  function initialize() {
394
461
  return _async_to_generator(function() {
395
462
  return _ts_generator(this, function(_state) {
396
- if (initialized) return [
397
- 2
398
- ];
399
- initialized = true;
400
- log("Initialized, VAST tag URL:", VAST_TAG_URL.split("?")[0]);
401
- return [
402
- 2
403
- ];
463
+ switch(_state.label){
464
+ case 0:
465
+ if (initialized) return [
466
+ 2
467
+ ];
468
+ initialized = true;
469
+ if (!options.licenseKey) return [
470
+ 3,
471
+ 2
472
+ ];
473
+ return [
474
+ 4,
475
+ fetchVastUrlFromApi()
476
+ ];
477
+ case 1:
478
+ _state.sent();
479
+ _state.label = 2;
480
+ case 2:
481
+ log("Initialized, VAST tag URL:", vastTagUrl.split("?")[0]);
482
+ return [
483
+ 2
484
+ ];
485
+ }
404
486
  });
405
487
  })();
406
488
  }
@@ -414,7 +496,7 @@ function createVastManager() {
414
496
  throw new Error("VastManager not initialized. Call initialize() first.");
415
497
  }
416
498
  correlator = Math.floor(Math.random() * 1e12).toString();
417
- url = VAST_TAG_URL.replace("[placeholder]", correlator);
499
+ url = vastTagUrl.replace("[placeholder]", correlator);
418
500
  log("Fetching VAST tag, correlator:", correlator);
419
501
  controller = typeof AbortController !== "undefined" ? new AbortController() : null;
420
502
  timeoutId = setTimeout(function() {
@@ -608,6 +690,7 @@ function createVastManager() {
608
690
  }
609
691
  function destroy() {
610
692
  initialized = false;
693
+ vastTagUrl = VAST_TAG_URL_FALLBACK;
611
694
  log("Destroyed");
612
695
  }
613
696
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/vastManager.cjs","../../src/sdk/vastManager.ts","../../src/sdk/vastParser.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","from","to","vastManager_exports","name","get","enumerable","__copyProps","except","desc","key","call","__toCommonJS","mod","value","createVastManager","module","exports","type","includes","parseVastXml","filter","xmlString","xmlDoc","parser","DOMParser","parseFromString","parserError","querySelector","console","error","logPrefix","textContent","adElement","warn","adId","getAttribute","isNoAdAvailable","title","toLowerCase","isMp4Type","durationText","durationParts","split","duration","parseInt","Math","round","parseFloat","mediaFileElements","querySelectorAll","mediaFiles","log","length","forEach","mf","index","url","trim","width","height","substring","isHls","isHlsType","isMp4","accepted"],"mappings":"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","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/vastManager.ts\nvar vastManager_exports = {};\n__export(vastManager_exports, {\n createVastManager: () => createVastManager\n});\nmodule.exports = __toCommonJS(vastManager_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}\n\n// src/sdk/vastManager.ts\nvar VAST_TAG_URL = \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\nvar DEFAULT_TIMEOUT_MS = 5e3;\nvar MAX_RETRIES = 3;\nvar RETRY_BACKOFF_MS = 1500;\nfunction createVastManager(options = {}) {\n let initialized = false;\n const debug = options.debug ?? false;\n function log(...args) {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n function warn(...args) {\n console.warn(\"[VastManager]\", ...args);\n }\n async function initialize() {\n if (initialized) return;\n initialized = true;\n log(\"Initialized, VAST tag URL:\", VAST_TAG_URL.split(\"?\")[0]);\n }\n async function requestBids(_context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = VAST_TAG_URL.replace(\"[placeholder]\", correlator);\n log(\"Fetching VAST tag, correlator:\", correlator);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n try {\n const fetchOptions = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\"\n };\n if (controller) fetchOptions.signal = controller.signal;\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n const bid = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration\n };\n return [bid];\n } catch (error) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n async function requestBidsUntilResponse(context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n function destroy() {\n initialized = false;\n log(\"Destroyed\");\n }\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n }\n };\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createVastManager\n});\n","import { parseVastXml } from \"./vastParser\";\nimport type { VastBidResponse, VastManager, AdBreakContext } from \"../types\";\n\nconst VAST_TAG_URL =\n \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst MAX_RETRIES = 3;\nconst RETRY_BACKOFF_MS = 1500;\n\nexport interface VastManagerOptions {\n debug?: boolean;\n}\n\nexport function createVastManager(\n options: VastManagerOptions = {}\n): VastManager {\n let initialized = false;\n const debug = options.debug ?? false;\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n\n function warn(...args: any[]): void {\n console.warn(\"[VastManager]\", ...args);\n }\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n initialized = true;\n log(\"Initialized, VAST tag URL:\", VAST_TAG_URL.split(\"?\")[0]);\n }\n\n async function requestBids(_context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = VAST_TAG_URL.replace(\"[placeholder]\", correlator);\n\n log(\"Fetching VAST tag, correlator:\", correlator);\n\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n\n try {\n const fetchOptions: RequestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\",\n };\n if (controller) fetchOptions.signal = controller.signal;\n\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n\n const bid: VastBidResponse = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration,\n };\n\n return [bid];\n } catch (error: any) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n\n async function requestBidsUntilResponse(context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError: unknown;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n\n function destroy(): void {\n initialized = false;\n log(\"Destroyed\");\n }\n\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\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\nasync function firePixelWithRetry(\n url: string,\n retries = 2,\n delayMs = 500,\n logPrefix = \"[VastParser]\"\n): Promise<void> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true,\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: 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 (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {});\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {};\n img.src = trackingUrl;\n }\n\n console.log(`${logPrefix} Fired tracking pixel: ${trackingUrl}`);\n } catch (error) {\n console.warn(`${logPrefix} Error firing tracking pixel:`, error);\n }\n });\n}\n"]}
1
+ {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/sdk/vastManager.cjs","../../src/sdk/vastParser.ts","../../src/sdk/vastManager.ts"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","__hasOwnProp","__export","from","getOwnPropertyNames","target","all","name","get","enumerable","__copyProps","to","except","desc","key","call","value","exports","__toCommonJS","isMp4Type","type","xmlDoc","isNoAdAvailable","adId","title","toLowerCase","includes","mod","vastManager_exports","createVastManager","isHlsType","parseVastXml","xmlString","filter","logPrefix","parser","DOMParser","parseFromString","parserError","querySelector","console","error","textContent","adElement","warn","getAttribute","durationText","durationParts","split","duration","parseInt","Math","round","parseFloat","mediaFileElements","querySelectorAll","mediaFiles","log","length","mf","index","url","width","substring","height","isHls","isMp4","accepted","trim","bitrateAttr","bitrateValue","push","bitrate","sort","a","b","aIsMp4","bIsMp4"],"mappings":"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","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/vastManager.ts\nvar vastManager_exports = {};\n__export(vastManager_exports, {\n createVastManager: () => createVastManager\n});\nmodule.exports = __toCommonJS(vastManager_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}\n\n// src/sdk/vastManager.ts\nvar VAST_TAG_URL_FALLBACK = \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\nvar ADSTORM_API_URL = \"https://adstorm.co/api-adstorm-dev/adstorm/ads/web\";\nvar DEFAULT_TIMEOUT_MS = 5e3;\nvar MAX_RETRIES = 3;\nvar RETRY_BACKOFF_MS = 1500;\nfunction createVastManager(options = {}) {\n let initialized = false;\n let vastTagUrl = VAST_TAG_URL_FALLBACK;\n const debug = options.debug ?? false;\n function log(...args) {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n function warn(...args) {\n console.warn(\"[VastManager]\", ...args);\n }\n async function fetchVastUrlFromApi() {\n const apiUrl = options.adstormApiUrl || ADSTORM_API_URL;\n try {\n const res = await fetch(apiUrl, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${options.licenseKey}`,\n Accept: \"application/json\"\n }\n });\n if (!res.ok) {\n warn(`Failed to fetch VAST URL from API (HTTP ${res.status}), using fallback`);\n return;\n }\n const data = await res.json();\n const payload = data?.response?.ima?.[\"publisherdesk.ima\"]?.payload;\n if (payload) {\n vastTagUrl = payload;\n log(\"VAST tag URL fetched from API:\", vastTagUrl.split(\"?\")[0]);\n } else {\n log(\"API response had no VAST payload, using fallback URL\");\n }\n } catch (err) {\n warn(\"Error fetching VAST URL from API, using fallback:\", err);\n }\n }\n async function initialize() {\n if (initialized) return;\n initialized = true;\n if (options.licenseKey) {\n await fetchVastUrlFromApi();\n }\n log(\"Initialized, VAST tag URL:\", vastTagUrl.split(\"?\")[0]);\n }\n async function requestBids(_context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = vastTagUrl.replace(\"[placeholder]\", correlator);\n log(\"Fetching VAST tag, correlator:\", correlator);\n const controller = typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n try {\n const fetchOptions = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\"\n };\n if (controller) fetchOptions.signal = controller.signal;\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n const bid = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration\n };\n return [bid];\n } catch (error) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n async function requestBidsUntilResponse(context) {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n function destroy() {\n initialized = false;\n vastTagUrl = VAST_TAG_URL_FALLBACK;\n log(\"Destroyed\");\n }\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n }\n };\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n createVastManager\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\nasync function firePixelWithRetry(\n url: string,\n retries = 2,\n delayMs = 500,\n logPrefix = \"[VastParser]\"\n): Promise<void> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n await fetch(url, {\n method: \"GET\",\n mode: \"no-cors\",\n cache: \"no-cache\",\n keepalive: true,\n });\n return;\n } catch {\n if (attempt < retries) {\n await new Promise((r) => setTimeout(r, delayMs * Math.pow(2, attempt)));\n } else {\n console.warn(`${logPrefix} Tracking pixel failed after ${retries + 1} attempts: ${url}`);\n }\n }\n }\n}\n\nexport function fireTrackingPixels(\n urls: string[],\n sessionId?: 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 (typeof fetch !== \"undefined\") {\n firePixelWithRetry(trackingUrl, 2, 500, logPrefix).catch(() => {});\n } else {\n const img = new Image(1, 1);\n img.onerror = () => {};\n img.src = trackingUrl;\n }\n\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 { parseVastXml } from \"./vastParser\";\nimport type { VastBidResponse, VastManager, AdBreakContext, StormcloudApiResponse } from \"../types\";\n\nconst VAST_TAG_URL_FALLBACK =\n \"https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click\";\n\nconst ADSTORM_API_URL = \"https://adstorm.co/api-adstorm-dev/adstorm/ads/web\";\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst MAX_RETRIES = 3;\nconst RETRY_BACKOFF_MS = 1500;\n\nexport interface VastManagerOptions {\n debug?: boolean;\n licenseKey?: string;\n adstormApiUrl?: string;\n}\n\nexport function createVastManager(\n options: VastManagerOptions = {}\n): VastManager {\n let initialized = false;\n let vastTagUrl = VAST_TAG_URL_FALLBACK;\n const debug = options.debug ?? false;\n\n function log(...args: any[]): void {\n if (debug) {\n console.log(\"[VastManager]\", ...args);\n }\n }\n\n function warn(...args: any[]): void {\n console.warn(\"[VastManager]\", ...args);\n }\n\n async function fetchVastUrlFromApi(): Promise<void> {\n const apiUrl = options.adstormApiUrl || ADSTORM_API_URL;\n try {\n const res = await fetch(apiUrl, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${options.licenseKey}`,\n Accept: \"application/json\",\n },\n });\n if (!res.ok) {\n warn(`Failed to fetch VAST URL from API (HTTP ${res.status}), using fallback`);\n return;\n }\n const data: StormcloudApiResponse = await res.json();\n const payload = data?.response?.ima?.[\"publisherdesk.ima\"]?.payload;\n if (payload) {\n vastTagUrl = payload;\n log(\"VAST tag URL fetched from API:\", vastTagUrl.split(\"?\")[0]);\n } else {\n log(\"API response had no VAST payload, using fallback URL\");\n }\n } catch (err) {\n warn(\"Error fetching VAST URL from API, using fallback:\", err);\n }\n }\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n initialized = true;\n if (options.licenseKey) {\n await fetchVastUrlFromApi();\n }\n log(\"Initialized, VAST tag URL:\", vastTagUrl.split(\"?\")[0]);\n }\n\n async function requestBids(_context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n\n const correlator = Math.floor(Math.random() * 1e12).toString();\n const url = vastTagUrl.replace(\"[placeholder]\", correlator);\n\n log(\"Fetching VAST tag, correlator:\", correlator);\n\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : null;\n const timeoutId = setTimeout(() => controller?.abort(), DEFAULT_TIMEOUT_MS);\n\n try {\n const fetchOptions: RequestInit = {\n method: \"GET\",\n mode: \"cors\",\n credentials: \"omit\",\n headers: { Accept: \"application/xml, text/xml, */*\" },\n referrerPolicy: \"no-referrer-when-downgrade\",\n };\n if (controller) fetchOptions.signal = controller.signal;\n\n const response = await fetch(url, fetchOptions);\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`VAST request returned HTTP ${response.status}`);\n }\n\n const vastXml = await response.text();\n log(\"VAST XML received, length:\", vastXml.length);\n\n const vastAd = parseVastXml(vastXml, \"mp4-first\", \"[VastManager]\");\n if (!vastAd) {\n log(\"VAST parsed but no usable ad found\");\n return [];\n }\n\n log(`Ad parsed: id=${vastAd.id}, duration=${vastAd.duration}s, mediaFiles=${vastAd.mediaFiles.length}`);\n\n const bid: VastBidResponse = {\n bidder: \"vast-direct\",\n cpm: 0,\n vastXml,\n width: vastAd.mediaFiles[0]?.width ?? 0,\n height: vastAd.mediaFiles[0]?.height ?? 0,\n adId: vastAd.id,\n impId: correlator,\n creativeId: vastAd.id,\n currency: \"USD\",\n durationSec: vastAd.duration,\n };\n\n return [bid];\n } catch (error: any) {\n clearTimeout(timeoutId);\n if (error?.name === \"AbortError\") {\n warn(`VAST request timed out after ${DEFAULT_TIMEOUT_MS}ms`);\n return [];\n }\n throw error;\n }\n }\n\n async function requestBidsUntilResponse(context?: AdBreakContext): Promise<VastBidResponse[]> {\n if (!initialized) {\n throw new Error(\"VastManager not initialized. Call initialize() first.\");\n }\n let lastError: unknown;\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const bids = await requestBids(context);\n if (bids.length > 0) {\n log(`requestBidsUntilResponse: got ${bids.length} ad(s) on attempt ${attempt}`);\n return bids;\n }\n log(`requestBidsUntilResponse: no ads on attempt ${attempt}/${MAX_RETRIES}`);\n } catch (err) {\n lastError = err;\n warn(`requestBidsUntilResponse: attempt ${attempt}/${MAX_RETRIES} failed:`, err);\n }\n if (attempt < MAX_RETRIES) {\n const delay = RETRY_BACKOFF_MS * attempt;\n log(`requestBidsUntilResponse: waiting ${delay}ms before retry`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n if (lastError instanceof Error) throw lastError;\n return [];\n }\n\n function destroy(): void {\n initialized = false;\n vastTagUrl = VAST_TAG_URL_FALLBACK;\n log(\"Destroyed\");\n }\n\n return {\n initialize,\n requestBids,\n requestBidsUntilResponse,\n destroy,\n get isInitialized() {\n return initialized;\n },\n };\n}\n"]}
@@ -2,6 +2,8 @@ import { a as VastManager } from '../types-DSKC4ySr.cjs';
2
2
 
3
3
  interface VastManagerOptions {
4
4
  debug?: boolean;
5
+ licenseKey?: string;
6
+ adstormApiUrl?: string;
5
7
  }
6
8
  declare function createVastManager(options?: VastManagerOptions): VastManager;
7
9
 
@@ -687,7 +687,8 @@ function fireTrackingPixels(urls, sessionId) {
687
687
  });
688
688
  }
689
689
  // src/sdk/vastManager.ts
690
- var VAST_TAG_URL = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
690
+ var VAST_TAG_URL_FALLBACK = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21821455290/Airy-Android&description_url=http%3A%2F%2Fairy.tv&tfcd=0&npa=0&sz=1x1%7C300x250%7C400x300%7C640x480&gdfp_req=1&unviewed_position_start=1&correlator=[placeholder]&vpos=preroll&output=vast&env=vp&vpmute=0&vpa=click";
691
+ var ADSTORM_API_URL = "https://adstorm.co/api-adstorm-dev/adstorm/ads/web";
691
692
  var DEFAULT_TIMEOUT_MS = 5e3;
692
693
  var MAX_RETRIES = 3;
693
694
  var RETRY_BACKOFF_MS = 1500;
@@ -695,6 +696,7 @@ function createVastManager() {
695
696
  var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
696
697
  var _options_debug;
697
698
  var initialized = false;
699
+ var vastTagUrl = VAST_TAG_URL_FALLBACK;
698
700
  var debug = (_options_debug = options.debug) !== null && _options_debug !== void 0 ? _options_debug : false;
699
701
  function log() {
700
702
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
@@ -716,17 +718,97 @@ function createVastManager() {
716
718
  "[VastManager]"
717
719
  ].concat(_to_consumable_array(args)));
718
720
  }
721
+ function fetchVastUrlFromApi() {
722
+ return _async_to_generator(function() {
723
+ var apiUrl, _data_response_ima_publisherdeskima, _data_response_ima, _data_response, res, data, payload, err;
724
+ return _ts_generator(this, function(_state) {
725
+ switch(_state.label){
726
+ case 0:
727
+ apiUrl = options.adstormApiUrl || ADSTORM_API_URL;
728
+ _state.label = 1;
729
+ case 1:
730
+ _state.trys.push([
731
+ 1,
732
+ 4,
733
+ ,
734
+ 5
735
+ ]);
736
+ return [
737
+ 4,
738
+ fetch(apiUrl, {
739
+ method: "GET",
740
+ headers: {
741
+ Authorization: "Bearer ".concat(options.licenseKey),
742
+ Accept: "application/json"
743
+ }
744
+ })
745
+ ];
746
+ case 2:
747
+ res = _state.sent();
748
+ if (!res.ok) {
749
+ warn("Failed to fetch VAST URL from API (HTTP ".concat(res.status, "), using fallback"));
750
+ return [
751
+ 2
752
+ ];
753
+ }
754
+ return [
755
+ 4,
756
+ res.json()
757
+ ];
758
+ case 3:
759
+ data = _state.sent();
760
+ payload = data === null || data === void 0 ? void 0 : (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
761
+ if (payload) {
762
+ vastTagUrl = payload;
763
+ log("VAST tag URL fetched from API:", vastTagUrl.split("?")[0]);
764
+ } else {
765
+ log("API response had no VAST payload, using fallback URL");
766
+ }
767
+ return [
768
+ 3,
769
+ 5
770
+ ];
771
+ case 4:
772
+ err = _state.sent();
773
+ warn("Error fetching VAST URL from API, using fallback:", err);
774
+ return [
775
+ 3,
776
+ 5
777
+ ];
778
+ case 5:
779
+ return [
780
+ 2
781
+ ];
782
+ }
783
+ });
784
+ })();
785
+ }
719
786
  function initialize() {
720
787
  return _async_to_generator(function() {
721
788
  return _ts_generator(this, function(_state) {
722
- if (initialized) return [
723
- 2
724
- ];
725
- initialized = true;
726
- log("Initialized, VAST tag URL:", VAST_TAG_URL.split("?")[0]);
727
- return [
728
- 2
729
- ];
789
+ switch(_state.label){
790
+ case 0:
791
+ if (initialized) return [
792
+ 2
793
+ ];
794
+ initialized = true;
795
+ if (!options.licenseKey) return [
796
+ 3,
797
+ 2
798
+ ];
799
+ return [
800
+ 4,
801
+ fetchVastUrlFromApi()
802
+ ];
803
+ case 1:
804
+ _state.sent();
805
+ _state.label = 2;
806
+ case 2:
807
+ log("Initialized, VAST tag URL:", vastTagUrl.split("?")[0]);
808
+ return [
809
+ 2
810
+ ];
811
+ }
730
812
  });
731
813
  })();
732
814
  }
@@ -740,7 +822,7 @@ function createVastManager() {
740
822
  throw new Error("VastManager not initialized. Call initialize() first.");
741
823
  }
742
824
  correlator = Math.floor(Math.random() * 1e12).toString();
743
- url = VAST_TAG_URL.replace("[placeholder]", correlator);
825
+ url = vastTagUrl.replace("[placeholder]", correlator);
744
826
  log("Fetching VAST tag, correlator:", correlator);
745
827
  controller = typeof AbortController !== "undefined" ? new AbortController() : null;
746
828
  timeoutId = setTimeout(function() {
@@ -934,6 +1016,7 @@ function createVastManager() {
934
1016
  }
935
1017
  function destroy() {
936
1018
  initialized = false;
1019
+ vastTagUrl = VAST_TAG_URL_FALLBACK;
937
1020
  log("Destroyed");
938
1021
  }
939
1022
  return {
@@ -975,6 +1058,7 @@ function createVastAdLayer(contentVideo, options) {
975
1058
  var adHls;
976
1059
  var adContainerEl;
977
1060
  var currentAd;
1061
+ var currentMediaFile;
978
1062
  var sessionId;
979
1063
  var destroyed = false;
980
1064
  var tornDown = false;
@@ -1221,7 +1305,12 @@ function createVastAdLayer(contentVideo, options) {
1221
1305
  adContainerEl.style.display = "none";
1222
1306
  adContainerEl.style.pointerEvents = "none";
1223
1307
  }
1224
- emit("ad_impression");
1308
+ emit("ad_impression", {
1309
+ adId: currentAd === null || currentAd === void 0 ? void 0 : currentAd.id,
1310
+ adTitle: currentAd === null || currentAd === void 0 ? void 0 : currentAd.title,
1311
+ adUrl: currentMediaFile === null || currentMediaFile === void 0 ? void 0 : currentMediaFile.url,
1312
+ mediaType: currentMediaFile === null || currentMediaFile === void 0 ? void 0 : currentMediaFile.type
1313
+ });
1225
1314
  emit("content_resume");
1226
1315
  }
1227
1316
  function handleAdError() {
@@ -1243,6 +1332,7 @@ function createVastAdLayer(contentVideo, options) {
1243
1332
  adHls.destroy();
1244
1333
  adHls = void 0;
1245
1334
  }
1335
+ currentMediaFile = void 0;
1246
1336
  if (adVideoElement) {
1247
1337
  if (singleElementMode && adVideoElement === contentVideo) {
1248
1338
  contentVideo.pause();
@@ -1407,6 +1497,7 @@ function createVastAdLayer(contentVideo, options) {
1407
1497
  adVideoElement.volume = Math.max(0, Math.min(1, adVolume2));
1408
1498
  adVideoElement.muted = false;
1409
1499
  mediaFile2 = selectBestMediaFile(ad.mediaFiles);
1500
+ currentMediaFile = mediaFile2;
1410
1501
  if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile2.url));
1411
1502
  startPlayback(mediaFile2);
1412
1503
  return [
@@ -1453,6 +1544,7 @@ function createVastAdLayer(contentVideo, options) {
1453
1544
  }
1454
1545
  emit("content_pause");
1455
1546
  mediaFile = selectBestMediaFile(ad.mediaFiles);
1547
+ currentMediaFile = mediaFile;
1456
1548
  if (debug) console.log("".concat(LOG, " Loading ad from: ").concat(mediaFile.url));
1457
1549
  startPlayback(mediaFile);
1458
1550
  return [
@@ -1618,6 +1710,7 @@ function createVastAdLayer(contentVideo, options) {
1618
1710
  ];
1619
1711
  mainHlsInstance === null || mainHlsInstance === void 0 ? void 0 : mainHlsInstance.detachMedia();
1620
1712
  teardownCurrentPlayback();
1713
+ currentMediaFile = slot.mediaFile;
1621
1714
  adVideoElement = contentVideo;
1622
1715
  adHls = void 0;
1623
1716
  adPlaying = true;
@@ -1652,6 +1745,7 @@ function createVastAdLayer(contentVideo, options) {
1652
1745
  case 2:
1653
1746
  if (smartTVMode && !slot.videoEl) {
1654
1747
  teardownCurrentPlayback();
1748
+ currentMediaFile = slot.mediaFile;
1655
1749
  if (adVideoElement) {
1656
1750
  adVideoElement.remove();
1657
1751
  adVideoElement = void 0;
@@ -1683,6 +1777,7 @@ function createVastAdLayer(contentVideo, options) {
1683
1777
  ];
1684
1778
  }
1685
1779
  teardownCurrentPlayback();
1780
+ currentMediaFile = slot.mediaFile;
1686
1781
  if (adVideoElement && adVideoElement !== slot.videoEl) {
1687
1782
  adVideoElement.remove();
1688
1783
  }
@@ -1814,6 +1909,7 @@ function createVastAdLayer(contentVideo, options) {
1814
1909
  }
1815
1910
  }
1816
1911
  currentAd = void 0;
1912
+ currentMediaFile = void 0;
1817
1913
  tornDown = false;
1818
1914
  return [
1819
1915
  2
@@ -1866,6 +1962,7 @@ function createVastAdLayer(contentVideo, options) {
1866
1962
  }
1867
1963
  adContainerEl = void 0;
1868
1964
  currentAd = void 0;
1965
+ currentMediaFile = void 0;
1869
1966
  listeners.clear();
1870
1967
  },
1871
1968
  isAdPlaying: function isAdPlaying() {
@@ -3107,9 +3204,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3107
3204
  this.video = config.videoElement;
3108
3205
  this.adTransitionGapMs = (_this_config_adTransitionGapMs = this.config.adTransitionGapMs) !== null && _this_config_adTransitionGapMs !== void 0 ? _this_config_adTransitionGapMs : 100;
3109
3206
  logBrowserInfo(config.debugAdTiming);
3110
- this.vastManager = createVastManager(config.debugAdTiming !== void 0 ? {
3111
- debug: !!config.debugAdTiming
3112
- } : {});
3207
+ this.vastManager = createVastManager(_object_spread({
3208
+ debug: config.debugAdTiming !== void 0 ? !!config.debugAdTiming : false
3209
+ }, config.licenseKey ? {
3210
+ licenseKey: config.licenseKey
3211
+ } : {}));
3113
3212
  var browserForAdLayer = detectBrowser();
3114
3213
  var isSinglePipeline = browserForAdLayer.isSmartTV || !!this.config.singlePipelineMode;
3115
3214
  this.adLayer = createVastAdLayer(this.video, {
@@ -3160,6 +3259,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3160
3259
  this.attach();
3161
3260
  }
3162
3261
  this.initializeTracking();
3262
+ if (!this.config.disableAds) {
3263
+ this.vastManager.initialize().catch(function() {});
3264
+ }
3163
3265
  if (!this.shouldUseNativeHls()) return [
3164
3266
  3,
3165
3267
  3
@@ -3613,13 +3715,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3613
3715
  key: "attachAdLayerEventListeners",
3614
3716
  value: function attachAdLayerEventListeners() {
3615
3717
  var _this = this;
3616
- this.adLayer.on("ad_impression", function() {
3718
+ this.adLayer.on("ad_impression", function(payload) {
3617
3719
  if (_this.config.licenseKey) {
3720
+ var _ref;
3721
+ var adUrl = (_ref = payload === null || payload === void 0 ? void 0 : payload.adUrl) !== null && _ref !== void 0 ? _ref : _this.lastServedAdUrl;
3722
+ if (adUrl) {
3723
+ _this.lastServedAdUrl = adUrl;
3724
+ }
3618
3725
  sendAdImpressionTracking(_this.config.licenseKey, _object_spread_props(_object_spread({
3619
3726
  source: _this.getAdSource(),
3620
3727
  adIndex: _this.currentAdIndex
3621
- }, _this.lastServedAdUrl ? {
3622
- adUrl: _this.lastServedAdUrl
3728
+ }, adUrl ? {
3729
+ adUrl: adUrl
3623
3730
  } : {}), {
3624
3731
  timestamp: /* @__PURE__ */ new Date().toISOString()
3625
3732
  }), _this.getAnalyticsContext());