@trillboards/ads-sdk 2.1.1 → 2.3.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/CHANGELOG.md +10 -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 +180 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +180 -14
- 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 +180 -11
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +180 -11
- package/dist/react.mjs.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +2 -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 +1 -1
package/dist/react-native.d.mts
CHANGED
|
@@ -42,9 +42,11 @@ interface TrillboardsState {
|
|
|
42
42
|
programmaticPlaying: boolean;
|
|
43
43
|
prefetchedReady: boolean;
|
|
44
44
|
waterfallMode: WaterfallMode;
|
|
45
|
+
adDeliveryProfileMode: AdDeliveryMode | null;
|
|
45
46
|
screenId: string | null;
|
|
46
47
|
deviceId: string | null;
|
|
47
48
|
}
|
|
49
|
+
type AdDeliveryMode = 'ima_sdk' | 'vast_fallback';
|
|
48
50
|
interface EventMap {
|
|
49
51
|
initialized: {
|
|
50
52
|
deviceId: string;
|
package/dist/react-native.d.ts
CHANGED
|
@@ -42,9 +42,11 @@ interface TrillboardsState {
|
|
|
42
42
|
programmaticPlaying: boolean;
|
|
43
43
|
prefetchedReady: boolean;
|
|
44
44
|
waterfallMode: WaterfallMode;
|
|
45
|
+
adDeliveryProfileMode: AdDeliveryMode | null;
|
|
45
46
|
screenId: string | null;
|
|
46
47
|
deviceId: string | null;
|
|
47
48
|
}
|
|
49
|
+
type AdDeliveryMode = 'ima_sdk' | 'vast_fallback';
|
|
48
50
|
interface EventMap {
|
|
49
51
|
initialized: {
|
|
50
52
|
deviceId: string;
|
package/dist/react-native.js
CHANGED
package/dist/react-native.js.map
CHANGED
|
@@ -1 +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"]}
|
|
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 AdDeliveryProfile,\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 adDeliveryProfile: AdDeliveryProfile | 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 adDeliveryProfileMode: null,\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 adDeliveryProfile: 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 adDeliveryProfileMode: internal.adDeliveryProfile?.mode ?? null,\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"]}
|
package/dist/react-native.mjs
CHANGED
|
@@ -1 +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"]}
|
|
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 AdDeliveryProfile,\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 adDeliveryProfile: AdDeliveryProfile | 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 adDeliveryProfileMode: null,\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 adDeliveryProfile: 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 adDeliveryProfileMode: internal.adDeliveryProfile?.mode ?? null,\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"]}
|
package/dist/react.d.mts
CHANGED
|
@@ -43,6 +43,7 @@ interface TrillboardsState {
|
|
|
43
43
|
programmaticPlaying: boolean;
|
|
44
44
|
prefetchedReady: boolean;
|
|
45
45
|
waterfallMode: WaterfallMode;
|
|
46
|
+
adDeliveryProfileMode: AdDeliveryMode | null;
|
|
46
47
|
screenId: string | null;
|
|
47
48
|
deviceId: string | null;
|
|
48
49
|
}
|
|
@@ -52,6 +53,7 @@ interface BridgeConfig {
|
|
|
52
53
|
events?: string[];
|
|
53
54
|
name?: string;
|
|
54
55
|
}
|
|
56
|
+
type AdDeliveryMode = 'ima_sdk' | 'vast_fallback';
|
|
55
57
|
interface EventMap {
|
|
56
58
|
initialized: {
|
|
57
59
|
deviceId: string;
|
|
@@ -189,6 +191,10 @@ declare class TrillboardsAds {
|
|
|
189
191
|
private refreshAds;
|
|
190
192
|
private startRefreshTimer;
|
|
191
193
|
private startHeartbeatTimer;
|
|
194
|
+
private sendHeartbeatTick;
|
|
195
|
+
private buildHeartbeatPayload;
|
|
196
|
+
private applyAdDeliveryProfile;
|
|
197
|
+
private runHeartbeatCommands;
|
|
192
198
|
private playNextAd;
|
|
193
199
|
private playProgrammatic;
|
|
194
200
|
private playDirect;
|
package/dist/react.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ interface TrillboardsState {
|
|
|
43
43
|
programmaticPlaying: boolean;
|
|
44
44
|
prefetchedReady: boolean;
|
|
45
45
|
waterfallMode: WaterfallMode;
|
|
46
|
+
adDeliveryProfileMode: AdDeliveryMode | null;
|
|
46
47
|
screenId: string | null;
|
|
47
48
|
deviceId: string | null;
|
|
48
49
|
}
|
|
@@ -52,6 +53,7 @@ interface BridgeConfig {
|
|
|
52
53
|
events?: string[];
|
|
53
54
|
name?: string;
|
|
54
55
|
}
|
|
56
|
+
type AdDeliveryMode = 'ima_sdk' | 'vast_fallback';
|
|
55
57
|
interface EventMap {
|
|
56
58
|
initialized: {
|
|
57
59
|
deviceId: string;
|
|
@@ -189,6 +191,10 @@ declare class TrillboardsAds {
|
|
|
189
191
|
private refreshAds;
|
|
190
192
|
private startRefreshTimer;
|
|
191
193
|
private startHeartbeatTimer;
|
|
194
|
+
private sendHeartbeatTick;
|
|
195
|
+
private buildHeartbeatPayload;
|
|
196
|
+
private applyAdDeliveryProfile;
|
|
197
|
+
private runHeartbeatCommands;
|
|
192
198
|
private playNextAd;
|
|
193
199
|
private playProgrammatic;
|
|
194
200
|
private playDirect;
|
package/dist/react.js
CHANGED
|
@@ -4,6 +4,9 @@ var react = require('react');
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
|
|
6
6
|
// src/react/TrillboardsProvider.tsx
|
|
7
|
+
|
|
8
|
+
// src/core/config.ts
|
|
9
|
+
var SDK_VERSION = "2.2.0";
|
|
7
10
|
var DEFAULT_CONFIG = {
|
|
8
11
|
API_BASE: "https://api.trillboards.com/v1/partner",
|
|
9
12
|
CDN_BASE: "https://cdn.trillboards.com",
|
|
@@ -58,6 +61,7 @@ var DEFAULT_PUBLIC_STATE = {
|
|
|
58
61
|
programmaticPlaying: false,
|
|
59
62
|
prefetchedReady: false,
|
|
60
63
|
waterfallMode: "programmatic_only",
|
|
64
|
+
adDeliveryProfileMode: null,
|
|
61
65
|
screenId: null,
|
|
62
66
|
deviceId: null
|
|
63
67
|
};
|
|
@@ -85,6 +89,7 @@ function createInitialState() {
|
|
|
85
89
|
programmaticRetryActive: false,
|
|
86
90
|
programmaticRetryCount: 0,
|
|
87
91
|
programmaticLastError: null,
|
|
92
|
+
adDeliveryProfile: null,
|
|
88
93
|
initialized: false,
|
|
89
94
|
screenOrientation: null,
|
|
90
95
|
screenDimensions: null,
|
|
@@ -102,6 +107,7 @@ function getPublicState(internal) {
|
|
|
102
107
|
programmaticPlaying: internal.programmaticPlaying,
|
|
103
108
|
prefetchedReady: internal.prefetchedReady ?? false,
|
|
104
109
|
waterfallMode: internal.waterfallMode,
|
|
110
|
+
adDeliveryProfileMode: internal.adDeliveryProfile?.mode ?? null,
|
|
105
111
|
screenId: internal.screenId,
|
|
106
112
|
deviceId: internal.deviceId
|
|
107
113
|
};
|
|
@@ -362,10 +368,9 @@ var ApiClient = class {
|
|
|
362
368
|
}
|
|
363
369
|
}
|
|
364
370
|
/**
|
|
365
|
-
* Ping
|
|
366
|
-
* Returns `true` on 2xx, `false` on any error.
|
|
371
|
+
* Ping heartbeat endpoint and return delivery profile + queued commands.
|
|
367
372
|
*/
|
|
368
|
-
async sendHeartbeat(deviceId, screenId) {
|
|
373
|
+
async sendHeartbeat(deviceId, screenId, payload = {}) {
|
|
369
374
|
logger.debug("Sending heartbeat", { deviceId });
|
|
370
375
|
try {
|
|
371
376
|
const response = await fetch(`${this.apiBase}/device/${deviceId}/heartbeat`, {
|
|
@@ -375,13 +380,24 @@ var ApiClient = class {
|
|
|
375
380
|
device_id: deviceId,
|
|
376
381
|
screen_id: screenId,
|
|
377
382
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
378
|
-
status: "active"
|
|
383
|
+
status: "active",
|
|
384
|
+
...payload
|
|
379
385
|
}),
|
|
380
386
|
signal: AbortSignal.timeout(5e3)
|
|
381
387
|
});
|
|
382
|
-
|
|
388
|
+
if (!response.ok) {
|
|
389
|
+
return { ok: false, data: null };
|
|
390
|
+
}
|
|
391
|
+
let data = null;
|
|
392
|
+
try {
|
|
393
|
+
const json = await response.json();
|
|
394
|
+
data = json?.data ?? null;
|
|
395
|
+
} catch {
|
|
396
|
+
data = null;
|
|
397
|
+
}
|
|
398
|
+
return { ok: true, data };
|
|
383
399
|
} catch {
|
|
384
|
-
return false;
|
|
400
|
+
return { ok: false, data: null };
|
|
385
401
|
}
|
|
386
402
|
}
|
|
387
403
|
/**
|
|
@@ -934,7 +950,7 @@ var WaterfallEngine = class {
|
|
|
934
950
|
};
|
|
935
951
|
|
|
936
952
|
// src/player/ProgrammaticPlayer.ts
|
|
937
|
-
var
|
|
953
|
+
var _ProgrammaticPlayer = class _ProgrammaticPlayer {
|
|
938
954
|
constructor(events, timeoutMs = 12e3) {
|
|
939
955
|
// ── Public state ──────────────────────────────────────────
|
|
940
956
|
this.vastTagUrl = null;
|
|
@@ -1021,8 +1037,11 @@ var ProgrammaticPlayer = class {
|
|
|
1021
1037
|
this.telemetry.recordRequest();
|
|
1022
1038
|
const correlator = Date.now();
|
|
1023
1039
|
const finalUrl = vastUrl.includes("correlator=") ? vastUrl.replace(/correlator=[^&]*/, `correlator=${correlator}`) : `${vastUrl}${vastUrl.includes("?") ? "&" : "?"}correlator=${correlator}`;
|
|
1024
|
-
|
|
1025
|
-
|
|
1040
|
+
const imaReady = await this.ensureImaSdk();
|
|
1041
|
+
if (!imaReady) {
|
|
1042
|
+
const msg = "Google IMA SDK not loaded";
|
|
1043
|
+
this.events.emit("programmatic_error", { error: msg, code: void 0 });
|
|
1044
|
+
onError(msg);
|
|
1026
1045
|
this.telemetry.recordError();
|
|
1027
1046
|
this.waterfallEngine.recordFailure(sourceName);
|
|
1028
1047
|
return;
|
|
@@ -1039,6 +1058,50 @@ var ProgrammaticPlayer = class {
|
|
|
1039
1058
|
onError(err instanceof Error ? err.message : String(err));
|
|
1040
1059
|
}
|
|
1041
1060
|
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Ensure Google IMA SDK is available. If already loaded, resolves
|
|
1063
|
+
* immediately. Otherwise injects the `<script>` tag and waits.
|
|
1064
|
+
* Matches the Lite SDK's `loadImaScript()` pattern.
|
|
1065
|
+
*/
|
|
1066
|
+
async ensureImaSdk() {
|
|
1067
|
+
if (typeof google !== "undefined" && google?.ima) return true;
|
|
1068
|
+
if (typeof document === "undefined") return false;
|
|
1069
|
+
const existing = document.querySelector(
|
|
1070
|
+
`script[src="${_ProgrammaticPlayer.IMA_SDK_URL}"]`
|
|
1071
|
+
);
|
|
1072
|
+
if (existing) {
|
|
1073
|
+
return new Promise((resolve) => {
|
|
1074
|
+
const start = Date.now();
|
|
1075
|
+
const check = () => {
|
|
1076
|
+
if (typeof google !== "undefined" && google?.ima) {
|
|
1077
|
+
resolve(true);
|
|
1078
|
+
} else if (Date.now() - start > 5e3) {
|
|
1079
|
+
resolve(false);
|
|
1080
|
+
} else {
|
|
1081
|
+
setTimeout(check, 100);
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
check();
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
if (!_ProgrammaticPlayer.imaLoadPromise) {
|
|
1088
|
+
_ProgrammaticPlayer.imaLoadPromise = new Promise((resolve) => {
|
|
1089
|
+
const script = document.createElement("script");
|
|
1090
|
+
script.src = _ProgrammaticPlayer.IMA_SDK_URL;
|
|
1091
|
+
script.async = true;
|
|
1092
|
+
script.onload = () => {
|
|
1093
|
+
_ProgrammaticPlayer.imaLoadPromise = null;
|
|
1094
|
+
resolve(true);
|
|
1095
|
+
};
|
|
1096
|
+
script.onerror = () => {
|
|
1097
|
+
_ProgrammaticPlayer.imaLoadPromise = null;
|
|
1098
|
+
resolve(false);
|
|
1099
|
+
};
|
|
1100
|
+
document.head.appendChild(script);
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
return _ProgrammaticPlayer.imaLoadPromise;
|
|
1104
|
+
}
|
|
1042
1105
|
// ── IMA request / playback lifecycle ──────────────────────
|
|
1043
1106
|
async requestAdsViaIMA(vastUrl, onComplete, onError) {
|
|
1044
1107
|
return new Promise((resolve) => {
|
|
@@ -1240,6 +1303,12 @@ var ProgrammaticPlayer = class {
|
|
|
1240
1303
|
this.telemetry.reset();
|
|
1241
1304
|
}
|
|
1242
1305
|
};
|
|
1306
|
+
// ── IMA SDK loader ──────────────────────────────────────────
|
|
1307
|
+
/** IMA script URL */
|
|
1308
|
+
_ProgrammaticPlayer.IMA_SDK_URL = "https://imasdk.googleapis.com/js/sdkloader/ima3.js";
|
|
1309
|
+
/** Singleton load promise so concurrent calls don't insert multiple scripts. */
|
|
1310
|
+
_ProgrammaticPlayer.imaLoadPromise = null;
|
|
1311
|
+
var ProgrammaticPlayer = _ProgrammaticPlayer;
|
|
1243
1312
|
|
|
1244
1313
|
// src/player/Player.ts
|
|
1245
1314
|
var MAX_AD_DURATION_SECONDS = 300;
|
|
@@ -1674,11 +1743,104 @@ var _TrillboardsAds = class _TrillboardsAds {
|
|
|
1674
1743
|
}
|
|
1675
1744
|
startHeartbeatTimer() {
|
|
1676
1745
|
if (this.state.heartbeatTimer) clearInterval(this.state.heartbeatTimer);
|
|
1746
|
+
const tick = () => {
|
|
1747
|
+
this.sendHeartbeatTick().catch(() => {
|
|
1748
|
+
});
|
|
1749
|
+
};
|
|
1750
|
+
tick();
|
|
1677
1751
|
this.state.heartbeatTimer = setInterval(() => {
|
|
1678
|
-
|
|
1752
|
+
tick();
|
|
1679
1753
|
}, this.config.heartbeatInterval);
|
|
1680
1754
|
}
|
|
1755
|
+
async sendHeartbeatTick() {
|
|
1756
|
+
const result = await this.api.sendHeartbeat(
|
|
1757
|
+
this.config.deviceId,
|
|
1758
|
+
this.state.screenId,
|
|
1759
|
+
this.buildHeartbeatPayload()
|
|
1760
|
+
);
|
|
1761
|
+
if (!result.ok || !result.data) return;
|
|
1762
|
+
if (result.data.ad_delivery_profile?.mode) {
|
|
1763
|
+
this.applyAdDeliveryProfile(result.data.ad_delivery_profile);
|
|
1764
|
+
}
|
|
1765
|
+
if (Array.isArray(result.data.commands) && result.data.commands.length > 0) {
|
|
1766
|
+
this.runHeartbeatCommands(result.data.commands);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
buildHeartbeatPayload() {
|
|
1770
|
+
const userAgent = typeof navigator !== "undefined" ? navigator.userAgent : "";
|
|
1771
|
+
const platform = typeof navigator !== "undefined" ? navigator.platform : null;
|
|
1772
|
+
const connection = typeof navigator !== "undefined" ? navigator.connection : null;
|
|
1773
|
+
const chromiumMatch = userAgent.match(/(?:Chrome|Chromium)\/(\d+)/i);
|
|
1774
|
+
const chromiumMajor = chromiumMatch ? Number(chromiumMatch[1]) : void 0;
|
|
1775
|
+
const imaSupported = typeof window !== "undefined" ? Boolean(window?.google?.ima) : null;
|
|
1776
|
+
const telemetry = {
|
|
1777
|
+
powerState: typeof document !== "undefined" && document.hidden ? "standby" : "on",
|
|
1778
|
+
agentStatus: typeof document !== "undefined" && document.hidden ? "background" : "foreground",
|
|
1779
|
+
os: platform || void 0,
|
|
1780
|
+
agentVersion: SDK_VERSION,
|
|
1781
|
+
ima_integration: "html5_webview",
|
|
1782
|
+
ima_supported: imaSupported,
|
|
1783
|
+
webview_chromium_major: Number.isFinite(chromiumMajor) ? chromiumMajor : void 0
|
|
1784
|
+
};
|
|
1785
|
+
const payload = {
|
|
1786
|
+
telemetry,
|
|
1787
|
+
sdk: {
|
|
1788
|
+
version: SDK_VERSION,
|
|
1789
|
+
ima_supported: imaSupported,
|
|
1790
|
+
ima_integration: "html5_webview",
|
|
1791
|
+
webview_chromium_major: Number.isFinite(chromiumMajor) ? chromiumMajor : void 0
|
|
1792
|
+
},
|
|
1793
|
+
device: {
|
|
1794
|
+
os: platform || void 0,
|
|
1795
|
+
model: userAgent || void 0
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
if (connection) {
|
|
1799
|
+
payload.network = {
|
|
1800
|
+
connectionType: connection.type || void 0,
|
|
1801
|
+
effectiveType: connection.effectiveType || void 0,
|
|
1802
|
+
downlinkMbps: typeof connection.downlink === "number" ? connection.downlink : void 0,
|
|
1803
|
+
bandwidthMbps: typeof connection.downlink === "number" ? connection.downlink : void 0,
|
|
1804
|
+
rtt: typeof connection.rtt === "number" ? connection.rtt : void 0,
|
|
1805
|
+
latencyRtt: typeof connection.rtt === "number" ? connection.rtt : void 0,
|
|
1806
|
+
saveData: typeof connection.saveData === "boolean" ? connection.saveData : void 0
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1809
|
+
return payload;
|
|
1810
|
+
}
|
|
1811
|
+
applyAdDeliveryProfile(profile) {
|
|
1812
|
+
if (!profile?.mode) return;
|
|
1813
|
+
const previousMode = this.state.adDeliveryProfile?.mode ?? null;
|
|
1814
|
+
this.state.adDeliveryProfile = profile;
|
|
1815
|
+
if (profile.mode === "vast_fallback" && this.state.programmaticPlaying) {
|
|
1816
|
+
this.programmaticPlayer.stop({ silent: true });
|
|
1817
|
+
this.state.programmaticPlaying = false;
|
|
1818
|
+
}
|
|
1819
|
+
if (previousMode !== profile.mode) {
|
|
1820
|
+
this.emitStateChanged();
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
runHeartbeatCommands(commands) {
|
|
1824
|
+
for (const command of commands) {
|
|
1825
|
+
const name = String(command?.command || "").toLowerCase();
|
|
1826
|
+
if (name === "refresh_ads") {
|
|
1827
|
+
this.refresh().catch(() => {
|
|
1828
|
+
});
|
|
1829
|
+
} else if (name === "restart") {
|
|
1830
|
+
if (typeof window !== "undefined" && typeof window.location?.reload === "function") {
|
|
1831
|
+
window.location.reload();
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
this.refresh().catch(() => {
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1681
1839
|
playNextAd() {
|
|
1840
|
+
if (this.state.adDeliveryProfile?.mode === "vast_fallback" && this.state.ads.length > 0) {
|
|
1841
|
+
this.playDirect();
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1682
1844
|
const mode = this.state.waterfallMode;
|
|
1683
1845
|
if (mode === "programmatic_only" || mode === "programmatic_then_direct") {
|
|
1684
1846
|
this.playProgrammatic();
|
|
@@ -1693,13 +1855,20 @@ var _TrillboardsAds = class _TrillboardsAds {
|
|
|
1693
1855
|
this.programmaticPlayer.play(
|
|
1694
1856
|
() => {
|
|
1695
1857
|
this.state.programmaticPlaying = false;
|
|
1858
|
+
this.resetProgrammaticBackoff();
|
|
1696
1859
|
this.emitStateChanged();
|
|
1697
1860
|
this.scheduleProgrammaticRetry();
|
|
1698
1861
|
},
|
|
1699
1862
|
(error) => {
|
|
1700
1863
|
this.state.programmaticPlaying = false;
|
|
1701
1864
|
this.state.programmaticLastError = error;
|
|
1702
|
-
|
|
1865
|
+
const normalizedError = String(error || "").toLowerCase();
|
|
1866
|
+
const isNoFillLike = normalizedError.includes("no fill") || normalizedError.includes("no ads vast response") || normalizedError.includes("waterfall_exhausted") || normalizedError === "throttled" || normalizedError === "busy";
|
|
1867
|
+
if (isNoFillLike) {
|
|
1868
|
+
this.state.programmaticRetryCount = 0;
|
|
1869
|
+
} else {
|
|
1870
|
+
this.state.programmaticRetryCount++;
|
|
1871
|
+
}
|
|
1703
1872
|
this.emitStateChanged();
|
|
1704
1873
|
if (this.state.waterfallMode === "programmatic_then_direct" && this.state.ads.length > 0) {
|
|
1705
1874
|
this.playDirect();
|