@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,190 @@
1
+ import { OptiViewAdsConfig, StartSessionConfig } from './types/OptiViewAdsConfig';
2
+ import { AdBreakStatus, OptiViewAdsEventType, OptiViewAdsEventHandler } from './types/Events';
3
+ import { DiagnosticHandler, DiagnosticReport } from './diagnostics/DiagnosticEvent';
4
+ /**
5
+ * OptiViewAds SDK - player-agnostic ad insertion for SGAI. Constructed once per application;
6
+ * the customer controls monetization with startSession() / endSession().
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { OptiViewAds } from '@dolby-optiview/ads-sdk-core';
11
+ * import { HlsJsAdapter } from '@dolby-optiview/ads-sdk-adapter-hlsjs';
12
+ *
13
+ * const sdk = new OptiViewAds({
14
+ * player: new HlsJsAdapter(hls, videoElement),
15
+ * container: document.getElementById('container'),
16
+ * createAdAdapter: (adContainer) => {
17
+ * const adVideo = document.createElement('video');
18
+ * adContainer.appendChild(adVideo);
19
+ * const h = new Hls(); h.attachMedia(adVideo);
20
+ * return new HlsJsAdapter(h, adVideo);
21
+ * },
22
+ * gam: {}, // presence enables GAM; the identity comes from the manifest
23
+ * });
24
+ *
25
+ * sdk.addEventListener('adbreakbegin', (e) => console.log('Break started', e));
26
+ *
27
+ * await sdk.startSession({
28
+ * manifestUrl: 'https://manifest.example.com/v1/acme/channels/sports',
29
+ * customAssetKey: 'asset-key',
30
+ * assetParameters: { userId: 'abc123' },
31
+ * });
32
+ * hls.loadSource(contentUrl);
33
+ *
34
+ * sdk.updateAssetParameters({ userId: 'def456', consent: '1' });
35
+ * sdk.endSession();
36
+ * ```
37
+ */
38
+ export declare class OptiViewAds {
39
+ /** The SDK version, readable without constructing an instance. @category Diagnostics */
40
+ static get version(): string;
41
+ private player;
42
+ /** Releases the scheduler's reload guard after a content error — see onContentError. */
43
+ private contentErrorReloadGuard;
44
+ /** How long a content error brackets scheduler position samples as reload noise. */
45
+ private readonly CONTENT_ERROR_RELOAD_GUARD_MS;
46
+ private manifestService?;
47
+ private breakScheduler?;
48
+ private adPlayerController?;
49
+ private pauseAdController?;
50
+ private mode;
51
+ private readonly hasExplicitMode;
52
+ private eventHandlers;
53
+ private diagnosticHandlers;
54
+ private destroyed;
55
+ private diagnosticBuffer;
56
+ /** Whether eligible replacement breaks may keep content playing. */
57
+ private continueContentDuringBreak;
58
+ private readonly lensReporter;
59
+ private readonly cmcdAdReporter;
60
+ private debug;
61
+ private readonly state;
62
+ private breakLifecycle?;
63
+ private sessionStarter;
64
+ private readonly adBreakStatusTracker;
65
+ private breakTransitionTimer?;
66
+ private readonly onContentSeeked;
67
+ private readonly onContentWaiting;
68
+ private readonly onContentPlaying;
69
+ private readonly onContentPause;
70
+ private readonly onContentEnded;
71
+ private readonly onContentError;
72
+ private metadataCueTracker;
73
+ /** Dedup keys of cues already surfaced as DA-ANVATO-CUE-OBSERVED; a re-fired ID3 frame must not spam diagnostics. */
74
+ private anvatoObservedLogged;
75
+ /** Break ids already reported as newly seen on DA-MANIFEST-POLLED (see notedManifestBreakIds). */
76
+ private seenManifestBreakIds;
77
+ private readonly onTimedMetadata;
78
+ constructor(config: OptiViewAdsConfig);
79
+ /** SSAI-mode construction: no manifest service, break scheduler, or ad-player overlay. */
80
+ private initSsai;
81
+ /** Content player events both modes subscribe to; unsubscribed again in destroy(). */
82
+ private contentListeners;
83
+ /**
84
+ * Start monetization for a piece of content: begins manifest polling and (if configured)
85
+ * GAM session initialization. Ends any previously active session first.
86
+ * @category Lifecycle */
87
+ startSession(config: StartSessionConfig): Promise<void>;
88
+ /** Resume content playback. No-op during a content-locking ad break. @category Playback & UI */
89
+ play(): Promise<void>;
90
+ /** Pause content playback. No-op during a content-locking ad break. @category Playback & UI */
91
+ pause(): void;
92
+ /** Seek the content stream (seconds). Blocked during breaks with controls.snapback; no-op without a session. @category Playback & UI */
93
+ seek(time: number): void;
94
+ /**
95
+ * Unified mute state: targets whichever player is audible — the ad player during a break,
96
+ * the content player otherwise — and bridges into IMA for a CSAI ad (IMA manages its own audio path).
97
+ *
98
+ * @example
99
+ * muteButton.onclick = () => { sdk.muted = !sdk.muted; };
100
+ * sdk.addEventListener('volumechange', (e) => {
101
+ * muteButton.textContent = e.muted ? 'Unmute' : 'Mute';
102
+ * });
103
+ * @category Playback & UI */
104
+ get muted(): boolean;
105
+ set muted(value: boolean);
106
+ /** Unified volume (0-1). See {@link muted} for which player is the effective target. @category Playback & UI */
107
+ get volume(): number;
108
+ set volume(value: number);
109
+ /**
110
+ * Skip the running ad break when the manifest's `controls.skipOffset` allows it. Returns
111
+ * `true` when applied (balanced `adend` + `adbreakend`), `false` when suppressed (no active
112
+ * break, no skip control, or before the offset). Suppression is diagnosed as
113
+ * `DA-AD-SKIP-SUPPRESSED`. Use {@link getAdBreakStatus} for a "Skip in Ns" affordance.
114
+ * @category Playback & UI */
115
+ skipAd(): boolean;
116
+ /**
117
+ * Report a click on the current ad and emit `adclick` with its `interaction.clickThrough`.
118
+ * Returns the destination URL, or `null` when no ad or click-through URL is available.
119
+ * The SDK does not open the URL; your application controls navigation.
120
+ * @category Playback & UI */
121
+ clickAd(): string | null;
122
+ /** Stop monetization: stops manifest polling, break scheduling, and resets the GAM session. @category Lifecycle */
123
+ endSession(): void;
124
+ /**
125
+ * Replace the live-update layer of the asset parameters for future breaks. Highest of the
126
+ * three layers, per key; it **replaces** the previous update (IMA `replaceAdTagParameters()`
127
+ * semantics). Consumed by GAM pods (IMA `adTagParameters`) and by VAST assets (appended to
128
+ * the tag URL). No-op with a warning without an active session.
129
+ * @category Lifecycle */
130
+ updateAssetParameters(params: Record<string, string>): void;
131
+ private endSessionInternal;
132
+ /**
133
+ * Subscribe to an SDK event.
134
+ * @category Events */
135
+ addEventListener<T extends OptiViewAdsEventType>(event: T, handler: OptiViewAdsEventHandler<T>): void;
136
+ /**
137
+ * Unsubscribe from an SDK event. Pass the same handler reference that was
138
+ * given to {@link addEventListener}; unknown handlers are ignored.
139
+ * @category Events */
140
+ removeEventListener<T extends OptiViewAdsEventType>(event: T, handler: OptiViewAdsEventHandler<T>): void;
141
+ private emit;
142
+ /** Redacted timeline entry for `exportDiagnostics()`: only stable identifiers (type, source, break/asset ids). */
143
+ private recordEventTimeline;
144
+ /** Subscribe to the structured diagnostic stream (stable `code`, `category`, `level`, JSON `context`). @category Diagnostics */
145
+ onDiagnostic(handler: DiagnosticHandler): void;
146
+ /** Unsubscribe from the structured diagnostic stream. @category Diagnostics */
147
+ offDiagnostic(handler: DiagnosticHandler): void;
148
+ /** Self-contained, redacted diagnostic report (no secrets or ad-tag-parameter values). @category Diagnostics */
149
+ exportDiagnostics(): DiagnosticReport;
150
+ /** Only Anvato break cues carry a schedulable instant; SSAI ID3, EXT-X-DATERANGE and emsg pass through untouched. */
151
+ private armBreakFromPresentedCue;
152
+ /**
153
+ * Break ids not seen in a manifest before this session. A break that leaves and returns is
154
+ * NOT re-reported: the metric is when the backend first signalled it.
155
+ */
156
+ private notedManifestBreakIds;
157
+ /** Only `type=cue` frames are surfaced; captions/beacons arrive once per segment and would flood the buffer. */
158
+ private diagnoseAnvatoCueObserved;
159
+ /** Push to the ring buffer, notify subscribers, mirror to the console in debug. Category/level come from the code catalog. */
160
+ private diagnose;
161
+ /** Whether an ad is currently playing. @category Playback & UI */
162
+ isAdPlaying(): boolean;
163
+ /** Whether the content player is in picture-in-picture. The browser reports this directly; nothing to wire up. @category Playback & UI */
164
+ isPictureInPicture(): boolean;
165
+ /** Current picture-in-picture status, visible media, window owner, and insertion mode.
166
+ * Use this snapshot to keep your player UI aligned with the SDK.
167
+ * @category Playback & UI */
168
+ getPresentationState(): {
169
+ pictureInPicture: boolean;
170
+ showing: 'ad' | 'content';
171
+ /** which element owns the PiP window — null when there is none (web only) */
172
+ windowOwner: 'content' | 'ad' | null;
173
+ /** `overlay` (own element) or `shared-element` (through the content element); content behaviour and `windowOwner` differ between them. */
174
+ insertion: 'overlay' | 'shared-element';
175
+ };
176
+ /**
177
+ * The format `breakInfo` will ACTUALLY play as. In PiP the browser renders only the PiP'd
178
+ * video, so multi-surface formats play as `single`; the declared one is kept in `DA-PIP-FORMAT-OVERRIDE`.
179
+ */
180
+ private effectiveFormatOf;
181
+ /** Whether a session is currently active. @category Lifecycle */
182
+ isSessionActive(): boolean;
183
+ /** Current playback-gated ad break status; for polling when an `adbreakstatus` event was missed. @category Playback & UI */
184
+ getAdBreakStatus(): AdBreakStatus;
185
+ /** Clean up all resources. Call when the SDK is no longer needed. @category Lifecycle */
186
+ destroy(): void;
187
+ /** Descriptive Error from an adapter media error, surfacing the underlying code/message. */
188
+ private toPlaybackError;
189
+ private log;
190
+ }
@@ -0,0 +1 @@
1
+ import{DEFAULT_MODE as e,DEFAULT_AD_PRELOAD_MODE as t,DEFAULT_AD_INSERTION_MODE as s,DEFAULT_AD_BREAK_CUT_SAFETY_MARGIN_SEC as r,DEFAULT_DOUBLE_BOX_AUDIO as i,resolveChaining as a,resolveTuneIn as n,resolveBreakWarnings as o,resolvePdtGraceSeconds as d}from"./types/OptiViewAdsConfig";import{SsaiController as l}from"./services/SsaiController";import{resolvePreloadMode as h}from"./services/detectPreloadMode";import{isSingleSurfaceWebDevice as c,resolveInsertionMode as u}from"./services/detectInsertionMode";import{ManifestService as m}from"./services/ManifestService";import{BreakScheduler as p}from"./services/BreakScheduler";import{MetadataCueTracker as g,isAnvatoCue as k,parseAnvatoPayload as f}from"./services/MetadataCueTracker";import{AdPlayerController as y}from"./services/AdPlayerController";import{effectiveFormat as S}from"./services/pictureInPicture";import{resolveBreakFormat as A}from"./services/AdBreakSequencer";import{connectPauseAd as v}from"./services/adPlayer/connectPauseAd";import{BreakTransitionTimer as b}from"./services/BreakTransitionTimer";import{LensReporter as C}from"./services/LensReporter";import{CmcdAdReporter as P}from"./services/CmcdAdReporter";import{DiagnosticBuffer as T}from"./diagnostics/DiagnosticBuffer";import{DIAGNOSTIC_CODES as B}from"./diagnostics/errorCodes";import{SDK_VERSION as w}from"./generated/version";import{playbackErrorContext as D}from"./diagnostics/playbackErrorContext";import{debugLog as E}from"./diagnostics/debugLog";import{AdBreakStatusTracker as I}from"./session/AdBreakStatusTracker";import{BreakLifecycle as O}from"./session/BreakLifecycle";import{SessionStarter as R}from"./session/SessionStarter";import{SessionState as M}from"./session/SessionState";export class OptiViewAds{static get version(){return w}constructor(l){if(this.contentErrorReloadGuard=null,this.CONTENT_ERROR_RELOAD_GUARD_MS=5e3,this.eventHandlers=new Map,this.diagnosticHandlers=new Set,this.destroyed=!1,this.continueContentDuringBreak=!1,this.state=new M,this.metadataCueTracker=null,this.anvatoObservedLogged=new Set,this.seenManifestBreakIds=new Set,this.player=l.player,this.debug=l.debug??!1,this.mode=l.mode??e,this.hasExplicitMode=void 0!==l.mode,this.lensReporter=new C((...e)=>this.log(...e)),this.cmcdAdReporter=new P(()=>this.lensReporter.handle,(...e)=>this.log(...e)),this.adBreakStatusTracker=new I({emit:(e,t)=>this.emit(e,t),effectiveFormatOf:e=>this.effectiveFormatOf(e),secondsUntilBreak:e=>this.breakScheduler?.getSecondsUntilBreak(e)??void 0,breakTransitionTimer:()=>this.breakTransitionTimer}),this.onContentSeeked=()=>{const e=this.breakScheduler?.getActiveBreak();if(!e?.controls?.snapback)return;if(this.state.snapbackSeekInFlight)return void(this.state.snapbackSeekInFlight=!1);const t="number"==typeof e.start?e.start:this.player.currentTime;Math.abs(this.player.currentTime-t)<=.5||(this.log("Snapback: seek detected during locked break, snapping back to break start"),this.state.snapbackSeekInFlight=!0,this.player.seek(t))},this.onContentWaiting=()=>{this.adPlayerController?.isAdPlaying()||this.emit("waiting",{type:"waiting",timestamp:Date.now(),source:"content"})},this.onContentPlaying=()=>{this.adPlayerController?.isAdPlaying()||(this.breakScheduler?.markPlaybackStart(),this.breakTransitionTimer?.settle("out-of-break"),!1!==this.pauseAdController?.onResume()?this.emit("playing",{type:"playing",timestamp:Date.now(),source:"content"}):this.player.pause())},this.onContentPause=()=>{this.adPlayerController?.isAdPlaying()||this.breakScheduler?.isAdStartDelayActive()||this.pauseAdController?.onPause()},this.onContentEnded=()=>{this.adPlayerController?.isAdPlaying()||this.breakScheduler?.markPlaybackEnd()},this.onContentError=e=>{const t=this.toPlaybackError(e,"Content playback error");this.diagnose("DA-CONTENT-PLAYBACK-ERROR",t.message,D(e)),this.breakScheduler?.setContentReloading(!0),this.contentErrorReloadGuard&&clearTimeout(this.contentErrorReloadGuard),this.contentErrorReloadGuard=setTimeout(()=>{this.contentErrorReloadGuard=null,this.breakScheduler?.setContentReloading(!1)},this.CONTENT_ERROR_RELOAD_GUARD_MS),this.emit("aderror",{type:"aderror",timestamp:Date.now(),source:"content",error:t})},this.onTimedMetadata=e=>{if(!e)return;const t=e,s=this.metadataCueTracker?.handleCue(t)??!1;this.diagnoseAnvatoCueObserved(t,s),"presented"===t.phase&&this.armBreakFromPresentedCue(t)},this.continueContentDuringBreak=l.continueContentDuringBreak??!1,"ssai"===this.mode)return void this.initSsai(l);if(!l.createAdAdapter)throw new Error("[OptiViewAds] createAdAdapter is required. Use the @dolby-optiview/ads-sdk package for a default HLS.js ad player, or supply your own createAdAdapter factory.");this.state.steeredSsaiOptions={maxBitrate:l.maxBitrate,autoplay:l.autoplay??!1,streamActivityMonitorId:l.gam?.streamActivityMonitorId};const k=h(l.adPreload??t),f=u(l.adInsertion??s),S=a(l.chaining),A=n(l.tuneIn),B=o(l.breakWarnings),w=d(l.pdtGraceSeconds);"anvatoCue"===l.ptsSource&&(this.metadataCueTracker=new g),this.diagnosticBuffer=new T(l.diagnostics?.bufferSize),this.breakTransitionTimer=new b(e=>{this.diagnose("DA-BREAK-TRANSITION",`Transition ${e.kind} took ${e.durationMs}ms`,{transition:e.kind,durationMs:e.durationMs,breakId:e.breakId,adPreload:k,adInsertion:f,...e.phases?{phases:e.phases}:{}})}),this.state.configSummary={mode:this.mode,adPreload:k,adInsertion:f,chaining:{enabled:S.enabled,maxGapSeconds:S.maxGapSeconds},tuneIn:{enabled:A.enabled,minBreakDurationSeconds:A.minBreakDurationSeconds},breakWarnings:{seconds:B.seconds},ptsSource:l.ptsSource??"mediaTime",continueContentDuringBreak:this.continueContentDuringBreak,gam:l.gam?{hasAssetParameters:!1,streamActivityMonitorId:l.gam.streamActivityMonitorId}:void 0};const E=l.adPreload??t;this.diagnose("DA-PRELOAD-MODE-RESOLVED",`Ad preload mode: ${k}`+(E!==k?` (configured "${E}")`:""),{configured:E,resolved:k}),"shared-element"===l.adInsertion&&"overlay"===f&&this.diagnose("DA-SHARED-ELEMENT-UNSUPPORTED",'adInsertion "shared-element" is unsupported on this platform (non-iPhone/iPod); fell back to "overlay".',{configured:"shared-element",resolved:f}),this.manifestService=new m(this.debug,l.interceptManifestResponse,(e,t,s)=>this.diagnose(e,t,s),l.interceptManifestRequest),this.breakScheduler=new p(this.player,this.debug,S,void 0,A,(e,t,s)=>this.diagnose(e,t,s),B,this.metadataCueTracker,w),this.adPlayerController=new y(l.player,l.container,l.playerContainer,l.createAdAdapter,this.debug,l.gam,k,f,l.adBreakCutSafetyMarginSec??r,l.doubleBoxAudio??i,c("undefined"!=typeof navigator?navigator.userAgent:"","undefined"!=typeof navigator?navigator.maxTouchPoints??0:0)),this.adPlayerController.setTransitionPhaseReporter(this.debug?e=>this.breakTransitionTimer?.phase(e):null),this.adPlayerController.setChainResolver(S.enabled?e=>this.breakScheduler.getChainedSuccessor(e):null),this.adPlayerController.initialize();const L=(e,t)=>void 0===e||void 0===t?{}:{adIndex:e,totalAds:t};this.adPlayerController.setGamEventCallbacks({onAdFirstQuartile:(e,t,s,r)=>{this.emit("adfirstquartile",{type:"adfirstquartile",timestamp:Date.now(),break:e,format:this.effectiveFormatOf(e),asset:t,...L(s,r)})},onAdMidpoint:(e,t,s,r)=>{this.emit("admidpoint",{type:"admidpoint",timestamp:Date.now(),break:e,format:this.effectiveFormatOf(e),asset:t,...L(s,r)})},onAdThirdQuartile:(e,t,s,r)=>{this.emit("adthirdquartile",{type:"adthirdquartile",timestamp:Date.now(),break:e,format:this.effectiveFormatOf(e),asset:t,...L(s,r)})}}),this.adPlayerController.setDiagnoseHandler((e,t,s)=>{this.diagnose(e,t,s)}),this.pauseAdController=v(this.adPlayerController,{debug:this.debug,diagnose:(e,t,s)=>this.diagnose(e,t,s)}),this.adPlayerController.setVolumeChangeCallback((e,t)=>{this.emit("volumechange",{type:"volumechange",timestamp:Date.now(),muted:e,volume:t})}),this.breakLifecycle=new O(this.state,{adPlayerController:this.adPlayerController,breakScheduler:this.breakScheduler,manifestService:this.manifestService,breakTransitionTimer:this.breakTransitionTimer,cmcdAdReporter:this.cmcdAdReporter,adBreakStatusTracker:this.adBreakStatusTracker,emit:(e,t)=>this.emit(e,t),diagnose:(e,t,s)=>this.diagnose(e,t,s),log:(...e)=>this.log(...e),effectiveFormatOf:e=>this.effectiveFormatOf(e),onBreakSettled:()=>this.sessionStarter?.applyPendingChannelSwitch()}),this.sessionStarter=new R(this.state,{player:this.player,debug:this.debug,mode:this.mode,hasExplicitMode:this.hasExplicitMode,continueContentDuringBreak:this.continueContentDuringBreak,manifestService:this.manifestService,breakScheduler:this.breakScheduler,adPlayerController:this.adPlayerController,pauseAdController:this.pauseAdController,breakLifecycle:this.breakLifecycle,cmcdAdReporter:this.cmcdAdReporter,lensReporter:this.lensReporter,adBreakStatusTracker:this.adBreakStatusTracker,emit:(e,t)=>this.emit(e,t),diagnose:(e,t,s)=>this.diagnose(e,t,s),log:(...e)=>this.log(...e),endSessionInternal:e=>this.endSessionInternal(e),notedManifestBreakIds:e=>this.notedManifestBreakIds(e)});for(const[e,t]of this.contentListeners())this.player.on(e,t);this.log("OptiViewAds SDK initialized")}initSsai(e){if(!e.gam)throw new Error('[OptiViewAds] mode "ssai" requires a gam config.');if(!e.ssai?.networkCode)throw new Error('[OptiViewAds] mode "ssai" requires an ssai config (networkCode).');const t=e.ssai;this.diagnosticBuffer=new T(e.diagnostics?.bufferSize);const s=e.autoplay??!1;this.state.configSummary={mode:this.mode,adPreload:"n/a",adInsertion:"ssai",chaining:{enabled:!1,maxGapSeconds:0},tuneIn:{enabled:!1,minBreakDurationSeconds:0},gam:{networkCode:t.networkCode,hasAssetParameters:!1,streamActivityMonitorId:e.gam.streamActivityMonitorId},ssai:{maxBitrate:e.maxBitrate,autoplay:s},continueContentDuringBreak:this.continueContentDuringBreak},this.state.ssaiController=new l(this.player,{gam:e.gam,ssai:t,maxBitrate:e.maxBitrate,autoplay:s,debug:this.debug},{emit:(e,t)=>this.emit(e,t),diagnose:(e,t,s)=>this.diagnose(e,t,s),log:(...e)=>this.log(...e)}),this.player.on("volumechange",()=>{this.emit("volumechange",{type:"volumechange",timestamp:Date.now(),muted:this.player.muted,volume:this.player.volume})}),this.sessionStarter=new R(this.state,{player:this.player,debug:this.debug,mode:this.mode,hasExplicitMode:this.hasExplicitMode,continueContentDuringBreak:this.continueContentDuringBreak,manifestService:this.manifestService,breakScheduler:this.breakScheduler,adPlayerController:this.adPlayerController,pauseAdController:this.pauseAdController,breakLifecycle:this.breakLifecycle,cmcdAdReporter:this.cmcdAdReporter,lensReporter:this.lensReporter,adBreakStatusTracker:this.adBreakStatusTracker,emit:(e,t)=>this.emit(e,t),diagnose:(e,t,s)=>this.diagnose(e,t,s),log:(...e)=>this.log(...e),endSessionInternal:e=>this.endSessionInternal(e),notedManifestBreakIds:e=>this.notedManifestBreakIds(e)});for(const[e,t]of this.contentListeners())this.player.on(e,t);this.log("OptiViewAds SDK initialized (SSAI mode)")}contentListeners(){const e=[["seeked",this.onContentSeeked],["waiting",this.onContentWaiting],["playing",this.onContentPlaying],["pause",this.onContentPause],["ended",this.onContentEnded],["error",this.onContentError]];return this.metadataCueTracker&&e.push(["timedmetadata",this.onTimedMetadata]),e}async startSession(e){return this.sessionStarter.startSession(e)}play(){return this.adPlayerController?.isAdPlaying()?(this.log("play() suppressed — ad break is active"),Promise.resolve()):this.player.play()}pause(){this.adPlayerController?.isAdPlaying()?this.log("pause() suppressed — ad break is active"):this.player.pause()}seek(e){if(!this.state.sessionActive)return;const t=this.breakScheduler?.getActiveBreak();t?.controls?.snapback?this.log("seek() suppressed — break has snapback enabled"):(this.breakScheduler?.notifyViewerSeek(),this.player.seek(e))}get muted(){return this.adPlayerController?this.adPlayerController.muted:this.player.muted}set muted(e){this.adPlayerController?this.adPlayerController.muted=e:this.player.muted=e}get volume(){return this.adPlayerController?this.adPlayerController.volume:this.player.volume}set volume(e){this.adPlayerController?this.adPlayerController.volume=e:this.player.volume=e}skipAd(){const e=this.adBreakStatusTracker.activeBreak;if(!this.state.sessionActive||!this.adPlayerController?.isAdPlaying()||!e)return this.log("skipAd() suppressed — no active ad break"),!1;const t=e.controls?.skipOffset;if(null==t)return this.log(`skipAd() suppressed — break '${e.id}' declares no controls.skipOffset`),this.diagnose("DA-AD-SKIP-SUPPRESSED","Skip requested but break declares no skipOffset",{breakId:e.id}),!1;const s=this.adBreakStatusTracker.activeBreakElapsedSec;return s<t?(this.log(`skipAd() suppressed — skipOffset ${t}s not reached (${s}s)`),this.diagnose("DA-AD-SKIP-SUPPRESSED","Skip requested before skipOffset",{breakId:e.id,skipOffset:t,elapsedSec:s}),!1):(this.log(`skipAd() — skipping break '${e.id}' at ${s}s (skipOffset ${t}s)`),this.diagnose("DA-AD-SKIPPED","Break skipped by viewer",{breakId:e.id,skipOffset:t,elapsedSec:s}),this.cmcdAdReporter.onSkipRequested(e.id),this.adPlayerController.skipBreak(),!0)}clickAd(){const e=this.adBreakStatusTracker.activeBreak,t=this.adPlayerController?.currentAdAsset()??null;if(!(this.state.sessionActive&&this.adPlayerController?.isAdPlaying()&&e&&t))return this.log("clickAd() suppressed — no ad on screen"),null;const s=t.interaction?.clickThrough;return this.diagnose("DA-AD-CLICKED","Ad clicked",{breakId:e.id,assetId:t.id,clickThrough:s??""}),this.emit("adclick",{type:"adclick",timestamp:Date.now(),break:e,format:this.effectiveFormatOf(e),asset:t,...s?{clickThrough:s}:{}}),s??null}endSession(){this.state.sessionActive&&this.endSessionInternal()}updateAssetParameters(e){if(this.state.sessionActive){if("ssai"===this.mode||this.state.steeredSsaiActive)return this.state.ssaiController.updateAssetParameters(e),void this.log("Asset parameters updated (SSAI)");this.adPlayerController.updateAssetParameters(e),this.log("Asset parameters updated")}else console.warn("[OptiViewAds] updateAssetParameters called but no active session.")}endSessionInternal(e="end-session"){this.state.sessionActive=!1,this.state.sessionGeneration++,this.breakLifecycle?.reportAbandonedBreak(e),"ssai"===this.mode?this.state.ssaiController?.stop():(this.state.steeredSsaiActive&&(this.state.ssaiController?.stop(),delete this.state.ssaiController,this.state.steeredSsaiActive=!1),this.manifestService?.reset(),this.breakScheduler?.stop(),this.breakScheduler?.destroy(),this.adBreakStatusTracker.resetAdBreakStatus(),this.state.pauseAdTickInterval&&(clearInterval(this.state.pauseAdTickInterval),this.state.pauseAdTickInterval=null),this.pauseAdController?.reset(),this.breakTransitionTimer?.reset(),this.adPlayerController?.stopActiveBreak(),this.adPlayerController?.releaseContentHold(),this.adPlayerController?.endGamSession()),this.state.clearSessionIdentity(),this.anvatoObservedLogged.clear(),this.seenManifestBreakIds.clear(),this.cmcdAdReporter.onSessionEnd(),this.lensReporter.endSession(),this.diagnose("DA-SESSION-ENDED","Session ended"),this.log("Session ended")}addEventListener(e,t){this.eventHandlers.has(e)||this.eventHandlers.set(e,new Set),this.eventHandlers.get(e).add(t)}removeEventListener(e,t){const s=this.eventHandlers.get(e);s&&s.delete(t)}emit(e,t){this.recordEventTimeline(t),this.cmcdAdReporter.onEvent(t);const s=this.eventHandlers.get(e);if(s)for(const e of s)try{e(t)}catch(e){this.log("Event handler error:",e)}}recordEventTimeline(e){const t={eventType:e.type},s=e;s.source&&(t.source=s.source),s.break?.id&&(t.breakId=s.break.id),s.asset?.id&&(t.assetId=s.asset.id),this.diagnosticBuffer.record({ts:e.timestamp,level:"aderror"===e.type?"error":"info",code:"DA-EVENT",category:"event",message:`SDK event: ${e.type}`,context:t})}onDiagnostic(e){this.diagnosticHandlers.add(e)}offDiagnostic(e){this.diagnosticHandlers.delete(e)}exportDiagnostics(){const e={...this.state.configSummary,...this.state.manifestOrigin?{manifestOrigin:this.state.manifestOrigin}:{},...this.state.configSummary.ssai&&this.state.stitcherOrigin?{ssai:{...this.state.configSummary.ssai,stitcherOrigin:this.state.stitcherOrigin}}:{}};return{sdkVersion:w,generatedAt:Date.now(),userAgent:"undefined"!=typeof navigator?navigator.userAgent:null,config:e,diagnostics:this.diagnosticBuffer.getAll()}}armBreakFromPresentedCue(e){if(!this.metadataCueTracker||!this.breakScheduler||!k(e))return;const t=f(e.messageData??"");if("cue"!==t.type)return;const s=Number(t.pts);Number.isFinite(s)&&this.breakScheduler.notifyCuePresented(s)}notedManifestBreakIds(e){const t=[];for(const s of e.breaks)this.seenManifestBreakIds.has(s.id)||(this.seenManifestBreakIds.add(s.id),t.push(s.id));return t}diagnoseAnvatoCueObserved(e,t){if(!this.metadataCueTracker||!k(e))return;const s=e.messageData??"",r=f(s);if("cue"!==r.type)return;const i=`${e.startTime}|${s}`;if(this.anvatoObservedLogged.has(i))return;this.anvatoObservedLogged.add(i);const a=Number(r.pts);this.diagnose("DA-ANVATO-CUE-OBSERVED",`Anvato cue observed: pts=${r.pts} at media time ${e.startTime}s`,{pts:Number.isFinite(a)?a:r.pts,mediaTime:e.startTime,playheadSec:this.player.currentTime,recorded:t,payload:s.slice(0,300)})}diagnose(e,t,s){if(this.destroyed)return;const r=B[e],i={ts:Date.now(),level:r?.level??"info",code:e,category:r?.category??"unknown",message:t,...s?{context:s}:{}};this.diagnosticBuffer.record(i);for(const e of this.diagnosticHandlers)try{e(i)}catch(e){this.log("Diagnostic handler error:",e)}this.debug&&E("[OptiViewAds]",e,t,s??"")}isAdPlaying(){return this.adPlayerController?.isAdPlaying()??!1}isPictureInPicture(){return this.adPlayerController?.isPictureInPicture()??!1}getPresentationState(){return{pictureInPicture:this.isPictureInPicture(),showing:this.adPlayerController?.isShowingAd()?"ad":"content",insertion:this.adPlayerController?.currentInsertionMode()??"overlay",windowOwner:this.adPlayerController?.pictureInPictureOwner()??null}}effectiveFormatOf(e){const t=this.adPlayerController?.declaredFormatOf(e)??A(e);return S(t,this.isPictureInPicture())}isSessionActive(){return this.state.sessionActive}getAdBreakStatus(){return this.adBreakStatusTracker.getAdBreakStatus()}destroy(){this.contentErrorReloadGuard&&(clearTimeout(this.contentErrorReloadGuard),this.contentErrorReloadGuard=null);for(const[e,t]of this.contentListeners())this.player.off(e,t);this.state.sessionActive&&this.endSessionInternal("destroy"),this.manifestService?.destroy(),this.pauseAdController?.destroy(),this.adPlayerController?.destroy(),this.state.ssaiController?.stop(),this.lensReporter.destroy(),this.eventHandlers.clear(),this.diagnosticHandlers.clear(),this.destroyed=!0,this.log("Destroyed")}toPlaybackError(e,t){const s=e;if(s&&("number"==typeof s.code||s.message)){const e="number"==typeof s.code?` (code ${s.code})`:"",r=s.message?`: ${s.message}`:"";return new Error(`${t}${e}${r}`)}return new Error(t)}log(...e){this.debug&&E("[OptiViewAds]",...e)}}
@@ -0,0 +1,23 @@
1
+ import { ManifestSignatureKey } from '../services/manifestSignature';
2
+ /**
3
+ * The embedded trusted Break Manifest signing keys (raw Ed25519 public keys,
4
+ * base64url). Baked into the SDK at build time — never fetched at runtime.
5
+ * Multiple keys are listed so the backend can rotate: a new key is shipped
6
+ * here first, the backend switches `kid`, then the old entry is removed.
7
+ */
8
+ export declare const PRODUCTION_MANIFEST_KEYS: ReadonlyArray<{
9
+ kid: string;
10
+ publicKey: string;
11
+ }>;
12
+ export declare function decodeManifestKey(entry: {
13
+ kid: string;
14
+ publicKey: string;
15
+ }): ManifestSignatureKey;
16
+ /**
17
+ * The trust list every published Web SDK artifact embeds — release, beta,
18
+ * feature, or custom builds all use exactly these three backend keys. No
19
+ * branch, version, environment, or CI selection changes it, and there is no
20
+ * runtime option to add keys. The repo-public test key (`conformance/keys/`)
21
+ * lives only in test-only code under `__tests__` and private test apps.
22
+ */
23
+ export declare function embeddedManifestKeys(): ManifestSignatureKey[];
@@ -0,0 +1 @@
1
+ export const PRODUCTION_MANIFEST_KEYS=[{kid:"ads-prod-2026-08",publicKey:"h6jbWWoz1G1_Osj1wkDJT_I8ZNtLhix1YuMoBP8coNs"},{kid:"ads-staging-2026-08",publicKey:"wVszV8cvem7uhwSh06DjzXRN_4p3JBbEhPHlhrkvuNA"},{kid:"ads-dev-2026-08",publicKey:"bsz__yOAX__YQ_USwfADt8_KoDkc6fxriRVdFHxkmdo"}];export function decodeManifestKey(e){const t=e.publicKey.replace(/-/g,"+").replace(/_/g,"/"),d=atob(t),i=new Uint8Array(d.length);for(let e=0;e<d.length;e++)i[e]=d.charCodeAt(e);return{kid:e.kid,publicKey:i}}export function embeddedManifestKeys(){return PRODUCTION_MANIFEST_KEYS.map(decodeManifestKey)}
@@ -0,0 +1,33 @@
1
+ import { DiagnosticEvent } from './DiagnosticEvent';
2
+ /**
3
+ * Default number of records retained in the diagnostic ring buffer.
4
+ */
5
+ export declare const DEFAULT_DIAGNOSTIC_BUFFER_SIZE = 200;
6
+ /**
7
+ * A bounded, in-memory ring buffer of {@link DiagnosticEvent}s.
8
+ *
9
+ * Retains the most recent `size` records (diagnostics + SDK-event timeline) so
10
+ * `OptiViewAds.exportDiagnostics()` can produce a self-contained report without
11
+ * unbounded memory growth on long-running live sessions.
12
+ */
13
+ export declare class DiagnosticBuffer {
14
+ private readonly size;
15
+ private events;
16
+ constructor(size?: number);
17
+ /**
18
+ * Append a record, evicting the oldest when the buffer is full.
19
+ */
20
+ record(event: DiagnosticEvent): void;
21
+ /**
22
+ * Return a shallow copy of the retained records, oldest first.
23
+ */
24
+ getAll(): DiagnosticEvent[];
25
+ /**
26
+ * Drop all retained records.
27
+ */
28
+ clear(): void;
29
+ /**
30
+ * Configured capacity of the buffer.
31
+ */
32
+ get capacity(): number;
33
+ }
@@ -0,0 +1 @@
1
+ export const DEFAULT_DIAGNOSTIC_BUFFER_SIZE=200;export class DiagnosticBuffer{constructor(t=200){this.events=[],this.size=t>0?Math.floor(t):200}record(t){this.events.push(t),this.events.length>this.size&&this.events.splice(0,this.events.length-this.size)}getAll(){return[...this.events]}clear(){this.events=[]}get capacity(){return this.size}}
@@ -0,0 +1,71 @@
1
+ import type { PtsSource } from '../types/OptiViewAdsConfig';
2
+ import { DiagnosticCategory, DiagnosticLevel } from './errorCodes';
3
+ /** Machine-readable diagnostic record (stable `code`, `category`, JSON-serialisable `context`) behind `onDiagnostic()` and `exportDiagnostics()`. @category Diagnostics */
4
+ export interface DiagnosticEvent {
5
+ /** Unix epoch milliseconds when the record was created. */
6
+ ts: number;
7
+ /** Severity of the record. */
8
+ level: DiagnosticLevel;
9
+ /** Stable, machine-readable code (e.g. `DA-MANIFEST-FETCH-FAILED`). */
10
+ code: string;
11
+ /** Functional area the record relates to. */
12
+ category: DiagnosticCategory;
13
+ /** Human-readable message. */
14
+ message: string;
15
+ /** Optional JSON-serialisable structured context. Never contains secrets. */
16
+ context?: Record<string, unknown>;
17
+ }
18
+ /** Handler for the structured diagnostic stream. @category Diagnostics */
19
+ export type DiagnosticHandler = (event: DiagnosticEvent) => void;
20
+ /** Redacted SDK configuration for a diagnostic report; secrets and PII (e.g. ad tag parameter VALUES) are stripped. @category Diagnostics */
21
+ export interface ConfigSummary {
22
+ /** Ad insertion architecture in effect (`sgai` or `ssai`). */
23
+ mode: string;
24
+ /** Origin only (scheme + host [+ port]); path/query may carry channel identity or a signed token. Absent before startSession() and in SSAI. */
25
+ manifestOrigin?: string;
26
+ adPreload: string;
27
+ adInsertion: string;
28
+ chaining: {
29
+ enabled: boolean;
30
+ maxGapSeconds: number;
31
+ };
32
+ tuneIn: {
33
+ enabled: boolean;
34
+ minBreakDurationSeconds: number;
35
+ };
36
+ /** Proactive pre-break warning configuration, if supplied. */
37
+ breakWarnings?: {
38
+ seconds: number[];
39
+ };
40
+ /** How PTS-timebase break starts are resolved (`mediaTime` or `anvatoCue`). */
41
+ ptsSource?: PtsSource;
42
+ /** Whether eligible replacement breaks may keep content playing. */
43
+ continueContentDuringBreak?: boolean;
44
+ gam?: {
45
+ /** CONFIGURED network code, `ssai` only; in `sgai` the identity is manifest-authored (`DA-GAM-CONFIG-RESOLVED`). */
46
+ networkCode?: string;
47
+ /** Whether any asset parameters were supplied for this session; values are omitted, only presence is reported. */
48
+ hasAssetParameters: boolean;
49
+ streamActivityMonitorId?: string | undefined;
50
+ } | undefined;
51
+ /** SSAI stitcher summary — present only in `ssai` mode. */
52
+ ssai?: {
53
+ /** Origin of the stitcher master URL — same redaction as manifestOrigin. */
54
+ stitcherOrigin?: string;
55
+ maxBitrate?: number | undefined;
56
+ autoplay: boolean;
57
+ } | undefined;
58
+ }
59
+ /** Self-contained, redacted report for a support engineer or the troubleshooting agent. @category Diagnostics */
60
+ export interface DiagnosticReport {
61
+ /** SDK version that produced the report. */
62
+ sdkVersion: string;
63
+ /** Unix epoch milliseconds when the report was generated. */
64
+ generatedAt: number;
65
+ /** Browser/runtime user agent, or null when unavailable. */
66
+ userAgent: string | null;
67
+ /** Redacted configuration summary. */
68
+ config: ConfigSummary;
69
+ /** Recent diagnostics and SDK-event timeline, oldest first. */
70
+ diagnostics: DiagnosticEvent[];
71
+ }
@@ -0,0 +1 @@
1
+ export{};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Internal sink for core's debug-gated `log()` helpers.
3
+ *
4
+ * Call sites keep their own debug gating. This single console sink is
5
+ * deliberately not exported from any package entry point, so it adds no
6
+ * public API surface.
7
+ */
8
+ export declare function debugLog(scope: string, ...args: unknown[]): void;
@@ -0,0 +1 @@
1
+ export function debugLog(o,...e){console.log(o,...e)}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Stable diagnostic taxonomy for the OptiViewAds SDK.
3
+ *
4
+ * Each code is a stable, machine-readable identifier that maps a runtime
5
+ * condition to a category and severity. Codes are consumed by:
6
+ * - the structured diagnostic stream (`OptiViewAds.onDiagnostic`),
7
+ * - `OptiViewAds.exportDiagnostics()` reports,
8
+ * - the `@dolby-optiview/ads-sdk-mcp` troubleshooting tools and their knowledge base.
9
+ *
10
+ * Codes are part of the public contract: do not rename or repurpose an existing
11
+ * code. Add new codes instead. The catalog itself ({@link DIAGNOSTIC_CODES}) is
12
+ * GENERATED from the language-neutral source of truth at
13
+ * `taxonomy/diagnostic-codes.json` (shared with the Kotlin/Swift cores); the
14
+ * human-readable docs in `packages/sdk/ai/reference/error-codes.md` derive from it.
15
+ * Edit the JSON source and run `npm run gen:taxonomy`, not this file.
16
+ */
17
+ import { DIAGNOSTIC_CODES } from '../generated/diagnosticCodes';
18
+ export { DIAGNOSTIC_CODES };
19
+ /**
20
+ * Functional area a diagnostic relates to.
21
+ * @category Diagnostics */
22
+ export type DiagnosticCategory = 'manifest' | 'session' | 'break' | 'preload' | 'gam' | 'playback' | 'chaining' | 'event' | 'lifecycle';
23
+ /**
24
+ * Severity of a diagnostic record.
25
+ * @category Diagnostics */
26
+ export type DiagnosticLevel = 'debug' | 'info' | 'warn' | 'error';
27
+ /**
28
+ * Static metadata describing a diagnostic code.
29
+ * @category Diagnostics */
30
+ export interface DiagnosticCodeInfo {
31
+ /** Functional area. */
32
+ category: DiagnosticCategory;
33
+ /** Default severity for this code. */
34
+ level: DiagnosticLevel;
35
+ /** One-line human summary of what the code means. */
36
+ summary: string;
37
+ }
38
+ /**
39
+ * Union of all known, statically-typed diagnostic codes.
40
+ * @category Diagnostics */
41
+ export type KnownDiagnosticCode = keyof typeof DIAGNOSTIC_CODES;
42
+ /**
43
+ * Look up the metadata for a known diagnostic code.
44
+ */
45
+ export declare function getDiagnosticCodeInfo(code: KnownDiagnosticCode): DiagnosticCodeInfo;
@@ -0,0 +1 @@
1
+ import{DIAGNOSTIC_CODES as o}from"../generated/diagnosticCodes";export{o as DIAGNOSTIC_CODES};export function getDiagnosticCodeInfo(e){return o[e]}
@@ -0,0 +1,6 @@
1
+ export type { DiagnosticEvent, DiagnosticHandler, DiagnosticReport, ConfigSummary, } from './DiagnosticEvent';
2
+ export type { DiagnosticCategory, DiagnosticLevel, DiagnosticCodeInfo, KnownDiagnosticCode, } from './errorCodes';
3
+ export { DIAGNOSTIC_CODES, getDiagnosticCodeInfo } from './errorCodes';
4
+ export { DiagnosticBuffer, DEFAULT_DIAGNOSTIC_BUFFER_SIZE } from './DiagnosticBuffer';
5
+ export { SDK_VERSION } from '../generated/version';
6
+ export { playbackErrorContext } from './playbackErrorContext';
@@ -0,0 +1 @@
1
+ export{DIAGNOSTIC_CODES,getDiagnosticCodeInfo}from"./errorCodes";export{DiagnosticBuffer,DEFAULT_DIAGNOSTIC_BUFFER_SIZE}from"./DiagnosticBuffer";export{SDK_VERSION}from"../generated/version";export{playbackErrorContext}from"./playbackErrorContext";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Structured detail for `DA-CONTENT-PLAYBACK-ERROR` / ad playback errors.
3
+ *
4
+ * The diagnostic used to carry the error's message and nothing else, and on every platform
5
+ * that message is the CATEGORY, not the cause: a media3 `PlaybackException` stringifies to
6
+ * "Source error", a `MediaError` to a terse browser string. Whoever is reading a failed run
7
+ * needs the next layer down — the HTTP status, the host that refused, the decoder that gave
8
+ * up — and it is one dereference away at the point the diagnostic is raised.
9
+ *
10
+ * That gap cost a real investigation: an intermittent BrowserStack failure produced
11
+ * `ERROR DA-CONTENT-PLAYBACK-ERROR` with no reason attached, while a neighbouring diagnostic
12
+ * (which happened to format its own message) named the unreachable host and port outright.
13
+ *
14
+ * Deliberately structural, not player-specific: the core drives a `PlayerAdapter` and must
15
+ * not depend on any one player's types. Everything here comes from the shape an error
16
+ * already has — a code, a name, a cause chain.
17
+ */
18
+ /**
19
+ * Flattens a playback error into diagnostic context. Never throws and never returns
20
+ * undefined keys — a diagnostic raised on an error path must not fail on the error.
21
+ */
22
+ export declare function playbackErrorContext(mediaError: unknown): Record<string, unknown>;
@@ -0,0 +1 @@
1
+ const e={1:"MEDIA_ERR_ABORTED",2:"MEDIA_ERR_NETWORK",3:"MEDIA_ERR_DECODE",4:"MEDIA_ERR_SRC_NOT_SUPPORTED"},t=new Set(["server","via","x-served-by","x-cache","x-cache-hits","x-cache-status","x-proxy","cf-ray","cf-cache-status","x-amz-cf-pop","x-amz-request-id","x-fastly-request-id","x-akamai-request-id","x-envoy-upstream-service-time","x-geo-country","x-country-code","cf-ipcountry","x-error","x-error-message","x-ratelimit-remaining","retry-after","www-authenticate","content-type","age","x-request-id","x-trace-id","location"]);function r(e){const r={},o=e.response??{},s=e.url??e.uri??o.url;"string"==typeof s&&s&&(r.url=s);const n=e.networkDetails??o.networkDetails??{},a=e.responseURL??o.responseURL??n.responseURL??e.finalUrl;"string"==typeof a&&a&&a!==r.url&&(r.finalUrl=a);const c=o.code??o.status??e.status??e.httpStatus;"number"==typeof c&&(r.httpStatus=c);const i=o.headers??e.headers??e.responseHeaders,u={};if(i&&"object"==typeof i)for(const[e,r]of Object.entries(i))!t.has(e.toLowerCase())||"string"!=typeof r&&"number"!=typeof r||(u[e.toLowerCase()]=String(r));const p=Object.entries(u).map(([e,t])=>`${e}=${t}`);return p.length&&(r.responseHeaders=p.join("; ").slice(0,400)),r}export function playbackErrorContext(t){const o={};if(null==t)return o;const s=t;"number"==typeof s.code?(o.errorCode=s.code,e[s.code]&&(o.errorName=e[s.code])):"string"==typeof s.code&&s.code&&(o.errorCode=s.code),"string"==typeof s.name&&s.name&&"Error"!==s.name&&(o.errorType=s.name);const n=[];let a=s.cause;for(let e=0;e<3&&a;e++){const e=a,t="string"==typeof e.name&&e.name?e.name:void 0,r="string"==typeof e.message?e.message:String(a);n.push(t?`${t}: ${r}`:r),a=e.cause}n.length&&(o.cause=n.join(" <- "));let c=t;for(let e=0;e<=3&&c;e++){if("object"==typeof c){const e=r(c);if(Object.keys(e).length){Object.assign(o,e);break}}c=c.cause}return o}