UNPKG

video-ad-sdk

Version:

VAST/VPAID SDK that allows video ads to be played on top of any player

133 lines (132 loc) 5.2 kB
import { parseXml } from '../xml'; import { isVastErrorCode, ErrorCode } from '../tracker'; import { getWrapperOptions, getFirstAd, getVASTAdTagURI, hasAdPod, isInline, isWrapper } from '../vastSelectors'; import { fetch } from './helpers/fetch'; import { VastError } from './helpers/vastError'; import { markAdAsRequested } from './helpers/adUtils'; const validateChain = (vastChain, { wrapperLimit = 5 }) => { if (vastChain.length > wrapperLimit) { const error = new VastError('Wrapper Limit reached'); error.code = ErrorCode.VAST_TOO_MANY_REDIRECTS; throw error; } }; const fetchAdXML = async (adTag, options) => { var _a; let response; try { response = await fetch(adTag, options); const XML = await response.text(); return { response, XML }; } catch (error) { error.code = ErrorCode.VAST_NONLINEAR_LOADING_FAILED; (_a = error.response) !== null && _a !== void 0 ? _a : (error.response = response); throw error; } }; const parseVastXml = (xml) => { try { return parseXml(xml); } catch (error) { error.code = ErrorCode.VAST_XML_PARSING_ERROR; throw error; } }; const getAd = (parsedXML) => { try { const ad = getFirstAd(parsedXML); if (ad) { markAdAsRequested(ad); return ad; } throw new Error('No Ad'); } catch (error) { error.code = ErrorCode.VAST_NO_ADS_AFTER_WRAPPER; throw error; } }; const validateResponse = ({ ad, parsedXML }, { allowMultipleAds = true, followAdditionalWrappers = true }) => { if (!isWrapper(ad) && !isInline(ad)) { const error = new VastError('Invalid VAST, ad contains neither Wrapper nor Inline'); error.code = ErrorCode.VAST_SCHEMA_VALIDATION_ERROR; throw error; } if (hasAdPod(parsedXML) && !allowMultipleAds) { const error = new VastError('Multiple ads are not allowed'); error.code = ErrorCode.VAST_UNEXPECTED_MEDIA_FILE; throw error; } if (isWrapper(ad) && !followAdditionalWrappers) { const error = new VastError('To follow additional wrappers is not allowed'); error.code = ErrorCode.VAST_UNEXPECTED_AD_TYPE; throw error; } }; const getOptions = (vastChain, options) => { const [parentAd] = vastChain; const parentAdIsWrapper = Boolean(parentAd) && parentAd.ad && isWrapper(parentAd.ad); const wrapperOptions = parentAdIsWrapper && parentAd.ad ? getWrapperOptions(parentAd.ad) : {}; return Object.assign(Object.assign({}, wrapperOptions), options); }; /** * Request the ad using the passed ad tag and returns an array with the {@link VastResponse} needed to get an inline ad. * * @param adTag The VAST ad tag request url. * @param options Options Map. The allowed properties are: * @param vastChain Optional vastChain with the previous VAST responses. * @returns Returns a Promise that will resolve with a VastChain with the newest VAST response at the beginning of the array. * If the {@link VastChain} had an error. The first VAST response of the array will contain an error and an errorCode entry. */ export const requestAd = async (adTag, options, vastChain = []) => { var _a; const vastAdResponse = { requestTag: adTag }; let epoch; let timeout; try { const resultOptions = getOptions(vastChain, options); validateChain(vastChain, resultOptions); let fetchPromise = fetchAdXML(adTag, resultOptions); if (typeof resultOptions.timeout === 'number') { timeout = resultOptions.timeout; epoch = Date.now(); fetchPromise = Promise.race([ fetchPromise, new Promise((_resolve, reject) => { setTimeout(() => { const error = new VastError('RequestAd timeout'); error.code = ErrorCode.VAST_LOAD_TIMEOUT; reject(error); }, timeout); }) ]); } const { response, XML } = await fetchPromise; vastAdResponse.response = response; vastAdResponse.XML = XML; vastAdResponse.parsedXML = parseVastXml(vastAdResponse.XML); vastAdResponse.ad = getAd(vastAdResponse.parsedXML); validateResponse(vastAdResponse, resultOptions); if (isWrapper(vastAdResponse.ad)) { if (epoch && timeout) { timeout -= Date.now() - epoch; } return requestAd(getVASTAdTagURI(vastAdResponse.ad), Object.assign(Object.assign({}, resultOptions), { timeout }), [vastAdResponse, ...vastChain]); } return [vastAdResponse, ...vastChain]; } catch (error) { /* istanbul ignore if */ if (!isVastErrorCode(error.code)) { error.code = ErrorCode.UNKNOWN_ERROR; } vastAdResponse.errorCode = error.code; vastAdResponse.error = error; (_a = vastAdResponse.response) !== null && _a !== void 0 ? _a : (vastAdResponse.response = error.response); return [vastAdResponse, ...vastChain]; } };