@streamlayer/feature-advertisement 1.1.1-rc.8.pd3aefe41 → 1.2.0

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.
Files changed (96) hide show
  1. package/lib/advertisement.d.ts +6 -6
  2. package/lib/advertisement.js +9 -9
  3. package/lib/index.d.ts +14 -15
  4. package/lib/index.js +9 -9
  5. package/lib/units/external-ad.d.ts +2 -2
  6. package/lib/units/external-ad.js +3 -3
  7. package/lib/units/external-pause-ad.js +1 -1
  8. package/lib/units/gam.js +1 -1
  9. package/lib/units/pause-ad.d.ts +1 -1
  10. package/lib/units/pause-ad.js +1 -1
  11. package/lib/units/sponsor-logo.d.ts +4 -12
  12. package/lib/units/sponsor-logo.js +3 -4
  13. package/lib/units/ssai-ad-break.d.ts +1 -1
  14. package/lib/units/ssai-creative.d.ts +1 -1
  15. package/lib/units/ssai-creative.js +1 -1
  16. package/lib/units/ssai-detector.d.ts +1 -1
  17. package/lib/units/ssai-detector.js +1 -1
  18. package/lib/units/ssai-preload.d.ts +1 -1
  19. package/lib/units/ssai-providers.d.ts +1 -1
  20. package/lib/units/ssai-providers.js +1 -1
  21. package/lib/units/vast-tracker.d.ts +1 -1
  22. package/package.json +9 -42
  23. package/classic/package.json +0 -5
  24. package/lib/cjs/advertisement.d.ts +0 -64
  25. package/lib/cjs/advertisement.js +0 -322
  26. package/lib/cjs/index.d.ts +0 -21
  27. package/lib/cjs/index.js +0 -41
  28. package/lib/cjs/package.json +0 -1
  29. package/lib/cjs/units/ad-macros.d.ts +0 -7
  30. package/lib/cjs/units/ad-macros.js +0 -91
  31. package/lib/cjs/units/external-ad.d.ts +0 -127
  32. package/lib/cjs/units/external-ad.js +0 -421
  33. package/lib/cjs/units/external-pause-ad.d.ts +0 -50
  34. package/lib/cjs/units/external-pause-ad.js +0 -259
  35. package/lib/cjs/units/gam.d.ts +0 -26
  36. package/lib/cjs/units/gam.js +0 -152
  37. package/lib/cjs/units/parse-vast-extensions.d.ts +0 -26
  38. package/lib/cjs/units/parse-vast-extensions.js +0 -56
  39. package/lib/cjs/units/pause-ad-card.d.ts +0 -49
  40. package/lib/cjs/units/pause-ad-card.js +0 -136
  41. package/lib/cjs/units/pause-ad.d.ts +0 -16
  42. package/lib/cjs/units/pause-ad.js +0 -52
  43. package/lib/cjs/units/sponsor-logo.d.ts +0 -78
  44. package/lib/cjs/units/sponsor-logo.js +0 -194
  45. package/lib/cjs/units/ssai-ad-break.d.ts +0 -21
  46. package/lib/cjs/units/ssai-ad-break.js +0 -11
  47. package/lib/cjs/units/ssai-creative.d.ts +0 -89
  48. package/lib/cjs/units/ssai-creative.js +0 -136
  49. package/lib/cjs/units/ssai-detector.d.ts +0 -180
  50. package/lib/cjs/units/ssai-detector.js +0 -1172
  51. package/lib/cjs/units/ssai-log.d.ts +0 -16
  52. package/lib/cjs/units/ssai-log.js +0 -23
  53. package/lib/cjs/units/ssai-preload.d.ts +0 -20
  54. package/lib/cjs/units/ssai-preload.js +0 -62
  55. package/lib/cjs/units/ssai-providers.d.ts +0 -117
  56. package/lib/cjs/units/ssai-providers.js +0 -300
  57. package/lib/cjs/units/vast-tracker.d.ts +0 -45
  58. package/lib/cjs/units/vast-tracker.js +0 -64
  59. package/lib/classic/_virtual/_rollupPluginBabelHelpers.js +0 -71
  60. package/lib/classic/advertisement.js +0 -348
  61. package/lib/classic/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -77
  62. package/lib/classic/cjs/advertisement.js +0 -350
  63. package/lib/classic/cjs/index.js +0 -49
  64. package/lib/classic/cjs/package.json +0 -1
  65. package/lib/classic/cjs/units/ad-macros.js +0 -115
  66. package/lib/classic/cjs/units/external-ad.js +0 -500
  67. package/lib/classic/cjs/units/external-pause-ad.js +0 -278
  68. package/lib/classic/cjs/units/gam.js +0 -173
  69. package/lib/classic/cjs/units/parse-vast-extensions.js +0 -60
  70. package/lib/classic/cjs/units/pause-ad-card.js +0 -134
  71. package/lib/classic/cjs/units/pause-ad.js +0 -72
  72. package/lib/classic/cjs/units/sponsor-logo.js +0 -201
  73. package/lib/classic/cjs/units/ssai-ad-break.js +0 -11
  74. package/lib/classic/cjs/units/ssai-creative.js +0 -142
  75. package/lib/classic/cjs/units/ssai-detector.js +0 -1195
  76. package/lib/classic/cjs/units/ssai-log.js +0 -23
  77. package/lib/classic/cjs/units/ssai-preload.js +0 -72
  78. package/lib/classic/cjs/units/ssai-providers.js +0 -361
  79. package/lib/classic/cjs/units/vast-tracker.js +0 -81
  80. package/lib/classic/index.js +0 -29
  81. package/lib/classic/units/ad-macros.js +0 -113
  82. package/lib/classic/units/external-ad.js +0 -491
  83. package/lib/classic/units/external-pause-ad.js +0 -275
  84. package/lib/classic/units/gam.js +0 -171
  85. package/lib/classic/units/parse-vast-extensions.js +0 -58
  86. package/lib/classic/units/pause-ad-card.js +0 -131
  87. package/lib/classic/units/pause-ad.js +0 -70
  88. package/lib/classic/units/sponsor-logo.js +0 -197
  89. package/lib/classic/units/ssai-ad-break.js +0 -9
  90. package/lib/classic/units/ssai-creative.js +0 -140
  91. package/lib/classic/units/ssai-detector.js +0 -1192
  92. package/lib/classic/units/ssai-log.js +0 -21
  93. package/lib/classic/units/ssai-preload.js +0 -68
  94. package/lib/classic/units/ssai-providers.js +0 -351
  95. package/lib/classic/units/vast-tracker.js +0 -77
  96. package/lib/vast-client.d.ts +0 -9
@@ -1,500 +0,0 @@
1
- 'use strict';
2
-
3
- var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
4
- require('core-js/modules/es.symbol.description.js');
5
- require('core-js/modules/es.error.cause.js');
6
- require('core-js/modules/es.array.iterator.js');
7
- require('core-js/modules/es.array.reduce.js');
8
- require('core-js/modules/es.array.sort.js');
9
- require('core-js/modules/es.json.stringify.js');
10
- require('core-js/modules/es.promise.js');
11
- require('core-js/modules/es.regexp.exec.js');
12
- require('core-js/modules/es.string.replace.js');
13
- require('core-js/modules/es.string.replace-all.js');
14
- require('core-js/modules/esnext.iterator.constructor.js');
15
- require('core-js/modules/esnext.iterator.filter.js');
16
- require('core-js/modules/esnext.iterator.find.js');
17
- require('core-js/modules/esnext.iterator.map.js');
18
- require('core-js/modules/esnext.iterator.reduce.js');
19
- require('core-js/modules/web.dom-collections.iterator.js');
20
- require('core-js/modules/web.url.js');
21
- require('core-js/modules/web.url.to-json.js');
22
- require('core-js/modules/web.url-search-params.js');
23
- require('core-js/modules/web.url-search-params.delete.js');
24
- require('core-js/modules/web.url-search-params.has.js');
25
- require('core-js/modules/web.url-search-params.size.js');
26
- var classic = require('@streamlayer/sdk-web-logger/classic');
27
- var vastClient = require('@dailymotion/vast-client');
28
- require('@streamlayer/sdk-web-api/classic');
29
- var VMAP = require('vmap');
30
- var gam = require('./gam.js');
31
- var parseVastExtensions = require('./parse-vast-extensions.js');
32
- var sponsorLogo = require('./sponsor-logo.js');
33
-
34
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
35
-
36
- var VMAP__default = /*#__PURE__*/_interopDefault(VMAP);
37
-
38
- const log = classic.createLogger('ui:gam-external-ad');
39
- /** Default budget for a single VAST resolution before it is treated as "no ad". */
40
- const VAST_FETCH_TIMEOUT_MS = 10000;
41
- /**
42
- * Resolve `promise`, but fall back to `undefined` if it doesn't settle within `ms`.
43
- * A slow/unreachable VAST endpoint must degrade to "no ad" instead of leaving the
44
- * fetcher (and the sidebar) stuck waiting. Uses a timer rather than `AbortController`
45
- * so it stays safe on the ES5/Chrome-32 target.
46
- */
47
- const withTimeout = (promise, ms) => {
48
- return Promise.race([promise, new Promise(resolve => {
49
- setTimeout(() => resolve(undefined), ms);
50
- })]);
51
- };
52
- // const preloadImage = (src: string) => {
53
- // return new Promise((resolve, reject) => {
54
- // const image = new Image()
55
- // image.onload = () => resolve(src)
56
- // image.onerror = () => reject()
57
- // image.src = src
58
- // })
59
- // }
60
- /**
61
- * Get the first valid creative from an ad
62
- */
63
- const getCreative = ad => {
64
- return ad.creatives.find(creative => getMediaFileUrl(creative));
65
- };
66
- /**
67
- * Get the URL of the first media file in the creative
68
- */
69
- const getMediaFileUrl = creative => {
70
- var _mediaFiles$find;
71
- const mediaFiles = creative === null || creative === void 0 ? void 0 : creative.mediaFiles;
72
- if (!(mediaFiles !== null && mediaFiles !== void 0 && mediaFiles.length)) {
73
- return '';
74
- }
75
- return ((_mediaFiles$find = mediaFiles.find(mediaFile => mediaFile.fileURL)) === null || _mediaFiles$find === void 0 ? void 0 : _mediaFiles$find.fileURL) || '';
76
- };
77
- /**
78
- * Extract the linear creative's `<ClickThrough>` URL. Sources the sidebar CTA (QR code
79
- * + click-through). `videoClickThroughURLTemplate` isn't strongly typed in the client lib.
80
- */
81
- const getClickThrough = creative => {
82
- var _creative$videoClickT;
83
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
84
- // @ts-ignore — vast-client types `videoClickThroughURLTemplate` loosely
85
- return (creative === null || creative === void 0 || (_creative$videoClickT = creative.videoClickThroughURLTemplate) === null || _creative$videoClickT === void 0 ? void 0 : _creative$videoClickT.url) || undefined;
86
- };
87
- /** Product companion mapping: the 300x75 companion is the logo, the banner-sized one the media. */
88
- const LOGO_COMPANION_WIDTH = 300;
89
- const LOGO_COMPANION_HEIGHT = 75;
90
- const isLogoSized = companion => (companion === null || companion === void 0 ? void 0 : companion.width) === LOGO_COMPANION_WIDTH && (companion === null || companion === void 0 ? void 0 : companion.height) === LOGO_COMPANION_HEIGHT;
91
- const companionArea = companion => (companion.width || 0) * (companion.height || 0);
92
- /**
93
- * Split a `<CompanionAds>` creative's variations into the logo and media slots.
94
- *
95
- * The pair mapping activates only for a tag that ships an exact 300x75 companion next to at
96
- * least one other. Deliberately conservative pending broader product sizes: on any other tag
97
- * no companion is promoted to the logo slot and the first one stays the media/strip candidate.
98
- *
99
- * Both halves of that gate are load-bearing and neither is an aspect rule: a 320x80 companion is
100
- * the same 4:1 shape as 300x75 and is still rejected, and a lone 300x75 companion is rejected too
101
- * (the Standard Ad Sidebar recovers that one as `AdData.loneLogo` when a Linear / NonLinear is
102
- * the media, so it is not needed here).
103
- * This is **narrower than iOS**, which has no size rule at all and fills its logo slot from a
104
- * single companion — see `docs/wiki/programmatic-ads-display-ios-parity.md`. Exported for
105
- * `external-ad.spec.ts` only; `src/index.ts` re-exports names explicitly, so this stays out of the
106
- * package's public API.
107
- */
108
- const selectCompanions = companions => {
109
- const logo = companions.length > 1 ? companions.find(companion => isLogoSized(companion)) : undefined;
110
- if (!logo) {
111
- return {
112
- logo: undefined,
113
- media: companions[0]
114
- };
115
- }
116
- const media = companions.filter(companion => companion !== logo).sort((a, b) => companionArea(a) - companionArea(b)).pop();
117
- return {
118
- logo,
119
- media
120
- };
121
- };
122
- /**
123
- * Map a parsed VAST response into our `AdData` shape. Shared by both acquisition
124
- * paths — the GAM/VMAP tag flow and the Prebid auction flow — so the two always
125
- * produce identical downstream data.
126
- *
127
- * Returns `undefined` for a no-ad, which is two distinct shapes: a response with no ad carrying
128
- * creatives, and an ad whose creatives carry no RENDERABLE asset — no linear `<MediaFile>`, no
129
- * `<NonLinear>` still and no `<Companion>` image. Both callers `filter(Boolean)` the result, so a
130
- * no-ad leaves `ads: []` and the card keeps whatever the server configured for it.
131
- *
132
- * Exported for `vast-mapping.spec.ts`, which drives it over the same fixture corpus the iOS suite
133
- * uses. `src/index.ts` re-exports names explicitly, so this stays out of the package's public API.
134
- */
135
- const buildAdData = (parsedVAST, order) => {
136
- var _validAd$extensions$f;
137
- // Defensive, and unreachable through either production path: `@dailymotion/vast-client` discards
138
- // an ad whose creatives all fail to parse (empty `<Linear>`, empty/missing `<Creatives>`, unknown
139
- // creative element) before `parseVAST` resolves, so it never yields an Ad with zero creatives.
140
- // Kept because it costs nothing and `buildAdData` is also reachable from tests with a hand-built
141
- // response — see the `invalid_ad` case in `vast-mapping.spec.ts`, which pins the parser contract
142
- // this relies on rather than pretending to exercise the guard.
143
- const validAd = parsedVAST.ads.find(ads => ads.creatives.length > 0);
144
- if (!validAd) {
145
- log.warn({
146
- order,
147
- ads: parsedVAST.ads.length
148
- }, 'vast response carries no ad with creatives — treated as no-ad');
149
- return undefined;
150
- }
151
- const extension = (_validAd$extensions$f = validAd.extensions.find(ext => ext.attributes.type.startsWith('streamlayer'))) === null || _validAd$extensions$f === void 0 ? void 0 : _validAd$extensions$f.children[0];
152
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
153
- // @ts-expect-error
154
- const parsedExtension = parseVastExtensions.parseVastExtension(extension);
155
- const creative = getCreative(validAd);
156
- const mediaFileUrl = getMediaFileUrl(creative);
157
- const images = sponsorLogo.collectAssets(validAd);
158
- const companions = images.filter(asset => asset.origin === 'companion');
159
- const nonLinear = images.find(asset => asset.origin === 'nonlinear');
160
- // An ad the parser KEPT whose creatives carry nothing any shell can draw is a no-ad, exactly
161
- // like a response with no ad at all. vast-client only discards a creative it cannot parse; a
162
- // `<NonLinear>` or `<Companion>` whose `<StaticResource>` body is empty parses fine and just
163
- // yields no url, so the guard above cannot catch it. Without this the fabricated promotion still
164
- // took the slot and drew the ad's TEXT — title and description over an empty media box — which
165
- // is a billable impression for a creative that does not exist.
166
- //
167
- // "Renderable" is the union of the three slots the shells can fill: a linear `<MediaFile>`, a
168
- // `<NonLinear>` still, or a `<Companion>` image. `collectAssets` already drops the imageless
169
- // ones, so a non-empty `companions` means at least one drawable image. A tag carrying only a
170
- // `<Mezzanine>` never reaches here — the parser drops that Linear itself — but it lands in the
171
- // same place either way.
172
- if (!mediaFileUrl && !nonLinear && companions.length === 0) {
173
- log.warn({
174
- order,
175
- adId: validAd.id,
176
- creatives: validAd.creatives.length
177
- }, 'vast ad carries no renderable asset (no media file, no nonlinear, no companion) — treated as no-ad');
178
- return undefined;
179
- }
180
- const {
181
- logo,
182
- media: mediaCompanion
183
- } = selectCompanions(companions);
184
- const clickThrough = getClickThrough(creative) || (nonLinear === null || nonLinear === void 0 ? void 0 : nonLinear.clickUrl) || (mediaCompanion === null || mediaCompanion === void 0 ? void 0 : mediaCompanion.clickUrl);
185
- // Mirror iOS's greedy `pool.select([hero, .cardLogo])`: the hero claims first and a claimed
186
- // asset is gone for later roles. Web's hero precedence (`createActiveAdFromVast`) is linear
187
- // video → pair media companion (unreachable here: a `logo` short-circuits the whole selection)
188
- // → NonLinear still → lone companion, so a companion is only unavailable to the logo slot when
189
- // it IS the hero, i.e. when the tag ships neither. `selectCardLogo` already filters to companion
190
- // origins, so the NonLinear never needs excluding.
191
- //
192
- // Excluding `companions[0]` (which is what `mediaCompanion` is when there is no `logo`) rather
193
- // than the largest-area asset is a deliberate difference from iOS's `areaDominant` hero: web's
194
- // content slot draws the FIRST companion in document order, so document order is the correct
195
- // criterion for "what the hero already claimed" on this platform.
196
- const companionIsHero = !mediaFileUrl && !nonLinear;
197
- const cardLogoAsset = logo ? undefined : sponsorLogo.selectCardLogo(validAd, companionIsHero ? [mediaCompanion] : []);
198
- // Share the selected resource wrapper so drawn-companion identity remains stable.
199
- const cardLogo = cardLogoAsset ? companions.find(item => item.variation === cardLogoAsset.variation && item.imageUrl === cardLogoAsset.imageUrl) : undefined;
200
- // Same collected instance as `companion` (identity matters to `drawnCompanions`). A lone
201
- // companion never satisfies the pair rule, so this can only fill a slot `logo` left empty.
202
- const loneLogo = companions.length === 1 && !companionIsHero && isLogoSized(companions[0]) ? companions[0] : undefined;
203
- log.info({
204
- order,
205
- adId: validAd.id,
206
- title: validAd.title || undefined,
207
- found: {
208
- linear: !!creative,
209
- mediaFile: mediaFileUrl || undefined,
210
- nonLinear: nonLinear ? `${nonLinear.width}x${nonLinear.height}` : undefined,
211
- companions: companions.map(item => `${item.width}x${item.height}`)
212
- },
213
- selected: {
214
- logo: logo ? {
215
- size: `${logo.width}x${logo.height}`,
216
- url: logo.imageUrl
217
- } : undefined,
218
- media: mediaCompanion ? {
219
- size: `${mediaCompanion.width}x${mediaCompanion.height}`,
220
- url: mediaCompanion.imageUrl
221
- } : undefined,
222
- cardLogo: cardLogo ? {
223
- size: `${cardLogo.width}x${cardLogo.height}`,
224
- url: cardLogo.imageUrl
225
- } : undefined,
226
- loneLogo: loneLogo ? {
227
- size: `${loneLogo.width}x${loneLogo.height}`,
228
- url: loneLogo.imageUrl
229
- } : undefined,
230
- clickThrough: !!clickThrough
231
- }
232
- }, 'vast ad parsed');
233
- return {
234
- creative,
235
- order,
236
- mediaFileUrl,
237
- companion: companions[0],
238
- logo,
239
- cardLogo,
240
- loneLogo,
241
- mediaCompanion,
242
- nonLinear,
243
- clickThrough,
244
- title: validAd.title || undefined,
245
- description: validAd.description || undefined,
246
- ad: validAd,
247
- extension: parsedExtension,
248
- raw: parsedVAST
249
- };
250
- };
251
- /** Path of the self-hosted Prebid Server OpenRTB auction endpoint. */
252
- const PREBID_AUCTION_PATH = '/openrtb2/auction';
253
- /**
254
- * A Prebid link points at our Prebid Server auction endpoint (staging:
255
- * `https://prebid.next.streamlayer.io/openrtb2/auction`) rather than at a VAST tag.
256
- * Detected by path so both staging and production hosts match.
257
- */
258
- const isPrebidUrl = url => url.pathname.endsWith(PREBID_AUCTION_PATH);
259
- /** Unique per-auction request id — Prebid responses are never cached/reused (RFC §5). */
260
- const createRequestId = () => `sl-web-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
261
- /**
262
- * Build the OpenRTB request body for a single video auction. Placement config is
263
- * carried on the Prebid link's query string so the consumer-facing interface stays a
264
- * single URL string:
265
- * - `configId` → `imp.ext.prebid.storedrequest.id` (production stored request).
266
- * - `storedauctionresponse` → `imp.ext.prebid.storedauctionresponse.id` (staging mock).
267
- * - `test=1` → top-level `test` flag.
268
- * - `w` / `h` → video dimensions (default 1920×1080).
269
- *
270
- * The host's GDPR consent (`AdTagParams`) rides the OpenRTB 2.5 extension fields Prebid Server
271
- * reads — `regs.ext.gdpr` and `user.ext.consent` — the same signal the `${GDPR}` /
272
- * `${GDPR_CONSENT}` macros carry for a VAST tag. Each is sent only when the host passed it.
273
- */
274
- const buildAuctionRequest = (url, adTagParams) => {
275
- var _ref, _params$get, _params$get2;
276
- const params = url.searchParams;
277
- const width = Number(params.get('w')) || 1920;
278
- const height = Number(params.get('h')) || 1080;
279
- const configId = (_ref = (_params$get = params.get('configId')) !== null && _params$get !== void 0 ? _params$get : params.get('config_id')) !== null && _ref !== void 0 ? _ref : undefined;
280
- const storedAuctionResponse = (_params$get2 = params.get('storedauctionresponse')) !== null && _params$get2 !== void 0 ? _params$get2 : undefined;
281
- const prebid = {};
282
- if (storedAuctionResponse) {
283
- prebid.storedauctionresponse = {
284
- id: storedAuctionResponse
285
- };
286
- }
287
- if (configId) {
288
- prebid.storedrequest = {
289
- id: configId
290
- };
291
- }
292
- prebid.bidder = {
293
- appnexus: {
294
- placementId: 13144370
295
- }
296
- };
297
- const request = {
298
- id: createRequestId(),
299
- imp: [{
300
- id: '1',
301
- video: {
302
- mimes: ['video/mp4'],
303
- protocols: [2, 3, 5, 6],
304
- w: width,
305
- h: height,
306
- placement: 1,
307
- linearity: 1
308
- },
309
- ext: {
310
- prebid
311
- }
312
- }],
313
- site: {
314
- page: typeof location !== 'undefined' ? location.href : url.origin
315
- },
316
- tmax: 500
317
- };
318
- if (params.get('test') === '1') {
319
- request.test = 1;
320
- }
321
- if ((adTagParams === null || adTagParams === void 0 ? void 0 : adTagParams.gdprApplies) !== undefined) {
322
- request.regs = {
323
- ext: {
324
- gdpr: adTagParams.gdprApplies ? 1 : 0
325
- }
326
- };
327
- }
328
- if (adTagParams !== null && adTagParams !== void 0 && adTagParams.tcString) {
329
- request.user = {
330
- ext: {
331
- consent: adTagParams.tcString
332
- }
333
- };
334
- }
335
- return request;
336
- };
337
- /**
338
- * Run one Prebid Server auction and turn the winning inline VAST into an `AdStore`.
339
- * Every bid's `adm` is inline VAST XML (no URL to fetch); bids are ordered by price
340
- * so the winner plays first (RFC §2). A single bad bid must not drop the batch.
341
- */
342
- const fetchPrebidAds = /*#__PURE__*/function () {
343
- var _ref2 = _rollupPluginBabelHelpers.asyncToGenerator(function* (prebidUrl, adTagParams) {
344
- var _auction$seatbid, _params$get3, _params$get4;
345
- const response = yield fetch(prebidUrl.toString(), {
346
- method: 'POST',
347
- headers: {
348
- 'Content-Type': 'application/json'
349
- },
350
- body: JSON.stringify(buildAuctionRequest(prebidUrl, adTagParams))
351
- });
352
- if (!response.ok) {
353
- throw new Error(`prebid auction failed with status ${response.status}`);
354
- }
355
- const auction = yield response.json();
356
- const bids = ((_auction$seatbid = auction.seatbid) !== null && _auction$seatbid !== void 0 ? _auction$seatbid : []).reduce((acc, seat) => {
357
- var _seat$bid;
358
- return acc.concat((_seat$bid = seat.bid) !== null && _seat$bid !== void 0 ? _seat$bid : []);
359
- }, []).filter(bid => !!bid.adm)
360
- // Highest price wins — the winner is order 0 (RFC §2).
361
- .sort((a, b) => {
362
- var _b$price, _a$price;
363
- return ((_b$price = b.price) !== null && _b$price !== void 0 ? _b$price : 0) - ((_a$price = a.price) !== null && _a$price !== void 0 ? _a$price : 0);
364
- });
365
- const parser = new DOMParser();
366
- const loadedAds = yield Promise.all(bids.map((bid, i) => {
367
- const xmlDoc = parser.parseFromString(bid.adm, 'text/xml');
368
- // A fresh `VASTParser` per bid isolates parser state, mirroring the fresh
369
- // `VASTClient` per link in the tag flow. `resolveAll: true` follows any
370
- // `VASTAdTagURI` wrapper chain the bid's inline VAST may still contain.
371
- return new vastClient.VASTParser()
372
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
373
- // @ts-ignore
374
- .parseVAST(xmlDoc, {
375
- resolveAll: true,
376
- wrapperLimit: 10,
377
- allowMultipleAds: true
378
- }).then(parsedVAST => buildAdData(parsedVAST, i)).catch(err => {
379
- // A single failing bid must not drop the whole batch.
380
- log.error(err, 'failed to parse prebid VAST');
381
- return undefined;
382
- });
383
- }));
384
- const params = prebidUrl.searchParams;
385
- const autoplay = ((_params$get3 = params.get('vpa')) === null || _params$get3 === void 0 ? void 0 : _params$get3.replaceAll('?', '')) !== 'click';
386
- const muted = ((_params$get4 = params.get('vpmute')) === null || _params$get4 === void 0 ? void 0 : _params$get4.replaceAll('?', '')) === '1';
387
- return {
388
- ads: loadedAds.filter(d => !!d),
389
- autoplay,
390
- muted
391
- };
392
- });
393
- return function fetchPrebidAds(_x, _x2) {
394
- return _ref2.apply(this, arguments);
395
- };
396
- }();
397
- const externalAd = instance => {
398
- return gamUrl => instance.transport.nanoquery.createFetcherStore([gamUrl], {
399
- dedupeTime: Infinity,
400
- revalidateInterval: 0,
401
- fetcher: function () {
402
- var _ref3 = _rollupPluginBabelHelpers.asyncToGenerator(function* (adUrl) {
403
- var _noncedLink$searchPar, _noncedLink$searchPar2, _noncedLink$searchPar3;
404
- if (!adUrl || typeof adUrl !== 'string') {
405
- throw new Error('ad url is empty');
406
- }
407
- const parsedAdUrl = (() => {
408
- try {
409
- return new URL(adUrl);
410
- } catch (_unused) {
411
- return undefined;
412
- }
413
- })();
414
- // The host's CURRENT macro values, read per request rather than baked into the store: the
415
- // store is cached by url for the session, and consent routinely arrives after the SDK
416
- // starts (a CMP answers asynchronously) or changes mid-session.
417
- const adTagParams = instance.sdk.options.get().adTagParams;
418
- // Prebid links hit our Prebid Server auction endpoint instead of a VAST tag.
419
- // Run the OpenRTB auction and parse the winning bid's inline VAST (`adm`) into
420
- // the same `AdStore` shape the GAM/VMAP path returns. See rfcs/prebid.
421
- if (parsedAdUrl && isPrebidUrl(parsedAdUrl)) {
422
- return fetchPrebidAds(parsedAdUrl, adTagParams);
423
- }
424
- const generateUrl = gam.gam(adUrl, undefined, adTagParams);
425
- const generatedUrl = yield generateUrl();
426
- const noncedLink = generatedUrl === null || generatedUrl === void 0 ? void 0 : generatedUrl.url;
427
- if (!noncedLink) {
428
- throw new Error('ad url is not generated');
429
- }
430
- let links;
431
- if (((_noncedLink$searchPar = noncedLink.searchParams.get('output')) === null || _noncedLink$searchPar === void 0 ? void 0 : _noncedLink$searchPar.replaceAll('?', '')) === 'vmap') {
432
- const response = yield withTimeout(fetch(noncedLink.toString()), VAST_FETCH_TIMEOUT_MS);
433
- if (!response) {
434
- throw new Error('vmap fetch timed out');
435
- }
436
- const parser = new DOMParser();
437
- const xmlStr = yield response.text();
438
- const xmlDoc = parser.parseFromString(xmlStr, 'text/xml');
439
- const vmap = new VMAP__default.default(xmlDoc);
440
- links = vmap.adBreaks.map(ad => {
441
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
442
- // @ts-expect-error
443
- return ad.adSource.adTagURI.uri;
444
- });
445
- } else {
446
- links = [noncedLink.toString()];
447
- }
448
- const loadedAds = yield Promise.all(links.map((link, i) => {
449
- // `resolveAll: true` makes the client follow every `VASTAdTagURI` wrapper chain
450
- // (up to the default depth of 10) and resolve all Ads, merging wrapper-level
451
- // Impression/tracking URLs into the inline Ad. The default (`resolveAll: false`)
452
- // only resolves the first standalone Ad and defers wrappers/remaining Ads to
453
- // `getNextAds()`, which this fetcher never calls. A fresh `VASTClient` per link
454
- // isolates parser state so concurrent (VMAP) resolutions don't clobber each other.
455
- return withTimeout(new vastClient.VASTClient()
456
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
457
- // @ts-ignore
458
- .get(link, {
459
- resolveAll: true,
460
- wrapperLimit: 10,
461
- allowMultipleAds: true
462
- }), VAST_FETCH_TIMEOUT_MS).then(parsedVAST => {
463
- // `parsedVAST` is `undefined` when the resolution timed out (see `withTimeout`).
464
- if (!parsedVAST) {
465
- log.warn({
466
- link,
467
- timeoutMs: VAST_FETCH_TIMEOUT_MS
468
- }, 'vast resolution timed out — treated as no-ad');
469
- return undefined;
470
- }
471
- return buildAdData(parsedVAST, i);
472
- }).catch(err => {
473
- // A single failing wrapper chain must not drop the whole batch.
474
- log.error(err, 'failed to resolve VAST');
475
- return undefined;
476
- });
477
- }));
478
- const autoplay = ((_noncedLink$searchPar2 = noncedLink.searchParams.get('vpa')) === null || _noncedLink$searchPar2 === void 0 ? void 0 : _noncedLink$searchPar2.replaceAll('?', '')) !== 'click';
479
- const muted = ((_noncedLink$searchPar3 = noncedLink.searchParams.get('vpmute')) === null || _noncedLink$searchPar3 === void 0 ? void 0 : _noncedLink$searchPar3.replaceAll('?', '')) === '1';
480
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
481
- // @ts-expect-error
482
- const nonceManager = generatedUrl.manager;
483
- return {
484
- ads: loadedAds.filter(d => !!d),
485
- autoplay,
486
- muted,
487
- nonceManager
488
- };
489
- });
490
- return function fetcher(_x3) {
491
- return _ref3.apply(this, arguments);
492
- };
493
- }()
494
- });
495
- };
496
-
497
- exports.buildAdData = buildAdData;
498
- exports.buildAuctionRequest = buildAuctionRequest;
499
- exports.externalAd = externalAd;
500
- exports.selectCompanions = selectCompanions;