@trillboards/ads-sdk 2.0.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.
@@ -0,0 +1,193 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
12
+ var _WebView = void 0;
13
+ function getWebView() {
14
+ if (_WebView === void 0) {
15
+ try {
16
+ _WebView = __require("react-native-webview").default;
17
+ } catch {
18
+ _WebView = null;
19
+ }
20
+ }
21
+ return _WebView;
22
+ }
23
+ var EMBED_BASE_URL = "https://screen.trillboards.com/partner-sdk/embed.html";
24
+ var TrillboardsWebView = react.forwardRef(
25
+ ({
26
+ deviceId,
27
+ waterfall = "programmatic_only",
28
+ autoStart = false,
29
+ apiBase,
30
+ style,
31
+ onReady,
32
+ onAdStarted,
33
+ onAdEnded,
34
+ onAdError,
35
+ onProgrammaticStarted,
36
+ onProgrammaticEnded,
37
+ onStateChanged
38
+ }, ref) => {
39
+ const webViewRef = react.useRef(null);
40
+ const [isReady, setIsReady] = react.useState(false);
41
+ const onReadyRef = react.useRef(onReady);
42
+ onReadyRef.current = onReady;
43
+ const onAdStartedRef = react.useRef(onAdStarted);
44
+ onAdStartedRef.current = onAdStarted;
45
+ const onAdEndedRef = react.useRef(onAdEnded);
46
+ onAdEndedRef.current = onAdEnded;
47
+ const onAdErrorRef = react.useRef(onAdError);
48
+ onAdErrorRef.current = onAdError;
49
+ const onProgrammaticStartedRef = react.useRef(onProgrammaticStarted);
50
+ onProgrammaticStartedRef.current = onProgrammaticStarted;
51
+ const onProgrammaticEndedRef = react.useRef(onProgrammaticEnded);
52
+ onProgrammaticEndedRef.current = onProgrammaticEnded;
53
+ const onStateChangedRef = react.useRef(onStateChanged);
54
+ onStateChangedRef.current = onStateChanged;
55
+ const embedUrl = (() => {
56
+ const params = new URLSearchParams({
57
+ device_id: deviceId,
58
+ waterfall,
59
+ auto_start: autoStart ? "1" : "0"
60
+ });
61
+ if (apiBase) params.set("api_base", apiBase);
62
+ return `${EMBED_BASE_URL}?${params.toString()}`;
63
+ })();
64
+ const sendCommand = react.useCallback(
65
+ (action, params = {}) => {
66
+ if (!webViewRef.current) return;
67
+ const js = `
68
+ window.postMessage({
69
+ type: 'trillboards-command',
70
+ action: ${JSON.stringify(action)},
71
+ params: ${JSON.stringify(params)}
72
+ }, '*');
73
+ true;
74
+ `;
75
+ webViewRef.current.injectJavaScript(js);
76
+ },
77
+ []
78
+ );
79
+ react.useImperativeHandle(
80
+ ref,
81
+ () => ({
82
+ show: () => sendCommand("show"),
83
+ hide: () => sendCommand("hide"),
84
+ skipAd: () => sendCommand("skip"),
85
+ refresh: () => sendCommand("refresh"),
86
+ getState: () => sendCommand("getState"),
87
+ configure: (params) => sendCommand("configure", params)
88
+ }),
89
+ [sendCommand]
90
+ );
91
+ const handleMessage = react.useCallback(
92
+ (event) => {
93
+ try {
94
+ const data = typeof event.nativeEvent.data === "string" ? JSON.parse(event.nativeEvent.data) : event.nativeEvent.data;
95
+ if (data.type !== "trillboards") return;
96
+ switch (data.event) {
97
+ case "initialized":
98
+ setIsReady(true);
99
+ onReadyRef.current?.();
100
+ break;
101
+ case "ad_started":
102
+ onAdStartedRef.current?.(data.data);
103
+ break;
104
+ case "ad_ended":
105
+ onAdEndedRef.current?.(data.data);
106
+ break;
107
+ case "ad_error":
108
+ onAdErrorRef.current?.(data.data);
109
+ break;
110
+ case "programmatic_started":
111
+ onProgrammaticStartedRef.current?.(data.data);
112
+ break;
113
+ case "programmatic_ended":
114
+ onProgrammaticEndedRef.current?.(data.data);
115
+ break;
116
+ case "state_changed":
117
+ onStateChangedRef.current?.(data.data);
118
+ break;
119
+ }
120
+ } catch {
121
+ }
122
+ },
123
+ []
124
+ );
125
+ const WebView = getWebView();
126
+ if (!WebView) return null;
127
+ return /* @__PURE__ */ jsxRuntime.jsx(
128
+ WebView,
129
+ {
130
+ ref: webViewRef,
131
+ source: { uri: embedUrl },
132
+ style: [{ flex: 1, backgroundColor: "#000" }, style],
133
+ onMessage: handleMessage,
134
+ javaScriptEnabled: true,
135
+ domStorageEnabled: true,
136
+ mediaPlaybackRequiresUserAction: false,
137
+ allowsInlineMediaPlayback: true,
138
+ mixedContentMode: "compatibility",
139
+ originWhitelist: ["https://*", "http://*"]
140
+ }
141
+ );
142
+ }
143
+ );
144
+ TrillboardsWebView.displayName = "TrillboardsWebView";
145
+
146
+ // src/core/state.ts
147
+ var DEFAULT_PUBLIC_STATE = {
148
+ initialized: false,
149
+ isPlaying: false,
150
+ isPaused: false,
151
+ isOffline: false,
152
+ currentAd: null,
153
+ adCount: 0,
154
+ programmaticPlaying: false,
155
+ prefetchedReady: false,
156
+ waterfallMode: "programmatic_only",
157
+ screenId: null,
158
+ deviceId: null
159
+ };
160
+
161
+ // src/react-native/useTrillboardsNative.ts
162
+ function useTrillboardsNative() {
163
+ const ref = react.useRef(null);
164
+ const [isReady, setIsReady] = react.useState(false);
165
+ const [state, setState] = react.useState(DEFAULT_PUBLIC_STATE);
166
+ const show = react.useCallback(() => ref.current?.show(), []);
167
+ const hide = react.useCallback(() => ref.current?.hide(), []);
168
+ const skipAd = react.useCallback(() => ref.current?.skipAd(), []);
169
+ const refresh = react.useCallback(() => ref.current?.refresh(), []);
170
+ const configure = react.useCallback(
171
+ (params) => ref.current?.configure(params),
172
+ []
173
+ );
174
+ const onReady = react.useCallback(() => setIsReady(true), []);
175
+ const onStateChanged = react.useCallback((newState) => setState(newState), []);
176
+ return {
177
+ ref,
178
+ isReady,
179
+ state,
180
+ show,
181
+ hide,
182
+ skipAd,
183
+ refresh,
184
+ configure,
185
+ onReady,
186
+ onStateChanged
187
+ };
188
+ }
189
+
190
+ exports.TrillboardsWebView = TrillboardsWebView;
191
+ exports.useTrillboardsNative = useTrillboardsNative;
192
+ //# sourceMappingURL=react-native.js.map
193
+ //# sourceMappingURL=react-native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-native/TrillboardsWebView.tsx","../src/core/state.ts","../src/react-native/useTrillboardsNative.ts"],"names":["forwardRef","useRef","useState","useCallback","useImperativeHandle","jsx"],"mappings":"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","file":"react-native.js","sourcesContent":["import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';\nimport type { TrillboardsState, EventMap, WaterfallMode } from '../core/types';\n\n// Type-only imports to avoid requiring react-native at build time\ntype WebViewType = any;\n\n// Lazy-load react-native-webview once, outside of render\nlet _WebView: any = undefined;\nfunction getWebView(): any {\n if (_WebView === undefined) {\n try {\n _WebView = require('react-native-webview').default;\n } catch {\n _WebView = null;\n }\n }\n return _WebView;\n}\n\ninterface TrillboardsWebViewProps {\n deviceId: string;\n waterfall?: WaterfallMode;\n autoStart?: boolean;\n apiBase?: string;\n style?: any;\n onReady?: () => void;\n onAdStarted?: (data: EventMap['ad_started']) => void;\n onAdEnded?: (data: EventMap['ad_ended']) => void;\n onAdError?: (data: EventMap['ad_error']) => void;\n onProgrammaticStarted?: (data: EventMap['programmatic_started']) => void;\n onProgrammaticEnded?: (data: EventMap['programmatic_ended']) => void;\n onStateChanged?: (state: TrillboardsState) => void;\n}\n\nexport interface TrillboardsWebViewHandle {\n show: () => void;\n hide: () => void;\n skipAd: () => void;\n refresh: () => void;\n getState: () => void;\n configure: (params: { waterfall?: WaterfallMode; volume?: number }) => void;\n}\n\nconst EMBED_BASE_URL = 'https://screen.trillboards.com/partner-sdk/embed.html';\n\nexport const TrillboardsWebView = forwardRef<TrillboardsWebViewHandle, TrillboardsWebViewProps>(\n (\n {\n deviceId,\n waterfall = 'programmatic_only',\n autoStart = false,\n apiBase,\n style,\n onReady,\n onAdStarted,\n onAdEnded,\n onAdError,\n onProgrammaticStarted,\n onProgrammaticEnded,\n onStateChanged,\n },\n ref\n ) => {\n const webViewRef = useRef<WebViewType>(null);\n const [isReady, setIsReady] = useState(false);\n\n // Store callbacks in refs to prevent unnecessary WebView re-renders\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n const onAdStartedRef = useRef(onAdStarted);\n onAdStartedRef.current = onAdStarted;\n const onAdEndedRef = useRef(onAdEnded);\n onAdEndedRef.current = onAdEnded;\n const onAdErrorRef = useRef(onAdError);\n onAdErrorRef.current = onAdError;\n const onProgrammaticStartedRef = useRef(onProgrammaticStarted);\n onProgrammaticStartedRef.current = onProgrammaticStarted;\n const onProgrammaticEndedRef = useRef(onProgrammaticEnded);\n onProgrammaticEndedRef.current = onProgrammaticEnded;\n const onStateChangedRef = useRef(onStateChanged);\n onStateChangedRef.current = onStateChanged;\n\n // Build embed URL\n const embedUrl = (() => {\n const params = new URLSearchParams({\n device_id: deviceId,\n waterfall,\n auto_start: autoStart ? '1' : '0',\n });\n if (apiBase) params.set('api_base', apiBase);\n return `${EMBED_BASE_URL}?${params.toString()}`;\n })();\n\n // Send command to WebView — use JSON.stringify for both action and params to prevent XSS\n const sendCommand = useCallback(\n (action: string, params: Record<string, unknown> = {}) => {\n if (!webViewRef.current) return;\n const js = `\n window.postMessage({\n type: 'trillboards-command',\n action: ${JSON.stringify(action)},\n params: ${JSON.stringify(params)}\n }, '*');\n true;\n `;\n webViewRef.current.injectJavaScript(js);\n },\n []\n );\n\n // Expose imperative handle\n useImperativeHandle(\n ref,\n () => ({\n show: () => sendCommand('show'),\n hide: () => sendCommand('hide'),\n skipAd: () => sendCommand('skip'),\n refresh: () => sendCommand('refresh'),\n getState: () => sendCommand('getState'),\n configure: (params) => sendCommand('configure', params),\n }),\n [sendCommand]\n );\n\n // Handle messages from WebView — use refs so dependency array is stable\n const handleMessage = useCallback(\n (event: any) => {\n try {\n const data = typeof event.nativeEvent.data === 'string'\n ? JSON.parse(event.nativeEvent.data)\n : event.nativeEvent.data;\n\n if (data.type !== 'trillboards') return;\n\n switch (data.event) {\n case 'initialized':\n setIsReady(true);\n onReadyRef.current?.();\n break;\n case 'ad_started':\n onAdStartedRef.current?.(data.data);\n break;\n case 'ad_ended':\n onAdEndedRef.current?.(data.data);\n break;\n case 'ad_error':\n onAdErrorRef.current?.(data.data);\n break;\n case 'programmatic_started':\n onProgrammaticStartedRef.current?.(data.data);\n break;\n case 'programmatic_ended':\n onProgrammaticEndedRef.current?.(data.data);\n break;\n case 'state_changed':\n onStateChangedRef.current?.(data.data);\n break;\n }\n } catch {\n // Ignore non-JSON messages\n }\n },\n []\n );\n\n const WebView = getWebView();\n if (!WebView) return null;\n\n return (\n <WebView\n ref={webViewRef}\n source={{ uri: embedUrl }}\n style={[{ flex: 1, backgroundColor: '#000' }, style]}\n onMessage={handleMessage}\n javaScriptEnabled={true}\n domStorageEnabled={true}\n mediaPlaybackRequiresUserAction={false}\n allowsInlineMediaPlayback={true}\n mixedContentMode=\"compatibility\"\n originWhitelist={['https://*', 'http://*']}\n />\n );\n }\n);\n\nTrillboardsWebView.displayName = 'TrillboardsWebView';\n","// ─────────────────────────────────────────────────────────────\n// @trillboards/ads-sdk — Internal + public state management\n// ─────────────────────────────────────────────────────────────\n\nimport type {\n AdItem,\n TrillboardsState,\n WaterfallMode,\n ProgrammaticSettings,\n ScreenDimensions,\n} from './types';\n\n/**\n * The full internal state held by the SDK engine.\n * This is NOT exposed to consumers — they receive the\n * trimmed-down `TrillboardsState` via `getPublicState()`.\n */\nexport interface InternalState {\n deviceId: string | null;\n partnerId: string | null;\n screenId: string | null;\n ads: AdItem[];\n currentAdIndex: number;\n isPlaying: boolean;\n isPaused: boolean;\n isOffline: boolean;\n settings: Record<string, unknown>;\n programmatic: ProgrammaticSettings | null;\n programmaticPlaying: boolean;\n prefetchedReady: boolean;\n waterfallMode: WaterfallMode;\n autoStart: boolean;\n container: HTMLElement | null;\n adTimer: ReturnType<typeof setTimeout> | null;\n refreshTimer: ReturnType<typeof setInterval> | null;\n heartbeatTimer: ReturnType<typeof setInterval> | null;\n programmaticRetryTimer: ReturnType<typeof setTimeout> | null;\n programmaticRetryActive: boolean;\n programmaticRetryCount: number;\n programmaticLastError: string | null;\n initialized: boolean;\n screenOrientation: string | null;\n screenDimensions: ScreenDimensions | null;\n etag: string | null;\n}\n\n/**\n * Default public state used by React components and the IIFE\n * entry point before the SDK is initialized.\n */\nexport const DEFAULT_PUBLIC_STATE: TrillboardsState = {\n initialized: false,\n isPlaying: false,\n isPaused: false,\n isOffline: false,\n currentAd: null,\n adCount: 0,\n programmaticPlaying: false,\n prefetchedReady: false,\n waterfallMode: 'programmatic_only',\n screenId: null,\n deviceId: null,\n};\n\n/**\n * Create a fresh internal state object with safe defaults.\n * Called once during SDK initialisation.\n */\nexport function createInitialState(): InternalState {\n return {\n deviceId: null,\n partnerId: null,\n screenId: null,\n ads: [],\n currentAdIndex: 0,\n isPlaying: false,\n isPaused: false,\n isOffline: false,\n settings: {},\n programmatic: null,\n programmaticPlaying: false,\n prefetchedReady: false,\n waterfallMode: 'programmatic_only',\n autoStart: true,\n container: null,\n adTimer: null,\n refreshTimer: null,\n heartbeatTimer: null,\n programmaticRetryTimer: null,\n programmaticRetryActive: false,\n programmaticRetryCount: 0,\n programmaticLastError: null,\n initialized: false,\n screenOrientation: null,\n screenDimensions: null,\n etag: null,\n };\n}\n\n/**\n * Project the internal state into a safe, read-only snapshot\n * that can be handed to consumers and event listeners.\n */\nexport function getPublicState(internal: InternalState): TrillboardsState {\n return {\n initialized: internal.initialized,\n isPlaying: internal.isPlaying,\n isPaused: internal.isPaused,\n isOffline: internal.isOffline,\n currentAd: internal.ads[internal.currentAdIndex] ?? null,\n adCount: internal.ads.length,\n programmaticPlaying: internal.programmaticPlaying,\n prefetchedReady: internal.prefetchedReady ?? false,\n waterfallMode: internal.waterfallMode,\n screenId: internal.screenId,\n deviceId: internal.deviceId,\n };\n}\n","import { useCallback, useRef, useState } from 'react';\nimport type { TrillboardsState, EventMap, WaterfallMode } from '../core/types';\nimport { DEFAULT_PUBLIC_STATE } from '../core/state';\nimport type { TrillboardsWebViewHandle } from './TrillboardsWebView';\n\nexport interface UseTrillboardsNativeReturn {\n ref: React.RefObject<TrillboardsWebViewHandle>;\n isReady: boolean;\n state: TrillboardsState;\n show: () => void;\n hide: () => void;\n skipAd: () => void;\n refresh: () => void;\n configure: (params: { waterfall?: WaterfallMode; volume?: number }) => void;\n onReady: () => void;\n onStateChanged: (state: TrillboardsState) => void;\n}\n\nexport function useTrillboardsNative(): UseTrillboardsNativeReturn {\n const ref = useRef<TrillboardsWebViewHandle>(null);\n const [isReady, setIsReady] = useState(false);\n const [state, setState] = useState<TrillboardsState>(DEFAULT_PUBLIC_STATE);\n\n const show = useCallback(() => ref.current?.show(), []);\n const hide = useCallback(() => ref.current?.hide(), []);\n const skipAd = useCallback(() => ref.current?.skipAd(), []);\n const refresh = useCallback(() => ref.current?.refresh(), []);\n const configure = useCallback(\n (params: { waterfall?: WaterfallMode; volume?: number }) => ref.current?.configure(params),\n []\n );\n\n const onReady = useCallback(() => setIsReady(true), []);\n const onStateChanged = useCallback((newState: TrillboardsState) => setState(newState), []);\n\n return {\n ref,\n isReady,\n state,\n show,\n hide,\n skipAd,\n refresh,\n configure,\n onReady,\n onStateChanged,\n };\n}\n"]}
@@ -0,0 +1,190 @@
1
+ import { forwardRef, useRef, useState, useCallback, useImperativeHandle } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
10
+ var _WebView = void 0;
11
+ function getWebView() {
12
+ if (_WebView === void 0) {
13
+ try {
14
+ _WebView = __require("react-native-webview").default;
15
+ } catch {
16
+ _WebView = null;
17
+ }
18
+ }
19
+ return _WebView;
20
+ }
21
+ var EMBED_BASE_URL = "https://screen.trillboards.com/partner-sdk/embed.html";
22
+ var TrillboardsWebView = forwardRef(
23
+ ({
24
+ deviceId,
25
+ waterfall = "programmatic_only",
26
+ autoStart = false,
27
+ apiBase,
28
+ style,
29
+ onReady,
30
+ onAdStarted,
31
+ onAdEnded,
32
+ onAdError,
33
+ onProgrammaticStarted,
34
+ onProgrammaticEnded,
35
+ onStateChanged
36
+ }, ref) => {
37
+ const webViewRef = useRef(null);
38
+ const [isReady, setIsReady] = useState(false);
39
+ const onReadyRef = useRef(onReady);
40
+ onReadyRef.current = onReady;
41
+ const onAdStartedRef = useRef(onAdStarted);
42
+ onAdStartedRef.current = onAdStarted;
43
+ const onAdEndedRef = useRef(onAdEnded);
44
+ onAdEndedRef.current = onAdEnded;
45
+ const onAdErrorRef = useRef(onAdError);
46
+ onAdErrorRef.current = onAdError;
47
+ const onProgrammaticStartedRef = useRef(onProgrammaticStarted);
48
+ onProgrammaticStartedRef.current = onProgrammaticStarted;
49
+ const onProgrammaticEndedRef = useRef(onProgrammaticEnded);
50
+ onProgrammaticEndedRef.current = onProgrammaticEnded;
51
+ const onStateChangedRef = useRef(onStateChanged);
52
+ onStateChangedRef.current = onStateChanged;
53
+ const embedUrl = (() => {
54
+ const params = new URLSearchParams({
55
+ device_id: deviceId,
56
+ waterfall,
57
+ auto_start: autoStart ? "1" : "0"
58
+ });
59
+ if (apiBase) params.set("api_base", apiBase);
60
+ return `${EMBED_BASE_URL}?${params.toString()}`;
61
+ })();
62
+ const sendCommand = useCallback(
63
+ (action, params = {}) => {
64
+ if (!webViewRef.current) return;
65
+ const js = `
66
+ window.postMessage({
67
+ type: 'trillboards-command',
68
+ action: ${JSON.stringify(action)},
69
+ params: ${JSON.stringify(params)}
70
+ }, '*');
71
+ true;
72
+ `;
73
+ webViewRef.current.injectJavaScript(js);
74
+ },
75
+ []
76
+ );
77
+ useImperativeHandle(
78
+ ref,
79
+ () => ({
80
+ show: () => sendCommand("show"),
81
+ hide: () => sendCommand("hide"),
82
+ skipAd: () => sendCommand("skip"),
83
+ refresh: () => sendCommand("refresh"),
84
+ getState: () => sendCommand("getState"),
85
+ configure: (params) => sendCommand("configure", params)
86
+ }),
87
+ [sendCommand]
88
+ );
89
+ const handleMessage = useCallback(
90
+ (event) => {
91
+ try {
92
+ const data = typeof event.nativeEvent.data === "string" ? JSON.parse(event.nativeEvent.data) : event.nativeEvent.data;
93
+ if (data.type !== "trillboards") return;
94
+ switch (data.event) {
95
+ case "initialized":
96
+ setIsReady(true);
97
+ onReadyRef.current?.();
98
+ break;
99
+ case "ad_started":
100
+ onAdStartedRef.current?.(data.data);
101
+ break;
102
+ case "ad_ended":
103
+ onAdEndedRef.current?.(data.data);
104
+ break;
105
+ case "ad_error":
106
+ onAdErrorRef.current?.(data.data);
107
+ break;
108
+ case "programmatic_started":
109
+ onProgrammaticStartedRef.current?.(data.data);
110
+ break;
111
+ case "programmatic_ended":
112
+ onProgrammaticEndedRef.current?.(data.data);
113
+ break;
114
+ case "state_changed":
115
+ onStateChangedRef.current?.(data.data);
116
+ break;
117
+ }
118
+ } catch {
119
+ }
120
+ },
121
+ []
122
+ );
123
+ const WebView = getWebView();
124
+ if (!WebView) return null;
125
+ return /* @__PURE__ */ jsx(
126
+ WebView,
127
+ {
128
+ ref: webViewRef,
129
+ source: { uri: embedUrl },
130
+ style: [{ flex: 1, backgroundColor: "#000" }, style],
131
+ onMessage: handleMessage,
132
+ javaScriptEnabled: true,
133
+ domStorageEnabled: true,
134
+ mediaPlaybackRequiresUserAction: false,
135
+ allowsInlineMediaPlayback: true,
136
+ mixedContentMode: "compatibility",
137
+ originWhitelist: ["https://*", "http://*"]
138
+ }
139
+ );
140
+ }
141
+ );
142
+ TrillboardsWebView.displayName = "TrillboardsWebView";
143
+
144
+ // src/core/state.ts
145
+ var DEFAULT_PUBLIC_STATE = {
146
+ initialized: false,
147
+ isPlaying: false,
148
+ isPaused: false,
149
+ isOffline: false,
150
+ currentAd: null,
151
+ adCount: 0,
152
+ programmaticPlaying: false,
153
+ prefetchedReady: false,
154
+ waterfallMode: "programmatic_only",
155
+ screenId: null,
156
+ deviceId: null
157
+ };
158
+
159
+ // src/react-native/useTrillboardsNative.ts
160
+ function useTrillboardsNative() {
161
+ const ref = useRef(null);
162
+ const [isReady, setIsReady] = useState(false);
163
+ const [state, setState] = useState(DEFAULT_PUBLIC_STATE);
164
+ const show = useCallback(() => ref.current?.show(), []);
165
+ const hide = useCallback(() => ref.current?.hide(), []);
166
+ const skipAd = useCallback(() => ref.current?.skipAd(), []);
167
+ const refresh = useCallback(() => ref.current?.refresh(), []);
168
+ const configure = useCallback(
169
+ (params) => ref.current?.configure(params),
170
+ []
171
+ );
172
+ const onReady = useCallback(() => setIsReady(true), []);
173
+ const onStateChanged = useCallback((newState) => setState(newState), []);
174
+ return {
175
+ ref,
176
+ isReady,
177
+ state,
178
+ show,
179
+ hide,
180
+ skipAd,
181
+ refresh,
182
+ configure,
183
+ onReady,
184
+ onStateChanged
185
+ };
186
+ }
187
+
188
+ export { TrillboardsWebView, useTrillboardsNative };
189
+ //# sourceMappingURL=react-native.mjs.map
190
+ //# sourceMappingURL=react-native.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-native/TrillboardsWebView.tsx","../src/core/state.ts","../src/react-native/useTrillboardsNative.ts"],"names":["useRef","useState","useCallback"],"mappings":"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","file":"react-native.mjs","sourcesContent":["import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';\nimport type { TrillboardsState, EventMap, WaterfallMode } from '../core/types';\n\n// Type-only imports to avoid requiring react-native at build time\ntype WebViewType = any;\n\n// Lazy-load react-native-webview once, outside of render\nlet _WebView: any = undefined;\nfunction getWebView(): any {\n if (_WebView === undefined) {\n try {\n _WebView = require('react-native-webview').default;\n } catch {\n _WebView = null;\n }\n }\n return _WebView;\n}\n\ninterface TrillboardsWebViewProps {\n deviceId: string;\n waterfall?: WaterfallMode;\n autoStart?: boolean;\n apiBase?: string;\n style?: any;\n onReady?: () => void;\n onAdStarted?: (data: EventMap['ad_started']) => void;\n onAdEnded?: (data: EventMap['ad_ended']) => void;\n onAdError?: (data: EventMap['ad_error']) => void;\n onProgrammaticStarted?: (data: EventMap['programmatic_started']) => void;\n onProgrammaticEnded?: (data: EventMap['programmatic_ended']) => void;\n onStateChanged?: (state: TrillboardsState) => void;\n}\n\nexport interface TrillboardsWebViewHandle {\n show: () => void;\n hide: () => void;\n skipAd: () => void;\n refresh: () => void;\n getState: () => void;\n configure: (params: { waterfall?: WaterfallMode; volume?: number }) => void;\n}\n\nconst EMBED_BASE_URL = 'https://screen.trillboards.com/partner-sdk/embed.html';\n\nexport const TrillboardsWebView = forwardRef<TrillboardsWebViewHandle, TrillboardsWebViewProps>(\n (\n {\n deviceId,\n waterfall = 'programmatic_only',\n autoStart = false,\n apiBase,\n style,\n onReady,\n onAdStarted,\n onAdEnded,\n onAdError,\n onProgrammaticStarted,\n onProgrammaticEnded,\n onStateChanged,\n },\n ref\n ) => {\n const webViewRef = useRef<WebViewType>(null);\n const [isReady, setIsReady] = useState(false);\n\n // Store callbacks in refs to prevent unnecessary WebView re-renders\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n const onAdStartedRef = useRef(onAdStarted);\n onAdStartedRef.current = onAdStarted;\n const onAdEndedRef = useRef(onAdEnded);\n onAdEndedRef.current = onAdEnded;\n const onAdErrorRef = useRef(onAdError);\n onAdErrorRef.current = onAdError;\n const onProgrammaticStartedRef = useRef(onProgrammaticStarted);\n onProgrammaticStartedRef.current = onProgrammaticStarted;\n const onProgrammaticEndedRef = useRef(onProgrammaticEnded);\n onProgrammaticEndedRef.current = onProgrammaticEnded;\n const onStateChangedRef = useRef(onStateChanged);\n onStateChangedRef.current = onStateChanged;\n\n // Build embed URL\n const embedUrl = (() => {\n const params = new URLSearchParams({\n device_id: deviceId,\n waterfall,\n auto_start: autoStart ? '1' : '0',\n });\n if (apiBase) params.set('api_base', apiBase);\n return `${EMBED_BASE_URL}?${params.toString()}`;\n })();\n\n // Send command to WebView — use JSON.stringify for both action and params to prevent XSS\n const sendCommand = useCallback(\n (action: string, params: Record<string, unknown> = {}) => {\n if (!webViewRef.current) return;\n const js = `\n window.postMessage({\n type: 'trillboards-command',\n action: ${JSON.stringify(action)},\n params: ${JSON.stringify(params)}\n }, '*');\n true;\n `;\n webViewRef.current.injectJavaScript(js);\n },\n []\n );\n\n // Expose imperative handle\n useImperativeHandle(\n ref,\n () => ({\n show: () => sendCommand('show'),\n hide: () => sendCommand('hide'),\n skipAd: () => sendCommand('skip'),\n refresh: () => sendCommand('refresh'),\n getState: () => sendCommand('getState'),\n configure: (params) => sendCommand('configure', params),\n }),\n [sendCommand]\n );\n\n // Handle messages from WebView — use refs so dependency array is stable\n const handleMessage = useCallback(\n (event: any) => {\n try {\n const data = typeof event.nativeEvent.data === 'string'\n ? JSON.parse(event.nativeEvent.data)\n : event.nativeEvent.data;\n\n if (data.type !== 'trillboards') return;\n\n switch (data.event) {\n case 'initialized':\n setIsReady(true);\n onReadyRef.current?.();\n break;\n case 'ad_started':\n onAdStartedRef.current?.(data.data);\n break;\n case 'ad_ended':\n onAdEndedRef.current?.(data.data);\n break;\n case 'ad_error':\n onAdErrorRef.current?.(data.data);\n break;\n case 'programmatic_started':\n onProgrammaticStartedRef.current?.(data.data);\n break;\n case 'programmatic_ended':\n onProgrammaticEndedRef.current?.(data.data);\n break;\n case 'state_changed':\n onStateChangedRef.current?.(data.data);\n break;\n }\n } catch {\n // Ignore non-JSON messages\n }\n },\n []\n );\n\n const WebView = getWebView();\n if (!WebView) return null;\n\n return (\n <WebView\n ref={webViewRef}\n source={{ uri: embedUrl }}\n style={[{ flex: 1, backgroundColor: '#000' }, style]}\n onMessage={handleMessage}\n javaScriptEnabled={true}\n domStorageEnabled={true}\n mediaPlaybackRequiresUserAction={false}\n allowsInlineMediaPlayback={true}\n mixedContentMode=\"compatibility\"\n originWhitelist={['https://*', 'http://*']}\n />\n );\n }\n);\n\nTrillboardsWebView.displayName = 'TrillboardsWebView';\n","// ─────────────────────────────────────────────────────────────\n// @trillboards/ads-sdk — Internal + public state management\n// ─────────────────────────────────────────────────────────────\n\nimport type {\n AdItem,\n TrillboardsState,\n WaterfallMode,\n ProgrammaticSettings,\n ScreenDimensions,\n} from './types';\n\n/**\n * The full internal state held by the SDK engine.\n * This is NOT exposed to consumers — they receive the\n * trimmed-down `TrillboardsState` via `getPublicState()`.\n */\nexport interface InternalState {\n deviceId: string | null;\n partnerId: string | null;\n screenId: string | null;\n ads: AdItem[];\n currentAdIndex: number;\n isPlaying: boolean;\n isPaused: boolean;\n isOffline: boolean;\n settings: Record<string, unknown>;\n programmatic: ProgrammaticSettings | null;\n programmaticPlaying: boolean;\n prefetchedReady: boolean;\n waterfallMode: WaterfallMode;\n autoStart: boolean;\n container: HTMLElement | null;\n adTimer: ReturnType<typeof setTimeout> | null;\n refreshTimer: ReturnType<typeof setInterval> | null;\n heartbeatTimer: ReturnType<typeof setInterval> | null;\n programmaticRetryTimer: ReturnType<typeof setTimeout> | null;\n programmaticRetryActive: boolean;\n programmaticRetryCount: number;\n programmaticLastError: string | null;\n initialized: boolean;\n screenOrientation: string | null;\n screenDimensions: ScreenDimensions | null;\n etag: string | null;\n}\n\n/**\n * Default public state used by React components and the IIFE\n * entry point before the SDK is initialized.\n */\nexport const DEFAULT_PUBLIC_STATE: TrillboardsState = {\n initialized: false,\n isPlaying: false,\n isPaused: false,\n isOffline: false,\n currentAd: null,\n adCount: 0,\n programmaticPlaying: false,\n prefetchedReady: false,\n waterfallMode: 'programmatic_only',\n screenId: null,\n deviceId: null,\n};\n\n/**\n * Create a fresh internal state object with safe defaults.\n * Called once during SDK initialisation.\n */\nexport function createInitialState(): InternalState {\n return {\n deviceId: null,\n partnerId: null,\n screenId: null,\n ads: [],\n currentAdIndex: 0,\n isPlaying: false,\n isPaused: false,\n isOffline: false,\n settings: {},\n programmatic: null,\n programmaticPlaying: false,\n prefetchedReady: false,\n waterfallMode: 'programmatic_only',\n autoStart: true,\n container: null,\n adTimer: null,\n refreshTimer: null,\n heartbeatTimer: null,\n programmaticRetryTimer: null,\n programmaticRetryActive: false,\n programmaticRetryCount: 0,\n programmaticLastError: null,\n initialized: false,\n screenOrientation: null,\n screenDimensions: null,\n etag: null,\n };\n}\n\n/**\n * Project the internal state into a safe, read-only snapshot\n * that can be handed to consumers and event listeners.\n */\nexport function getPublicState(internal: InternalState): TrillboardsState {\n return {\n initialized: internal.initialized,\n isPlaying: internal.isPlaying,\n isPaused: internal.isPaused,\n isOffline: internal.isOffline,\n currentAd: internal.ads[internal.currentAdIndex] ?? null,\n adCount: internal.ads.length,\n programmaticPlaying: internal.programmaticPlaying,\n prefetchedReady: internal.prefetchedReady ?? false,\n waterfallMode: internal.waterfallMode,\n screenId: internal.screenId,\n deviceId: internal.deviceId,\n };\n}\n","import { useCallback, useRef, useState } from 'react';\nimport type { TrillboardsState, EventMap, WaterfallMode } from '../core/types';\nimport { DEFAULT_PUBLIC_STATE } from '../core/state';\nimport type { TrillboardsWebViewHandle } from './TrillboardsWebView';\n\nexport interface UseTrillboardsNativeReturn {\n ref: React.RefObject<TrillboardsWebViewHandle>;\n isReady: boolean;\n state: TrillboardsState;\n show: () => void;\n hide: () => void;\n skipAd: () => void;\n refresh: () => void;\n configure: (params: { waterfall?: WaterfallMode; volume?: number }) => void;\n onReady: () => void;\n onStateChanged: (state: TrillboardsState) => void;\n}\n\nexport function useTrillboardsNative(): UseTrillboardsNativeReturn {\n const ref = useRef<TrillboardsWebViewHandle>(null);\n const [isReady, setIsReady] = useState(false);\n const [state, setState] = useState<TrillboardsState>(DEFAULT_PUBLIC_STATE);\n\n const show = useCallback(() => ref.current?.show(), []);\n const hide = useCallback(() => ref.current?.hide(), []);\n const skipAd = useCallback(() => ref.current?.skipAd(), []);\n const refresh = useCallback(() => ref.current?.refresh(), []);\n const configure = useCallback(\n (params: { waterfall?: WaterfallMode; volume?: number }) => ref.current?.configure(params),\n []\n );\n\n const onReady = useCallback(() => setIsReady(true), []);\n const onStateChanged = useCallback((newState: TrillboardsState) => setState(newState), []);\n\n return {\n ref,\n isReady,\n state,\n show,\n hide,\n skipAd,\n refresh,\n configure,\n onReady,\n onStateChanged,\n };\n}\n"]}