@adhese/sdk 0.1.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/dist/cjs/devtools.js +1786 -0
- package/dist/cjs/devtools.js.map +1 -0
- package/dist/cjs/index.js +1012 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/es/devtools.js +1766 -0
- package/dist/es/devtools.js.map +1 -0
- package/dist/es/index.js +1012 -0
- package/dist/es/index.js.map +1 -0
- package/dist/index.d.ts +734 -0
- package/dist/style.css +47 -0
- package/package.json +38 -0
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => {
|
|
5
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
|
+
const lodashEs = require("lodash-es");
|
|
10
|
+
const zod = require("zod");
|
|
11
|
+
async function waitForDomLoad() {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
function onDomLoad() {
|
|
14
|
+
resolve();
|
|
15
|
+
window.removeEventListener("DOMContentLoaded", onDomLoad);
|
|
16
|
+
}
|
|
17
|
+
if (document.readyState === "loading")
|
|
18
|
+
document.addEventListener("DOMContentLoaded", onDomLoad);
|
|
19
|
+
else
|
|
20
|
+
resolve();
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function createEventManager() {
|
|
24
|
+
const disposables = /* @__PURE__ */ new Set();
|
|
25
|
+
function dispose() {
|
|
26
|
+
for (const disposable of disposables)
|
|
27
|
+
disposable();
|
|
28
|
+
}
|
|
29
|
+
return new Proxy({
|
|
30
|
+
dispose
|
|
31
|
+
}, {
|
|
32
|
+
// eslint-disable-next-line ts/explicit-function-return-type
|
|
33
|
+
get(target, key, receiver) {
|
|
34
|
+
if (!(key in target) && typeof key === "string") {
|
|
35
|
+
const event = createEvent();
|
|
36
|
+
disposables.add(() => {
|
|
37
|
+
event.listeners.clear();
|
|
38
|
+
});
|
|
39
|
+
Reflect.set(target, key, event, receiver);
|
|
40
|
+
}
|
|
41
|
+
return Reflect.get(target, key, receiver);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function createEvent() {
|
|
46
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
47
|
+
function dispatch(data) {
|
|
48
|
+
for (const listener of listeners)
|
|
49
|
+
void listener(data);
|
|
50
|
+
}
|
|
51
|
+
async function dispatchAsync(data) {
|
|
52
|
+
await Promise.allSettled(
|
|
53
|
+
Array.from(listeners).map((listener) => listener(data))
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function addListener(listener) {
|
|
57
|
+
listeners.add(listener);
|
|
58
|
+
}
|
|
59
|
+
function removeListener(listener) {
|
|
60
|
+
listeners.delete(listener);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
listeners,
|
|
64
|
+
dispatch,
|
|
65
|
+
dispatchAsync,
|
|
66
|
+
addListener,
|
|
67
|
+
removeListener
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function findDomSlots(context) {
|
|
71
|
+
await waitForDomLoad();
|
|
72
|
+
return (await Promise.all(Array.from(document.querySelectorAll(".adunit")).filter((element) => Boolean(element.dataset.format)).map((element) => createSlot({
|
|
73
|
+
format: element.dataset.format,
|
|
74
|
+
containingElement: element,
|
|
75
|
+
slot: element.dataset.slot,
|
|
76
|
+
context
|
|
77
|
+
})))).filter((slot) => {
|
|
78
|
+
var _a;
|
|
79
|
+
return !((_a = context.getAll) == null ? void 0 : _a.call(context).some((activeSlot) => activeSlot.getName() === slot.getName()));
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async function createSlotManager({
|
|
83
|
+
initialSlots = [],
|
|
84
|
+
context
|
|
85
|
+
}) {
|
|
86
|
+
const slots = /* @__PURE__ */ new Map();
|
|
87
|
+
await Promise.allSettled(initialSlots.map(async (slot) => add({
|
|
88
|
+
...slot,
|
|
89
|
+
lazyLoading: false
|
|
90
|
+
})));
|
|
91
|
+
function getAll() {
|
|
92
|
+
return Array.from(slots).map(([, slot]) => slot);
|
|
93
|
+
}
|
|
94
|
+
async function add(options) {
|
|
95
|
+
var _a, _b;
|
|
96
|
+
const slot = await createSlot({
|
|
97
|
+
...options,
|
|
98
|
+
onDispose,
|
|
99
|
+
onNameChange,
|
|
100
|
+
context
|
|
101
|
+
});
|
|
102
|
+
function onDispose() {
|
|
103
|
+
var _a2, _b2;
|
|
104
|
+
slots.delete(slot.getName());
|
|
105
|
+
logger.debug("Slot removed", {
|
|
106
|
+
slot,
|
|
107
|
+
slots: Array.from(slots)
|
|
108
|
+
});
|
|
109
|
+
(_a2 = context.events) == null ? void 0 : _a2.removeSlot.dispatch(slot);
|
|
110
|
+
(_b2 = context.events) == null ? void 0 : _b2.changeSlots.dispatch(Array.from(slots.values()));
|
|
111
|
+
}
|
|
112
|
+
slots.set(slot.getName(), slot);
|
|
113
|
+
function onNameChange(newName, previousName) {
|
|
114
|
+
var _a2;
|
|
115
|
+
slots.set(newName, slot);
|
|
116
|
+
slots.delete(previousName);
|
|
117
|
+
(_a2 = context.events) == null ? void 0 : _a2.changeSlots.dispatch(Array.from(slots.values()));
|
|
118
|
+
}
|
|
119
|
+
logger.debug("Slot added", {
|
|
120
|
+
slot,
|
|
121
|
+
slots: Array.from(slots.values())
|
|
122
|
+
});
|
|
123
|
+
(_a = context.events) == null ? void 0 : _a.addSlot.dispatch(slot);
|
|
124
|
+
(_b = context.events) == null ? void 0 : _b.changeSlots.dispatch(Array.from(slots.values()));
|
|
125
|
+
return slot;
|
|
126
|
+
}
|
|
127
|
+
async function findDomSlots$1() {
|
|
128
|
+
var _a;
|
|
129
|
+
const domSlots = await findDomSlots(
|
|
130
|
+
context
|
|
131
|
+
);
|
|
132
|
+
for (const slot of domSlots) {
|
|
133
|
+
slots.set(slot.getName(), slot);
|
|
134
|
+
(_a = context.events) == null ? void 0 : _a.changeSlots.dispatch(Array.from(slots.values()));
|
|
135
|
+
}
|
|
136
|
+
return domSlots;
|
|
137
|
+
}
|
|
138
|
+
function get(name) {
|
|
139
|
+
return slots.get(name);
|
|
140
|
+
}
|
|
141
|
+
function dispose() {
|
|
142
|
+
var _a;
|
|
143
|
+
for (const slot of slots.values())
|
|
144
|
+
slot.dispose();
|
|
145
|
+
slots.clear();
|
|
146
|
+
(_a = context.events) == null ? void 0 : _a.changeSlots.dispatch(Array.from(slots.values()));
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
getAll,
|
|
150
|
+
add,
|
|
151
|
+
findDomSlots: findDomSlots$1,
|
|
152
|
+
get,
|
|
153
|
+
dispose
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function onTcfConsentChange(callback) {
|
|
157
|
+
var _a;
|
|
158
|
+
(_a = window.__tcfapi) == null ? void 0 : _a.call(window, "addEventListener", 2, callback);
|
|
159
|
+
return () => {
|
|
160
|
+
var _a2;
|
|
161
|
+
return (_a2 = window.__tcfapi) == null ? void 0 : _a2.call(window, "removeEventListener", 2, callback);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function createQueryDetector({
|
|
165
|
+
onChange,
|
|
166
|
+
queries = {
|
|
167
|
+
mobile: "(max-width: 768px) and (pointer: coarse)",
|
|
168
|
+
tablet: "(min-width: 769px) and (max-width: 1024px) and (pointer: coarse)",
|
|
169
|
+
desktop: "(min-width: 1025px) and (pointer: fine)"
|
|
170
|
+
}
|
|
171
|
+
} = {}) {
|
|
172
|
+
const mediaMap = new Map(
|
|
173
|
+
Object.entries(queries).map(([key, query]) => [key, window.matchMedia(query)])
|
|
174
|
+
);
|
|
175
|
+
function getQuery() {
|
|
176
|
+
for (const [device, query] of Object.entries(queries)) {
|
|
177
|
+
if (window.matchMedia(query).matches)
|
|
178
|
+
return device;
|
|
179
|
+
}
|
|
180
|
+
return "unknown";
|
|
181
|
+
}
|
|
182
|
+
const handleOnChange = lodashEs.debounce(() => {
|
|
183
|
+
void (onChange == null ? void 0 : onChange(getQuery()));
|
|
184
|
+
logger.debug(`Change device ${getQuery()}`);
|
|
185
|
+
}, 50);
|
|
186
|
+
if (onChange) {
|
|
187
|
+
for (const query of mediaMap.values())
|
|
188
|
+
query.addEventListener("change", handleOnChange);
|
|
189
|
+
}
|
|
190
|
+
function dispose() {
|
|
191
|
+
for (const query of mediaMap.values())
|
|
192
|
+
query.removeEventListener("change", handleOnChange);
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
queries: mediaMap,
|
|
196
|
+
getQuery,
|
|
197
|
+
dispose
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const defaultLogLevels = ["trace", "debug", "info", "warn", "error"];
|
|
201
|
+
function createLogger({
|
|
202
|
+
scope,
|
|
203
|
+
logLevels = defaultLogLevels,
|
|
204
|
+
minLogLevelThreshold = logLevels[2]
|
|
205
|
+
}) {
|
|
206
|
+
const logs = /* @__PURE__ */ new Set();
|
|
207
|
+
let currentMinLogLevelThreshold = minLogLevelThreshold;
|
|
208
|
+
const events = createEventManager();
|
|
209
|
+
const logFunctions = Object.fromEntries(logLevels.map((level, index) => {
|
|
210
|
+
const logFunction = (message, attributes) => {
|
|
211
|
+
logs.add({
|
|
212
|
+
scope,
|
|
213
|
+
level,
|
|
214
|
+
message,
|
|
215
|
+
attributes,
|
|
216
|
+
timestamp: Date.now(),
|
|
217
|
+
id: lodashEs.uniqueId()
|
|
218
|
+
});
|
|
219
|
+
events.log.dispatch({
|
|
220
|
+
scope,
|
|
221
|
+
level,
|
|
222
|
+
message,
|
|
223
|
+
attributes,
|
|
224
|
+
timestamp: Date.now(),
|
|
225
|
+
id: lodashEs.uniqueId()
|
|
226
|
+
});
|
|
227
|
+
if (index >= logLevels.indexOf(currentMinLogLevelThreshold)) {
|
|
228
|
+
if (["warn", "error", "trace"].includes(level)) {
|
|
229
|
+
console[level](...[
|
|
230
|
+
`%c${scope}`,
|
|
231
|
+
"color: red; font-weight: bold;",
|
|
232
|
+
message,
|
|
233
|
+
attributes
|
|
234
|
+
].filter(Boolean));
|
|
235
|
+
} else {
|
|
236
|
+
console.log(...[
|
|
237
|
+
`%c${scope} %c${level.toUpperCase()}`,
|
|
238
|
+
"color: red; font-weight: bold;",
|
|
239
|
+
"font-weight: bold;",
|
|
240
|
+
message,
|
|
241
|
+
attributes
|
|
242
|
+
].filter(Boolean));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
return [level, logFunction];
|
|
247
|
+
}));
|
|
248
|
+
return {
|
|
249
|
+
...logFunctions,
|
|
250
|
+
scope,
|
|
251
|
+
events,
|
|
252
|
+
setMinLogLevelThreshold(level) {
|
|
253
|
+
currentMinLogLevelThreshold = level;
|
|
254
|
+
},
|
|
255
|
+
resetMinLogLevelThreshold() {
|
|
256
|
+
currentMinLogLevelThreshold = minLogLevelThreshold;
|
|
257
|
+
},
|
|
258
|
+
getMinLogLevelThreshold() {
|
|
259
|
+
return currentMinLogLevelThreshold;
|
|
260
|
+
},
|
|
261
|
+
getLogs() {
|
|
262
|
+
return Array.from(logs);
|
|
263
|
+
},
|
|
264
|
+
resetLogs() {
|
|
265
|
+
events.reset.dispatch();
|
|
266
|
+
logs.clear();
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
const logger = createLogger({
|
|
271
|
+
scope: "Adhese SDK"
|
|
272
|
+
});
|
|
273
|
+
function createParameters(options, queryDetector) {
|
|
274
|
+
const parameters = new MapWithEvents();
|
|
275
|
+
if (options.logReferrer)
|
|
276
|
+
parameters.set("re", btoa(document.referrer));
|
|
277
|
+
if (options.logUrl)
|
|
278
|
+
parameters.set("ur", btoa(window.location.href));
|
|
279
|
+
for (const [key, value] of Object.entries({
|
|
280
|
+
...options.parameters ?? {},
|
|
281
|
+
tl: options.consent ? "all" : "none",
|
|
282
|
+
dt: queryDetector.getQuery(),
|
|
283
|
+
br: queryDetector.getQuery(),
|
|
284
|
+
rn: lodashEs.random(1e4).toString()
|
|
285
|
+
}))
|
|
286
|
+
parameters.set(key, value);
|
|
287
|
+
return parameters;
|
|
288
|
+
}
|
|
289
|
+
function setupLogging(mergedOptions) {
|
|
290
|
+
if (mergedOptions.debug || window.location.search.includes("adhese_debug=true")) {
|
|
291
|
+
logger.setMinLogLevelThreshold("debug");
|
|
292
|
+
logger.debug("Debug logging enabled");
|
|
293
|
+
}
|
|
294
|
+
logger.debug("Created Adhese SDK instance", {
|
|
295
|
+
mergedOptions
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function isPreviewMode() {
|
|
299
|
+
return window.location.search.includes("adhesePreviewCreativeId");
|
|
300
|
+
}
|
|
301
|
+
class MapWithEvents extends Map {
|
|
302
|
+
constructor() {
|
|
303
|
+
super(...arguments);
|
|
304
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
305
|
+
}
|
|
306
|
+
addEventListener(listener) {
|
|
307
|
+
this.listeners.add(listener);
|
|
308
|
+
}
|
|
309
|
+
removeEventListener(listener) {
|
|
310
|
+
this.listeners.delete(listener);
|
|
311
|
+
}
|
|
312
|
+
set(key, value) {
|
|
313
|
+
const set = super.set(key, value);
|
|
314
|
+
this.listeners.forEach((listener) => {
|
|
315
|
+
listener();
|
|
316
|
+
});
|
|
317
|
+
return set;
|
|
318
|
+
}
|
|
319
|
+
clear() {
|
|
320
|
+
super.clear();
|
|
321
|
+
this.listeners.forEach((listener) => {
|
|
322
|
+
listener();
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
delete(key) {
|
|
326
|
+
const deleted = super.delete(key);
|
|
327
|
+
this.listeners.forEach((listener) => {
|
|
328
|
+
listener();
|
|
329
|
+
});
|
|
330
|
+
return deleted;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Remove all listeners and clear the map.
|
|
334
|
+
*/
|
|
335
|
+
dispose() {
|
|
336
|
+
this.listeners.clear();
|
|
337
|
+
super.clear();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function createDevtools(context) {
|
|
341
|
+
const devtools = await Promise.resolve().then(() => require("./devtools.js"));
|
|
342
|
+
const wrapperElement = document.createElement("div");
|
|
343
|
+
document.body.appendChild(wrapperElement);
|
|
344
|
+
const unmount = devtools.createAdheseDevtools(wrapperElement, context);
|
|
345
|
+
return () => {
|
|
346
|
+
unmount();
|
|
347
|
+
wrapperElement.outerHTML = "";
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
async function createAdhese(options) {
|
|
351
|
+
const mergedOptions = {
|
|
352
|
+
host: `https://ads-${options.account}.adhese.com`,
|
|
353
|
+
poolHost: `https://pool-${options.account}.adhese.com`,
|
|
354
|
+
location: "homepage",
|
|
355
|
+
requestType: "POST",
|
|
356
|
+
debug: false,
|
|
357
|
+
initialSlots: [],
|
|
358
|
+
findDomSlotsOnLoad: false,
|
|
359
|
+
consent: false,
|
|
360
|
+
logReferrer: true,
|
|
361
|
+
logUrl: true,
|
|
362
|
+
eagerRendering: false,
|
|
363
|
+
viewabilityTracking: true,
|
|
364
|
+
...options
|
|
365
|
+
};
|
|
366
|
+
setupLogging(mergedOptions);
|
|
367
|
+
const context = new Proxy({
|
|
368
|
+
location: mergedOptions.location,
|
|
369
|
+
consent: mergedOptions.consent,
|
|
370
|
+
debug: mergedOptions.debug,
|
|
371
|
+
getAll,
|
|
372
|
+
get,
|
|
373
|
+
options: mergedOptions,
|
|
374
|
+
logger
|
|
375
|
+
}, {});
|
|
376
|
+
context.events = createEventManager();
|
|
377
|
+
function getLocation() {
|
|
378
|
+
return context.location;
|
|
379
|
+
}
|
|
380
|
+
function setLocation(newLocation) {
|
|
381
|
+
var _a;
|
|
382
|
+
context.location = newLocation;
|
|
383
|
+
(_a = context.events) == null ? void 0 : _a.locationChange.dispatch(newLocation);
|
|
384
|
+
}
|
|
385
|
+
const queryDetector = createQueryDetector({
|
|
386
|
+
onChange: onQueryChange,
|
|
387
|
+
queries: mergedOptions.queries
|
|
388
|
+
});
|
|
389
|
+
context.parameters = createParameters(mergedOptions, queryDetector);
|
|
390
|
+
context.parameters.addEventListener(onParametersChange);
|
|
391
|
+
let unmountDevtools;
|
|
392
|
+
if (mergedOptions.debug || window.location.search.includes("adhese_debug=true") || isPreviewMode())
|
|
393
|
+
unmountDevtools = await createDevtools(context);
|
|
394
|
+
function onParametersChange() {
|
|
395
|
+
var _a;
|
|
396
|
+
if (context.parameters)
|
|
397
|
+
(_a = context.events) == null ? void 0 : _a.parametersChange.dispatch(context.parameters);
|
|
398
|
+
}
|
|
399
|
+
async function onQueryChange() {
|
|
400
|
+
var _a, _b;
|
|
401
|
+
const query = queryDetector.getQuery();
|
|
402
|
+
(_a = context.parameters) == null ? void 0 : _a.set("dt", query);
|
|
403
|
+
(_b = context.parameters) == null ? void 0 : _b.set("br", query);
|
|
404
|
+
await fetchAndRenderAllSlots();
|
|
405
|
+
}
|
|
406
|
+
function getConsent() {
|
|
407
|
+
return context.consent;
|
|
408
|
+
}
|
|
409
|
+
function setConsent(newConsent) {
|
|
410
|
+
var _a, _b;
|
|
411
|
+
(_a = context.parameters) == null ? void 0 : _a.set("tl", newConsent ? "all" : "none");
|
|
412
|
+
context.consent = newConsent;
|
|
413
|
+
(_b = context.events) == null ? void 0 : _b.consentChange.dispatch(newConsent);
|
|
414
|
+
}
|
|
415
|
+
const slotManager = await createSlotManager({
|
|
416
|
+
initialSlots: mergedOptions.initialSlots,
|
|
417
|
+
context
|
|
418
|
+
});
|
|
419
|
+
function getAll() {
|
|
420
|
+
return slotManager.getAll();
|
|
421
|
+
}
|
|
422
|
+
function get(name) {
|
|
423
|
+
return slotManager.get(name);
|
|
424
|
+
}
|
|
425
|
+
async function addSlot(slotOptions) {
|
|
426
|
+
const slot = await slotManager.add(slotOptions);
|
|
427
|
+
if (!slot.lazyLoading) {
|
|
428
|
+
const ad = await requestAd({
|
|
429
|
+
slot,
|
|
430
|
+
host: mergedOptions.host,
|
|
431
|
+
parameters: context.parameters,
|
|
432
|
+
account: mergedOptions.account,
|
|
433
|
+
context
|
|
434
|
+
});
|
|
435
|
+
await slot.setAd(ad);
|
|
436
|
+
}
|
|
437
|
+
return slot;
|
|
438
|
+
}
|
|
439
|
+
async function findDomSlots2() {
|
|
440
|
+
const domSlots = (await slotManager.findDomSlots()).filter((slot) => !slot.lazyLoading);
|
|
441
|
+
const ads = await requestAds({
|
|
442
|
+
host: mergedOptions.host,
|
|
443
|
+
slots: domSlots,
|
|
444
|
+
method: mergedOptions.requestType,
|
|
445
|
+
account: mergedOptions.account,
|
|
446
|
+
parameters: context.parameters,
|
|
447
|
+
context
|
|
448
|
+
});
|
|
449
|
+
await Promise.allSettled(ads.map((ad) => {
|
|
450
|
+
var _a;
|
|
451
|
+
return (_a = slotManager.get(ad.slotName)) == null ? void 0 : _a.setAd(ad);
|
|
452
|
+
}));
|
|
453
|
+
return domSlots;
|
|
454
|
+
}
|
|
455
|
+
async function toggleDebug() {
|
|
456
|
+
context.debug = !context.debug;
|
|
457
|
+
if (context.debug && !unmountDevtools) {
|
|
458
|
+
unmountDevtools = await createDevtools(context);
|
|
459
|
+
logger.setMinLogLevelThreshold("debug");
|
|
460
|
+
logger.debug("Debug mode enabled");
|
|
461
|
+
} else {
|
|
462
|
+
logger.debug("Debug mode disabled");
|
|
463
|
+
unmountDevtools == null ? void 0 : unmountDevtools();
|
|
464
|
+
unmountDevtools = void 0;
|
|
465
|
+
logger.setMinLogLevelThreshold("info");
|
|
466
|
+
}
|
|
467
|
+
return context.debug;
|
|
468
|
+
}
|
|
469
|
+
async function fetchAndRenderAllSlots() {
|
|
470
|
+
const slots = slotManager.getAll().filter((slot) => !slot.lazyLoading);
|
|
471
|
+
if (slots.length === 0)
|
|
472
|
+
return;
|
|
473
|
+
const ads = await requestAds({
|
|
474
|
+
host: mergedOptions.host,
|
|
475
|
+
slots,
|
|
476
|
+
method: mergedOptions.requestType,
|
|
477
|
+
account: mergedOptions.account,
|
|
478
|
+
parameters: context.parameters,
|
|
479
|
+
context
|
|
480
|
+
});
|
|
481
|
+
await Promise.allSettled(ads.map((ad) => {
|
|
482
|
+
var _a;
|
|
483
|
+
return (_a = slotManager.get(ad.slotName)) == null ? void 0 : _a.setAd(ad);
|
|
484
|
+
}));
|
|
485
|
+
}
|
|
486
|
+
const disposeOnTcfConsentChange = onTcfConsentChange(async (data) => {
|
|
487
|
+
var _a, _b;
|
|
488
|
+
if (!data.tcString)
|
|
489
|
+
return;
|
|
490
|
+
logger.debug("TCF v2 consent data received", {
|
|
491
|
+
data
|
|
492
|
+
});
|
|
493
|
+
(_a = context.parameters) == null ? void 0 : _a.set("xt", data.tcString);
|
|
494
|
+
(_b = context.parameters) == null ? void 0 : _b.delete("tl");
|
|
495
|
+
await fetchAndRenderAllSlots();
|
|
496
|
+
});
|
|
497
|
+
if (slotManager.getAll().length > 0)
|
|
498
|
+
await fetchAndRenderAllSlots().catch(logger.error);
|
|
499
|
+
function dispose() {
|
|
500
|
+
var _a, _b, _c;
|
|
501
|
+
queryDetector.dispose();
|
|
502
|
+
slotManager.dispose();
|
|
503
|
+
queryDetector.dispose();
|
|
504
|
+
disposeOnTcfConsentChange();
|
|
505
|
+
(_a = context.parameters) == null ? void 0 : _a.dispose();
|
|
506
|
+
(_b = context.parameters) == null ? void 0 : _b.clear();
|
|
507
|
+
logger.resetLogs();
|
|
508
|
+
(_c = context.events) == null ? void 0 : _c.dispose();
|
|
509
|
+
unmountDevtools == null ? void 0 : unmountDevtools();
|
|
510
|
+
logger.info("Adhese instance disposed");
|
|
511
|
+
}
|
|
512
|
+
if (mergedOptions.findDomSlotsOnLoad)
|
|
513
|
+
await slotManager.findDomSlots();
|
|
514
|
+
return {
|
|
515
|
+
...mergedOptions,
|
|
516
|
+
...slotManager,
|
|
517
|
+
parameters: context.parameters,
|
|
518
|
+
events: context.events,
|
|
519
|
+
getLocation,
|
|
520
|
+
setLocation,
|
|
521
|
+
getConsent,
|
|
522
|
+
setConsent,
|
|
523
|
+
addSlot,
|
|
524
|
+
findDomSlots: findDomSlots2,
|
|
525
|
+
dispose,
|
|
526
|
+
toggleDebug
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
function addTrackingPixel(url) {
|
|
530
|
+
const img = document.createElement("img");
|
|
531
|
+
img.src = url.toString();
|
|
532
|
+
img.style.height = "1px";
|
|
533
|
+
img.style.width = "1px";
|
|
534
|
+
img.style.margin = "-1px";
|
|
535
|
+
img.style.border = "0";
|
|
536
|
+
img.style.position = "absolute";
|
|
537
|
+
img.style.top = "0";
|
|
538
|
+
return document.body.appendChild(img);
|
|
539
|
+
}
|
|
540
|
+
function renderIframe(ad, element) {
|
|
541
|
+
const iframe = document.createElement("iframe");
|
|
542
|
+
iframe.srcdoc = `
|
|
543
|
+
<!DOCTYPE html>
|
|
544
|
+
<html>
|
|
545
|
+
<head>
|
|
546
|
+
<style>
|
|
547
|
+
body {
|
|
548
|
+
margin: 0;
|
|
549
|
+
padding: 0;
|
|
550
|
+
overflow: hidden;
|
|
551
|
+
}
|
|
552
|
+
</style>
|
|
553
|
+
</head>
|
|
554
|
+
<body>
|
|
555
|
+
${ad.tag}
|
|
556
|
+
</body>
|
|
557
|
+
`.replaceAll(/\s+/g, " ").trim();
|
|
558
|
+
iframe.style.border = "none";
|
|
559
|
+
iframe.style.width = ad.width ? `${ad.width}px` : "100%";
|
|
560
|
+
iframe.style.height = ad.height ? `${ad.height}px` : "100%";
|
|
561
|
+
element.replaceChildren(iframe);
|
|
562
|
+
}
|
|
563
|
+
function renderInline(ad, element) {
|
|
564
|
+
element.style.width = ad.width ? `${ad.width}px` : "100%";
|
|
565
|
+
element.style.height = ad.height ? `${ad.height}px` : "100%";
|
|
566
|
+
element.innerHTML = ad.tag;
|
|
567
|
+
}
|
|
568
|
+
const renderFunctions = {
|
|
569
|
+
iframe: renderIframe,
|
|
570
|
+
inline: renderInline
|
|
571
|
+
};
|
|
572
|
+
async function createSlot(options) {
|
|
573
|
+
var _a;
|
|
574
|
+
const {
|
|
575
|
+
containingElement,
|
|
576
|
+
slot,
|
|
577
|
+
context,
|
|
578
|
+
renderMode = "iframe"
|
|
579
|
+
} = options;
|
|
580
|
+
await waitForDomLoad();
|
|
581
|
+
const parameters = new Map(Object.entries(options.parameters ?? {}));
|
|
582
|
+
let format;
|
|
583
|
+
let queryDetector = null;
|
|
584
|
+
if (typeof options.format === "string") {
|
|
585
|
+
format = options.format;
|
|
586
|
+
} else {
|
|
587
|
+
queryDetector = createQueryDetector({
|
|
588
|
+
onChange: setFormat,
|
|
589
|
+
queries: Object.fromEntries(options.format.map((item) => [item.format, item.query]))
|
|
590
|
+
});
|
|
591
|
+
format = queryDetector.getQuery();
|
|
592
|
+
}
|
|
593
|
+
async function setFormat(newFormat) {
|
|
594
|
+
var _a2;
|
|
595
|
+
const oldName = getName();
|
|
596
|
+
format = newFormat;
|
|
597
|
+
(_a2 = options.onNameChange) == null ? void 0 : _a2.call(options, getName(), oldName);
|
|
598
|
+
const newAd = await requestAd({
|
|
599
|
+
slot: {
|
|
600
|
+
getName,
|
|
601
|
+
parameters
|
|
602
|
+
},
|
|
603
|
+
account: context.options.account,
|
|
604
|
+
host: context.options.host,
|
|
605
|
+
parameters: context.parameters,
|
|
606
|
+
context
|
|
607
|
+
});
|
|
608
|
+
cleanElement();
|
|
609
|
+
await setAd(newAd);
|
|
610
|
+
}
|
|
611
|
+
function getFormat() {
|
|
612
|
+
return format;
|
|
613
|
+
}
|
|
614
|
+
let element = typeof containingElement === "string" || !containingElement ? document.querySelector(`.adunit[data-format="${format}"]#${containingElement}${slot ? `[data-slot="${slot}"]` : ""}`) : containingElement;
|
|
615
|
+
function getElement() {
|
|
616
|
+
if (renderMode === "iframe")
|
|
617
|
+
return (element == null ? void 0 : element.querySelector("iframe")) ?? null;
|
|
618
|
+
return (element == null ? void 0 : element.innerHTML) ? element.firstElementChild : null;
|
|
619
|
+
}
|
|
620
|
+
let impressionTrackingPixelElement = null;
|
|
621
|
+
let viewabilityTrackingPixelElement = null;
|
|
622
|
+
let isInViewport = false;
|
|
623
|
+
let ad = null;
|
|
624
|
+
function getAd() {
|
|
625
|
+
return ad;
|
|
626
|
+
}
|
|
627
|
+
async function setAd(newAd) {
|
|
628
|
+
var _a2, _b;
|
|
629
|
+
ad = newAd;
|
|
630
|
+
if (isInViewport || context.options.eagerRendering)
|
|
631
|
+
await render(ad);
|
|
632
|
+
if (element) {
|
|
633
|
+
element.style.width = `${ad.width}px`;
|
|
634
|
+
element.style.height = `${ad.height}px`;
|
|
635
|
+
}
|
|
636
|
+
await ((_b = context.events) == null ? void 0 : _b.changeSlots.dispatchAsync(Array.from(((_a2 = context.getAll) == null ? void 0 : _a2.call(context)) ?? [])));
|
|
637
|
+
}
|
|
638
|
+
const renderIntersectionObserver = new IntersectionObserver((entries) => {
|
|
639
|
+
isInViewport = entries.some((entry) => entry.isIntersecting);
|
|
640
|
+
if (isInViewport) {
|
|
641
|
+
(async () => {
|
|
642
|
+
if (!ad && options.lazyLoading)
|
|
643
|
+
await render();
|
|
644
|
+
else if (ad)
|
|
645
|
+
await render(ad);
|
|
646
|
+
})().catch(logger.error);
|
|
647
|
+
}
|
|
648
|
+
}, {
|
|
649
|
+
rootMargin: ((_a = options.lazyLoadingOptions) == null ? void 0 : _a.rootMargin) ?? "200px",
|
|
650
|
+
threshold: 0
|
|
651
|
+
});
|
|
652
|
+
let timeoutId = null;
|
|
653
|
+
const {
|
|
654
|
+
threshold,
|
|
655
|
+
duration,
|
|
656
|
+
rootMargin
|
|
657
|
+
} = {
|
|
658
|
+
threshold: 0.2,
|
|
659
|
+
duration: 1e3,
|
|
660
|
+
rootMargin: "0px",
|
|
661
|
+
...context.options.viewabilityTrackingOptions
|
|
662
|
+
};
|
|
663
|
+
const viewabilityObserver = new IntersectionObserver(([entry]) => {
|
|
664
|
+
if (context.options.viewabilityTracking && !viewabilityTrackingPixelElement && ad) {
|
|
665
|
+
const ratio = lodashEs.round(entry.intersectionRatio, 1);
|
|
666
|
+
if (ratio >= threshold && !timeoutId) {
|
|
667
|
+
timeoutId = setTimeout(() => {
|
|
668
|
+
var _a2, _b;
|
|
669
|
+
timeoutId = null;
|
|
670
|
+
if (ad == null ? void 0 : ad.viewableImpressionCounter) {
|
|
671
|
+
viewabilityTrackingPixelElement = addTrackingPixel(ad.viewableImpressionCounter);
|
|
672
|
+
logger.debug(`Viewability tracking pixel fired for ${getName()}`);
|
|
673
|
+
(_b = context.events) == null ? void 0 : _b.changeSlots.dispatch(Array.from(((_a2 = context.getAll) == null ? void 0 : _a2.call(context)) ?? []));
|
|
674
|
+
}
|
|
675
|
+
}, duration);
|
|
676
|
+
} else if (ratio < threshold && timeoutId) {
|
|
677
|
+
clearTimeout(timeoutId);
|
|
678
|
+
timeoutId = null;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}, {
|
|
682
|
+
rootMargin,
|
|
683
|
+
threshold: Array.from({ length: 11 }, (_, i) => i * 0.1)
|
|
684
|
+
});
|
|
685
|
+
if (element && context.options.viewabilityTracking)
|
|
686
|
+
viewabilityObserver.observe(element);
|
|
687
|
+
if (element)
|
|
688
|
+
renderIntersectionObserver.observe(element);
|
|
689
|
+
async function render(adToRender) {
|
|
690
|
+
var _a2, _b;
|
|
691
|
+
await waitForDomLoad();
|
|
692
|
+
ad = adToRender ?? ad ?? await requestAd({
|
|
693
|
+
slot: {
|
|
694
|
+
getName,
|
|
695
|
+
parameters
|
|
696
|
+
},
|
|
697
|
+
account: context.options.account,
|
|
698
|
+
host: context.options.host,
|
|
699
|
+
parameters: context.parameters,
|
|
700
|
+
context
|
|
701
|
+
});
|
|
702
|
+
if (!element) {
|
|
703
|
+
const error = `Could not create slot for format ${format}. No element found.`;
|
|
704
|
+
logger.error(error, options);
|
|
705
|
+
throw new Error(error);
|
|
706
|
+
}
|
|
707
|
+
if (context.debug)
|
|
708
|
+
element.style.position = "relative";
|
|
709
|
+
renderFunctions[renderMode](ad, element);
|
|
710
|
+
if ((ad == null ? void 0 : ad.impressionCounter) && !impressionTrackingPixelElement) {
|
|
711
|
+
impressionTrackingPixelElement = addTrackingPixel(ad.impressionCounter);
|
|
712
|
+
logger.debug(`Impression tracking pixel fired for ${getName()}`);
|
|
713
|
+
}
|
|
714
|
+
logger.debug("Slot rendered", {
|
|
715
|
+
renderedElement: element,
|
|
716
|
+
location: context.location,
|
|
717
|
+
format,
|
|
718
|
+
containingElement
|
|
719
|
+
});
|
|
720
|
+
renderIntersectionObserver.disconnect();
|
|
721
|
+
await ((_b = context.events) == null ? void 0 : _b.changeSlots.dispatchAsync(Array.from(((_a2 = context.getAll) == null ? void 0 : _a2.call(context)) ?? [])));
|
|
722
|
+
return element;
|
|
723
|
+
}
|
|
724
|
+
function cleanElement() {
|
|
725
|
+
if (!element)
|
|
726
|
+
return;
|
|
727
|
+
element.innerHTML = "";
|
|
728
|
+
element.style.position = "";
|
|
729
|
+
element.style.width = "";
|
|
730
|
+
element.style.height = "";
|
|
731
|
+
}
|
|
732
|
+
function getName() {
|
|
733
|
+
return `${context.location}${slot ? `${slot}` : ""}-${format}`;
|
|
734
|
+
}
|
|
735
|
+
function dispose() {
|
|
736
|
+
var _a2;
|
|
737
|
+
cleanElement();
|
|
738
|
+
impressionTrackingPixelElement == null ? void 0 : impressionTrackingPixelElement.remove();
|
|
739
|
+
viewabilityTrackingPixelElement == null ? void 0 : viewabilityTrackingPixelElement.remove();
|
|
740
|
+
element = null;
|
|
741
|
+
ad = null;
|
|
742
|
+
renderIntersectionObserver.disconnect();
|
|
743
|
+
viewabilityObserver.disconnect();
|
|
744
|
+
(_a2 = options.onDispose) == null ? void 0 : _a2.call(options);
|
|
745
|
+
queryDetector == null ? void 0 : queryDetector.dispose();
|
|
746
|
+
}
|
|
747
|
+
function isViewabilityTracked() {
|
|
748
|
+
return Boolean(viewabilityTrackingPixelElement);
|
|
749
|
+
}
|
|
750
|
+
function isImpressionTracked() {
|
|
751
|
+
return Boolean(impressionTrackingPixelElement);
|
|
752
|
+
}
|
|
753
|
+
return {
|
|
754
|
+
location: context.location,
|
|
755
|
+
lazyLoading: options.lazyLoading ?? false,
|
|
756
|
+
slot,
|
|
757
|
+
parameters,
|
|
758
|
+
setFormat,
|
|
759
|
+
getFormat,
|
|
760
|
+
render,
|
|
761
|
+
getElement,
|
|
762
|
+
getName,
|
|
763
|
+
getAd,
|
|
764
|
+
setAd,
|
|
765
|
+
isViewabilityTracked,
|
|
766
|
+
isImpressionTracked,
|
|
767
|
+
dispose
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
const numberLike = zod.union([zod.coerce.string().regex(/^\d+$/), zod.literal("")]).transform((value) => value === "" ? void 0 : Number(value));
|
|
771
|
+
const booleanLike = zod.union([zod.coerce.boolean(), zod.literal("")]);
|
|
772
|
+
const urlLike = zod.union([zod.coerce.string(), zod.literal("")]).transform((value) => {
|
|
773
|
+
try {
|
|
774
|
+
return new URL(value);
|
|
775
|
+
} catch {
|
|
776
|
+
return void 0;
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
const dateLike = zod.union([zod.coerce.string(), zod.literal("")]).transform((value) => {
|
|
780
|
+
if (value === "")
|
|
781
|
+
return void 0;
|
|
782
|
+
const date = new Date(numberLike.safeParse(value).success ? Number(value) : value);
|
|
783
|
+
if (Number.isNaN(date.getTime()))
|
|
784
|
+
return void 0;
|
|
785
|
+
return date;
|
|
786
|
+
});
|
|
787
|
+
const baseAdResponseScheme = zod.object({
|
|
788
|
+
adDuration: numberLike.optional(),
|
|
789
|
+
adDuration2nd: numberLike.optional(),
|
|
790
|
+
adDuration3rd: numberLike.optional(),
|
|
791
|
+
adDuration4th: numberLike.optional(),
|
|
792
|
+
adDuration5th: numberLike.optional(),
|
|
793
|
+
adDuration6th: numberLike.optional(),
|
|
794
|
+
adFormat: zod.string().optional(),
|
|
795
|
+
adType: zod.string(),
|
|
796
|
+
additionalCreativeTracker: urlLike.optional(),
|
|
797
|
+
additionalViewableTracker: zod.string().optional(),
|
|
798
|
+
adspaceEnd: dateLike.optional(),
|
|
799
|
+
adspaceId: zod.string().optional(),
|
|
800
|
+
adspaceKey: zod.string().optional(),
|
|
801
|
+
adspaceStart: dateLike.optional(),
|
|
802
|
+
advertiserId: zod.string().optional(),
|
|
803
|
+
altText: zod.string().optional(),
|
|
804
|
+
auctionable: booleanLike.optional(),
|
|
805
|
+
body: zod.string().optional(),
|
|
806
|
+
clickTag: urlLike.optional(),
|
|
807
|
+
comment: zod.string().optional(),
|
|
808
|
+
creativeName: zod.string().optional(),
|
|
809
|
+
deliveryGroupId: zod.string().optional(),
|
|
810
|
+
deliveryMultiples: zod.string().optional(),
|
|
811
|
+
dm: zod.string().optional(),
|
|
812
|
+
ext: zod.string().optional(),
|
|
813
|
+
extension: zod.object({
|
|
814
|
+
mediaType: zod.string(),
|
|
815
|
+
prebid: zod.unknown().optional()
|
|
816
|
+
}).optional(),
|
|
817
|
+
extraField1: zod.string().optional(),
|
|
818
|
+
extraField2: zod.string().optional(),
|
|
819
|
+
height: numberLike.optional(),
|
|
820
|
+
height3rd: numberLike.optional(),
|
|
821
|
+
height4th: numberLike.optional(),
|
|
822
|
+
height5th: numberLike.optional(),
|
|
823
|
+
height6th: numberLike.optional(),
|
|
824
|
+
heightLarge: numberLike.optional(),
|
|
825
|
+
id: zod.string().optional(),
|
|
826
|
+
impressionCounter: urlLike.optional(),
|
|
827
|
+
libId: zod.string().optional(),
|
|
828
|
+
orderId: zod.string().optional(),
|
|
829
|
+
orderName: zod.string().optional(),
|
|
830
|
+
orderProperty: zod.string().optional(),
|
|
831
|
+
origin: zod.string().optional(),
|
|
832
|
+
originData: zod.unknown().optional(),
|
|
833
|
+
poolPath: urlLike.optional(),
|
|
834
|
+
preview: booleanLike.optional(),
|
|
835
|
+
priority: numberLike.optional(),
|
|
836
|
+
share: zod.string().optional(),
|
|
837
|
+
// eslint-disable-next-line ts/naming-convention
|
|
838
|
+
slotID: zod.string(),
|
|
839
|
+
slotName: zod.string(),
|
|
840
|
+
swfSrc: urlLike.optional(),
|
|
841
|
+
swfSrc2nd: zod.string().optional(),
|
|
842
|
+
swfSrc3rd: zod.string().optional(),
|
|
843
|
+
swfSrc4th: zod.string().optional(),
|
|
844
|
+
swfSrc5th: zod.string().optional(),
|
|
845
|
+
swfSrc6th: zod.string().optional(),
|
|
846
|
+
tag: zod.string(),
|
|
847
|
+
tagUrl: urlLike.optional(),
|
|
848
|
+
timeStamp: dateLike.optional(),
|
|
849
|
+
trackedImpressionCounter: urlLike.optional(),
|
|
850
|
+
tracker: urlLike.optional(),
|
|
851
|
+
trackingUrl: urlLike.optional(),
|
|
852
|
+
url: urlLike.optional(),
|
|
853
|
+
viewableImpressionCounter: urlLike.optional(),
|
|
854
|
+
width: numberLike.optional(),
|
|
855
|
+
width3rd: numberLike.optional(),
|
|
856
|
+
width4th: numberLike.optional(),
|
|
857
|
+
width5th: numberLike.optional(),
|
|
858
|
+
width6th: numberLike.optional(),
|
|
859
|
+
widthLarge: numberLike.optional()
|
|
860
|
+
});
|
|
861
|
+
const adResponseSchema = baseAdResponseScheme.extend({
|
|
862
|
+
additionalCreatives: zod.lazy(() => zod.union([adResponseSchema.array(), zod.string()]).optional())
|
|
863
|
+
});
|
|
864
|
+
const adSchema = adResponseSchema.transform(({
|
|
865
|
+
additionalCreatives,
|
|
866
|
+
...data
|
|
867
|
+
}) => {
|
|
868
|
+
const filteredValue = Object.fromEntries(
|
|
869
|
+
Object.entries(data).filter(([, value]) => Boolean(value) && JSON.stringify(value) !== "{}" && JSON.stringify(value) !== "[]")
|
|
870
|
+
);
|
|
871
|
+
return {
|
|
872
|
+
...filteredValue,
|
|
873
|
+
additionalCreatives: Array.isArray(additionalCreatives) ? additionalCreatives.map((creative) => adSchema.parse(creative)) : additionalCreatives
|
|
874
|
+
};
|
|
875
|
+
});
|
|
876
|
+
async function requestPreviews(account) {
|
|
877
|
+
const previewObjects = getPreviewObjects();
|
|
878
|
+
const list = (await Promise.allSettled(previewObjects.filter((previewObject) => "adhesePreviewCreativeId" in previewObject).map(async (previewObject) => {
|
|
879
|
+
const endpoint = new URL(`https://${account}-preview.adhese.org/creatives/preview/json/tag.do`);
|
|
880
|
+
endpoint.searchParams.set(
|
|
881
|
+
"id",
|
|
882
|
+
previewObject.adhesePreviewCreativeId
|
|
883
|
+
);
|
|
884
|
+
const response = await fetch(endpoint.href, {
|
|
885
|
+
method: "GET",
|
|
886
|
+
headers: {
|
|
887
|
+
accept: "application/json"
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
if (!response.ok)
|
|
891
|
+
return Promise.reject(new Error(`Failed to request preview ad with ID: ${previewObject.adhesePreviewCreativeId}`));
|
|
892
|
+
return await response.json();
|
|
893
|
+
}))).filter((response) => {
|
|
894
|
+
if (response.status === "rejected") {
|
|
895
|
+
logger.error(response.reason);
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
return response.status === "fulfilled";
|
|
899
|
+
}).map((response) => response.value.map((item) => ({
|
|
900
|
+
...item,
|
|
901
|
+
preview: true
|
|
902
|
+
})));
|
|
903
|
+
return adSchema.array().parse(list.flat());
|
|
904
|
+
}
|
|
905
|
+
function getPreviewObjects() {
|
|
906
|
+
const currentUrl = new URL(window.location.href);
|
|
907
|
+
const previewObjects = [];
|
|
908
|
+
let currentObject = {};
|
|
909
|
+
for (const [key, value] of currentUrl.searchParams.entries()) {
|
|
910
|
+
if (key === "adhesePreviewCreativeId" && Object.keys(currentObject).length > 0) {
|
|
911
|
+
previewObjects.push(currentObject);
|
|
912
|
+
currentObject = {};
|
|
913
|
+
}
|
|
914
|
+
currentObject[key] = value;
|
|
915
|
+
}
|
|
916
|
+
if (Object.keys(currentObject).length > 0)
|
|
917
|
+
previewObjects.push(currentObject);
|
|
918
|
+
return previewObjects;
|
|
919
|
+
}
|
|
920
|
+
function requestWithPost({
|
|
921
|
+
host,
|
|
922
|
+
...options
|
|
923
|
+
}) {
|
|
924
|
+
const payload = {
|
|
925
|
+
...options,
|
|
926
|
+
slots: options.slots.map((slot) => ({
|
|
927
|
+
slotname: slot.getName(),
|
|
928
|
+
parameters: parseParameters(slot.parameters)
|
|
929
|
+
})),
|
|
930
|
+
parameters: options.parameters && parseParameters(options.parameters)
|
|
931
|
+
};
|
|
932
|
+
return fetch(`${new URL(host).href}json`, {
|
|
933
|
+
method: "POST",
|
|
934
|
+
body: JSON.stringify(payload),
|
|
935
|
+
headers: {
|
|
936
|
+
// eslint-disable-next-line ts/naming-convention
|
|
937
|
+
"Content-Type": "application/json"
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
async function requestWithGet(options) {
|
|
942
|
+
return fetch(new URL(`${options.host}/json/sl${options.slots.map((slot) => slot.getName()).join("/sl")}`), {
|
|
943
|
+
method: "GET",
|
|
944
|
+
headers: {
|
|
945
|
+
// eslint-disable-next-line ts/naming-convention
|
|
946
|
+
"Content-Type": "application/json"
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
function parseParameters(parameters) {
|
|
951
|
+
return Object.fromEntries(Array.from(parameters.entries()).filter(([key]) => {
|
|
952
|
+
if (key.length === 2)
|
|
953
|
+
return true;
|
|
954
|
+
logger.warn(`Invalid parameter key: ${key}. Key should be exactly 2 characters long. Key will be ignored.`);
|
|
955
|
+
return false;
|
|
956
|
+
}));
|
|
957
|
+
}
|
|
958
|
+
async function requestAds({
|
|
959
|
+
method = "POST",
|
|
960
|
+
context,
|
|
961
|
+
...options
|
|
962
|
+
}) {
|
|
963
|
+
var _a, _b, _c, _d;
|
|
964
|
+
try {
|
|
965
|
+
(_a = context.events) == null ? void 0 : _a.requestAd.dispatch({
|
|
966
|
+
...options,
|
|
967
|
+
context,
|
|
968
|
+
method
|
|
969
|
+
});
|
|
970
|
+
const [response, previews] = await Promise.all([(method == null ? void 0 : method.toUpperCase()) === "POST" ? requestWithPost(options) : requestWithGet(options), requestPreviews(options.account)]);
|
|
971
|
+
logger.debug("Received response", response);
|
|
972
|
+
if (!response.ok)
|
|
973
|
+
throw new Error(`Failed to request ad: ${response.status} ${response.statusText}`);
|
|
974
|
+
const result = adSchema.array().parse(await response.json());
|
|
975
|
+
logger.debug("Parsed ad", result);
|
|
976
|
+
if (previews.length > 0)
|
|
977
|
+
logger.info(`Found ${previews.length} ${previews.length === 1 ? "preview" : "previews"}. Replacing ads in response with preview items`, previews);
|
|
978
|
+
const matchedPreviews = previews.map(({ slotName, ...preview }) => {
|
|
979
|
+
const partnerAd = result.find((ad) => ad.libId === preview.libId);
|
|
980
|
+
return {
|
|
981
|
+
slotName: `${(partnerAd == null ? void 0 : partnerAd.slotName) ?? slotName}`,
|
|
982
|
+
...preview
|
|
983
|
+
};
|
|
984
|
+
});
|
|
985
|
+
if (matchedPreviews.length > 0)
|
|
986
|
+
(_b = context.events) == null ? void 0 : _b.previewReceived.dispatch(matchedPreviews);
|
|
987
|
+
const mergedResult = [
|
|
988
|
+
...result.filter((ad) => !previews.some((preview) => preview.libId === ad.libId)),
|
|
989
|
+
...matchedPreviews
|
|
990
|
+
];
|
|
991
|
+
if (mergedResult.length === 0)
|
|
992
|
+
throw new Error("No ads found");
|
|
993
|
+
(_c = context.events) == null ? void 0 : _c.responseReceived.dispatch(mergedResult);
|
|
994
|
+
return mergedResult;
|
|
995
|
+
} catch (error) {
|
|
996
|
+
logger.error(String(error));
|
|
997
|
+
(_d = context.events) == null ? void 0 : _d.requestError.dispatch(error);
|
|
998
|
+
throw error;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
async function requestAd({
|
|
1002
|
+
slot,
|
|
1003
|
+
...options
|
|
1004
|
+
}) {
|
|
1005
|
+
const [ad] = await requestAds({
|
|
1006
|
+
slots: [slot],
|
|
1007
|
+
...options
|
|
1008
|
+
});
|
|
1009
|
+
return ad;
|
|
1010
|
+
}
|
|
1011
|
+
exports.createAdhese = createAdhese;
|
|
1012
|
+
//# sourceMappingURL=index.js.map
|