@adtogether/web-sdk 0.1.0 → 0.1.5
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/CHANGELOG.md +15 -0
- package/README.md +147 -0
- package/dist/chunk-7IJIBJD4.mjs +85 -0
- package/dist/index.d.mts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +41 -13
- package/dist/index.mjs +1 -1
- package/dist/react/index.d.mts +18 -1
- package/dist/react/index.d.ts +18 -1
- package/dist/react/index.js +330 -17
- package/dist/react/index.mjs +288 -4
- package/doc/Banner_Example.png +0 -0
- package/doc/Interstitial_Example.png +0 -0
- package/package.json +3 -3
- package/src/core/AdTogether.ts +52 -14
- package/src/core/types.ts +8 -1
- package/src/react/AdTogetherBanner.tsx +2 -2
- package/src/react/AdTogetherInterstitial.tsx +328 -0
- package/src/react/index.ts +1 -0
- package/dist/chunk-IDJUJZAL.mjs +0 -57
package/dist/react/index.js
CHANGED
|
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/react/index.ts
|
|
21
21
|
var react_exports = {};
|
|
22
22
|
__export(react_exports, {
|
|
23
|
-
AdTogetherBanner: () => AdTogetherBanner
|
|
23
|
+
AdTogetherBanner: () => AdTogetherBanner,
|
|
24
|
+
AdTogetherInterstitial: () => AdTogetherInterstitial
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(react_exports);
|
|
26
27
|
|
|
@@ -30,7 +31,8 @@ var import_react = require("react");
|
|
|
30
31
|
// src/core/AdTogether.ts
|
|
31
32
|
var AdTogether = class _AdTogether {
|
|
32
33
|
constructor() {
|
|
33
|
-
this.
|
|
34
|
+
this.allowSelfAds = true;
|
|
35
|
+
this.baseUrl = "https://adtogether.relaxsoftwareapps.com";
|
|
34
36
|
}
|
|
35
37
|
static get shared() {
|
|
36
38
|
if (!_AdTogether.instance) {
|
|
@@ -40,11 +42,16 @@ var AdTogether = class _AdTogether {
|
|
|
40
42
|
}
|
|
41
43
|
static initialize(options) {
|
|
42
44
|
const sdk = _AdTogether.shared;
|
|
43
|
-
sdk.appId = options.appId;
|
|
45
|
+
sdk.appId = options.apiKey || options.appId;
|
|
46
|
+
if (options.allowSelfAds !== void 0) {
|
|
47
|
+
sdk.allowSelfAds = options.allowSelfAds;
|
|
48
|
+
}
|
|
44
49
|
if (options.baseUrl) {
|
|
45
50
|
sdk.baseUrl = options.baseUrl;
|
|
51
|
+
} else if (typeof window !== "undefined") {
|
|
52
|
+
sdk.baseUrl = "";
|
|
46
53
|
}
|
|
47
|
-
console.log(`AdTogether SDK Initialized with App ID: ${
|
|
54
|
+
console.log(`AdTogether SDK Initialized with App ID: ${sdk.appId}`);
|
|
48
55
|
}
|
|
49
56
|
assertInitialized() {
|
|
50
57
|
if (!this.appId) {
|
|
@@ -53,30 +60,52 @@ var AdTogether = class _AdTogether {
|
|
|
53
60
|
}
|
|
54
61
|
return true;
|
|
55
62
|
}
|
|
56
|
-
static async fetchAd(adUnitId) {
|
|
63
|
+
static async fetchAd(adUnitId, adType) {
|
|
57
64
|
if (!_AdTogether.shared.assertInitialized()) {
|
|
58
65
|
throw new Error("AdTogether not initialized");
|
|
59
66
|
}
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
try {
|
|
68
|
+
const sdk = _AdTogether.shared;
|
|
69
|
+
let url = `${sdk.baseUrl}/api/ads/serve?country=global&adUnitId=${adUnitId}&apiKey=${sdk.appId}`;
|
|
70
|
+
if (adType) {
|
|
71
|
+
url += `&adType=${adType}`;
|
|
72
|
+
}
|
|
73
|
+
if (sdk.lastAdId) {
|
|
74
|
+
url += `&exclude=${sdk.lastAdId}`;
|
|
75
|
+
}
|
|
76
|
+
url += `&allowSelfAds=${sdk.allowSelfAds}`;
|
|
77
|
+
if (typeof window !== "undefined") {
|
|
78
|
+
url += `&sourceUrl=${encodeURIComponent(window.location.href)}`;
|
|
79
|
+
}
|
|
80
|
+
const response = await fetch(url);
|
|
81
|
+
if (response.ok) {
|
|
82
|
+
const ad = await response.json();
|
|
83
|
+
sdk.lastAdId = ad.id;
|
|
84
|
+
return ad;
|
|
85
|
+
}
|
|
62
86
|
throw new Error(`Failed to fetch ad. Status: ${response.status}`);
|
|
87
|
+
} catch (err) {
|
|
88
|
+
throw err;
|
|
63
89
|
}
|
|
64
|
-
return response.json();
|
|
65
90
|
}
|
|
66
|
-
static trackImpression(adId) {
|
|
67
|
-
this.trackEvent("/api/ads/impression", adId);
|
|
91
|
+
static trackImpression(adId, token) {
|
|
92
|
+
this.trackEvent("/api/ads/impression", adId, token);
|
|
68
93
|
}
|
|
69
|
-
static trackClick(adId) {
|
|
70
|
-
this.trackEvent("/api/ads/click", adId);
|
|
94
|
+
static trackClick(adId, token) {
|
|
95
|
+
this.trackEvent("/api/ads/click", adId, token);
|
|
71
96
|
}
|
|
72
|
-
static trackEvent(endpoint, adId) {
|
|
97
|
+
static trackEvent(endpoint, adId, token) {
|
|
73
98
|
if (!_AdTogether.shared.assertInitialized()) return;
|
|
74
99
|
fetch(`${_AdTogether.shared.baseUrl}${endpoint}`, {
|
|
75
100
|
method: "POST",
|
|
76
101
|
headers: {
|
|
77
102
|
"Content-Type": "application/json"
|
|
78
103
|
},
|
|
79
|
-
body: JSON.stringify({
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
adId,
|
|
106
|
+
token,
|
|
107
|
+
apiKey: _AdTogether.shared.appId
|
|
108
|
+
})
|
|
80
109
|
}).catch(console.error);
|
|
81
110
|
}
|
|
82
111
|
};
|
|
@@ -136,7 +165,7 @@ var AdTogetherBanner = ({
|
|
|
136
165
|
(entries) => {
|
|
137
166
|
if (entries[0].isIntersecting && entries[0].intersectionRatio >= 0.5 && !impressionTrackedRef.current) {
|
|
138
167
|
impressionTrackedRef.current = true;
|
|
139
|
-
AdTogether.trackImpression(adData.id);
|
|
168
|
+
AdTogether.trackImpression(adData.id, adData.token);
|
|
140
169
|
observer.disconnect();
|
|
141
170
|
}
|
|
142
171
|
},
|
|
@@ -149,7 +178,7 @@ var AdTogetherBanner = ({
|
|
|
149
178
|
}, [adData, isLoading, hasError]);
|
|
150
179
|
const handleContainerClick = () => {
|
|
151
180
|
if (!adData) return;
|
|
152
|
-
AdTogether.trackClick(adData.id);
|
|
181
|
+
AdTogether.trackClick(adData.id, adData.token);
|
|
153
182
|
if (adData.clickUrl) {
|
|
154
183
|
window.open(adData.clickUrl, "_blank", "noopener,noreferrer");
|
|
155
184
|
}
|
|
@@ -225,7 +254,291 @@ var AdTogetherBanner = ({
|
|
|
225
254
|
}
|
|
226
255
|
);
|
|
227
256
|
};
|
|
257
|
+
|
|
258
|
+
// src/react/AdTogetherInterstitial.tsx
|
|
259
|
+
var import_react2 = require("react");
|
|
260
|
+
var import_react_dom = require("react-dom");
|
|
261
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
262
|
+
var AdTogetherInterstitial = ({
|
|
263
|
+
adUnitId,
|
|
264
|
+
isOpen,
|
|
265
|
+
onClose,
|
|
266
|
+
onAdLoaded,
|
|
267
|
+
onAdFailedToLoad,
|
|
268
|
+
theme = "auto",
|
|
269
|
+
closeDelay = 3
|
|
270
|
+
}) => {
|
|
271
|
+
const [adData, setAdData] = (0, import_react2.useState)(null);
|
|
272
|
+
const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
|
|
273
|
+
const [hasError, setHasError] = (0, import_react2.useState)(false);
|
|
274
|
+
const [isDarkMode, setIsDarkMode] = (0, import_react2.useState)(theme === "dark");
|
|
275
|
+
const [canClose, setCanClose] = (0, import_react2.useState)(false);
|
|
276
|
+
const [countdown, setCountdown] = (0, import_react2.useState)(closeDelay);
|
|
277
|
+
const impressionTrackedRef = (0, import_react2.useRef)(false);
|
|
278
|
+
const closeTimerRef = (0, import_react2.useRef)(null);
|
|
279
|
+
const countdownRef = (0, import_react2.useRef)(null);
|
|
280
|
+
(0, import_react2.useEffect)(() => {
|
|
281
|
+
if (theme === "auto") {
|
|
282
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
283
|
+
setIsDarkMode(mediaQuery.matches);
|
|
284
|
+
const handler = (e) => setIsDarkMode(e.matches);
|
|
285
|
+
mediaQuery.addEventListener("change", handler);
|
|
286
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
287
|
+
} else {
|
|
288
|
+
setIsDarkMode(theme === "dark");
|
|
289
|
+
}
|
|
290
|
+
}, [theme]);
|
|
291
|
+
(0, import_react2.useEffect)(() => {
|
|
292
|
+
if (!isOpen) {
|
|
293
|
+
setAdData(null);
|
|
294
|
+
setIsLoading(false);
|
|
295
|
+
setHasError(false);
|
|
296
|
+
setCanClose(false);
|
|
297
|
+
setCountdown(closeDelay);
|
|
298
|
+
impressionTrackedRef.current = false;
|
|
299
|
+
if (closeTimerRef.current) clearTimeout(closeTimerRef.current);
|
|
300
|
+
if (countdownRef.current) clearInterval(countdownRef.current);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
let isMounted = true;
|
|
304
|
+
setIsLoading(true);
|
|
305
|
+
AdTogether.fetchAd(adUnitId, "interstitial").then((ad) => {
|
|
306
|
+
if (isMounted) {
|
|
307
|
+
setAdData(ad);
|
|
308
|
+
setIsLoading(false);
|
|
309
|
+
onAdLoaded?.();
|
|
310
|
+
}
|
|
311
|
+
}).catch((err) => {
|
|
312
|
+
if (isMounted) {
|
|
313
|
+
console.error("AdTogether Failed to load interstitial:", err);
|
|
314
|
+
setHasError(true);
|
|
315
|
+
setIsLoading(false);
|
|
316
|
+
onAdFailedToLoad?.(err);
|
|
317
|
+
onClose();
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
return () => {
|
|
321
|
+
isMounted = false;
|
|
322
|
+
};
|
|
323
|
+
}, [isOpen, adUnitId]);
|
|
324
|
+
(0, import_react2.useEffect)(() => {
|
|
325
|
+
if (!isOpen || !adData) return;
|
|
326
|
+
setCountdown(closeDelay);
|
|
327
|
+
countdownRef.current = setInterval(() => {
|
|
328
|
+
setCountdown((prev) => {
|
|
329
|
+
if (prev <= 1) {
|
|
330
|
+
if (countdownRef.current) clearInterval(countdownRef.current);
|
|
331
|
+
setCanClose(true);
|
|
332
|
+
return 0;
|
|
333
|
+
}
|
|
334
|
+
return prev - 1;
|
|
335
|
+
});
|
|
336
|
+
}, 1e3);
|
|
337
|
+
return () => {
|
|
338
|
+
if (countdownRef.current) clearInterval(countdownRef.current);
|
|
339
|
+
};
|
|
340
|
+
}, [isOpen, adData, closeDelay]);
|
|
341
|
+
(0, import_react2.useEffect)(() => {
|
|
342
|
+
if (!adData || !isOpen || impressionTrackedRef.current) return;
|
|
343
|
+
impressionTrackedRef.current = true;
|
|
344
|
+
AdTogether.trackImpression(adData.id, adData.token);
|
|
345
|
+
}, [adData, isOpen]);
|
|
346
|
+
const handleAdClick = (0, import_react2.useCallback)(() => {
|
|
347
|
+
if (!adData) return;
|
|
348
|
+
AdTogether.trackClick(adData.id, adData.token);
|
|
349
|
+
if (adData.clickUrl) {
|
|
350
|
+
window.open(adData.clickUrl, "_blank", "noopener,noreferrer");
|
|
351
|
+
}
|
|
352
|
+
}, [adData]);
|
|
353
|
+
const handleClose = (0, import_react2.useCallback)(() => {
|
|
354
|
+
if (canClose) {
|
|
355
|
+
onClose();
|
|
356
|
+
}
|
|
357
|
+
}, [canClose, onClose]);
|
|
358
|
+
(0, import_react2.useEffect)(() => {
|
|
359
|
+
if (isOpen) {
|
|
360
|
+
document.body.style.overflow = "hidden";
|
|
361
|
+
} else {
|
|
362
|
+
document.body.style.overflow = "";
|
|
363
|
+
}
|
|
364
|
+
return () => {
|
|
365
|
+
document.body.style.overflow = "";
|
|
366
|
+
};
|
|
367
|
+
}, [isOpen]);
|
|
368
|
+
if (!isOpen) return null;
|
|
369
|
+
const bgOverlay = "rgba(0, 0, 0, 0.7)";
|
|
370
|
+
const cardBg = isDarkMode ? "#1F2937" : "#ffffff";
|
|
371
|
+
const borderColor = isDarkMode ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)";
|
|
372
|
+
const textColor = isDarkMode ? "#F9FAFB" : "#111827";
|
|
373
|
+
const descColor = isDarkMode ? "#9CA3AF" : "#6B7280";
|
|
374
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
375
|
+
"div",
|
|
376
|
+
{
|
|
377
|
+
className: "adtogether-interstitial-overlay",
|
|
378
|
+
style: {
|
|
379
|
+
position: "fixed",
|
|
380
|
+
top: 0,
|
|
381
|
+
left: 0,
|
|
382
|
+
width: "100vw",
|
|
383
|
+
height: "100vh",
|
|
384
|
+
backgroundColor: bgOverlay,
|
|
385
|
+
display: "flex",
|
|
386
|
+
alignItems: "center",
|
|
387
|
+
justifyContent: "center",
|
|
388
|
+
zIndex: 1e5,
|
|
389
|
+
backdropFilter: "blur(8px)",
|
|
390
|
+
animation: "adtogether-fade-in 0.3s ease-out"
|
|
391
|
+
},
|
|
392
|
+
onClick: (e) => {
|
|
393
|
+
if (e.target === e.currentTarget && canClose) handleClose();
|
|
394
|
+
},
|
|
395
|
+
children: [
|
|
396
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `
|
|
397
|
+
@keyframes adtogether-fade-in {
|
|
398
|
+
from { opacity: 0; }
|
|
399
|
+
to { opacity: 1; }
|
|
400
|
+
}
|
|
401
|
+
@keyframes adtogether-scale-in {
|
|
402
|
+
from { opacity: 0; transform: scale(0.9); }
|
|
403
|
+
to { opacity: 1; transform: scale(1); }
|
|
404
|
+
}
|
|
405
|
+
` }),
|
|
406
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#fff", fontSize: "18px" }, children: "Loading Ad..." }) : adData ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
407
|
+
"div",
|
|
408
|
+
{
|
|
409
|
+
style: {
|
|
410
|
+
position: "relative",
|
|
411
|
+
maxWidth: "800px",
|
|
412
|
+
width: "95%",
|
|
413
|
+
backgroundColor: cardBg,
|
|
414
|
+
borderRadius: "24px",
|
|
415
|
+
border: `1px solid ${borderColor}`,
|
|
416
|
+
overflow: "hidden",
|
|
417
|
+
boxShadow: "0 25px 50px rgba(0, 0, 0, 0.5)",
|
|
418
|
+
animation: "adtogether-scale-in 0.3s ease-out"
|
|
419
|
+
},
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "absolute", top: "12px", right: "12px", zIndex: 10 }, children: canClose ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
422
|
+
"button",
|
|
423
|
+
{
|
|
424
|
+
onClick: handleClose,
|
|
425
|
+
style: {
|
|
426
|
+
width: "36px",
|
|
427
|
+
height: "36px",
|
|
428
|
+
borderRadius: "50%",
|
|
429
|
+
backgroundColor: "rgba(0,0,0,0.6)",
|
|
430
|
+
border: "none",
|
|
431
|
+
color: "#fff",
|
|
432
|
+
fontSize: "18px",
|
|
433
|
+
cursor: "pointer",
|
|
434
|
+
display: "flex",
|
|
435
|
+
alignItems: "center",
|
|
436
|
+
justifyContent: "center",
|
|
437
|
+
backdropFilter: "blur(4px)"
|
|
438
|
+
},
|
|
439
|
+
"aria-label": "Close ad",
|
|
440
|
+
children: "\u2715"
|
|
441
|
+
}
|
|
442
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
443
|
+
"div",
|
|
444
|
+
{
|
|
445
|
+
style: {
|
|
446
|
+
width: "36px",
|
|
447
|
+
height: "36px",
|
|
448
|
+
borderRadius: "50%",
|
|
449
|
+
backgroundColor: "rgba(0,0,0,0.6)",
|
|
450
|
+
color: "#fff",
|
|
451
|
+
fontSize: "14px",
|
|
452
|
+
fontWeight: "bold",
|
|
453
|
+
display: "flex",
|
|
454
|
+
alignItems: "center",
|
|
455
|
+
justifyContent: "center",
|
|
456
|
+
backdropFilter: "blur(4px)"
|
|
457
|
+
},
|
|
458
|
+
children: countdown
|
|
459
|
+
}
|
|
460
|
+
) }),
|
|
461
|
+
adData.imageUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
462
|
+
"div",
|
|
463
|
+
{
|
|
464
|
+
style: { cursor: "pointer", position: "relative" },
|
|
465
|
+
onClick: handleAdClick,
|
|
466
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
467
|
+
"img",
|
|
468
|
+
{
|
|
469
|
+
src: adData.imageUrl,
|
|
470
|
+
alt: adData.title,
|
|
471
|
+
style: {
|
|
472
|
+
width: "100%",
|
|
473
|
+
aspectRatio: "16/9",
|
|
474
|
+
objectFit: "cover",
|
|
475
|
+
display: "block"
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
}
|
|
480
|
+
),
|
|
481
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
482
|
+
"div",
|
|
483
|
+
{
|
|
484
|
+
style: { padding: "20px", cursor: "pointer" },
|
|
485
|
+
onClick: handleAdClick,
|
|
486
|
+
children: [
|
|
487
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: "8px" }, children: [
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontWeight: "bold", fontSize: "18px", color: textColor }, children: adData.title }),
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
490
|
+
"span",
|
|
491
|
+
{
|
|
492
|
+
style: {
|
|
493
|
+
backgroundColor: "#FBBF24",
|
|
494
|
+
color: "#000",
|
|
495
|
+
fontSize: "10px",
|
|
496
|
+
fontWeight: "bold",
|
|
497
|
+
padding: "3px 6px",
|
|
498
|
+
borderRadius: "4px",
|
|
499
|
+
marginLeft: "8px",
|
|
500
|
+
flexShrink: 0
|
|
501
|
+
},
|
|
502
|
+
children: "AD"
|
|
503
|
+
}
|
|
504
|
+
)
|
|
505
|
+
] }),
|
|
506
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { fontSize: "14px", color: descColor, margin: 0, lineHeight: 1.5 }, children: adData.description }),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
508
|
+
"button",
|
|
509
|
+
{
|
|
510
|
+
style: {
|
|
511
|
+
marginTop: "16px",
|
|
512
|
+
width: "100%",
|
|
513
|
+
padding: "12px",
|
|
514
|
+
backgroundColor: "#F59E0B",
|
|
515
|
+
color: "#000",
|
|
516
|
+
fontWeight: "bold",
|
|
517
|
+
fontSize: "14px",
|
|
518
|
+
border: "none",
|
|
519
|
+
borderRadius: "12px",
|
|
520
|
+
cursor: "pointer"
|
|
521
|
+
},
|
|
522
|
+
onClick: (e) => {
|
|
523
|
+
e.stopPropagation();
|
|
524
|
+
handleAdClick();
|
|
525
|
+
},
|
|
526
|
+
children: "Learn More \u2192"
|
|
527
|
+
}
|
|
528
|
+
)
|
|
529
|
+
]
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
]
|
|
533
|
+
}
|
|
534
|
+
) : null
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
return (0, import_react_dom.createPortal)(content, document.body);
|
|
539
|
+
};
|
|
228
540
|
// Annotate the CommonJS export names for ESM import in node:
|
|
229
541
|
0 && (module.exports = {
|
|
230
|
-
AdTogetherBanner
|
|
542
|
+
AdTogetherBanner,
|
|
543
|
+
AdTogetherInterstitial
|
|
231
544
|
});
|