@trillboards/ads-sdk 2.1.0 → 2.2.1
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 +18 -0
- package/README.md +9 -1
- package/dist/cli.js +2 -2
- package/dist/index.d.mts +45 -5
- package/dist/index.d.ts +45 -5
- package/dist/index.js +128 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +128 -11
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +2 -0
- package/dist/react-native.d.ts +2 -0
- package/dist/react-native.js +1 -0
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +1 -0
- package/dist/react-native.mjs.map +1 -1
- package/dist/react.d.mts +6 -0
- package/dist/react.d.ts +6 -0
- package/dist/react.js +130 -8
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +130 -8
- package/dist/react.mjs.map +1 -1
- package/dist/server.js +6 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +6 -2
- package/dist/server.mjs.map +1 -1
- package/dist/trillboards-lite.global.js +1 -1
- package/dist/trillboards-lite.global.js.map +1 -1
- package/package.json +19 -19
package/dist/react.mjs
CHANGED
|
@@ -2,6 +2,9 @@ import { createContext, useState, useEffect, useMemo, useContext, useCallback, u
|
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/react/TrillboardsProvider.tsx
|
|
5
|
+
|
|
6
|
+
// src/core/config.ts
|
|
7
|
+
var SDK_VERSION = "2.2.0";
|
|
5
8
|
var DEFAULT_CONFIG = {
|
|
6
9
|
API_BASE: "https://api.trillboards.com/v1/partner",
|
|
7
10
|
CDN_BASE: "https://cdn.trillboards.com",
|
|
@@ -56,6 +59,7 @@ var DEFAULT_PUBLIC_STATE = {
|
|
|
56
59
|
programmaticPlaying: false,
|
|
57
60
|
prefetchedReady: false,
|
|
58
61
|
waterfallMode: "programmatic_only",
|
|
62
|
+
adDeliveryProfileMode: null,
|
|
59
63
|
screenId: null,
|
|
60
64
|
deviceId: null
|
|
61
65
|
};
|
|
@@ -83,6 +87,7 @@ function createInitialState() {
|
|
|
83
87
|
programmaticRetryActive: false,
|
|
84
88
|
programmaticRetryCount: 0,
|
|
85
89
|
programmaticLastError: null,
|
|
90
|
+
adDeliveryProfile: null,
|
|
86
91
|
initialized: false,
|
|
87
92
|
screenOrientation: null,
|
|
88
93
|
screenDimensions: null,
|
|
@@ -100,6 +105,7 @@ function getPublicState(internal) {
|
|
|
100
105
|
programmaticPlaying: internal.programmaticPlaying,
|
|
101
106
|
prefetchedReady: internal.prefetchedReady ?? false,
|
|
102
107
|
waterfallMode: internal.waterfallMode,
|
|
108
|
+
adDeliveryProfileMode: internal.adDeliveryProfile?.mode ?? null,
|
|
103
109
|
screenId: internal.screenId,
|
|
104
110
|
deviceId: internal.deviceId
|
|
105
111
|
};
|
|
@@ -225,6 +231,9 @@ var Logger = class {
|
|
|
225
231
|
}
|
|
226
232
|
};
|
|
227
233
|
var logger = new Logger();
|
|
234
|
+
function setLogLevel(level) {
|
|
235
|
+
logger.setLevel(level);
|
|
236
|
+
}
|
|
228
237
|
|
|
229
238
|
// src/api/client.ts
|
|
230
239
|
function getPlayerTruth(container) {
|
|
@@ -357,10 +366,9 @@ var ApiClient = class {
|
|
|
357
366
|
}
|
|
358
367
|
}
|
|
359
368
|
/**
|
|
360
|
-
* Ping
|
|
361
|
-
* Returns `true` on 2xx, `false` on any error.
|
|
369
|
+
* Ping heartbeat endpoint and return delivery profile + queued commands.
|
|
362
370
|
*/
|
|
363
|
-
async sendHeartbeat(deviceId, screenId) {
|
|
371
|
+
async sendHeartbeat(deviceId, screenId, payload = {}) {
|
|
364
372
|
logger.debug("Sending heartbeat", { deviceId });
|
|
365
373
|
try {
|
|
366
374
|
const response = await fetch(`${this.apiBase}/device/${deviceId}/heartbeat`, {
|
|
@@ -370,13 +378,24 @@ var ApiClient = class {
|
|
|
370
378
|
device_id: deviceId,
|
|
371
379
|
screen_id: screenId,
|
|
372
380
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
373
|
-
status: "active"
|
|
381
|
+
status: "active",
|
|
382
|
+
...payload
|
|
374
383
|
}),
|
|
375
384
|
signal: AbortSignal.timeout(5e3)
|
|
376
385
|
});
|
|
377
|
-
|
|
386
|
+
if (!response.ok) {
|
|
387
|
+
return { ok: false, data: null };
|
|
388
|
+
}
|
|
389
|
+
let data = null;
|
|
390
|
+
try {
|
|
391
|
+
const json = await response.json();
|
|
392
|
+
data = json?.data ?? null;
|
|
393
|
+
} catch {
|
|
394
|
+
data = null;
|
|
395
|
+
}
|
|
396
|
+
return { ok: true, data };
|
|
378
397
|
} catch {
|
|
379
|
-
return false;
|
|
398
|
+
return { ok: false, data: null };
|
|
380
399
|
}
|
|
381
400
|
}
|
|
382
401
|
/**
|
|
@@ -1393,6 +1412,9 @@ var _TrillboardsAds = class _TrillboardsAds {
|
|
|
1393
1412
|
this.offlineHandler = null;
|
|
1394
1413
|
this.visibilityHandler = null;
|
|
1395
1414
|
this.config = resolveConfig(config);
|
|
1415
|
+
if (this.config.debug) {
|
|
1416
|
+
setLogLevel("debug");
|
|
1417
|
+
}
|
|
1396
1418
|
this.state = createInitialState();
|
|
1397
1419
|
this.events = new EventEmitter();
|
|
1398
1420
|
this.api = new ApiClient(this.config.apiBase);
|
|
@@ -1666,11 +1688,104 @@ var _TrillboardsAds = class _TrillboardsAds {
|
|
|
1666
1688
|
}
|
|
1667
1689
|
startHeartbeatTimer() {
|
|
1668
1690
|
if (this.state.heartbeatTimer) clearInterval(this.state.heartbeatTimer);
|
|
1691
|
+
const tick = () => {
|
|
1692
|
+
this.sendHeartbeatTick().catch(() => {
|
|
1693
|
+
});
|
|
1694
|
+
};
|
|
1695
|
+
tick();
|
|
1669
1696
|
this.state.heartbeatTimer = setInterval(() => {
|
|
1670
|
-
|
|
1697
|
+
tick();
|
|
1671
1698
|
}, this.config.heartbeatInterval);
|
|
1672
1699
|
}
|
|
1700
|
+
async sendHeartbeatTick() {
|
|
1701
|
+
const result = await this.api.sendHeartbeat(
|
|
1702
|
+
this.config.deviceId,
|
|
1703
|
+
this.state.screenId,
|
|
1704
|
+
this.buildHeartbeatPayload()
|
|
1705
|
+
);
|
|
1706
|
+
if (!result.ok || !result.data) return;
|
|
1707
|
+
if (result.data.ad_delivery_profile?.mode) {
|
|
1708
|
+
this.applyAdDeliveryProfile(result.data.ad_delivery_profile);
|
|
1709
|
+
}
|
|
1710
|
+
if (Array.isArray(result.data.commands) && result.data.commands.length > 0) {
|
|
1711
|
+
this.runHeartbeatCommands(result.data.commands);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
buildHeartbeatPayload() {
|
|
1715
|
+
const userAgent = typeof navigator !== "undefined" ? navigator.userAgent : "";
|
|
1716
|
+
const platform = typeof navigator !== "undefined" ? navigator.platform : null;
|
|
1717
|
+
const connection = typeof navigator !== "undefined" ? navigator.connection : null;
|
|
1718
|
+
const chromiumMatch = userAgent.match(/(?:Chrome|Chromium)\/(\d+)/i);
|
|
1719
|
+
const chromiumMajor = chromiumMatch ? Number(chromiumMatch[1]) : void 0;
|
|
1720
|
+
const imaSupported = typeof window !== "undefined" ? Boolean(window?.google?.ima) : null;
|
|
1721
|
+
const telemetry = {
|
|
1722
|
+
powerState: typeof document !== "undefined" && document.hidden ? "standby" : "on",
|
|
1723
|
+
agentStatus: typeof document !== "undefined" && document.hidden ? "background" : "foreground",
|
|
1724
|
+
os: platform || void 0,
|
|
1725
|
+
agentVersion: SDK_VERSION,
|
|
1726
|
+
ima_integration: "html5_webview",
|
|
1727
|
+
ima_supported: imaSupported,
|
|
1728
|
+
webview_chromium_major: Number.isFinite(chromiumMajor) ? chromiumMajor : void 0
|
|
1729
|
+
};
|
|
1730
|
+
const payload = {
|
|
1731
|
+
telemetry,
|
|
1732
|
+
sdk: {
|
|
1733
|
+
version: SDK_VERSION,
|
|
1734
|
+
ima_supported: imaSupported,
|
|
1735
|
+
ima_integration: "html5_webview",
|
|
1736
|
+
webview_chromium_major: Number.isFinite(chromiumMajor) ? chromiumMajor : void 0
|
|
1737
|
+
},
|
|
1738
|
+
device: {
|
|
1739
|
+
os: platform || void 0,
|
|
1740
|
+
model: userAgent || void 0
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
if (connection) {
|
|
1744
|
+
payload.network = {
|
|
1745
|
+
connectionType: connection.type || void 0,
|
|
1746
|
+
effectiveType: connection.effectiveType || void 0,
|
|
1747
|
+
downlinkMbps: typeof connection.downlink === "number" ? connection.downlink : void 0,
|
|
1748
|
+
bandwidthMbps: typeof connection.downlink === "number" ? connection.downlink : void 0,
|
|
1749
|
+
rtt: typeof connection.rtt === "number" ? connection.rtt : void 0,
|
|
1750
|
+
latencyRtt: typeof connection.rtt === "number" ? connection.rtt : void 0,
|
|
1751
|
+
saveData: typeof connection.saveData === "boolean" ? connection.saveData : void 0
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
return payload;
|
|
1755
|
+
}
|
|
1756
|
+
applyAdDeliveryProfile(profile) {
|
|
1757
|
+
if (!profile?.mode) return;
|
|
1758
|
+
const previousMode = this.state.adDeliveryProfile?.mode ?? null;
|
|
1759
|
+
this.state.adDeliveryProfile = profile;
|
|
1760
|
+
if (profile.mode === "vast_fallback" && this.state.programmaticPlaying) {
|
|
1761
|
+
this.programmaticPlayer.stop({ silent: true });
|
|
1762
|
+
this.state.programmaticPlaying = false;
|
|
1763
|
+
}
|
|
1764
|
+
if (previousMode !== profile.mode) {
|
|
1765
|
+
this.emitStateChanged();
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
runHeartbeatCommands(commands) {
|
|
1769
|
+
for (const command of commands) {
|
|
1770
|
+
const name = String(command?.command || "").toLowerCase();
|
|
1771
|
+
if (name === "refresh_ads") {
|
|
1772
|
+
this.refresh().catch(() => {
|
|
1773
|
+
});
|
|
1774
|
+
} else if (name === "restart") {
|
|
1775
|
+
if (typeof window !== "undefined" && typeof window.location?.reload === "function") {
|
|
1776
|
+
window.location.reload();
|
|
1777
|
+
return;
|
|
1778
|
+
}
|
|
1779
|
+
this.refresh().catch(() => {
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1673
1784
|
playNextAd() {
|
|
1785
|
+
if (this.state.adDeliveryProfile?.mode === "vast_fallback" && this.state.ads.length > 0) {
|
|
1786
|
+
this.playDirect();
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1674
1789
|
const mode = this.state.waterfallMode;
|
|
1675
1790
|
if (mode === "programmatic_only" || mode === "programmatic_then_direct") {
|
|
1676
1791
|
this.playProgrammatic();
|
|
@@ -1685,13 +1800,20 @@ var _TrillboardsAds = class _TrillboardsAds {
|
|
|
1685
1800
|
this.programmaticPlayer.play(
|
|
1686
1801
|
() => {
|
|
1687
1802
|
this.state.programmaticPlaying = false;
|
|
1803
|
+
this.resetProgrammaticBackoff();
|
|
1688
1804
|
this.emitStateChanged();
|
|
1689
1805
|
this.scheduleProgrammaticRetry();
|
|
1690
1806
|
},
|
|
1691
1807
|
(error) => {
|
|
1692
1808
|
this.state.programmaticPlaying = false;
|
|
1693
1809
|
this.state.programmaticLastError = error;
|
|
1694
|
-
|
|
1810
|
+
const normalizedError = String(error || "").toLowerCase();
|
|
1811
|
+
const isNoFillLike = normalizedError.includes("no fill") || normalizedError.includes("no ads vast response") || normalizedError.includes("waterfall_exhausted") || normalizedError === "throttled" || normalizedError === "busy";
|
|
1812
|
+
if (isNoFillLike) {
|
|
1813
|
+
this.state.programmaticRetryCount = 0;
|
|
1814
|
+
} else {
|
|
1815
|
+
this.state.programmaticRetryCount++;
|
|
1816
|
+
}
|
|
1695
1817
|
this.emitStateChanged();
|
|
1696
1818
|
if (this.state.waterfallMode === "programmatic_then_direct" && this.state.ads.length > 0) {
|
|
1697
1819
|
this.playDirect();
|