@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.
- package/lib/advertisement.d.ts +6 -6
- package/lib/advertisement.js +9 -9
- package/lib/index.d.ts +14 -15
- package/lib/index.js +9 -9
- package/lib/units/external-ad.d.ts +2 -2
- package/lib/units/external-ad.js +3 -3
- package/lib/units/external-pause-ad.js +1 -1
- package/lib/units/gam.js +1 -1
- package/lib/units/pause-ad.d.ts +1 -1
- package/lib/units/pause-ad.js +1 -1
- package/lib/units/sponsor-logo.d.ts +4 -12
- package/lib/units/sponsor-logo.js +3 -4
- package/lib/units/ssai-ad-break.d.ts +1 -1
- package/lib/units/ssai-creative.d.ts +1 -1
- package/lib/units/ssai-creative.js +1 -1
- package/lib/units/ssai-detector.d.ts +1 -1
- package/lib/units/ssai-detector.js +1 -1
- package/lib/units/ssai-preload.d.ts +1 -1
- package/lib/units/ssai-providers.d.ts +1 -1
- package/lib/units/ssai-providers.js +1 -1
- package/lib/units/vast-tracker.d.ts +1 -1
- package/package.json +9 -42
- package/classic/package.json +0 -5
- package/lib/cjs/advertisement.d.ts +0 -64
- package/lib/cjs/advertisement.js +0 -322
- package/lib/cjs/index.d.ts +0 -21
- package/lib/cjs/index.js +0 -41
- package/lib/cjs/package.json +0 -1
- package/lib/cjs/units/ad-macros.d.ts +0 -7
- package/lib/cjs/units/ad-macros.js +0 -91
- package/lib/cjs/units/external-ad.d.ts +0 -127
- package/lib/cjs/units/external-ad.js +0 -421
- package/lib/cjs/units/external-pause-ad.d.ts +0 -50
- package/lib/cjs/units/external-pause-ad.js +0 -259
- package/lib/cjs/units/gam.d.ts +0 -26
- package/lib/cjs/units/gam.js +0 -152
- package/lib/cjs/units/parse-vast-extensions.d.ts +0 -26
- package/lib/cjs/units/parse-vast-extensions.js +0 -56
- package/lib/cjs/units/pause-ad-card.d.ts +0 -49
- package/lib/cjs/units/pause-ad-card.js +0 -136
- package/lib/cjs/units/pause-ad.d.ts +0 -16
- package/lib/cjs/units/pause-ad.js +0 -52
- package/lib/cjs/units/sponsor-logo.d.ts +0 -78
- package/lib/cjs/units/sponsor-logo.js +0 -194
- package/lib/cjs/units/ssai-ad-break.d.ts +0 -21
- package/lib/cjs/units/ssai-ad-break.js +0 -11
- package/lib/cjs/units/ssai-creative.d.ts +0 -89
- package/lib/cjs/units/ssai-creative.js +0 -136
- package/lib/cjs/units/ssai-detector.d.ts +0 -180
- package/lib/cjs/units/ssai-detector.js +0 -1172
- package/lib/cjs/units/ssai-log.d.ts +0 -16
- package/lib/cjs/units/ssai-log.js +0 -23
- package/lib/cjs/units/ssai-preload.d.ts +0 -20
- package/lib/cjs/units/ssai-preload.js +0 -62
- package/lib/cjs/units/ssai-providers.d.ts +0 -117
- package/lib/cjs/units/ssai-providers.js +0 -300
- package/lib/cjs/units/vast-tracker.d.ts +0 -45
- package/lib/cjs/units/vast-tracker.js +0 -64
- package/lib/classic/_virtual/_rollupPluginBabelHelpers.js +0 -71
- package/lib/classic/advertisement.js +0 -348
- package/lib/classic/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -77
- package/lib/classic/cjs/advertisement.js +0 -350
- package/lib/classic/cjs/index.js +0 -49
- package/lib/classic/cjs/package.json +0 -1
- package/lib/classic/cjs/units/ad-macros.js +0 -115
- package/lib/classic/cjs/units/external-ad.js +0 -500
- package/lib/classic/cjs/units/external-pause-ad.js +0 -278
- package/lib/classic/cjs/units/gam.js +0 -173
- package/lib/classic/cjs/units/parse-vast-extensions.js +0 -60
- package/lib/classic/cjs/units/pause-ad-card.js +0 -134
- package/lib/classic/cjs/units/pause-ad.js +0 -72
- package/lib/classic/cjs/units/sponsor-logo.js +0 -201
- package/lib/classic/cjs/units/ssai-ad-break.js +0 -11
- package/lib/classic/cjs/units/ssai-creative.js +0 -142
- package/lib/classic/cjs/units/ssai-detector.js +0 -1195
- package/lib/classic/cjs/units/ssai-log.js +0 -23
- package/lib/classic/cjs/units/ssai-preload.js +0 -72
- package/lib/classic/cjs/units/ssai-providers.js +0 -361
- package/lib/classic/cjs/units/vast-tracker.js +0 -81
- package/lib/classic/index.js +0 -29
- package/lib/classic/units/ad-macros.js +0 -113
- package/lib/classic/units/external-ad.js +0 -491
- package/lib/classic/units/external-pause-ad.js +0 -275
- package/lib/classic/units/gam.js +0 -171
- package/lib/classic/units/parse-vast-extensions.js +0 -58
- package/lib/classic/units/pause-ad-card.js +0 -131
- package/lib/classic/units/pause-ad.js +0 -70
- package/lib/classic/units/sponsor-logo.js +0 -197
- package/lib/classic/units/ssai-ad-break.js +0 -9
- package/lib/classic/units/ssai-creative.js +0 -140
- package/lib/classic/units/ssai-detector.js +0 -1192
- package/lib/classic/units/ssai-log.js +0 -21
- package/lib/classic/units/ssai-preload.js +0 -68
- package/lib/classic/units/ssai-providers.js +0 -351
- package/lib/classic/units/vast-tracker.js +0 -77
- package/lib/vast-client.d.ts +0 -9
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var classic = require('@streamlayer/sdk-web-logger/classic');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* `ssaiq` — the SSAI ad NARRATIVE log: one line per thing that happens to a
|
|
7
|
-
* server-stitched ad, in the order it happens. The manifest tag the playout
|
|
8
|
-
* published, the metadata round trip it triggers, the break the SDK opens from
|
|
9
|
-
* it, and every beacon fired against it.
|
|
10
|
-
*
|
|
11
|
-
* Named for the Quortex/Synamedia DAI integration it was built for, but it is
|
|
12
|
-
* the path itself that is logged, so a StreamLayer-dialect stream tells the same
|
|
13
|
-
* story. Detector internals — clock sources, poll ticks, fold bookkeeping — stay
|
|
14
|
-
* on `ssai:*`, where `SL_DEBUG` can reach them without filling a demo window.
|
|
15
|
-
*
|
|
16
|
-
* A host publishes it to the page with `SL_LOG_EVENTS=ssaiq` (see
|
|
17
|
-
* `sdk-web-logger`); the demo's log window renders exactly that.
|
|
18
|
-
*/
|
|
19
|
-
// Explicit type: the inferred pino type is not nameable across package
|
|
20
|
-
// boundaries (TS2742) when this file is compiled on its own.
|
|
21
|
-
const ssaiq = classic.createLogger('ssaiq');
|
|
22
|
-
|
|
23
|
-
exports.ssaiq = ssaiq;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
require('core-js/modules/es.array.iterator.js');
|
|
4
|
-
require('core-js/modules/es.promise.js');
|
|
5
|
-
require('core-js/modules/esnext.iterator.constructor.js');
|
|
6
|
-
require('core-js/modules/esnext.iterator.filter.js');
|
|
7
|
-
require('core-js/modules/web.dom-collections.iterator.js');
|
|
8
|
-
var classic = require('@streamlayer/sdk-web-logger/classic');
|
|
9
|
-
|
|
10
|
-
const log = classic.createLogger('ssai:preload');
|
|
11
|
-
/**
|
|
12
|
-
* How long the overlay is willing to wait for artwork. A slow or dead image host
|
|
13
|
-
* must never hold the bar back — the ad is already playing, and a bar that shows
|
|
14
|
-
* late is worse than one that shows without its logo (the logo is hidden on error
|
|
15
|
-
* anyway). Warming the browser cache is the goal; blocking is not.
|
|
16
|
-
*/
|
|
17
|
-
const DEFAULT_PRELOAD_TIMEOUT_MS = 2000;
|
|
18
|
-
/**
|
|
19
|
-
* Fetch images into the browser cache and resolve once they are all settled, or
|
|
20
|
-
* once `timeoutMs` elapses — whichever comes first. Never rejects: a creative
|
|
21
|
-
* whose artwork fails is still a creative worth showing.
|
|
22
|
-
*/
|
|
23
|
-
const preloadImages = (urls, timeoutMs = DEFAULT_PRELOAD_TIMEOUT_MS) => {
|
|
24
|
-
const targets = urls.filter(url => !!url);
|
|
25
|
-
// `Image` is absent in SSR/worker contexts; there is nothing to warm there.
|
|
26
|
-
if (targets.length === 0 || typeof Image === 'undefined') {
|
|
27
|
-
return Promise.resolve();
|
|
28
|
-
}
|
|
29
|
-
return new Promise(resolve => {
|
|
30
|
-
let settled = false;
|
|
31
|
-
let remaining = targets.length;
|
|
32
|
-
const finish = () => {
|
|
33
|
-
if (settled) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
settled = true;
|
|
37
|
-
clearTimeout(timer);
|
|
38
|
-
resolve();
|
|
39
|
-
};
|
|
40
|
-
const timer = setTimeout(() => {
|
|
41
|
-
log.debug({
|
|
42
|
-
remaining
|
|
43
|
-
}, 'ssai preload timed out, showing anyway');
|
|
44
|
-
finish();
|
|
45
|
-
}, timeoutMs);
|
|
46
|
-
const one = () => {
|
|
47
|
-
remaining -= 1;
|
|
48
|
-
if (remaining <= 0) {
|
|
49
|
-
finish();
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
for (const url of targets) {
|
|
53
|
-
const image = new Image();
|
|
54
|
-
image.onload = one;
|
|
55
|
-
image.onerror = one;
|
|
56
|
-
image.src = url;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
};
|
|
60
|
-
/**
|
|
61
|
-
* Warm every image the creative carries — the overlay's brand logo, and the
|
|
62
|
-
* companion banner for hosts that render one — so the bar fades in complete
|
|
63
|
-
* rather than popping its artwork in a beat later.
|
|
64
|
-
*/
|
|
65
|
-
const preloadCreativeAssets = (creative, timeoutMs) => {
|
|
66
|
-
var _creative$companion;
|
|
67
|
-
return preloadImages([creative.iconUrl, (_creative$companion = creative.companion) === null || _creative$companion === void 0 ? void 0 : _creative$companion.staticResource], timeoutMs);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
exports.DEFAULT_PRELOAD_TIMEOUT_MS = DEFAULT_PRELOAD_TIMEOUT_MS;
|
|
71
|
-
exports.preloadCreativeAssets = preloadCreativeAssets;
|
|
72
|
-
exports.preloadImages = preloadImages;
|
|
@@ -1,361 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
|
|
4
|
-
require('core-js/modules/es.error.cause.js');
|
|
5
|
-
require('core-js/modules/es.array.iterator.js');
|
|
6
|
-
require('core-js/modules/es.promise.js');
|
|
7
|
-
require('core-js/modules/es.regexp.exec.js');
|
|
8
|
-
require('core-js/modules/es.string.replace.js');
|
|
9
|
-
require('core-js/modules/esnext.iterator.constructor.js');
|
|
10
|
-
require('core-js/modules/esnext.iterator.filter.js');
|
|
11
|
-
require('core-js/modules/esnext.iterator.find.js');
|
|
12
|
-
require('core-js/modules/esnext.iterator.map.js');
|
|
13
|
-
require('core-js/modules/web.dom-collections.iterator.js');
|
|
14
|
-
require('core-js/modules/web.dom-exception.stack.js');
|
|
15
|
-
var classic = require('@streamlayer/sdk-web-logger/classic');
|
|
16
|
-
var vastClient = require('@dailymotion/vast-client');
|
|
17
|
-
var ssaiLog = require('./ssai-log.js');
|
|
18
|
-
|
|
19
|
-
const log = classic.createLogger('ssai:provider');
|
|
20
|
-
const DEFAULT_CREATIVE_API_BASE = 'https://hls.next.streamlayer.io/api/creatives/';
|
|
21
|
-
/**
|
|
22
|
-
* One creative-metadata round trip, on the narrative log: the request the SDK
|
|
23
|
-
* made and the body the ad service answered with, verbatim. This is the half of
|
|
24
|
-
* the story the manifest cannot tell — the ad's identity comes from the playout,
|
|
25
|
-
* its content comes from here.
|
|
26
|
-
*/
|
|
27
|
-
const fetchCreativeJson = /*#__PURE__*/function () {
|
|
28
|
-
var _ref = _rollupPluginBabelHelpers.asyncToGenerator(function* (providerId, url, signal) {
|
|
29
|
-
var _raw, _raw2, _raw3;
|
|
30
|
-
// `adApiBase` is customer infrastructure and may carry a key in its query;
|
|
31
|
-
// the request uses the URL as given, the log gets it with such values masked.
|
|
32
|
-
const shown = maskUrlSecrets(url);
|
|
33
|
-
ssaiLog.ssaiq.info({
|
|
34
|
-
provider: providerId,
|
|
35
|
-
url: shown
|
|
36
|
-
}, `[GET] → ${shown}`);
|
|
37
|
-
let response;
|
|
38
|
-
try {
|
|
39
|
-
response = yield fetch(url, {
|
|
40
|
-
signal
|
|
41
|
-
});
|
|
42
|
-
} catch (error) {
|
|
43
|
-
// An abort is the SDK cancelling its own request (break ended, creative
|
|
44
|
-
// changed) — a note, not a failure.
|
|
45
|
-
if ((error === null || error === void 0 ? void 0 : error.name) === 'AbortError') {
|
|
46
|
-
ssaiLog.ssaiq.debug({
|
|
47
|
-
provider: providerId,
|
|
48
|
-
url: shown
|
|
49
|
-
}, `[GET] ✗ aborted ${shown}`);
|
|
50
|
-
} else {
|
|
51
|
-
ssaiLog.ssaiq.warn({
|
|
52
|
-
provider: providerId,
|
|
53
|
-
url: shown,
|
|
54
|
-
error: String(error)
|
|
55
|
-
}, `[GET] ✗ ${shown}`);
|
|
56
|
-
}
|
|
57
|
-
throw error;
|
|
58
|
-
}
|
|
59
|
-
if (!response.ok) {
|
|
60
|
-
ssaiLog.ssaiq.warn({
|
|
61
|
-
provider: providerId,
|
|
62
|
-
url: shown,
|
|
63
|
-
status: response.status
|
|
64
|
-
}, `[GET] ✗ ${response.status} ${shown}`);
|
|
65
|
-
throw new Error(`${providerId} creative request failed: ${response.status}`);
|
|
66
|
-
}
|
|
67
|
-
let raw;
|
|
68
|
-
try {
|
|
69
|
-
raw = yield response.json();
|
|
70
|
-
} catch (error) {
|
|
71
|
-
// A 200 with a body that is not JSON would otherwise leave the log looking
|
|
72
|
-
// like a request still in flight.
|
|
73
|
-
ssaiLog.ssaiq.warn({
|
|
74
|
-
provider: providerId,
|
|
75
|
-
url: shown,
|
|
76
|
-
error: String(error)
|
|
77
|
-
}, `[GET] ✗ ${response.status} ${shown} — not JSON`);
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
ssaiLog.ssaiq.info({
|
|
81
|
-
provider: providerId,
|
|
82
|
-
status: response.status,
|
|
83
|
-
body: raw
|
|
84
|
-
}, `[GET] ← ${response.status} ad metadata — ${((_raw = raw) === null || _raw === void 0 ? void 0 : _raw.advertiser) || ((_raw2 = raw) === null || _raw2 === void 0 ? void 0 : _raw2.title) || ((_raw3 = raw) === null || _raw3 === void 0 ? void 0 : _raw3.creativeId) || 'ad'}`);
|
|
85
|
-
return raw;
|
|
86
|
-
});
|
|
87
|
-
return function fetchCreativeJson(_x, _x2, _x3) {
|
|
88
|
-
return _ref.apply(this, arguments);
|
|
89
|
-
};
|
|
90
|
-
}();
|
|
91
|
-
/** `?apiKey=…` → `?apiKey=«redacted»`, for URLs that go on a screen. Regex, not `URL`: this ships to 2016 TV engines. */
|
|
92
|
-
const maskUrlSecrets = url => url.replace(/([?&][^=&]*(?:token|secret|password|key|authorization)[^=&]*=)[^&]*/gi, '$1«redacted»');
|
|
93
|
-
/**
|
|
94
|
-
* Shared low-level beacon helper. Prefers `navigator.sendBeacon` and falls back
|
|
95
|
-
* to a no-cors `fetch`. Used by the default impression path and available to
|
|
96
|
-
* providers that fire URL-based tracking pixels.
|
|
97
|
-
*/
|
|
98
|
-
const fireBeacon = url => {
|
|
99
|
-
try {
|
|
100
|
-
if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {
|
|
101
|
-
navigator.sendBeacon(url);
|
|
102
|
-
} else {
|
|
103
|
-
void fetch(url, {
|
|
104
|
-
mode: 'no-cors'
|
|
105
|
-
}).catch(error => {
|
|
106
|
-
log.warn(error, 'ssai beacon failed');
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
} catch (error) {
|
|
110
|
-
log.warn(error, 'ssai beacon failed');
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
const resolveAdvertiser = (advertiser, title) => {
|
|
114
|
-
if (advertiser) {
|
|
115
|
-
return advertiser;
|
|
116
|
-
}
|
|
117
|
-
if (title) {
|
|
118
|
-
return title;
|
|
119
|
-
}
|
|
120
|
-
return 'Ad';
|
|
121
|
-
};
|
|
122
|
-
const buildCreativeUrl = (base, creativeId) => {
|
|
123
|
-
const normalizedBase = base.endsWith('/') ? base : `${base}/`;
|
|
124
|
-
return `${normalizedBase}${encodeURIComponent(creativeId)}`;
|
|
125
|
-
};
|
|
126
|
-
const mapApiResponse = raw => {
|
|
127
|
-
const trackingEvents = Array.isArray(raw.trackingEvents) ? raw.trackingEvents.filter(entry => Boolean((entry === null || entry === void 0 ? void 0 : entry.event) && (entry === null || entry === void 0 ? void 0 : entry.url))).map(entry => ({
|
|
128
|
-
event: entry.event,
|
|
129
|
-
url: entry.url
|
|
130
|
-
})) : [];
|
|
131
|
-
const rawCompanion = Array.isArray(raw.companions) ? raw.companions.find(entry => !!(entry !== null && entry !== void 0 && entry.staticResource)) : undefined;
|
|
132
|
-
const companion = rawCompanion !== null && rawCompanion !== void 0 && rawCompanion.staticResource ? {
|
|
133
|
-
staticResource: rawCompanion.staticResource,
|
|
134
|
-
width: Number(rawCompanion.width) || 0,
|
|
135
|
-
height: Number(rawCompanion.height) || 0,
|
|
136
|
-
clickThrough: rawCompanion.clickThrough,
|
|
137
|
-
clickTracking: Array.isArray(rawCompanion.clickTracking) ? rawCompanion.clickTracking.filter(url => typeof url === 'string' && !!url) : []
|
|
138
|
-
} : undefined;
|
|
139
|
-
return {
|
|
140
|
-
creativeId: raw.creativeId,
|
|
141
|
-
advertiser: resolveAdvertiser(raw.advertiser, raw.title),
|
|
142
|
-
title: raw.title || resolveAdvertiser(raw.advertiser, raw.title),
|
|
143
|
-
iconUrl: raw.iconUrl || undefined,
|
|
144
|
-
clickThroughUrl: raw.clickThroughUrl || undefined,
|
|
145
|
-
trackingEvents,
|
|
146
|
-
companion
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* Fire every tracking event with the given name, and report how many went out.
|
|
151
|
-
*
|
|
152
|
-
* ALL matches, not the first: the creative contract states that a creative may
|
|
153
|
-
* repeat an `event` value to carry several URLs, and that consumers must not
|
|
154
|
-
* assume uniqueness. Today's payloads carry one URL per event, so this is not a
|
|
155
|
-
* change in what goes on the wire — it just stops being wrong the day a server
|
|
156
|
-
* sends two.
|
|
157
|
-
*/
|
|
158
|
-
const fireTrackingEvents = (creative, event) => {
|
|
159
|
-
const matches = creative.trackingEvents.filter(entry => entry.event === event);
|
|
160
|
-
for (const match of matches) {
|
|
161
|
-
fireBeacon(match.url);
|
|
162
|
-
}
|
|
163
|
-
return matches.length;
|
|
164
|
-
};
|
|
165
|
-
/**
|
|
166
|
-
* Shared default impression behavior: fire the `impression` tracking events.
|
|
167
|
-
* Used by the StreamLayer provider and as the fallback in
|
|
168
|
-
* {@link SsaiCreativeCache} when a provider doesn't override `fireImpression`.
|
|
169
|
-
* Exported so both call sites share one definition.
|
|
170
|
-
*/
|
|
171
|
-
const fireDefaultImpression = creative => {
|
|
172
|
-
fireTrackingEvents(creative, 'impression');
|
|
173
|
-
};
|
|
174
|
-
/**
|
|
175
|
-
* StreamLayer's internal creative provider. Resolves creatives from the JSON
|
|
176
|
-
* creative API (`GET {creativeApiBase}{encodeURIComponent(creativeId)}`) and
|
|
177
|
-
* fires impressions from the `'impression'` tracking event via `sendBeacon`.
|
|
178
|
-
*/
|
|
179
|
-
const createStreamLayerProvider = (config = {}) => {
|
|
180
|
-
var _config$creativeApiBa;
|
|
181
|
-
const creativeApiBase = (_config$creativeApiBa = config.creativeApiBase) !== null && _config$creativeApiBa !== void 0 ? _config$creativeApiBa : DEFAULT_CREATIVE_API_BASE;
|
|
182
|
-
return {
|
|
183
|
-
id: 'streamlayer',
|
|
184
|
-
resolve: function () {
|
|
185
|
-
var _ref2 = _rollupPluginBabelHelpers.asyncToGenerator(function* (creativeId, signal) {
|
|
186
|
-
const raw = yield fetchCreativeJson('streamlayer', buildCreativeUrl(creativeApiBase, creativeId), signal);
|
|
187
|
-
return mapApiResponse(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, raw), {}, {
|
|
188
|
-
creativeId: raw.creativeId || creativeId
|
|
189
|
-
}));
|
|
190
|
-
});
|
|
191
|
-
return function resolve(_x4, _x5) {
|
|
192
|
-
return _ref2.apply(this, arguments);
|
|
193
|
-
};
|
|
194
|
-
}(),
|
|
195
|
-
fireImpression: fireDefaultImpression
|
|
196
|
-
};
|
|
197
|
-
};
|
|
198
|
-
const buildQuortexUrl = (base, tenantName, adId) => {
|
|
199
|
-
// Deliberately string concatenation rather than `URL`/`URLSearchParams`: this
|
|
200
|
-
// package ships to 2016-era TV engines (see the chrome-32 classic build).
|
|
201
|
-
const separator = base.indexOf('?') === -1 ? '?' : '&';
|
|
202
|
-
const tenant = tenantName ? `TenantName=${encodeURIComponent(tenantName)}&` : '';
|
|
203
|
-
return `${base}${separator}${tenant}adID=${encodeURIComponent(adId)}&info=1`;
|
|
204
|
-
};
|
|
205
|
-
/**
|
|
206
|
-
* Quortex / Synamedia DAI ad metadata provider.
|
|
207
|
-
*
|
|
208
|
-
* `GET {adApiBase}?TenantName={tenantName}&adID={adId}&info=1` (the `TenantName`
|
|
209
|
-
* part omitted when `adApiBase` already carries it) — the ad id comes
|
|
210
|
-
* from the manifest's `X-AD-ID` DATERANGE attribute (see `ssai-detector.ts`, which
|
|
211
|
-
* reconstructs the ad window from the tracking-marker burst those tags form).
|
|
212
|
-
*
|
|
213
|
-
* The response is byte-compatible with the StreamLayer creative API, so the same
|
|
214
|
-
* `mapApiResponse` normalizes both.
|
|
215
|
-
*
|
|
216
|
-
* Known limitation: impressions fire the `impression` tracking event from the API
|
|
217
|
-
* response, not the per-session beacon the manifest carries in `X-AD-URL`. The two
|
|
218
|
-
* differ in `trackingid`/`USERID`, so Quortex-side attribution will see the
|
|
219
|
-
* generic id rather than the viewer's session until the manifest beacons are
|
|
220
|
-
* plumbed through to the provider.
|
|
221
|
-
*/
|
|
222
|
-
const createQuortexProvider = (config = {}) => {
|
|
223
|
-
const {
|
|
224
|
-
adApiBase,
|
|
225
|
-
tenantName
|
|
226
|
-
} = config;
|
|
227
|
-
if (!adApiBase) {
|
|
228
|
-
// Loud, but not thrown: this runs inside the host's render effect via
|
|
229
|
-
// `startSsaiMonitoring`, and taking the app down over a config typo is worse
|
|
230
|
-
// than an overlay that never appears and says why.
|
|
231
|
-
log.error({
|
|
232
|
-
adApiBase,
|
|
233
|
-
tenantName
|
|
234
|
-
}, 'quortex provider requires `adApiBase`');
|
|
235
|
-
}
|
|
236
|
-
return {
|
|
237
|
-
id: 'quortex',
|
|
238
|
-
resolve: function () {
|
|
239
|
-
var _ref3 = _rollupPluginBabelHelpers.asyncToGenerator(function* (adId, signal) {
|
|
240
|
-
if (!adApiBase) {
|
|
241
|
-
throw new Error('quortex provider is missing `adApiBase`');
|
|
242
|
-
}
|
|
243
|
-
const raw = yield fetchCreativeJson('quortex', buildQuortexUrl(adApiBase, tenantName, adId), signal);
|
|
244
|
-
return mapApiResponse(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, raw), {}, {
|
|
245
|
-
creativeId: raw.creativeId || adId
|
|
246
|
-
}));
|
|
247
|
-
});
|
|
248
|
-
return function resolve(_x6, _x7) {
|
|
249
|
-
return _ref3.apply(this, arguments);
|
|
250
|
-
};
|
|
251
|
-
}(),
|
|
252
|
-
fireImpression: fireDefaultImpression
|
|
253
|
-
};
|
|
254
|
-
};
|
|
255
|
-
// --- VAST provider ---------------------------------------------------------
|
|
256
|
-
const mapVastResponse = /*#__PURE__*/function () {
|
|
257
|
-
var _ref4 = _rollupPluginBabelHelpers.asyncToGenerator(function* (creativeId, signal) {
|
|
258
|
-
var _validAd$advertiser$f;
|
|
259
|
-
const vastClient$1 = new vastClient.VASTClient();
|
|
260
|
-
const parsedVAST = yield vastClient$1.get(creativeId, {
|
|
261
|
-
timeout: 8000
|
|
262
|
-
});
|
|
263
|
-
if (signal.aborted) {
|
|
264
|
-
throw new DOMException('aborted', 'AbortError');
|
|
265
|
-
}
|
|
266
|
-
const validAd = parsedVAST.ads.find(ad => ad.creatives.length > 0);
|
|
267
|
-
if (!validAd) {
|
|
268
|
-
throw new Error('no_valid_ad');
|
|
269
|
-
}
|
|
270
|
-
const advertiserValue = Array.isArray(validAd.advertiser) ? (_validAd$advertiser$f = validAd.advertiser.find(entry => !!(entry !== null && entry !== void 0 && entry.value))) === null || _validAd$advertiser$f === void 0 ? void 0 : _validAd$advertiser$f.value : undefined;
|
|
271
|
-
const advertiser = resolveAdvertiser(advertiserValue, validAd.title || undefined);
|
|
272
|
-
let iconUrl;
|
|
273
|
-
let clickThroughUrl;
|
|
274
|
-
let companion;
|
|
275
|
-
for (const creative of validAd.creatives) {
|
|
276
|
-
if (creative.type === 'linear') {
|
|
277
|
-
var _linear$icons, _linear$videoClickThr;
|
|
278
|
-
const linear = creative;
|
|
279
|
-
iconUrl = iconUrl || ((_linear$icons = linear.icons) === null || _linear$icons === void 0 || (_linear$icons = _linear$icons.find(icon => !!(icon !== null && icon !== void 0 && icon.staticResource))) === null || _linear$icons === void 0 ? void 0 : _linear$icons.staticResource) || undefined;
|
|
280
|
-
clickThroughUrl = clickThroughUrl || ((_linear$videoClickThr = linear.videoClickThroughURLTemplate) === null || _linear$videoClickThr === void 0 ? void 0 : _linear$videoClickThr.url);
|
|
281
|
-
}
|
|
282
|
-
if (creative.type === 'companion') {
|
|
283
|
-
var _creative$variations, _variation$staticReso;
|
|
284
|
-
const variation = (_creative$variations = creative.variations) === null || _creative$variations === void 0 ? void 0 : _creative$variations[0];
|
|
285
|
-
const staticResource = variation === null || variation === void 0 || (_variation$staticReso = variation.staticResources) === null || _variation$staticReso === void 0 || (_variation$staticReso = _variation$staticReso[0]) === null || _variation$staticReso === void 0 ? void 0 : _variation$staticReso.url;
|
|
286
|
-
if (staticResource && !companion) {
|
|
287
|
-
var _variation$companionC, _variation$companionC2;
|
|
288
|
-
companion = {
|
|
289
|
-
staticResource,
|
|
290
|
-
width: Number(variation === null || variation === void 0 ? void 0 : variation.width) || 0,
|
|
291
|
-
height: Number(variation === null || variation === void 0 ? void 0 : variation.height) || 0,
|
|
292
|
-
clickThrough: variation === null || variation === void 0 || (_variation$companionC = variation.companionClickThroughURLTemplate) === null || _variation$companionC === void 0 ? void 0 : _variation$companionC.url,
|
|
293
|
-
clickTracking: ((_variation$companionC2 = variation === null || variation === void 0 ? void 0 : variation.companionClickTrackingURLTemplates) !== null && _variation$companionC2 !== void 0 ? _variation$companionC2 : []).map(entry => entry === null || entry === void 0 ? void 0 : entry.url).filter(url => !!url)
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
return {
|
|
299
|
-
creativeId,
|
|
300
|
-
advertiser,
|
|
301
|
-
title: validAd.title || advertiser,
|
|
302
|
-
iconUrl,
|
|
303
|
-
clickThroughUrl,
|
|
304
|
-
trackingEvents: [],
|
|
305
|
-
companion
|
|
306
|
-
};
|
|
307
|
-
});
|
|
308
|
-
return function mapVastResponse(_x8, _x9) {
|
|
309
|
-
return _ref4.apply(this, arguments);
|
|
310
|
-
};
|
|
311
|
-
}();
|
|
312
|
-
/**
|
|
313
|
-
* Maps a VAST tag into the normalized SsaiCreative shape.
|
|
314
|
-
*
|
|
315
|
-
* Note: `fireImpression` is intentionally left to the shared default for now.
|
|
316
|
-
* Proper VAST impression/tracking wiring through `VASTTracker` is a documented
|
|
317
|
-
* follow-up; it requires retaining the parsed ad/tracker per creative.
|
|
318
|
-
*/
|
|
319
|
-
const createVastProvider = (_config = {}) => {
|
|
320
|
-
return {
|
|
321
|
-
id: 'vast',
|
|
322
|
-
resolve: mapVastResponse
|
|
323
|
-
};
|
|
324
|
-
};
|
|
325
|
-
/** Built-in provider factories keyed by name. */
|
|
326
|
-
const BUILTIN_PROVIDERS = {
|
|
327
|
-
streamlayer: config => createStreamLayerProvider(config),
|
|
328
|
-
quortex: config => createQuortexProvider(config),
|
|
329
|
-
vast: () => createVastProvider()
|
|
330
|
-
};
|
|
331
|
-
const isProviderInstance = option => {
|
|
332
|
-
return typeof option === 'object' && typeof option.resolve === 'function';
|
|
333
|
-
};
|
|
334
|
-
/**
|
|
335
|
-
* Resolve a {@link SsaiProviderOption} into a concrete {@link SsaiCreativeProvider}.
|
|
336
|
-
* Defaults to the StreamLayer provider (using `fallbackConfig`) when no option is
|
|
337
|
-
* supplied.
|
|
338
|
-
*/
|
|
339
|
-
const resolveProvider = (option, fallbackConfig) => {
|
|
340
|
-
var _option$config;
|
|
341
|
-
if (!option) {
|
|
342
|
-
return createStreamLayerProvider(fallbackConfig);
|
|
343
|
-
}
|
|
344
|
-
if (typeof option === 'string') {
|
|
345
|
-
return BUILTIN_PROVIDERS[option](fallbackConfig);
|
|
346
|
-
}
|
|
347
|
-
if (isProviderInstance(option)) {
|
|
348
|
-
return option;
|
|
349
|
-
}
|
|
350
|
-
return BUILTIN_PROVIDERS[option.name]((_option$config = option.config) !== null && _option$config !== void 0 ? _option$config : fallbackConfig);
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
exports.BUILTIN_PROVIDERS = BUILTIN_PROVIDERS;
|
|
354
|
-
exports.DEFAULT_CREATIVE_API_BASE = DEFAULT_CREATIVE_API_BASE;
|
|
355
|
-
exports.createQuortexProvider = createQuortexProvider;
|
|
356
|
-
exports.createStreamLayerProvider = createStreamLayerProvider;
|
|
357
|
-
exports.createVastProvider = createVastProvider;
|
|
358
|
-
exports.fireBeacon = fireBeacon;
|
|
359
|
-
exports.fireDefaultImpression = fireDefaultImpression;
|
|
360
|
-
exports.fireTrackingEvents = fireTrackingEvents;
|
|
361
|
-
exports.resolveProvider = resolveProvider;
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var vastClient = require('@dailymotion/vast-client');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* One place that constructs a `VASTTracker`.
|
|
7
|
-
*
|
|
8
|
-
* Every StreamLayer surface that reports VAST beacons — the GAM video player, both pause-ad
|
|
9
|
-
* renderers and the Standard Ad sidebar — needs the same `(ad, creative, variation)` triple, and
|
|
10
|
-
* each was assembling it by hand behind its own `@ts-ignore`. The parsed shapes those triples
|
|
11
|
-
* come from (`AdData` / `AdCompanion` / `AdNonLinear`) are defined in this package, so the
|
|
12
|
-
* mapping belongs here too.
|
|
13
|
-
*
|
|
14
|
-
* Deliberately *only* construction: when a beacon may fire, and how a surface de-duplicates its
|
|
15
|
-
* impression, stays with that surface. Those policies differ on purpose (per-ad-id in module
|
|
16
|
-
* scope for the sidebar, per component instance for the pause ads, per tracker identity for the
|
|
17
|
-
* player) and they are billing-visible, so collapsing them here would silently change counts.
|
|
18
|
-
*/
|
|
19
|
-
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
20
|
-
/// <reference path="../module.d.ts" />
|
|
21
|
-
const createVastTracker = ({
|
|
22
|
-
ad,
|
|
23
|
-
creative,
|
|
24
|
-
variation
|
|
25
|
-
}) =>
|
|
26
|
-
// The first argument is the `VASTClient` the tracker may update; every surface here drives
|
|
27
|
-
// playback itself and only wants the beacons, so it is always `null`.
|
|
28
|
-
//
|
|
29
|
-
// The type shim declares the 3rd argument as `VastCreativeLinear` and the 4th as another
|
|
30
|
-
// *creative*. At runtime `vast-client` accepts any creative in the 3rd and expects the
|
|
31
|
-
// `<Companion>` / `<NonLinear>` *variation* in the 4th. The casts encode that runtime contract
|
|
32
|
-
// once here rather than at every call site.
|
|
33
|
-
new vastClient.VASTTracker(null, ad, creative, variation);
|
|
34
|
-
/**
|
|
35
|
-
* A tracker for a single `<Companion>`. A `<CompanionAds>` creative has no creative-level
|
|
36
|
-
* `<TrackingEvents>` — each variation owns its own `creativeView` — so a companion is reported
|
|
37
|
-
* through its own tracker. `undefined` when the companion was parsed without them (nothing to
|
|
38
|
-
* report against).
|
|
39
|
-
*/
|
|
40
|
-
const createCompanionTracker = (ad, companion) => companion.creative && companion.variation ? createVastTracker({
|
|
41
|
-
ad,
|
|
42
|
-
creative: companion.creative,
|
|
43
|
-
variation: companion.variation
|
|
44
|
-
}) : undefined;
|
|
45
|
-
/**
|
|
46
|
-
* The creative a parsed ad reports its impression / playback beacons through, in the order the
|
|
47
|
-
* shells draw them: the `<Linear>` creative first, then the `<NonLinear>` still, then — for a tag
|
|
48
|
-
* whose only creative is `<CompanionAds>` — the companion that was actually drawn.
|
|
49
|
-
*
|
|
50
|
-
* `drawnCompanion` is a parameter rather than `adData.companion` because only the rendering shell
|
|
51
|
-
* knows which companion reached the screen, and reporting one that did not is a false view.
|
|
52
|
-
*/
|
|
53
|
-
const resolveVastTrackerTarget = (adData, drawnCompanion) => {
|
|
54
|
-
// `AdData.creative` is not optional in the type but `getCreative` can return nothing: a
|
|
55
|
-
// programmatic tag does not have to carry a `<Linear>` creative.
|
|
56
|
-
if (adData.creative) {
|
|
57
|
-
return {
|
|
58
|
-
ad: adData.ad,
|
|
59
|
-
creative: adData.creative
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
if (adData.nonLinear) {
|
|
63
|
-
return {
|
|
64
|
-
ad: adData.ad,
|
|
65
|
-
creative: adData.nonLinear.creative,
|
|
66
|
-
variation: adData.nonLinear.variation
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (drawnCompanion !== null && drawnCompanion !== void 0 && drawnCompanion.creative && drawnCompanion.variation) {
|
|
70
|
-
return {
|
|
71
|
-
ad: adData.ad,
|
|
72
|
-
creative: drawnCompanion.creative,
|
|
73
|
-
variation: drawnCompanion.variation
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
return undefined;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
exports.createCompanionTracker = createCompanionTracker;
|
|
80
|
-
exports.createVastTracker = createVastTracker;
|
|
81
|
-
exports.resolveVastTrackerTarget = resolveVastTrackerTarget;
|
package/lib/classic/index.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Advertisement } from './advertisement.js';
|
|
2
|
-
export { isFullbleedVideoTemplate } from './units/external-pause-ad.js';
|
|
3
|
-
export { INSIGHT_BODY_MAX_LENGTH } from './units/pause-ad-card.js';
|
|
4
|
-
export { selectSponsorLogo } from './units/sponsor-logo.js';
|
|
5
|
-
export { gam } from './units/gam.js';
|
|
6
|
-
export { createCompanionTracker, createVastTracker, resolveVastTrackerTarget } from './units/vast-tracker.js';
|
|
7
|
-
import 'core-js/modules/es.array.iterator.js';
|
|
8
|
-
import 'core-js/modules/es.promise.js';
|
|
9
|
-
import 'core-js/modules/esnext.iterator.constructor.js';
|
|
10
|
-
import 'core-js/modules/esnext.iterator.for-each.js';
|
|
11
|
-
import 'core-js/modules/web.dom-collections.for-each.js';
|
|
12
|
-
import 'core-js/modules/web.dom-collections.iterator.js';
|
|
13
|
-
export { BUILTIN_PROVIDERS, DEFAULT_CREATIVE_API_BASE, createQuortexProvider, createStreamLayerProvider, createVastProvider, fireBeacon, fireTrackingEvents, resolveProvider } from './units/ssai-providers.js';
|
|
14
|
-
export { DEFAULT_PRELOAD_TIMEOUT_MS, preloadCreativeAssets, preloadImages } from './units/ssai-preload.js';
|
|
15
|
-
|
|
16
|
-
const advertisement = (instance, _opts, done) => {
|
|
17
|
-
instance.sdk.advertisement = new Advertisement(instance);
|
|
18
|
-
instance.sdk.onMount({
|
|
19
|
-
name: 'advertisement'
|
|
20
|
-
}, () => {
|
|
21
|
-
instance.sdk.advertisement.connect();
|
|
22
|
-
return () => {
|
|
23
|
-
instance.sdk.advertisement.disconnect();
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
done();
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export { advertisement };
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import 'core-js/modules/es.regexp.exec.js';
|
|
2
|
-
import 'core-js/modules/es.string.replace.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Ad-tag macro substitution, for every ad server — not just GAM.
|
|
6
|
-
*
|
|
7
|
-
* Studio stores a programmatic tag verbatim (`gamRawUrl`, returned untouched by
|
|
8
|
-
* `processGamAdvertisement`), so whatever macros the ad server's own tag builder emitted reach the
|
|
9
|
-
* SDK literal. `gam()` used to fill only the GAM `[placeholder]` token, and only for
|
|
10
|
-
* `pubads.g.doubleclick.net` — every other vendor's tag went out with its macros unexpanded.
|
|
11
|
-
*
|
|
12
|
-
* That is not inert. Measured against the ADITION tag on event 11089
|
|
13
|
-
* (`…/banner?…&ts=[timestamp]&clickurl=[clickmacro]`): ADITION prepends the value of `clickurl` to
|
|
14
|
-
* its own redi URL, so a literal `[clickmacro]` came back inside `<CompanionClickThrough>` as
|
|
15
|
-
* `[clickmacro]https%3A%2F%2Fad1…` — a broken click-through. Sending `clickurl=` empty answers with
|
|
16
|
-
* a valid redi URL.
|
|
17
|
-
*
|
|
18
|
-
* **Two sources.** The cache buster is the SDK's own. The consent family — `${GDPR}` and
|
|
19
|
-
* `${GDPR_CONSENT_<gvlid>}`, IAB TCF, where the id is the vendor's Global Vendor List entry (39 is
|
|
20
|
-
* ADITION / Virtual Minds) — and the click macro come from the host app (`AdTagParams`, set through
|
|
21
|
-
* the `adTagParams` option or `sdk.setAdTagParams`). The SDK never reads a CMP and never guesses
|
|
22
|
-
* consent: a value the host did not pass goes out EMPTY, which ad servers read as "unknown" — never
|
|
23
|
-
* as `gdpr=0`. Empty rather than literal because a literal is not inert either: ADITION copied
|
|
24
|
-
* `${GDPR}` into its own redirect URL (`gdpr%3D%24%7BGDPR%7D`). See
|
|
25
|
-
* `docs/wiki/programmatic-ads-macros.md`.
|
|
26
|
-
*
|
|
27
|
-
* An unknown macro is left exactly as configured, which is what keeps the GAM `[placeholder]`
|
|
28
|
-
* tokens for the PAL path (`gam.ts` fills those per parameter, not per token).
|
|
29
|
-
*/
|
|
30
|
-
/**
|
|
31
|
-
* All three spellings in the wild — `[NAME]` (IAB / SpotX), `${NAME}` (Google) and bare `{NAME}` —
|
|
32
|
-
* each with its delimiters either literal or PERCENT-ENCODED.
|
|
33
|
-
*
|
|
34
|
-
* Neither half of that is theoretical. ADITION emitted `[timestamp]` / `[clickmacro]` for the
|
|
35
|
-
* campaign on event 11089 and `{CACHEBUSTER}` / `{GDPR}` for the one on 6203 — same ad server, same
|
|
36
|
-
* advertiser, different tag builder. And Studio stores the 6203 tag as `ts=%7BCACHEBUSTER%7D`, so
|
|
37
|
-
* matching only literal braces made the whole substitution a silent no-op on it: an unexpanded
|
|
38
|
-
* macro raises no error and the ad server still answers 200. `searchParams.get()` decodes on read,
|
|
39
|
-
* which is what hides the encoding from anyone inspecting the parsed URL.
|
|
40
|
-
*
|
|
41
|
-
* The `$` is optional rather than a fourth branch — an unowned `${NAME}` still returns its full
|
|
42
|
-
* matched text, `$` included, so the brace forms cannot corrupt each other.
|
|
43
|
-
*/
|
|
44
|
-
const MACRO_PATTERN = /(?:\[|%5B)([a-z0-9_]+)(?:\]|%5D)|(?:\$|%24)?(?:\{|%7B)([a-z0-9_]+)(?:\}|%7D)/gi;
|
|
45
|
-
/**
|
|
46
|
-
* Every host value lands inside a query-string VALUE, so it is encoded exactly once. That matters
|
|
47
|
-
* most for the click URL, which carries its own `?`/`&`: sent raw it re-opens the tag's query, the
|
|
48
|
-
* way the malformed 6203 tag did (`clickurl` truncated, every following parameter duplicated).
|
|
49
|
-
*/
|
|
50
|
-
const hostValue = value => value ? encodeURIComponent(value) : '';
|
|
51
|
-
const gdprConsent = ({
|
|
52
|
-
params
|
|
53
|
-
}) => hostValue(params === null || params === void 0 ? void 0 : params.tcString);
|
|
54
|
-
/**
|
|
55
|
-
* Macro name (lower-cased) → the value this SDK sends for it.
|
|
56
|
-
*
|
|
57
|
-
* `clickurl` / `clickmacro` take the host's click tracker, which the ad server PREPENDS to its own
|
|
58
|
-
* redirect — so the viewer's click passes host tracker → vendor redirect → landing page. The SDK
|
|
59
|
-
* does not fire that tracker itself; it would count the click twice. Without one it is empty, the
|
|
60
|
-
* documented "no player tracker" value. VAST click beacons are reported separately by
|
|
61
|
-
* `useSidebarVastTracker`.
|
|
62
|
-
*/
|
|
63
|
-
const MACRO_VALUES = {
|
|
64
|
-
// One family, one value: every name here means "make this request unique so nothing caches it".
|
|
65
|
-
// Epoch milliseconds satisfies that for all of them, and keeps the value already shipped for
|
|
66
|
-
// `timestamp` unchanged. (IAB defines `[CACHEBUSTING]` as a random 8-digit number and
|
|
67
|
-
// `[TIMESTAMP]` as ISO-8601, but those describe VAST *tracking* URLs; this substitution only
|
|
68
|
-
// ever touches the ad REQUEST url, where every ad server documents the parameter as a number.)
|
|
69
|
-
timestamp: ({
|
|
70
|
-
now
|
|
71
|
-
}) => String(now),
|
|
72
|
-
cachebuster: ({
|
|
73
|
-
now
|
|
74
|
-
}) => String(now),
|
|
75
|
-
cachebusting: ({
|
|
76
|
-
now
|
|
77
|
-
}) => String(now),
|
|
78
|
-
clickmacro: ({
|
|
79
|
-
params
|
|
80
|
-
}) => hostValue(params === null || params === void 0 ? void 0 : params.clickUrl),
|
|
81
|
-
clickurl: ({
|
|
82
|
-
params
|
|
83
|
-
}) => hostValue(params === null || params === void 0 ? void 0 : params.clickUrl),
|
|
84
|
-
// `1` / `0` only from an explicit boolean — an absent value is unknown, not "does not apply".
|
|
85
|
-
gdpr: ({
|
|
86
|
-
params
|
|
87
|
-
}) => (params === null || params === void 0 ? void 0 : params.gdprApplies) === undefined ? '' : params.gdprApplies ? '1' : '0',
|
|
88
|
-
gdpr_consent: gdprConsent
|
|
89
|
-
};
|
|
90
|
-
/** `GDPR_CONSENT_<gvlid>`: the vendor id names whose tag this is; the value is the same TC string. */
|
|
91
|
-
const GDPR_CONSENT_FOR_VENDOR = /^gdpr_consent_\d+$/;
|
|
92
|
-
const resolveMacro = name => {
|
|
93
|
-
var _MACRO_VALUES$name;
|
|
94
|
-
return (_MACRO_VALUES$name = MACRO_VALUES[name]) !== null && _MACRO_VALUES$name !== void 0 ? _MACRO_VALUES$name : GDPR_CONSENT_FOR_VENDOR.test(name) ? gdprConsent : undefined;
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* Fill the macros this SDK knows in an ad-tag URL. One timestamp per call, so a tag naming the macro
|
|
98
|
-
* twice stays self-consistent. `params` is read as given — the caller passes the host's CURRENT
|
|
99
|
-
* values at request time.
|
|
100
|
-
*/
|
|
101
|
-
const substituteAdTagMacros = (url, params) => {
|
|
102
|
-
const now = Date.now();
|
|
103
|
-
return url.replace(MACRO_PATTERN, (match, bracketed, braced) => {
|
|
104
|
-
var _ref;
|
|
105
|
-
const value = resolveMacro(((_ref = bracketed !== null && bracketed !== void 0 ? bracketed : braced) !== null && _ref !== void 0 ? _ref : '').toLowerCase());
|
|
106
|
-
return value ? value({
|
|
107
|
-
now,
|
|
108
|
-
params
|
|
109
|
-
}) : match;
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export { substituteAdTagMacros };
|