@adhese/sdk 0.16.2 → 0.18.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/index.js CHANGED
@@ -1,116 +1,10 @@
1
- import { createLogger, toValue, ref, computed, waitForDomLoad, watch, effectScope, uniqueId, reactive, createEventManager, awaitTimeout } from "@adhese/sdk-shared";
1
+ import { createLogger, toValue, ref, computed, waitForDomLoad, watch, createAsyncHook, createPassiveHook, effectScope, uniqueId, reactive, addTrackingPixel, createSyncHook, createEventManager, awaitTimeout } from "@adhese/sdk-shared";
2
2
  import { debounce, round, isDeepEqual, doNothing } from "remeda";
3
3
  const name = "@adhese/sdk";
4
- const version = "0.16.2";
5
- function addTrackingPixel(url) {
6
- const img = document.createElement("img");
7
- img.src = url.toString();
8
- img.style.height = "1px";
9
- img.style.width = "1px";
10
- img.style.margin = "-1px";
11
- img.style.border = "0";
12
- img.style.position = "absolute";
13
- img.style.top = "0";
14
- return document.body.appendChild(img);
15
- }
16
- const hookMap = /* @__PURE__ */ new Map();
17
- function clearAllHooks() {
18
- hookMap.clear();
19
- }
20
- function createAsyncHook(name2, {
21
- onRun,
22
- onAdd
23
- } = {}) {
24
- hookMap.set(name2, /* @__PURE__ */ new Set());
25
- const run = async (arg) => {
26
- let latestResult = arg;
27
- for (const callback of hookMap.get(name2) ?? [])
28
- latestResult = await callback(latestResult) ?? latestResult;
29
- onRun == null ? void 0 : onRun(hookMap.get(name2));
30
- return latestResult;
31
- };
32
- function dispose() {
33
- hookMap.delete(name2);
34
- }
35
- return [run, (callback) => add(callback, { name: name2, onAdd }), dispose];
36
- }
37
- function createSyncHook(name2, {
38
- onRun,
39
- onAdd
40
- } = {}) {
41
- hookMap.set(name2, /* @__PURE__ */ new Set());
42
- const run = (arg) => {
43
- let latestResult = arg;
44
- const promisedCallbacks = [];
45
- for (const callback of hookMap.get(name2) ?? []) {
46
- if (isCallbackAsync(callback))
47
- promisedCallbacks.push(callback);
48
- else
49
- latestResult = callback(latestResult) ?? latestResult;
50
- }
51
- Promise.allSettled(promisedCallbacks.map((callback) => callback(latestResult))).catch(console.trace);
52
- onRun == null ? void 0 : onRun(hookMap.get(name2));
53
- return latestResult;
54
- };
55
- function dispose() {
56
- hookMap.delete(name2);
57
- }
58
- return [run, (callback) => add(callback, { name: name2, onAdd }), dispose];
59
- }
60
- function createPassiveHook(name2, {
61
- onRun,
62
- onAdd
63
- } = {}) {
64
- hookMap.set(name2, /* @__PURE__ */ new Set());
65
- function run(arg) {
66
- Promise.allSettled(Array.from(hookMap.get(name2) ?? []).map((callback) => callback(arg))).catch(console.trace);
67
- onRun == null ? void 0 : onRun(hookMap.get(name2));
68
- }
69
- function dispose() {
70
- hookMap.delete(name2);
71
- }
72
- return [run, (callback) => add(callback, { name: name2, onAdd }), dispose];
73
- }
74
- function isCallbackAsync(callback) {
75
- return callback.constructor.name === "AsyncFunction";
76
- }
77
- function add(callback, {
78
- name: name2,
79
- onAdd
80
- }) {
81
- const hookSet = hookMap.get(name2);
82
- if (hookSet)
83
- hookSet.add(callback);
84
- else
85
- hookMap.set(name2, /* @__PURE__ */ new Set([callback]));
86
- onAdd == null ? void 0 : onAdd(hookSet);
87
- return () => {
88
- var _a;
89
- (_a = hookMap.get(name2)) == null ? void 0 : _a.delete(callback);
90
- };
91
- }
92
- let resolveOnInitPromise = () => {
93
- };
94
- let isInit = false;
95
- const waitOnInit = new Promise((resolve) => {
96
- resolveOnInitPromise = resolve;
97
- });
98
- const [runOnInit, onInit] = createSyncHook("onInit", {
99
- onRun(callbacks) {
100
- isInit = true;
101
- resolveOnInitPromise();
102
- callbacks == null ? void 0 : callbacks.clear();
103
- },
104
- onAdd() {
105
- if (isInit)
106
- runOnInit();
107
- }
108
- });
4
+ const version = "0.18.0";
109
5
  const logger = createLogger({
110
6
  scope: `${name}@${version}`
111
7
  });
112
- const [runOnRequest, onRequest] = createAsyncHook("onRequest");
113
- const [runOnResponse, onResponse] = createAsyncHook("onResponse");
114
8
  async function requestPreviews(account) {
115
9
  const previewObjects = getPreviewObjects();
116
10
  const [list, adSchema] = await Promise.all([
@@ -236,7 +130,7 @@ async function requestAd(options) {
236
130
  }
237
131
  async function requestAds(requestOptions) {
238
132
  var _a, _b, _c, _d, _e;
239
- const options = await runOnRequest(requestOptions);
133
+ const options = await requestOptions.context.hooks.runOnRequest(requestOptions);
240
134
  const { context } = options;
241
135
  try {
242
136
  (_a = context == null ? void 0 : context.events) == null ? void 0 : _a.requestAd.dispatch({
@@ -264,7 +158,7 @@ async function requestAds(requestOptions) {
264
158
  });
265
159
  if (matchedPreviews.length > 0)
266
160
  (_c = context.events) == null ? void 0 : _c.previewReceived.dispatch(matchedPreviews);
267
- const mergedResult = await runOnResponse([
161
+ const mergedResult = await context.hooks.runOnResponse([
268
162
  ...result.filter((ad) => !previews.some((preview) => preview.libId === ad.libId)),
269
163
  ...matchedPreviews
270
164
  ]);
@@ -276,19 +170,7 @@ async function requestAds(requestOptions) {
276
170
  throw error;
277
171
  }
278
172
  }
279
- const [runOnSlotCreate, onSlotCreate] = createSyncHook("onSlotCreate");
280
- let isDisposed = false;
281
- const [runOnDispose, onDispose] = createSyncHook("onDispose", {
282
- onRun(callbacks) {
283
- isDisposed = true;
284
- callbacks == null ? void 0 : callbacks.clear();
285
- },
286
- onAdd() {
287
- if (isDisposed)
288
- runOnDispose();
289
- }
290
- });
291
- function useQueryDetector(queries = {
173
+ function useQueryDetector(context, queries = {
292
174
  mobile: "(max-width: 768px)",
293
175
  tablet: "(min-width: 769px) and (max-width: 1024px)",
294
176
  desktop: "(min-width: 1025px)"
@@ -301,7 +183,7 @@ function useQueryDetector(queries = {
301
183
  }, {
302
184
  waitMs: 50
303
185
  });
304
- onInit(() => {
186
+ context.hooks.onInit(() => {
305
187
  for (const query of queryList)
306
188
  query.addEventListener("change", handleOnChange.call);
307
189
  handleOnChange.call();
@@ -310,7 +192,7 @@ function useQueryDetector(queries = {
310
192
  for (const query of queryList)
311
193
  query.removeEventListener("change", handleOnChange.call);
312
194
  }
313
- onDispose(dispose);
195
+ context.hooks.onDispose(dispose);
314
196
  return [computed(() => active.value), dispose];
315
197
  }
316
198
  function getQuery(entries) {
@@ -349,9 +231,9 @@ function renderInline(ad, element) {
349
231
  function generateName(location, format, slot) {
350
232
  return `${location}${slot ? `${slot}` : ""}-${format}`;
351
233
  }
352
- function useDomLoaded() {
234
+ function useDomLoaded(context) {
353
235
  const isDomLoaded = ref(false);
354
- onInit(async () => {
236
+ context.hooks.onInit(async () => {
355
237
  await waitForDomLoad();
356
238
  isDomLoaded.value = true;
357
239
  });
@@ -396,7 +278,7 @@ function useViewabilityObserver({ context, slotContext, hooks, onTracked }) {
396
278
  ...context.options.viewabilityTrackingOptions
397
279
  };
398
280
  const trackingPixel = ref(null);
399
- const isTracked = computed(() => Boolean(trackingPixel.value));
281
+ const isTracked = ref(false);
400
282
  const viewabilityObserver = new IntersectionObserver(([entry]) => {
401
283
  if (context.options.viewabilityTracking && !trackingPixel.value) {
402
284
  const ratio = round(entry.intersectionRatio, 1);
@@ -404,6 +286,7 @@ function useViewabilityObserver({ context, slotContext, hooks, onTracked }) {
404
286
  timeoutId = setTimeout(() => {
405
287
  timeoutId = null;
406
288
  onTracked == null ? void 0 : onTracked(trackingPixel);
289
+ isTracked.value = true;
407
290
  }, duration);
408
291
  } else if (ratio < threshold && timeoutId) {
409
292
  clearTimeout(timeoutId);
@@ -440,27 +323,27 @@ function useViewabilityObserver({ context, slotContext, hooks, onTracked }) {
440
323
  });
441
324
  return isTracked;
442
325
  }
443
- function useSlotHooks({ setup }, slotContext, id) {
444
- const [runOnBeforeRender, onBeforeRender, disposeOnBeforeRender] = createAsyncHook(`onBeforeRender:${id}`);
445
- const [runOnRender, onRender, disposeOnRender] = createAsyncHook(`onRender:${id}`);
446
- const [runOnBeforeRequest, onBeforeRequest, disposeOnBeforeRequest] = createAsyncHook(`onBeforeRequest:${id}`);
447
- const [runOnRequest2, onRequest2, disposeOnRequest] = createAsyncHook(`onRequest:${id}`);
448
- const [runOnDispose2, onDispose2, disposeOnDispose] = createPassiveHook(`onDispose:${id}`);
326
+ function useSlotHooks({ setup }, slotContext) {
327
+ const [runOnBeforeRender, onBeforeRender, disposeOnBeforeRender] = createAsyncHook();
328
+ const [runOnRender, onRender, disposeOnRender] = createAsyncHook();
329
+ const [runOnBeforeRequest, onBeforeRequest, disposeOnBeforeRequest] = createAsyncHook();
330
+ const [runOnRequest, onRequest, disposeOnRequest] = createAsyncHook();
331
+ const [runOnDispose, onDispose, disposeOnDispose] = createPassiveHook();
449
332
  setup == null ? void 0 : setup(slotContext, {
450
333
  onBeforeRender,
451
334
  onRender,
452
335
  onBeforeRequest,
453
- onDispose: onDispose2,
454
- onRequest: onRequest2
336
+ onDispose,
337
+ onRequest
455
338
  });
456
- onDispose2(() => {
339
+ onDispose(() => {
457
340
  disposeOnBeforeRender();
458
341
  disposeOnRender();
459
342
  disposeOnBeforeRequest();
460
343
  disposeOnRequest();
461
344
  disposeOnDispose();
462
345
  });
463
- return { runOnBeforeRender, runOnRender, runOnBeforeRequest, runOnRequest: runOnRequest2, runOnDispose: runOnDispose2, onDispose: onDispose2, onBeforeRequest, onRequest: onRequest2, onBeforeRender, onRender };
346
+ return { runOnBeforeRender, runOnRender, runOnBeforeRequest, runOnRequest, runOnDispose, onDispose, onBeforeRequest, onRequest, onBeforeRender, onRender };
464
347
  }
465
348
  const renderFunctions = {
466
349
  iframe: renderIframe,
@@ -475,7 +358,7 @@ function createSlot(slotOptions) {
475
358
  const scope = effectScope();
476
359
  return scope.run(() => {
477
360
  const slotContext = ref(null);
478
- const options = runOnSlotCreate({
361
+ const options = slotOptions.context.hooks.runOnSlotCreate({
479
362
  ...defaultOptions,
480
363
  ...slotOptions
481
364
  });
@@ -491,13 +374,13 @@ function createSlot(slotOptions) {
491
374
  runOnBeforeRender,
492
375
  runOnRender,
493
376
  runOnBeforeRequest,
494
- runOnRequest: runOnRequest2,
495
- runOnDispose: runOnDispose2,
377
+ runOnRequest,
378
+ runOnDispose,
496
379
  ...hooks
497
- } = useSlotHooks(options, slotContext, id);
498
- const isDisposed2 = ref(false);
380
+ } = useSlotHooks(options, slotContext);
381
+ const isDisposed = ref(false);
499
382
  const parameters = reactive(new Map(Object.entries(options.parameters ?? {})));
500
- const [device, disposeQueryDetector] = useQueryDetector(typeof options.format === "string" ? {
383
+ const [device, disposeQueryDetector] = useQueryDetector(context, typeof options.format === "string" ? {
501
384
  [options.format]: "(min-width: 0px)"
502
385
  } : Object.fromEntries(options.format.map((item) => [item.format, item.query])));
503
386
  const format = computed(() => typeof options.format === "string" ? options.format : device.value);
@@ -515,7 +398,7 @@ function createSlot(slotOptions) {
515
398
  data.value = newAd;
516
399
  originalData.value = newAd;
517
400
  });
518
- const isDomLoaded = useDomLoaded();
401
+ const isDomLoaded = useDomLoaded(context);
519
402
  const element = computed(
520
403
  () => {
521
404
  var _a;
@@ -542,7 +425,7 @@ function createSlot(slotOptions) {
542
425
  hooks.onDispose(() => {
543
426
  disposeQueryDetector();
544
427
  });
545
- onInit(async () => {
428
+ context.hooks.onInit(async () => {
546
429
  var _a;
547
430
  status.value = "initialized";
548
431
  if (options.lazyLoading)
@@ -562,7 +445,11 @@ function createSlot(slotOptions) {
562
445
  }
563
446
  });
564
447
  const impressionTrackingPixelElement = ref(null);
565
- const isImpressionTracked = computed(() => Boolean(impressionTrackingPixelElement.value));
448
+ const isImpressionTracked = ref(false);
449
+ hooks.onDispose(() => {
450
+ if (impressionTrackingPixelElement.value)
451
+ impressionTrackingPixelElement.value.remove();
452
+ });
566
453
  async function request() {
567
454
  if (options.lazyLoading && !isInViewport.value)
568
455
  return null;
@@ -578,7 +465,7 @@ function createSlot(slotOptions) {
578
465
  });
579
466
  }
580
467
  if (response)
581
- response = await runOnRequest2(response);
468
+ response = await runOnRequest(response);
582
469
  data.value = response;
583
470
  if (!originalData.value)
584
471
  originalData.value = response;
@@ -590,7 +477,6 @@ function createSlot(slotOptions) {
590
477
  async function render(adToRender) {
591
478
  status.value = "rendering";
592
479
  await waitForDomLoad();
593
- await waitOnInit;
594
480
  let renderAd = adToRender ?? data.value ?? originalData.value ?? await request();
595
481
  renderAd = renderAd && await runOnBeforeRender(renderAd);
596
482
  if (!renderAd) {
@@ -613,10 +499,9 @@ function createSlot(slotOptions) {
613
499
  throw new Error(error);
614
500
  }
615
501
  renderFunctions[renderMode](renderAd, element.value);
616
- if (renderAd.impressionCounter && !impressionTrackingPixelElement.value) {
502
+ if (renderAd.impressionCounter && !impressionTrackingPixelElement.value)
617
503
  impressionTrackingPixelElement.value = addTrackingPixel(renderAd.impressionCounter);
618
- logger.debug(`Impression tracking pixel fired for ${name2.value}`);
619
- }
504
+ isImpressionTracked.value = true;
620
505
  logger.debug("Slot rendered", {
621
506
  renderedElement: element,
622
507
  location: context.location,
@@ -638,12 +523,10 @@ function createSlot(slotOptions) {
638
523
  originalData.value = null;
639
524
  }
640
525
  function dispose() {
641
- var _a;
642
526
  cleanElement();
643
- (_a = impressionTrackingPixelElement.value) == null ? void 0 : _a.remove();
644
527
  data.value = null;
645
- runOnDispose2();
646
- isDisposed2.value = true;
528
+ runOnDispose();
529
+ isDisposed.value = true;
647
530
  scope.stop();
648
531
  }
649
532
  const state = reactive({
@@ -659,7 +542,7 @@ function createSlot(slotOptions) {
659
542
  isImpressionTracked,
660
543
  status,
661
544
  element,
662
- isDisposed: isDisposed2,
545
+ isDisposed,
663
546
  id,
664
547
  render,
665
548
  request,
@@ -706,7 +589,7 @@ function createSlotManager({
706
589
  function getAll() {
707
590
  return Array.from(context.slots).map(([, slot]) => slot);
708
591
  }
709
- function add2(options) {
592
+ function add(options) {
710
593
  var _a;
711
594
  const slot = createSlot({
712
595
  ...options,
@@ -753,14 +636,14 @@ function createSlotManager({
753
636
  context.slots.clear();
754
637
  }
755
638
  for (const options of initialSlots) {
756
- add2({
639
+ add({
757
640
  ...options,
758
641
  lazyLoading: false
759
642
  });
760
643
  }
761
644
  return {
762
645
  getAll,
763
- add: add2,
646
+ add,
764
647
  findDomSlots: findDomSlots$1,
765
648
  get,
766
649
  dispose
@@ -773,11 +656,11 @@ function useConsent(context) {
773
656
  if (data.tcString)
774
657
  consent.value = data.tcString;
775
658
  }
776
- onInit(() => {
659
+ context.hooks.onInit(() => {
777
660
  var _a;
778
661
  (_a = window.__tcfapi) == null ? void 0 : _a.call(window, "addEventListener", 2, onTcfConsentChange);
779
662
  });
780
- onDispose(() => {
663
+ context.hooks.onDispose(() => {
781
664
  var _a;
782
665
  (_a = window.__tcfapi) == null ? void 0 : _a.call(window, "removeEventListener", 2, onTcfConsentChange);
783
666
  });
@@ -814,7 +697,7 @@ async function fetchAllUnrenderedSlots(slots) {
814
697
  await Promise.allSettled(filteredSlots.map((slot) => slot.request()));
815
698
  }
816
699
  function useMainQueryDetector(mergedOptions, context) {
817
- const [device] = useQueryDetector(mergedOptions.queries);
700
+ const [device] = useQueryDetector(context, mergedOptions.queries);
818
701
  watch(device, async (newDevice) => {
819
702
  var _a, _b;
820
703
  context.device = newDevice;
@@ -838,7 +721,7 @@ function useMainDebugMode(context) {
838
721
  }, {
839
722
  immediate: true
840
723
  });
841
- onDispose(() => {
724
+ context.hooks.onDispose(() => {
842
725
  context.logger.resetLogs();
843
726
  context.logger.info("Adhese instance disposed");
844
727
  });
@@ -866,6 +749,56 @@ function useMainParameters(context, options) {
866
749
  }
867
750
  );
868
751
  }
752
+ function createGlobalHooks() {
753
+ const disposeFunctions = /* @__PURE__ */ new Set();
754
+ let isInit = false;
755
+ const [runOnInit, onInit, disposeOnInit] = createSyncHook({
756
+ onRun(callbacks) {
757
+ isInit = true;
758
+ callbacks == null ? void 0 : callbacks.clear();
759
+ },
760
+ onAdd() {
761
+ if (isInit)
762
+ runOnInit();
763
+ }
764
+ });
765
+ disposeFunctions.add(disposeOnInit);
766
+ let isDisposed = false;
767
+ const [runOnDispose, onDispose, disposeOnDispose] = createSyncHook({
768
+ onRun(callbacks) {
769
+ isDisposed = true;
770
+ callbacks == null ? void 0 : callbacks.clear();
771
+ },
772
+ onAdd() {
773
+ if (isDisposed)
774
+ runOnDispose();
775
+ }
776
+ });
777
+ disposeFunctions.add(disposeOnDispose);
778
+ const [runOnRequest, onRequest, disposeOnRequest] = createAsyncHook();
779
+ disposeFunctions.add(disposeOnRequest);
780
+ const [runOnResponse, onResponse, disposeOnResponse] = createAsyncHook();
781
+ disposeFunctions.add(disposeOnResponse);
782
+ const [runOnSlotCreate, onSlotCreate, disposeOnSlotCreate] = createSyncHook();
783
+ disposeFunctions.add(disposeOnSlotCreate);
784
+ function clearAll() {
785
+ for (const disposeFunction of disposeFunctions)
786
+ disposeFunction();
787
+ }
788
+ return {
789
+ runOnInit,
790
+ onInit,
791
+ runOnDispose,
792
+ onDispose,
793
+ runOnRequest,
794
+ onRequest,
795
+ runOnResponse,
796
+ onResponse,
797
+ runOnSlotCreate,
798
+ onSlotCreate,
799
+ clearAll
800
+ };
801
+ }
869
802
  function createAdhese(options) {
870
803
  const scope = effectScope();
871
804
  return scope.run(() => {
@@ -886,6 +819,7 @@ function createAdhese(options) {
886
819
  ...options
887
820
  };
888
821
  setupLogging(mergedOptions);
822
+ const hooks = createGlobalHooks();
889
823
  const context = reactive({
890
824
  location: mergedOptions.location,
891
825
  consent: mergedOptions.consent,
@@ -897,6 +831,7 @@ function createAdhese(options) {
897
831
  events: createEventManager(),
898
832
  slots: /* @__PURE__ */ new Map(),
899
833
  device: "unknown",
834
+ hooks,
900
835
  dispose,
901
836
  findDomSlots: findDomSlots2,
902
837
  getAll,
@@ -907,11 +842,7 @@ function createAdhese(options) {
907
842
  plugin(context, {
908
843
  index,
909
844
  version,
910
- onInit,
911
- onDispose,
912
- onRequest,
913
- onResponse,
914
- onSlotCreate
845
+ hooks
915
846
  });
916
847
  }
917
848
  watch(() => context.location, (newLocation) => {
@@ -952,12 +883,12 @@ function createAdhese(options) {
952
883
  slotManager.dispose();
953
884
  (_a = context.parameters) == null ? void 0 : _a.clear();
954
885
  (_b = context.events) == null ? void 0 : _b.dispose();
955
- runOnDispose();
956
- clearAllHooks();
886
+ hooks.runOnDispose();
887
+ hooks.clearAll();
957
888
  scope.stop();
958
889
  }
959
890
  context.dispose = dispose;
960
- onInit(async () => {
891
+ hooks.onInit(async () => {
961
892
  var _a;
962
893
  await awaitTimeout(0);
963
894
  if ((slotManager.getAll().length ?? 0) > 0)
@@ -969,7 +900,7 @@ function createAdhese(options) {
969
900
  if (!scope.active)
970
901
  dispose();
971
902
  });
972
- runOnInit();
903
+ hooks.runOnInit();
973
904
  return context;
974
905
  });
975
906
  }