@dolby-optiview/ads-sdk-core 1.0.0-beta.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.
Files changed (187) hide show
  1. package/dist/OptiViewAds.d.ts +190 -0
  2. package/dist/OptiViewAds.js +1 -0
  3. package/dist/config/keys.d.ts +23 -0
  4. package/dist/config/keys.js +1 -0
  5. package/dist/diagnostics/DiagnosticBuffer.d.ts +33 -0
  6. package/dist/diagnostics/DiagnosticBuffer.js +1 -0
  7. package/dist/diagnostics/DiagnosticEvent.d.ts +71 -0
  8. package/dist/diagnostics/DiagnosticEvent.js +1 -0
  9. package/dist/diagnostics/debugLog.d.ts +8 -0
  10. package/dist/diagnostics/debugLog.js +1 -0
  11. package/dist/diagnostics/errorCodes.d.ts +45 -0
  12. package/dist/diagnostics/errorCodes.js +1 -0
  13. package/dist/diagnostics/index.d.ts +6 -0
  14. package/dist/diagnostics/index.js +1 -0
  15. package/dist/diagnostics/playbackErrorContext.d.ts +22 -0
  16. package/dist/diagnostics/playbackErrorContext.js +1 -0
  17. package/dist/generated/diagnosticCodes.d.ts +487 -0
  18. package/dist/generated/diagnosticCodes.js +1 -0
  19. package/dist/generated/version.d.ts +5 -0
  20. package/dist/generated/version.js +1 -0
  21. package/dist/id3/buildId3.d.ts +25 -0
  22. package/dist/id3/buildId3.js +1 -0
  23. package/dist/id3/index.d.ts +3 -0
  24. package/dist/id3/index.js +1 -0
  25. package/dist/id3/parseId3Geob.d.ts +28 -0
  26. package/dist/id3/parseId3Geob.js +1 -0
  27. package/dist/index.d.ts +45 -0
  28. package/dist/index.js +1 -0
  29. package/dist/interfaces/PlayerAdapter.d.ts +163 -0
  30. package/dist/interfaces/PlayerAdapter.js +1 -0
  31. package/dist/internal/index.d.ts +1 -0
  32. package/dist/internal/index.js +1 -0
  33. package/dist/server/index.d.ts +20 -0
  34. package/dist/server/index.js +1 -0
  35. package/dist/services/AdBreakSequencer.d.ts +146 -0
  36. package/dist/services/AdBreakSequencer.js +1 -0
  37. package/dist/services/AdPlayerController.d.ts +495 -0
  38. package/dist/services/AdPlayerController.js +1 -0
  39. package/dist/services/BreakScheduler.d.ts +215 -0
  40. package/dist/services/BreakScheduler.js +1 -0
  41. package/dist/services/BreakTransitionTimer.d.ts +48 -0
  42. package/dist/services/BreakTransitionTimer.js +1 -0
  43. package/dist/services/CmcdAdReporter.d.ts +81 -0
  44. package/dist/services/CmcdAdReporter.js +1 -0
  45. package/dist/services/GamPodAdTracker.d.ts +65 -0
  46. package/dist/services/GamPodAdTracker.js +1 -0
  47. package/dist/services/GamPodUrlBuilder.d.ts +30 -0
  48. package/dist/services/GamPodUrlBuilder.js +1 -0
  49. package/dist/services/GamStreamManager.d.ts +67 -0
  50. package/dist/services/GamStreamManager.js +1 -0
  51. package/dist/services/LensReporter.d.ts +30 -0
  52. package/dist/services/LensReporter.js +1 -0
  53. package/dist/services/ManifestService.d.ts +91 -0
  54. package/dist/services/ManifestService.js +1 -0
  55. package/dist/services/MetadataCueTracker.d.ts +44 -0
  56. package/dist/services/MetadataCueTracker.js +1 -0
  57. package/dist/services/PauseAdController.d.ts +108 -0
  58. package/dist/services/PauseAdController.js +1 -0
  59. package/dist/services/RewindRearm.d.ts +109 -0
  60. package/dist/services/RewindRearm.js +1 -0
  61. package/dist/services/SsaiController.d.ts +59 -0
  62. package/dist/services/SsaiController.js +1 -0
  63. package/dist/services/StitcherUrlBuilder.d.ts +34 -0
  64. package/dist/services/StitcherUrlBuilder.js +1 -0
  65. package/dist/services/VastAdManager.d.ts +89 -0
  66. package/dist/services/VastAdManager.js +1 -0
  67. package/dist/services/adPlayer/AdPlayerEvents.d.ts +39 -0
  68. package/dist/services/adPlayer/AdPlayerEvents.js +1 -0
  69. package/dist/services/adPlayer/AdPlayerState.d.ts +98 -0
  70. package/dist/services/adPlayer/AdPlayerState.js +1 -0
  71. package/dist/services/adPlayer/AdPreloader.d.ts +54 -0
  72. package/dist/services/adPlayer/AdPreloader.js +1 -0
  73. package/dist/services/adPlayer/AdStage.d.ts +57 -0
  74. package/dist/services/adPlayer/AdStage.js +1 -0
  75. package/dist/services/adPlayer/AssetParameterResolver.d.ts +44 -0
  76. package/dist/services/adPlayer/AssetParameterResolver.js +1 -0
  77. package/dist/services/adPlayer/AssetPlayback.d.ts +71 -0
  78. package/dist/services/adPlayer/AssetPlayback.js +1 -0
  79. package/dist/services/adPlayer/BreakSequenceDriver.d.ts +46 -0
  80. package/dist/services/adPlayer/BreakSequenceDriver.js +1 -0
  81. package/dist/services/adPlayer/ContentResumeCoordinator.d.ts +44 -0
  82. package/dist/services/adPlayer/ContentResumeCoordinator.js +1 -0
  83. package/dist/services/adPlayer/ContinueContentPlayout.d.ts +26 -0
  84. package/dist/services/adPlayer/ContinueContentPlayout.js +1 -0
  85. package/dist/services/adPlayer/GamPodBridge.d.ts +66 -0
  86. package/dist/services/adPlayer/GamPodBridge.js +1 -0
  87. package/dist/services/adPlayer/PauseAdPresenter.d.ts +60 -0
  88. package/dist/services/adPlayer/PauseAdPresenter.js +1 -0
  89. package/dist/services/adPlayer/PresentationModeTracker.d.ts +66 -0
  90. package/dist/services/adPlayer/PresentationModeTracker.js +1 -0
  91. package/dist/services/adPlayer/SharedElementBreakPlayer.d.ts +54 -0
  92. package/dist/services/adPlayer/SharedElementBreakPlayer.js +1 -0
  93. package/dist/services/adPlayer/VariantSelector.d.ts +38 -0
  94. package/dist/services/adPlayer/VariantSelector.js +1 -0
  95. package/dist/services/adPlayer/connectPauseAd.d.ts +10 -0
  96. package/dist/services/adPlayer/connectPauseAd.js +1 -0
  97. package/dist/services/adPlayer/liveEdge.d.ts +6 -0
  98. package/dist/services/adPlayer/liveEdge.js +1 -0
  99. package/dist/services/assetParameterMacroTable.d.ts +9 -0
  100. package/dist/services/assetParameterMacroTable.js +1 -0
  101. package/dist/services/assetParameterMacros.d.ts +69 -0
  102. package/dist/services/assetParameterMacros.js +1 -0
  103. package/dist/services/breakTiming.d.ts +60 -0
  104. package/dist/services/breakTiming.js +1 -0
  105. package/dist/services/channelSwitch.d.ts +32 -0
  106. package/dist/services/channelSwitch.js +1 -0
  107. package/dist/services/detectDeviceType.d.ts +15 -0
  108. package/dist/services/detectDeviceType.js +1 -0
  109. package/dist/services/detectInsertionMode.d.ts +38 -0
  110. package/dist/services/detectInsertionMode.js +1 -0
  111. package/dist/services/detectPreloadMode.d.ts +13 -0
  112. package/dist/services/detectPreloadMode.js +1 -0
  113. package/dist/services/ed25519.d.ts +19 -0
  114. package/dist/services/ed25519.js +1 -0
  115. package/dist/services/fetchWithTimeout.d.ts +35 -0
  116. package/dist/services/fetchWithTimeout.js +1 -0
  117. package/dist/services/lensBackend.d.ts +16 -0
  118. package/dist/services/lensBackend.js +1 -0
  119. package/dist/services/lensBackendDevelopment.d.ts +1 -0
  120. package/dist/services/lensBackendDevelopment.js +1 -0
  121. package/dist/services/lensBackendProduction.d.ts +9 -0
  122. package/dist/services/lensBackendProduction.js +1 -0
  123. package/dist/services/manifestSignature.d.ts +43 -0
  124. package/dist/services/manifestSignature.js +1 -0
  125. package/dist/services/manifestTrustedKeys.d.ts +9 -0
  126. package/dist/services/manifestTrustedKeys.js +1 -0
  127. package/dist/services/parseBreakManifest.d.ts +15 -0
  128. package/dist/services/parseBreakManifest.js +1 -0
  129. package/dist/services/parseVastCompanion.d.ts +31 -0
  130. package/dist/services/parseVastCompanion.js +1 -0
  131. package/dist/services/parseVastLinear.d.ts +36 -0
  132. package/dist/services/parseVastLinear.js +1 -0
  133. package/dist/services/pictureInPicture.d.ts +28 -0
  134. package/dist/services/pictureInPicture.js +1 -0
  135. package/dist/services/resolveAssetParameters.d.ts +6 -0
  136. package/dist/services/resolveAssetParameters.js +1 -0
  137. package/dist/services/resolveDeliveryMode.d.ts +54 -0
  138. package/dist/services/resolveDeliveryMode.js +1 -0
  139. package/dist/services/resolveGamVendorConfiguration.d.ts +55 -0
  140. package/dist/services/resolveGamVendorConfiguration.js +1 -0
  141. package/dist/services/resolvePauseResumePoint.d.ts +32 -0
  142. package/dist/services/resolvePauseResumePoint.js +1 -0
  143. package/dist/services/resolvePollingDecision.d.ts +24 -0
  144. package/dist/services/resolvePollingDecision.js +1 -0
  145. package/dist/services/resolveResumePoint.d.ts +38 -0
  146. package/dist/services/resolveResumePoint.js +1 -0
  147. package/dist/services/resolveTargetedUri.d.ts +22 -0
  148. package/dist/services/resolveTargetedUri.js +1 -0
  149. package/dist/services/resolveVastAdmission.d.ts +34 -0
  150. package/dist/services/resolveVastAdmission.js +1 -0
  151. package/dist/services/selectVariant.d.ts +47 -0
  152. package/dist/services/selectVariant.js +1 -0
  153. package/dist/services/urlOrigin.d.ts +23 -0
  154. package/dist/services/urlOrigin.js +1 -0
  155. package/dist/session/AdBreakStatusTracker.d.ts +49 -0
  156. package/dist/session/AdBreakStatusTracker.js +1 -0
  157. package/dist/session/BreakLifecycle.d.ts +62 -0
  158. package/dist/session/BreakLifecycle.js +1 -0
  159. package/dist/session/SessionStarter.d.ts +98 -0
  160. package/dist/session/SessionStarter.js +1 -0
  161. package/dist/session/SessionState.d.ts +37 -0
  162. package/dist/session/SessionState.js +1 -0
  163. package/dist/types/BreakManifest.d.ts +335 -0
  164. package/dist/types/BreakManifest.js +1 -0
  165. package/dist/types/Events.d.ts +245 -0
  166. package/dist/types/Events.js +1 -0
  167. package/dist/types/OptiViewAdsConfig.d.ts +425 -0
  168. package/dist/types/OptiViewAdsConfig.js +1 -0
  169. package/dist/types/VendorAdError.d.ts +12 -0
  170. package/dist/types/VendorAdError.js +1 -0
  171. package/dist/vendor/lens-sdk/THIRD-PARTY-NOTICES.txt +266 -0
  172. package/dist/vendor/lens-sdk/compat.d.ts +9 -0
  173. package/dist/vendor/lens-sdk/encoding-cmcd.d.ts +9 -0
  174. package/dist/vendor/lens-sdk/encoding-json.d.ts +9 -0
  175. package/dist/vendor/lens-sdk/encoding.d.ts +42 -0
  176. package/dist/vendor/lens-sdk/environment.d.ts +35 -0
  177. package/dist/vendor/lens-sdk/index.d.ts +3 -0
  178. package/dist/vendor/lens-sdk/index.js +1 -0
  179. package/dist/vendor/lens-sdk/legacy.d.ts +12 -0
  180. package/dist/vendor/lens-sdk/lens-core-Q5lbQGMC.js +1 -0
  181. package/dist/vendor/lens-sdk/lens-global.d.ts +23 -0
  182. package/dist/vendor/lens-sdk/lens.d.ts +21 -0
  183. package/dist/vendor/lens-sdk/transport.d.ts +46 -0
  184. package/dist/vendor/lens-sdk/types.d.ts +218 -0
  185. package/dist/vendor/lens-sdk/user-id.d.ts +5 -0
  186. package/dist/vendor/lens-sdk/validation.d.ts +30 -0
  187. package/package.json +57 -0
@@ -0,0 +1,15 @@
1
+ import { DeviceType } from '../types/BreakManifest';
2
+ /**
3
+ * Heuristic: classify a User-Agent string into a {@link DeviceType} for
4
+ * per-URI asset targeting (see {@link resolveTargetedUri}).
5
+ *
6
+ * This is web-platform glue, not portable brain behaviour — Kotlin/Swift
7
+ * determine their device class natively (Android TV / tvOS APIs) rather than
8
+ * by parsing a User-Agent string, so this heuristic has no cross-language
9
+ * conformance fixture (mirrors `isSharedElementUserAgent` /
10
+ * `isSingleDecoderUserAgent`, which are likewise UA-only web glue).
11
+ *
12
+ * Checked in order TV → tablet → mobile → desktop (default), since a tablet
13
+ * or TV UA can otherwise coincidentally match a broader mobile pattern.
14
+ */
15
+ export declare function detectDeviceType(ua?: string): DeviceType;
@@ -0,0 +1 @@
1
+ import{DeviceType as e}from"../types/BreakManifest";export function detectDeviceType(t=("undefined"!=typeof navigator?navigator.userAgent:"")){return t?/SMART-TV|SmartTV|Tizen|Web0S|WebOS|GoogleTV|AppleTV|HbbTV|NetCast|VIDAA|BRAVIA/i.test(t)?e.TV:/iPad/i.test(t)||/Android/i.test(t)&&!/Mobile/i.test(t)?e.TABLET:/iPhone|iPod|Mobi|Android.*Mobile/i.test(t)?e.MOBILE:e.DESKTOP:e.DESKTOP}
@@ -0,0 +1,38 @@
1
+ import { AdInsertionMode } from '../types/OptiViewAdsConfig';
2
+ /**
3
+ * Concrete insertion strategy (`auto` is always resolved before the controller).
4
+ * - `overlay`: separate `<video>` layered over content; all formats.
5
+ * - `shared-element`: ad plays through the content `<video>` so iOS native fullscreen survives;
6
+ * single fullscreen ads only, `lshape_content` skipped.
7
+ * - `adaptive`: iPhone/iPod on iOS 17.1+ (Managed Media Source): `overlay` while inline,
8
+ * `shared-element` only in OS-native fullscreen where DOM overlays cannot render.
9
+ */
10
+ export type ResolvedInsertionMode = 'overlay' | 'shared-element' | 'adaptive';
11
+ /** Media Source capabilities; on iPhone/iPod the insertion choice hinges on them. */
12
+ export interface MediaSourceCapabilities {
13
+ /** Native (unmanaged) Media Source Extensions — `window.MediaSource`. */
14
+ hasNativeMse: boolean;
15
+ /** Managed Media Source — `window.ManagedMediaSource` (iOS 17.1+). */
16
+ hasManagedMediaSource: boolean;
17
+ }
18
+ /**
19
+ * iPhone / iPod: fullscreen is the OS native player, where DOM overlays cannot render. iPad is
20
+ * excluded (element fullscreen + MSE work there; iPadOS 13+ also reports a "Macintosh" UA).
21
+ */
22
+ export declare function isSharedElementUserAgent(ua: string): boolean;
23
+ /**
24
+ * Handheld/tablet web device where a split (two-box) layout cannot be read, so the manifest
25
+ * spec's platform-capability fallback degrades advanced formats to a single fullscreen ad.
26
+ * Android TV and other big-screen UAs are excluded. Web counterpart of the Kotlin fallback.
27
+ */
28
+ export declare function isSingleSurfaceWebDevice(ua: string, maxTouchPoints?: number): boolean;
29
+ /**
30
+ * iPhone Safari had no Media Source, forcing native HLS through one `<video>` (the precondition
31
+ * for shared-element). iOS 17.1+ `ManagedMediaSource` lets HLS.js drive the overlay compositor.
32
+ */
33
+ export declare function detectMediaSourceCapabilities(): MediaSourceCapabilities;
34
+ /**
35
+ * Resolve a configured AdInsertionMode. `auto` on iPhone/iPod: native MSE → `overlay`; Managed
36
+ * Media Source → `adaptive`; neither (iOS < 17.1) → `shared-element`. Other UAs → `overlay`.
37
+ */
38
+ export declare function resolveInsertionMode(mode: AdInsertionMode, ua?: string, caps?: MediaSourceCapabilities): ResolvedInsertionMode;
@@ -0,0 +1 @@
1
+ export function isSharedElementUserAgent(e){return!!e&&/iPhone|iPod/i.test(e)}export function isSingleSurfaceWebDevice(e,t=0){return!!e&&(!/\b(TV|SMART-TV|CrKey|AFT[A-Z]?)\b/i.test(e)&&(!(!/iPad|iPhone|iPod/i.test(e)&&!/Android/i.test(e))||/Macintosh/i.test(e)&&t>1))}export function detectMediaSourceCapabilities(){return{hasNativeMse:"undefined"!=typeof MediaSource,hasManagedMediaSource:void 0!==globalThis.ManagedMediaSource}}export function resolveInsertionMode(e,t=("undefined"!=typeof navigator?navigator.userAgent:""),i=detectMediaSourceCapabilities()){return"overlay"===e?"overlay":"shared-element"===e?isSharedElementUserAgent(t)?"shared-element":(console.warn('[OptiViewAds] adInsertion "shared-element" is only supported on iPhone/iPod (native HLS); falling back to "overlay" insertion on this platform.'),"overlay"):"adaptive"===e?"adaptive":isSharedElementUserAgent(t)?i.hasNativeMse?"overlay":i.hasManagedMediaSource?"adaptive":"shared-element":"overlay"}
@@ -0,0 +1,13 @@
1
+ import { AdPreloadMode } from '../types/OptiViewAdsConfig';
2
+ /** Concrete preload strategy (`auto` is always resolved before the controller). */
3
+ export type ResolvedPreloadMode = 'parallel' | 'single-decoder' | 'none';
4
+ /**
5
+ * Single-decoder Smart TV that cannot buffer a second MediaSource beside content. EVERY Samsung
6
+ * (Tizen), LG (webOS) and VIZIO (SmartCast) TV, regardless of version: a 2024 Tizen 8 panel
7
+ * deadlocked on a second attached MediaSource (black screen, no events), so version is not a
8
+ * reliable signal. Cheap to be broad: `single-decoder` still warms the HTTP cache and prefetches
9
+ * detached. Unknown UAs (desktop, mobile) are treated as parallel-capable.
10
+ */
11
+ export declare function isSingleDecoderUserAgent(ua: string): boolean;
12
+ /** Resolve a configured AdPreloadMode; `adapterSupportsParallel === false` forces `single-decoder` in `auto`. */
13
+ export declare function resolvePreloadMode(mode: AdPreloadMode, ua?: string, adapterSupportsParallel?: boolean): ResolvedPreloadMode;
@@ -0,0 +1 @@
1
+ export function isSingleDecoderUserAgent(e){return!!e&&(!!/Tizen/i.test(e)||(!!/Web[0O]S/i.test(e)||(!!/VIZIO/i.test(e)||!!/SmartCast/i.test(e))))}export function resolvePreloadMode(e,n=("undefined"!=typeof navigator?navigator.userAgent:""),r){return"parallel"===e?"parallel":"single-decoder"===e?"single-decoder":"none"===e?"none":!1===r||isSingleDecoderUserAgent(n)?"single-decoder":"parallel"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Ed25519 signature verification (RFC 8032), ported from the public-domain
3
+ * TweetNaCl reference implementation (`crypto_sign_open`, verify path only).
4
+ *
5
+ * Self-contained on purpose: `crypto.subtle` is async (this verifier must stay
6
+ * synchronous), missing entirely in insecure contexts, and its Ed25519 support
7
+ * never reached the legacy TV browsers this core still runs on, while
8
+ * `node:crypto` does not exist in the browser. Vendoring the verify path keeps
9
+ * `@dolby-optiview/ads-sdk-core` at zero runtime dependencies, and — because the Kotlin
10
+ * (`Ed25519.kt`) and Swift (`Ed25519.swift`) cores port the same TweetNaCl
11
+ * lineage — keeps all three cores in agreement on edge cases. SHA-512
12
+ * (TweetNaCl `crypto_hash`) is included for the same reason.
13
+ *
14
+ * Field elements are 16 radix-2^16 limbs in `Float64Array`s with carries via
15
+ * exact double arithmetic — the same representation TweetNaCl's own JS build
16
+ * uses, so every intermediate stays well inside the 53-bit integer range.
17
+ */
18
+ /** Verify a detached Ed25519 `signature` over `message` with a raw 32-byte `publicKey`. */
19
+ export declare function ed25519Verify(message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean;
@@ -0,0 +1 @@
1
+ const t=16,n=Float64Array.from([61785,9906,39828,60374,45398,33411,5274,224,53552,61171,33010,6542,64743,22239,55772,9222]),r=Float64Array.from([54554,36645,11616,51542,42930,38181,51040,26924,56412,64982,57905,49316,21502,52590,14035,8553]),o=Float64Array.from([26200,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214,26214]),e=Float64Array.from([41136,18958,6951,50414,58488,44335,6150,12099,55207,15867,153,11085,57099,20417,9344,11139]),f=Float64Array.from([30883,4953,19914,30187,55467,16705,2637,112,59544,30585,16505,36039,65139,11119,27886,20995]),l=Float64Array.from([237,211,245,92,26,99,18,88,214,156,247,162,222,249,222,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16]);function c(){return new Float64Array(t)}function a(){const t=c();return t[0]=1,t}function u(n){let r=1;for(let o=0;o<t;o++){const t=n[o]+r+65535;r=Math.floor(t/65536),n[o]=t-65536*r}n[0]+=r-1+37*(r-1)}function s(n,r,o){const e=~(o-1);for(let o=0;o<t;o++){const t=e&(n[o]^r[o]);n[o]^=t,r[o]^=t}}function i(n,r){const o=c(),e=new Float64Array(r);u(e),u(e),u(e);for(let t=0;t<2;t++){o[0]=e[0]-65517;for(let t=1;t<15;t++)o[t]=e[t]-65535-(o[t-1]>>16&1),o[t-1]&=65535;o[15]=e[15]-32767-(o[14]>>16&1);const t=o[15]>>16&1;o[14]&=65535,s(e,o,1-t)}for(let r=0;r<t;r++)n[2*r]=255&e[r],n[2*r+1]=e[r]>>8&255}function y(t,n){const r=new Uint8Array(32),o=new Uint8Array(32);i(r,t),i(o,n);let e=0;for(let t=0;t<32;t++)e|=r[t]^o[t];return 0!==e}function A(t){const n=new Uint8Array(32);return i(n,t),1&n[0]}function F(n,r,o){for(let e=0;e<t;e++)n[e]=r[e]+o[e]}function w(n,r,o){for(let e=0;e<t;e++)n[e]=r[e]-o[e]}function h(n,r,o){const e=new Float64Array(31);for(let n=0;n<t;n++)for(let f=0;f<t;f++)e[n+f]+=r[n]*o[f];for(let t=0;t<15;t++)e[t]+=38*e[t+16];for(let r=0;r<t;r++)n[r]=e[r];u(n),u(n)}function g(t,n){h(t,n,n)}function m(t,r){const o=c(),e=c(),f=c(),l=c(),a=c(),u=c(),s=c(),i=c(),y=c();w(o,t[1],t[0]),w(y,r[1],r[0]),h(o,o,y),F(e,t[0],t[1]),F(y,r[0],r[1]),h(e,e,y),h(f,t[3],r[3]),h(f,f,n),h(l,t[2],r[2]),F(l,l,l),w(a,e,o),w(u,l,f),F(s,l,f),F(i,e,o),h(t[0],a,u),h(t[1],i,s),h(t[2],s,u),h(t[3],a,i)}function U(t,n,r){for(let o=0;o<4;o++)s(t[o],n[o],r)}function M(t,n){const r=c(),o=c(),e=c();!function(t,n){const r=new Float64Array(n);for(let t=253;t>=0;t--)g(r,r),2!==t&&4!==t&&h(r,r,n);t.set(r)}(e,n[2]),h(r,n[0],e),h(o,n[1],e),i(t,o),t[31]^=A(r)<<7}function b(t,n,r){t[0]=c(),t[1]=a(),t[2]=a(),t[3]=c();for(let o=255;o>=0;o--){const e=r[o>>3]>>(7&o)&1;U(t,n,e),m(n,t),m(t,t),U(t,n,e)}}function d(n,r){const o=c(),l=c(),u=c(),s=c(),i=c(),m=c(),U=c();return n[2]=a(),n[0]=c(),n[1]=c(),n[3]=c(),function(n,r){for(let o=0;o<t;o++)n[o]=r[2*o]+(r[2*o+1]<<8);n[15]&=32767}(n[1],r),g(u,n[1]),h(s,u,f),w(u,u,n[2]),F(s,n[2],s),g(i,s),g(m,i),h(U,m,i),h(o,U,u),h(o,o,s),function(t,n){const r=new Float64Array(n);for(let t=250;t>=0;t--)g(r,r),1!==t&&h(r,r,n);t.set(r)}(o,o),h(o,o,u),h(o,o,s),h(o,o,s),h(n[0],o,s),g(l,n[0]),h(l,l,s),y(l,u)&&h(n[0],n[0],e),g(l,n[0]),h(l,l,s),!y(l,u)&&(A(n[0])===r[31]>>7&&w(n[0],c(),n[0]),h(n[3],n[0],n[1]),!0)}function p(t){const n=new Float64Array(64);for(let r=0;r<64;r++)n[r]=t[r];for(let n=0;n<64;n++)t[n]=0;!function(t,n){let r;for(let t=63;t>=32;t--){r=0;let o=t-32;for(;o<t-12;)n[o]+=r-16*n[t]*l[o-(t-32)],r=Math.floor((n[o]+128)/256),n[o]-=256*r,o++;n[o]+=r,n[t]=0}r=0;for(let t=0;t<32;t++)n[t]+=r-(n[31]>>4)*l[t],r=n[t]>>8,n[t]&=255;for(let t=0;t<32;t++)n[t]-=r*l[t];for(let r=0;r<32;r++)n[r+1]+=n[r]>>8,t[r]=255&n[r]}(t,n)}export function ed25519Verify(t,n,e){if(64!==n.length||32!==e.length)return!1;const f=[c(),c(),c(),c()];if(!d(f,e))return!1;const l=new Uint8Array(32+e.length+t.length);l.set(n.subarray(0,32)),l.set(e,32),l.set(t,64);const u=function(t){const n=Float64Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),r=Float64Array.from([4089235720,2227873595,4271175723,1595750129,2917565137,725511199,4215389547,327033209]),o=function(t){const n=t.length%128,r=new Uint8Array(t.length-n+(n<112?128:256));r.set(t),r[t.length]=128;const o=8*t.length,e=Math.floor(o/4294967296),f=o>>>0;for(let t=0;t<4;t++)r[r.length-8+t]=e>>>24-8*t&255,r[r.length-4+t]=f>>>24-8*t&255;return r}(t),e=new Float64Array(80),f=new Float64Array(80);for(let t=0;t<o.length;t+=128){for(let n=0;n<16;n++){const r=t+8*n;e[n]=(o[r]<<24|o[r+1]<<16|o[r+2]<<8|o[r+3])>>>0,f[n]=(o[r+4]<<24|o[r+5]<<16|o[r+6]<<8|o[r+7])>>>0}for(let t=16;t<80;t++){const[n,r]=j(e[t-15],f[t-15],1),[o,l]=j(e[t-15],f[t-15],8),[c,a]=k(e[t-15],f[t-15],7),[u,s]=j(e[t-2],f[t-2],19),[i,y]=j(e[t-2],f[t-2],61),[A,F]=k(e[t-2],f[t-2],6);[e[t],f[t]]=q(e[t-16],f[t-16],(n^o^c)>>>0,(r^l^a)>>>0,e[t-7],f[t-7],(u^i^A)>>>0,(s^y^F)>>>0)}const l=new Float64Array(n),c=new Float64Array(r);for(let t=0;t<80;t++){const[n,r]=j(l[4],c[4],14),[o,a]=j(l[4],c[4],18),[u,s]=j(l[4],c[4],41),[i,y]=q(l[7],c[7],(n^o^u)>>>0,(r^a^s)>>>0,(l[4]&l[5]^~l[4]&l[6])>>>0,(c[4]&c[5]^~c[4]&c[6])>>>0,x[t],V[t],e[t],f[t]),[A,F]=j(l[0],c[0],28),[w,h]=j(l[0],c[0],34),[g,m]=j(l[0],c[0],39),[U,M]=q((A^w^g)>>>0,(F^h^m)>>>0,(l[0]&l[1]^l[0]&l[2]^l[1]&l[2])>>>0,(c[0]&c[1]^c[0]&c[2]^c[1]&c[2])>>>0);l[7]=l[6],c[7]=c[6],l[6]=l[5],c[6]=c[5],l[5]=l[4],c[5]=c[4],[l[4],c[4]]=q(l[3],c[3],i,y),l[3]=l[2],c[3]=c[2],l[2]=l[1],c[2]=c[1],l[1]=l[0],c[1]=c[0],[l[0],c[0]]=q(i,y,U,M)}for(let t=0;t<8;t++)[n[t],r[t]]=q(n[t],r[t],l[t],c[t])}const l=new Uint8Array(64);for(let t=0;t<8;t++)for(let o=0;o<4;o++)l[8*t+o]=n[t]>>>24-8*o&255,l[8*t+4+o]=r[t]>>>24-8*o&255;return l}(l);p(u);const s=[c(),c(),c(),c()];b(s,f,u);const i=[c(),c(),c(),c()];!function(t,n){const e=[new Float64Array(r),new Float64Array(o),a(),c()];h(e[3],r,o),b(t,e,n)}(i,n.subarray(32,64)),m(s,i);const y=new Uint8Array(32);M(y,s);let A=0;for(let t=0;t<32;t++)A|=y[t]^n[t];return 0===A}const x=Float64Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298,3391569614,3515267271,3940187606,4118630271,116418474,174292421,289380356,460393269,685471733,852142971,1017036298,1126000580,1288033470,1501505948,1607167915,1816402316]),V=Float64Array.from([3609767458,602891725,3964484399,2173295548,4081628472,3053834265,2937671579,3664609560,2734883394,1164996542,1323610764,3590304994,4068182383,991336113,633803317,3479774868,2666613458,944711139,2341262773,2007800933,1495990901,1856431235,3175218132,2198950837,3999719339,766784016,2566594879,3203337956,1034457026,2466948901,3758326383,168717936,1188179964,1546045734,1522805485,2643833823,2343527390,1014477480,1206759142,344077627,1290863460,3158454273,3505952657,106217008,3606008344,1432725776,1467031594,851169720,3100823752,1363258195,3750685593,3785050280,3318307427,3812723403,2003034995,3602036899,1575990012,1125592928,2716904306,442776044,593698344,3733110249,2999351573,3815920427,3928383900,566280711,3454069534,4000239992,1914138554,2731055270,3203993006,320620315,587496836,1086792851,365543100,2618297676,3409855158,4234509866,987167468,1246189591]);function j(t,n,r){if(r<32)return[(t>>>r|n<<32-r)>>>0,(n>>>r|t<<32-r)>>>0];const o=r-32;return[(n>>>o|t<<32-o)>>>0,(t>>>o|n<<32-o)>>>0]}function k(t,n,r){return[t>>>r,(n>>>r|t<<32-r)>>>0]}function q(...t){let n=0,r=0;for(let o=0;o<t.length;o+=2)n+=t[o],r+=t[o+1];return n+=Math.floor(r/4294967296),[n>>>0,r>>>0]}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Bounded `fetch` — the only way this SDK should reach the network.
3
+ *
4
+ * `fetch` has NO timeout of its own: a server that accepts the connection and
5
+ * then never finishes the response leaves the promise pending forever, and the
6
+ * failure is silent (no rejection, no diagnostic, just an `await` that never
7
+ * resumes). Every network read therefore goes through here so a stalled server
8
+ * degrades into a fast, observable failure instead of a hang.
9
+ *
10
+ * Kotlin bounds the same reads with `connectTimeout`/`readTimeout`
11
+ * (`OverlayAdRenderer.openBoundedStream`) and Swift with a timeout-carrying
12
+ * `URLSession`; this is the web arm of that agreement.
13
+ */
14
+ /**
15
+ * Whole-call bound for short auxiliary reads (VAST tag, `Content-Type` probe).
16
+ * Matches Kotlin's `HTTP_TIMEOUT_MS`, so a stalled server fails after the same
17
+ * wall time on every platform. Deliberately far tighter than the manifest
18
+ * bound: these reads happen with a break already in flight, so the cut timer is
19
+ * the real deadline and a slow answer is worthless anyway.
20
+ */
21
+ export declare const AUX_FETCH_TIMEOUT_MS = 5000;
22
+ /**
23
+ * Run `fetch` with a whole-call timeout.
24
+ *
25
+ * @param url resource to read.
26
+ * @param init standard fetch init; a caller-supplied `signal` is honoured in
27
+ * addition to the timeout (either one aborts the request).
28
+ * @param timeoutMs whole-call bound in milliseconds.
29
+ * @param timeoutMessage message for the thrown error when the bound is hit —
30
+ * an `AbortError` on its own reads like the caller cancelled, which sends the
31
+ * reader down the wrong path.
32
+ * @throws Error with `timeoutMessage` when the bound elapses; otherwise
33
+ * whatever `fetch` itself rejected with.
34
+ */
35
+ export declare function fetchWithTimeout(url: string, init?: RequestInit, timeoutMs?: number, timeoutMessage?: string): Promise<Response>;
@@ -0,0 +1 @@
1
+ export const AUX_FETCH_TIMEOUT_MS=5e3;export async function fetchWithTimeout(t,r={},e=5e3,o=`no response within ${e}ms`){const n=r.signal??void 0;if(n?.aborted){const t=new Error("The operation was aborted.");throw t.name="AbortError",t}const a=new AbortController,i=setTimeout(()=>a.abort(),e),s=()=>a.abort();n?.addEventListener("abort",s);try{return await fetch(t,{...r,signal:a.signal})}catch(t){if(a.signal.aborted&&!n?.aborted)throw new Error(o,{cause:t});throw t}finally{clearTimeout(i),n?.removeEventListener("abort",s)}}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Which Lens ingest this build reports to — the whole switch is the re-export
3
+ * below, and `scripts/ci-stamp-lens-backend.sh` rewrites it during CI artefact
4
+ * builds (never committed, like the version stamp):
5
+ *
6
+ * main branch → production (committed default, no stamp)
7
+ * any other branch → development (rp2 ingest)
8
+ *
9
+ * The committed default is production on purpose: a build that somehow skips the
10
+ * stamp must degrade to "reports to production", never to "release artefact
11
+ * carrying the development URL".
12
+ *
13
+ * Not part of the public API surface — integrators cannot select, redirect or
14
+ * disable the Lens backend.
15
+ */
16
+ export { configureLensBackend } from './lensBackendProduction';
@@ -0,0 +1 @@
1
+ export{configureLensBackend}from"./lensBackendProduction";
@@ -0,0 +1 @@
1
+ export declare function configureLensBackend(): void;
@@ -0,0 +1 @@
1
+ export function configureLensBackend(){throw new Error("OptiView Ads SDK: the development Lens backend is not part of production artefacts.")}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The production variant of the Lens backend seam: nothing to do. Lens's own
3
+ * built-in default is the production ingest, so this file deliberately imports
4
+ * no Lens module at all — which is what keeps the development ingest URL out of
5
+ * release artefacts (it only exists inside `@dolby-optiview/lens-sdk/dev`).
6
+ *
7
+ * The variant is chosen at build time; see `lensBackend.ts`.
8
+ */
9
+ export declare function configureLensBackend(): void;
@@ -0,0 +1 @@
1
+ export function configureLensBackend(){}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Break Manifest signature verification (detached JWS, spec "Manifest
3
+ * signature" section).
4
+ *
5
+ * The backend signs every manifest response body and sends the signature in
6
+ * the `X-Manifest-Signature` header as a detached compact JWS (RFC 7515
7
+ * Appendix F) with an unencoded payload (RFC 7797, `b64:false`):
8
+ *
9
+ * <base64url(protected-header)>..<base64url(signature)>
10
+ *
11
+ * The signing input is `ASCII(base64url(protected-header)) || '.' || <body
12
+ * bytes>`, where the body bytes are the exact response body after transfer/
13
+ * content decoding — verified BEFORE the body is parsed as JSON.
14
+ */
15
+ /** The header carrying the detached JWS over the manifest response body. */
16
+ export declare const MANIFEST_SIGNATURE_HEADER = "X-Manifest-Signature";
17
+ /** A trusted Ed25519 verification key, resolved by the protected `kid`. */
18
+ export interface ManifestSignatureKey {
19
+ kid: string;
20
+ /** Raw 32-byte Ed25519 public key. */
21
+ publicKey: Uint8Array;
22
+ }
23
+ /**
24
+ * Why a manifest signature was rejected. The identifiers are shared verbatim
25
+ * across the TS/Kotlin/Swift cores and pinned by conformance fixtures.
26
+ */
27
+ export type ManifestSignatureRejection = 'missing-header' | 'malformed-jws' | 'invalid-protected-header' | 'unsupported-alg' | 'invalid-b64' | 'unknown-critical' | 'unknown-kid' | 'signature-mismatch';
28
+ export type ManifestSignatureResult = {
29
+ valid: true;
30
+ kid: string;
31
+ } | {
32
+ valid: false;
33
+ reason: ManifestSignatureRejection;
34
+ };
35
+ /**
36
+ * Verify a detached JWS over the exact manifest response body bytes.
37
+ *
38
+ * Fail-closed: any missing, malformed, or unverifiable signature yields an
39
+ * invalid result with a specific rejection reason; only a signature by a key
40
+ * in `trustedKeys` (resolved by `kid`) validates. Unknown NON-critical
41
+ * protected-header parameters are ignored; unknown critical ones reject.
42
+ */
43
+ export declare function verifyManifestSignature(signatureHeader: string | null | undefined, bodyBytes: Uint8Array, trustedKeys: readonly ManifestSignatureKey[]): ManifestSignatureResult;
@@ -0,0 +1 @@
1
+ import{ed25519Verify as e}from"./ed25519";export const MANIFEST_SIGNATURE_HEADER="X-Manifest-Signature";const r=new Set(["b64"]);function n(e){if(0===e.length||!/^[A-Za-z0-9_-]+$/.test(e))return null;const r=e.replace(/-/g,"+").replace(/_/g,"/");try{const e=atob(r),n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e.charCodeAt(r);return n}catch{return null}}export function verifyManifestSignature(t,i,a){if(null==t||""===t.trim())return{valid:!1,reason:"missing-header"};const o=t.trim().split(".");if(3!==o.length||""!==o[1])return{valid:!1,reason:"malformed-jws"};const[l,,s]=o,d=n(l),c=n(s);if(!d||!c||64!==c.length)return{valid:!1,reason:"malformed-jws"};let u;try{u=JSON.parse((new TextDecoder).decode(d))}catch{return{valid:!1,reason:"invalid-protected-header"}}if("object"!=typeof u||null===u||Array.isArray(u))return{valid:!1,reason:"invalid-protected-header"};const f=u;if("EdDSA"!==f.alg)return{valid:!1,reason:"unsupported-alg"};const g=f.crit;if(!Array.isArray(g)||!g.includes("b64")||!1!==f.b64)return{valid:!1,reason:"invalid-b64"};for(const e of g)if("string"!=typeof e||!r.has(e))return{valid:!1,reason:"unknown-critical"};const h=f.kid;if("string"!=typeof h)return{valid:!1,reason:"invalid-protected-header"};const v=a.find(e=>e.kid===h);if(!v)return{valid:!1,reason:"unknown-kid"};const p=`${l}.`,y=new Uint8Array(p.length+i.length);for(let e=0;e<p.length;e++)y[e]=p.charCodeAt(e);return y.set(i,p.length),e(y,c,v.publicKey)?{valid:!0,kid:h}:{valid:!1,reason:"signature-mismatch"}}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The Break Manifest trust list this build embeds: unconditionally the three
3
+ * production backend keys (`../config/keys.ts`) for every published artifact.
4
+ * This module stays a separate seam so package-internal test tooling (the
5
+ * core Jest config and the private demo/test-app Vite configs) can alias it
6
+ * to a test-only provider; nothing selects a different list at build or run
7
+ * time otherwise.
8
+ */
9
+ export { embeddedManifestKeys } from '../config/keys';
@@ -0,0 +1 @@
1
+ export{embeddedManifestKeys}from"../config/keys";
@@ -0,0 +1,15 @@
1
+ import { BreakManifest } from '../types/BreakManifest';
2
+ /**
3
+ * Supported major version of the break manifest.
4
+ */
5
+ export declare const SUPPORTED_MANIFEST_MAJOR_VERSION = 1;
6
+ /**
7
+ * Parse and validate raw break-manifest data into a {@link BreakManifest}.
8
+ *
9
+ * Pure (no I/O): callers fetch the bytes and pass the decoded JSON. Shared by
10
+ * the client `ManifestService` and the server-side SSAI stitcher so both apply
11
+ * identical version/timebase/breaks validation.
12
+ *
13
+ * @throws Error when the data is not a valid v1 break manifest.
14
+ */
15
+ export declare function parseBreakManifest(data: unknown): BreakManifest;
@@ -0,0 +1 @@
1
+ export const SUPPORTED_MANIFEST_MAJOR_VERSION=1;export function parseBreakManifest(r){if(!r||"object"!=typeof r)throw new Error("Invalid manifest: expected object");const t=r;if("string"!=typeof t.version)throw new Error("Invalid manifest: missing version");if(1!==parseInt(t.version.split(".")[0],10))throw new Error(`Unsupported manifest version: ${t.version}. Supported major version: 1`);const n=t.timebase;if("wallclock"!==n&&"pts"!==n&&"mediatime"!==n)throw new Error("Invalid manifest: invalid or missing timebase");if(!Array.isArray(t.breaks))throw new Error("Invalid manifest: breaks must be an array");for(const r of t.breaks)e(r);if(void 0!==t.delivery){if(!Array.isArray(t.delivery)||0===t.delivery.length)throw new Error("Invalid manifest: delivery must be a non-empty array");for(const e of t.delivery)if(!e||"object"!=typeof e||"string"!=typeof e.mode)throw new Error("Invalid manifest: each delivery rule must have a string mode")}if(void 0!==t.vendorConfiguration&&!Array.isArray(t.vendorConfiguration))throw new Error("Invalid manifest: vendorConfiguration must be an array");if(void 0!==t.adStartDelay&&("number"!=typeof t.adStartDelay||!Number.isFinite(t.adStartDelay)||t.adStartDelay<0))throw new Error("Invalid manifest: adStartDelay must be a number >= 0");return t}function e(e){if(!e||"object"!=typeof e)return;const r=e.start;if(!r||"object"!=typeof r)return;const t=r;if("event"!==t.type||"string"!=typeof t.event)throw new Error('Invalid manifest: break start object must be { type: "event", event: string }');if(void 0!==t.delay&&("number"!=typeof t.delay||!Number.isFinite(t.delay)||t.delay<0))throw new Error("Invalid manifest: event trigger delay must be a number >= 0")}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Portable VAST `CompanionAds` parser for pause ads.
3
+ *
4
+ * Pause ads use a **static image** companion creative, not a linear video, so we
5
+ * do not need Google IMA: we extract the image directly from the VAST XML. This
6
+ * parser is part of the portable brain (locked by the cross-language conformance
7
+ * harness), so it must run identically in the browser and under Node — it is
8
+ * therefore **dependency-free** and does not rely on `DOMParser`. It performs a
9
+ * tolerant, targeted extraction of the `CompanionAds` shape rather than full
10
+ * VAST parsing.
11
+ */
12
+ /** The image creative extracted from a VAST `CompanionAds` response. */
13
+ export interface VastCompanionImage {
14
+ /** The `StaticResource` image URL. */
15
+ imageUrl: string;
16
+ /** `CompanionClickThrough` navigation target, when present. */
17
+ clickThrough?: string;
18
+ /** `creativeView` tracking URLs, fired once when the image is displayed. */
19
+ impressions: string[];
20
+ }
21
+ /**
22
+ * Extract the first image companion from a VAST document.
23
+ *
24
+ * Reads the **first** `CompanionAds/Companion` whose `StaticResource` has an
25
+ * `image/*` `creativeType`, plus its optional `CompanionClickThrough` and
26
+ * `creativeView` tracking. Returns `null` when no image companion is found (the
27
+ * caller then skips the pause ad with a diagnostic).
28
+ *
29
+ * @param xml - The raw VAST XML string.
30
+ */
31
+ export declare function parseVastCompanionImage(xml: string): VastCompanionImage | null;
@@ -0,0 +1 @@
1
+ function e(e){const n=/<!\[CDATA\[([\s\S]*?)\]\]>/.exec(e);return(n?n[1]:e).trim()}export function parseVastCompanionImage(n){if(!n||"string"!=typeof n)return null;const i=/<Companion\b[^>]*>([\s\S]*?)<\/Companion>/gi;let o;for(;null!==(o=i.exec(n));){const n=o[1],i=/<StaticResource\b([^>]*)>([\s\S]*?)<\/StaticResource>/i.exec(n);if(!i)continue;const t=i[1],c=/creativeType\s*=\s*["']([^"']+)["']/i.exec(t);if(!c||!/^image\//i.test(c[1]))continue;const s=e(i[2]);if(!s)continue;const r=/<CompanionClickThrough\b[^>]*>([\s\S]*?)<\/CompanionClickThrough>/i.exec(n),u=r?e(r[1]):"",a=[],l=/<Tracking\b[^>]*\bevent\s*=\s*["']creativeView["'][^>]*>([\s\S]*?)<\/Tracking>/gi;let g;for(;null!==(g=l.exec(n));){const n=e(g[1]);n&&a.push(n)}return{imageUrl:s,...u?{clickThrough:u}:{},impressions:a}}return null}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Portable VAST `Linear` MediaFile parser for **video** pause ads.
3
+ *
4
+ * A video pause ad may be sourced from a VAST `InLine` whose `Creative` carries
5
+ * a `Linear` element with one or more progressive `MediaFile`s. Unlike a linear
6
+ * playout ad (which would go through Google IMA), a pause ad just needs a
7
+ * directly-playable MP4 URL that the render layer can attach to a muted,
8
+ * play-once `<video>`/AVPlayer/ExoPlayer. We therefore extract the MediaFile URL
9
+ * directly from the VAST XML rather than invoking IMA.
10
+ *
11
+ * Like {@link ./parseVastCompanion}, this parser is part of the portable brain
12
+ * (locked by the cross-language conformance harness), so it must run identically
13
+ * in the browser and under Node — it is **dependency-free** and does not rely on
14
+ * `DOMParser`. It performs a tolerant, targeted extraction of the `Linear`
15
+ * `MediaFile` shape rather than full VAST parsing.
16
+ */
17
+ /** The video creative extracted from a VAST `Linear` response. */
18
+ export interface VastLinearMediaFile {
19
+ /** The progressive `MediaFile` MP4 URL. */
20
+ mediaFileUrl: string;
21
+ /** `VideoClicks/ClickThrough` navigation target, when present. */
22
+ clickThrough?: string;
23
+ /** `Impression` URLs, fired once when the video is displayed. */
24
+ impressions: string[];
25
+ }
26
+ /**
27
+ * Extract the first progressive MP4 media file from a VAST document.
28
+ *
29
+ * Reads the **first** `MediaFile` whose `delivery` is `progressive` and whose
30
+ * `type` is `video/mp4`, plus the optional `VideoClicks/ClickThrough` and all
31
+ * `Impression` URLs. Returns `null` when no usable MP4 media file is found (the
32
+ * caller then skips the pause ad with a diagnostic).
33
+ *
34
+ * @param xml - The raw VAST XML string.
35
+ */
36
+ export declare function parseVastLinearMediaFile(xml: string): VastLinearMediaFile | null;
@@ -0,0 +1 @@
1
+ function e(e){const i=/<!\[CDATA\[([\s\S]*?)\]\]>/.exec(e);return(i?i[1]:e).trim()}export function parseVastLinearMediaFile(i){if(!i||"string"!=typeof i)return null;const s=/<MediaFile\b([^>]*)>([\s\S]*?)<\/MediaFile>/gi;let n,r="";for(;null!==(n=s.exec(i));){const i=n[1],s=/delivery\s*=\s*["']([^"']+)["']/i.exec(i),t=/type\s*=\s*["']([^"']+)["']/i.exec(i);if(!s||!/progressive/i.test(s[1]))continue;if(!t||!/^video\/mp4\b/i.test(t[1].trim()))continue;const o=e(n[2]);if(o){r=o;break}}if(!r)return null;const t=/<ClickThrough\b[^>]*>([\s\S]*?)<\/ClickThrough>/i.exec(i),o=t?e(t[1]):"",c=[],l=/<Impression\b[^>]*>([\s\S]*?)<\/Impression>/gi;let u;for(;null!==(u=l.exec(i));){const i=e(u[1]);i&&c.push(i)}return{mediaFileUrl:r,...o?{clickThrough:o}:{},impressions:c}}
@@ -0,0 +1,28 @@
1
+ import { BreakFormat } from '../types/BreakManifest';
2
+ import type { Break } from '../types/BreakManifest';
3
+ /**
4
+ * True when `declared` would be overruled by PiP — i.e. the caller must also drop the
5
+ * companion, play a single asset, and report `single` on the public events.
6
+ */
7
+ export declare function pipOverridesFormat(declared: BreakFormat | undefined, pictureInPicture: boolean): boolean;
8
+ /**
9
+ * True when `declared` is an {@link BreakFormat.LSHAPE_CONTENT} break playing in PiP, where
10
+ * the window shows the main content: the caller must NOT draw the backdrop and must NOT
11
+ * reframe content into its corner box.
12
+ *
13
+ * This format cannot follow the `single` rule the others do — it carries no fullscreen video
14
+ * ad to promote, only decoration around content that keeps playing. Squeezed into a PiP
15
+ * window that decoration is unreadable, and shrinking content inside an already tiny window
16
+ * leaves the viewer with almost nothing. So the break still runs (it keeps its declared
17
+ * format and its duration on the public events); it simply renders nothing.
18
+ */
19
+ export declare function pipSuppressesBackdrop(declared: BreakFormat | undefined, pictureInPicture: boolean): boolean;
20
+ /** `declared` as it will ACTUALLY play, given the current PiP state. */
21
+ export declare function effectiveFormat(declared: BreakFormat | undefined, pictureInPicture: boolean): BreakFormat | undefined;
22
+ /**
23
+ * The format `breakInfo` will ACTUALLY play as — {@link resolveBreakFormat} with the PiP
24
+ * override applied. This is what the public events report, so a consumer laying out its own
25
+ * UI sees the format the viewer is really getting rather than the one the manifest asked
26
+ * for. The declared format is not lost: `DA-PIP-FORMAT-OVERRIDE` records both.
27
+ */
28
+ export declare function effectiveBreakFormat(breakInfo: Break, pictureInPicture: boolean): BreakFormat | undefined;
@@ -0,0 +1 @@
1
+ import{BreakFormat as e}from"../types/BreakManifest";import{resolveBreakFormat as r}from"./AdBreakSequencer";const t=[e.DOUBLE,e.LSHAPE_AD,e.OVERLAY];export function pipOverridesFormat(e,r){return r&&void 0!==e&&t.includes(e)}export function pipSuppressesBackdrop(r,t){return t&&r===e.LSHAPE_CONTENT}export function effectiveFormat(r,t){return pipOverridesFormat(r,t)?e.SINGLE:r}export function effectiveBreakFormat(e,t){return effectiveFormat(r(e),t)}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Merge asset parameters in conformance-locked order, lowest to highest:
3
+ * SessionConfig < updateAssetParameters() < manifest session < per-asset.
4
+ * Each layer overwrites earlier values per key; undefined is returned when all layers are empty.
5
+ */
6
+ export declare function resolveAssetParameters(sessionConfigParameters: Record<string, string> | undefined, updateParameters: Record<string, string> | undefined, manifestSessionParameters: Record<string, string> | undefined, assetParameters: Record<string, string> | undefined): Record<string, string> | undefined;
@@ -0,0 +1 @@
1
+ export function resolveAssetParameters(e,t,r,s){const n={...e??{},...t??{},...r??{},...s??{}};return Object.keys(n).length>0?n:void 0}
@@ -0,0 +1,54 @@
1
+ import { BreakManifest, DeliveryMode, DeliveryRule, DeviceType, VendorConfiguration } from '../types/BreakManifest';
2
+ import { type StitchedStreamVendor } from './resolveGamVendorConfiguration';
3
+ export type { StitchedStreamVendor } from './resolveGamVendorConfiguration';
4
+ /**
5
+ * Thrown when the manifest steers the session to ssai but no vendor
6
+ * configuration can provide a stitched stream. Deliberately catchable by the
7
+ * application (no silent fallback to sgai): the app decides which stream to
8
+ * play instead.
9
+ */
10
+ export declare class SsaiUnavailableError extends Error {
11
+ constructor(message: string);
12
+ }
13
+ /**
14
+ * Outcome of the once-per-session delivery-mode resolution.
15
+ */
16
+ export interface DeliveryModeDecision {
17
+ mode: DeliveryMode;
18
+ /** Index of the delivery rule that decided the mode, or null when none matched. */
19
+ ruleIndex: number | null;
20
+ /**
21
+ * Set when the matching rule carried an unrecognized mode value: the raw
22
+ * value, which the resolver replaced with sgai (forward compatibility).
23
+ */
24
+ unknownMode: string | null;
25
+ }
26
+ /**
27
+ * Resolve the delivery mode from a manifest's ordered `delivery` rules for the
28
+ * requesting device, as a pure function shared (by behavioural contract) with
29
+ * the Kotlin and Swift cores and locked by the cross-language conformance
30
+ * harness.
31
+ *
32
+ * Selection order:
33
+ * 1. Rules are evaluated in array order; the first rule whose
34
+ * `targeting.deviceType` matches `deviceType` — or that carries no
35
+ * `targeting.deviceType` (the manifest's default rule) — wins.
36
+ * 2. No `delivery` array, or no matching rule → sgai (preserves the pre-steering
37
+ * behaviour).
38
+ * 3. A matching rule with an unrecognized mode value → sgai, with the raw value
39
+ * reported via `unknownMode` so the caller can log it (forward compatibility).
40
+ */
41
+ export declare function resolveDeliveryMode(delivery: DeliveryRule[] | undefined, deviceType: DeviceType): DeliveryModeDecision;
42
+ /**
43
+ * Find the first vendor configuration entry able to provide a server-stitched
44
+ * stream — currently a `gam` entry carrying a full-service `assetKey`. Returns
45
+ * null when the manifest offers none, in which case an ssai session cannot
46
+ * start (the SDK throws; no silent fallback to sgai).
47
+ */
48
+ export declare function resolveStitchedStreamVendor(vendorConfiguration: VendorConfiguration[] | undefined): StitchedStreamVendor | null;
49
+ /**
50
+ * Strip timebased breaks from a manifest for a manifest-steered ssai session:
51
+ * the stitched stream carries those server-side, while event-triggered
52
+ * (spec `start.type: 'event'`, or positional pre) breaks remain scheduled and rendered client-side.
53
+ */
54
+ export declare function filterSsaiClientBreaks(manifest: BreakManifest): BreakManifest;
@@ -0,0 +1 @@
1
+ import{DeliveryMode as e,getBreakEvent as r}from"../types/BreakManifest";import{resolveGamVendorConfiguration as n}from"./resolveGamVendorConfiguration";export class SsaiUnavailableError extends Error{constructor(e){super(e),this.name="SsaiUnavailableError"}}export function resolveDeliveryMode(r,n){if(!Array.isArray(r))return{mode:e.SGAI,ruleIndex:null,unknownMode:null};for(let o=0;o<r.length;o++){const t=r[o],i=t?.targeting?.deviceType;if(void 0===i||i===n)return t.mode===e.SGAI||t.mode===e.SSAI?{mode:t.mode,ruleIndex:o,unknownMode:null}:{mode:e.SGAI,ruleIndex:o,unknownMode:String(t.mode)}}return{mode:e.SGAI,ruleIndex:null,unknownMode:null}}export function resolveStitchedStreamVendor(e){return n(void 0===e?{}:{vendorConfiguration:e}).ssai}export function filterSsaiClientBreaks(e){return{...e,breaks:e.breaks.filter(e=>null!==r(e))}}
@@ -0,0 +1,55 @@
1
+ import type { BreakManifest } from '../types/BreakManifest';
2
+ /**
3
+ * GAM stream identity for the IMA/DAI session. Both required: a blank value yields a pod URL like
4
+ * `.../network//custom_asset/...` whose 404 reads as a GAM outage instead of a config error.
5
+ */
6
+ export interface GamSessionIdentity {
7
+ networkCode: string;
8
+ customAssetKey: string;
9
+ }
10
+ export interface StitchedStreamVendor {
11
+ networkCode: string;
12
+ assetKey: string;
13
+ assetParameters: Record<string, string> | undefined;
14
+ }
15
+ /** Why no identity could be resolved. `ok` means one was. */
16
+ export type GamVendorConfigurationReason = 'ok' | 'absent' | 'missing-network-code' | 'missing-custom-asset-key';
17
+ export interface GamVendorConfigurationResult {
18
+ /** The resolved identity, or null when `reason !== 'ok'`. */
19
+ identity: GamSessionIdentity | null;
20
+ reason: GamVendorConfigurationReason;
21
+ /** Unrecognised `type` values, in manifest order, deduped. Ignored per the forward-compat rule. */
22
+ unknownTypes: string[];
23
+ /** True when more than one `type: 'gam'` entry was present; the first one won. */
24
+ duplicateGam: boolean;
25
+ sgaiAssetParameters: Record<string, string> | undefined;
26
+ ssai: StitchedStreamVendor | null;
27
+ }
28
+ /**
29
+ * The ONLY place any core reads `vendorConfiguration`. Validated defensively from the typed
30
+ * model: `parseBreakManifest` ends in a pass-through cast, while the Kotlin/Swift parsers build
31
+ * field by field, so this keeps the three cores answering identically. Spec: at most one entry
32
+ * per type (FIRST `gam` wins, duplicate reported), unknown types ignored and collected.
33
+ */
34
+ export declare function resolveGamVendorConfiguration(manifest: Pick<BreakManifest, 'vendorConfiguration'>): GamVendorConfigurationResult;
35
+ /** One field on which a pod asset disagrees with the session it would be served under. */
36
+ export interface GamPodIdentityMismatch {
37
+ field: 'networkCode' | 'customAssetKey';
38
+ assetValue: string;
39
+ sessionValue: string;
40
+ }
41
+ /**
42
+ * Fields on which a pod asset's `vendorParameters` disagree with the session identity
43
+ * (`networkCode` first). The pod URL carries the ASSET's identity while `stream_id` was
44
+ * registered under the session's; Google answers a crossed pair with HTTP 410 Gone (measured
45
+ * 2026-08-27), so a mismatch is a provisioning bug and the caller reports both values.
46
+ */
47
+ export declare function gamPodIdentityMismatches(session: GamSessionIdentity, assetParams: {
48
+ networkCode: string;
49
+ customAssetKey: string;
50
+ }): GamPodIdentityMismatch[];
51
+ /**
52
+ * GAM is activated by the MANIFEST, not client config. A manifest without gam
53
+ * `vendorConfiguration` is normal when it has no GAM assets, so a missing identity is only worth reporting when one is needed.
54
+ */
55
+ export declare function manifestHasGamAssets(manifest: Pick<BreakManifest, 'breaks'>): boolean;
@@ -0,0 +1 @@
1
+ function e(e){return"string"==typeof e&&""!==e.trim()?e:null}export function resolveGamVendorConfiguration(t){const n=t.vendorConfiguration,o={identity:null,unknownTypes:[],duplicateGam:!1,sgaiAssetParameters:void 0,ssai:null};if(!Array.isArray(n))return{...o,reason:"absent"};const r=[];let a=null,i=0;for(const s of n){if("object"!=typeof s||null===s)continue;const t=s,n=e(t.type);null!==n&&("gam"!==n?r.includes(n)||r.push(n):(i+=1,null===a&&(a=t)))}const u=i>1;if(null===a)return{...o,reason:"absent",unknownTypes:r,duplicateGam:u};const l=e(a.networkCode);if(null===l)return{...o,reason:"missing-network-code",unknownTypes:r,duplicateGam:u};const c=Array.isArray(a.ssai)?a.ssai[0]:void 0,y=("object"==typeof c&&null!==c?e(c.assetKey):null)??e(a.assetKey),f=y?{networkCode:l,assetKey:y,assetParameters:s("object"==typeof c&&null!==c?c.assetParameters:void 0)}:null,d=Array.isArray(a.sgai)?a.sgai[0]:void 0,m=("object"==typeof d&&null!==d?e(d.customAssetKey):null)??e(a.customAssetKey);if(null===m)return{...o,reason:"missing-custom-asset-key",unknownTypes:r,duplicateGam:u,ssai:f};return{identity:{networkCode:l,customAssetKey:m},reason:"ok",unknownTypes:r,duplicateGam:u,sgaiAssetParameters:s("object"==typeof d&&null!==d?d.assetParameters:void 0),ssai:f}}function s(e){if("object"!=typeof e||null===e||Array.isArray(e))return;const s=Object.fromEntries(Object.entries(e).filter(([,e])=>"string"==typeof e));return Object.keys(s).length>0?s:void 0}export function gamPodIdentityMismatches(e,s){const t=[];return s.networkCode!==e.networkCode&&t.push({field:"networkCode",assetValue:s.networkCode,sessionValue:e.networkCode}),s.customAssetKey!==e.customAssetKey&&t.push({field:"customAssetKey",assetValue:s.customAssetKey,sessionValue:e.customAssetKey}),t}export function manifestHasGamAssets(e){for(const s of e.breaks??[]){const e=[...s.variants??[],...s.variant?[s.variant]:[]];for(const s of e)for(const e of s?.assets??[])if("gam"===e?.vendor)return!0}return!1}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Where content should resume after a pause ad, as a pure function shared (by
3
+ * behavioural contract) with the Kotlin and Swift cores and locked by the
4
+ * cross-language conformance harness.
5
+ *
6
+ * A pause ad holds the viewer at a fixed position while the stream keeps
7
+ * advancing. On a live stream with a DVR window that position is only playable
8
+ * for as long as it stays inside the window — pause for longer than the DVR
9
+ * depth and it falls off the back, at which point resuming "where you were" is
10
+ * not a choice the player can honour.
11
+ *
12
+ * So there are exactly two outcomes:
13
+ *
14
+ * 1. **The pinned position is still inside the window** → `null`, meaning
15
+ * *resume in place with no seek*. This is the normal case and the one the
16
+ * viewer expects: press play, continue exactly where you paused. Returning
17
+ * `null` rather than the pinned position is deliberate — it tells the caller
18
+ * not to seek at all, so a stream that never lost its position is never
19
+ * nudged by a redundant seek.
20
+ * 2. **The pinned position has dropped below the window's start** → the live
21
+ * edge, because the paused content no longer exists to resume into.
22
+ *
23
+ * VOD needs no special case: a VOD asset's seekable range starts at 0 and the
24
+ * pinned position can never fall below it, so branch 1 always applies.
25
+ */
26
+ export declare function resolvePauseResumePoint(
27
+ /** `currentTime` captured when the pause ad appeared. */
28
+ pinnedPosition: number,
29
+ /** `seekable.start(0)` now — the back edge of the DVR window. */
30
+ seekableStart: number,
31
+ /** `seekable.end(len - 1)` now — the live edge. */
32
+ seekableEnd: number): number | null;
@@ -0,0 +1 @@
1
+ export function resolvePauseResumePoint(e,i,n){return Number.isFinite(e)&&Number.isFinite(i)?!Number.isFinite(n)||n<=i||e>=i?null:n:null}
@@ -0,0 +1,24 @@
1
+ import { Polling } from '../types/BreakManifest';
2
+ /**
3
+ * The polling behaviour the manifest dictates for the current moment.
4
+ *
5
+ * - `once` — the manifest carries no `polling` object, so it is fetched
6
+ * exactly once per session and never re-polled.
7
+ * - `poll` — re-fetch on a timer, using the manifest's own `active` interval
8
+ * while an ad break is active and its `idle` interval otherwise.
9
+ */
10
+ export type PollingDecision = {
11
+ mode: 'once';
12
+ } | {
13
+ mode: 'poll';
14
+ intervalSeconds: number;
15
+ };
16
+ /**
17
+ * Pure spec-compliant cadence resolution (shared brain, conformance-tested).
18
+ *
19
+ * The manifest is the only source of the polling cadence: there is no client
20
+ * default and no configuration override. Callers re-resolve whenever the
21
+ * active state flips or a freshly polled manifest changes/removes `polling`,
22
+ * and restart their timer when the decision changes.
23
+ */
24
+ export declare function resolvePollingDecision(polling: Polling | undefined, active: boolean): PollingDecision;
@@ -0,0 +1 @@
1
+ export function resolvePollingDecision(e,o){return e?{mode:"poll",intervalSeconds:o?e.active:e.idle}:{mode:"once"}}