@videts/vide 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vide contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,276 @@
1
+ # vide
2
+
3
+ Modular video player library. Use only what you need.
4
+
5
+ ```ts
6
+ import { createPlayer } from "@videts/vide";
7
+ import { vast } from "@videts/vide/vast";
8
+ import { hls } from "@videts/vide/hls";
9
+
10
+ const player = createPlayer(document.querySelector("video")!);
11
+ player.use(hls());
12
+ player.use(vast({ tagUrl: "https://example.com/vast.xml" }));
13
+ ```
14
+
15
+ | Plugin | What | gzip |
16
+ |--------|------|-----:|
17
+ | `@videts/vide` | Core player | 1.7 KB |
18
+ | `@videts/vide/vast` | VAST 4.2 ads | 1.5 KB |
19
+ | `@videts/vide/vmap` | VMAP scheduling | 2.6 KB |
20
+ | `@videts/vide/hls` | HLS streaming | 0.6 KB |
21
+ | `@videts/vide/dash` | DASH streaming | 0.6 KB |
22
+ | `@videts/vide/drm` | DRM (Widevine + FairPlay) | 0.8 KB |
23
+ | `@videts/vide/ssai` | SSAI (server-side ads) | 1.4 KB |
24
+ | `@videts/vide/omid` | Open Measurement | 1.7 KB |
25
+ | `@videts/vide/simid` | Interactive ads | 2.4 KB |
26
+ | `@videts/vide/ui` | Headless UI | 4.7 KB |
27
+ | `@videts/vide/ui/theme.css` | Default theme | 3.4 KB |
28
+
29
+ > HLS and DASH plugins require `hls.js` and `dashjs` as peer dependencies.
30
+
31
+ Zero config. No data attributes. No class scanning. No side effects.
32
+ Web standards first — if the browser can do it, we don't reinvent it.
33
+
34
+ ## Install
35
+
36
+ ```sh
37
+ npm install @videts/vide
38
+ ```
39
+
40
+ > Package is published as **@videts/vide** on npm. The project name is **vide**.
41
+
42
+ ## Quick Start
43
+
44
+ ```ts
45
+ import { createPlayer } from "@videts/vide";
46
+ // import type { PlayerEventMap } from "@videts/vide";
47
+
48
+ const player = createPlayer(document.querySelector("video")!);
49
+
50
+ // HTMLVideoElement-compatible — play, pause, src, currentTime, … all proxied
51
+ player.play();
52
+ // player.pause();
53
+ // player.src = "video.mp4";
54
+ // player.currentTime = 30;
55
+
56
+ // player.el — direct access to the underlying <video> element
57
+ // player.el.requestPictureInPicture();
58
+
59
+ // player.on() — typed custom events (statechange, ad:start, error, …)
60
+ player.on("statechange", ({ from, to }) => console.log(`${from} → ${to}`));
61
+ // player.on("volumechange", (e) => console.log(e.target)); // native events too
62
+
63
+ // addEventListener() delegates directly to the <video> element
64
+ // player.addEventListener("canplay", () => { ... });
65
+ ```
66
+
67
+ ## Plugins
68
+
69
+ Plugins are explicit opt-in. Import only what you need.
70
+
71
+ ### HLS Streaming
72
+
73
+ ```sh
74
+ npm install hls.js
75
+ ```
76
+
77
+ ```ts
78
+ import { createPlayer } from "@videts/vide";
79
+ import { hls } from "@videts/vide/hls";
80
+
81
+ const player = createPlayer(document.querySelector("video")!);
82
+ player.use(hls());
83
+
84
+ player.src = "https://example.com/stream.m3u8";
85
+ ```
86
+
87
+ ```ts
88
+ // Pass config directly to hls.js constructor
89
+ player.use(hls({ hlsConfig: { maxBufferLength: 60 } }));
90
+ ```
91
+
92
+ ### DASH Streaming
93
+
94
+ ```sh
95
+ npm install dashjs
96
+ ```
97
+
98
+ ```ts
99
+ import { createPlayer } from "@videts/vide";
100
+ import { dash } from "@videts/vide/dash";
101
+
102
+ const player = createPlayer(document.querySelector("video")!);
103
+ player.use(dash());
104
+
105
+ player.src = "https://example.com/stream.mpd";
106
+ ```
107
+
108
+ ```ts
109
+ // Pass settings directly to dashjs.updateSettings()
110
+ player.use(dash({ dashConfig: { streaming: { buffer: { bufferTimeDefault: 20 } } } }));
111
+ ```
112
+
113
+ ### DRM
114
+
115
+ Widevine (Chrome/Firefox/Edge) and FairPlay (Safari/iOS). The plugin detects the browser's key system automatically — just pass the license server URL.
116
+
117
+ ```ts
118
+ import { createPlayer } from "@videts/vide";
119
+ import { hls } from "@videts/vide/hls";
120
+ import { drm } from "@videts/vide/drm";
121
+
122
+ const player = createPlayer(document.querySelector("video")!);
123
+ player.use(hls());
124
+ player.use(drm({
125
+ widevine: {
126
+ licenseUrl: "https://license.example.com/widevine",
127
+ },
128
+ fairplay: {
129
+ licenseUrl: "https://license.example.com/fairplay",
130
+ certificateUrl: "https://certificate.example.com/fairplay.cer",
131
+ },
132
+ }));
133
+
134
+ player.src = "https://example.com/encrypted-stream.m3u8";
135
+ ```
136
+
137
+ Works with both HLS and DASH — plugin order doesn't matter.
138
+
139
+ ```ts
140
+ // Custom headers for license requests (e.g. auth tokens)
141
+ player.use(drm({
142
+ widevine: {
143
+ licenseUrl: "https://license.example.com/widevine",
144
+ headers: { Authorization: "Bearer <token>" },
145
+ },
146
+ }));
147
+ ```
148
+
149
+ ### SSAI (Server-Side Ad Insertion)
150
+
151
+ Detects ad breaks from HLS/DASH in-band metadata and fires standard ad events. No vendor SDK required.
152
+
153
+ ```ts
154
+ import { createPlayer } from "@videts/vide";
155
+ import { hls } from "@videts/vide/hls";
156
+ import { ssai } from "@videts/vide/ssai";
157
+
158
+ const player = createPlayer(document.querySelector("video")!);
159
+ player.use(hls());
160
+ player.use(ssai());
161
+
162
+ player.on("ad:start", ({ adId }) => console.log("ad started", adId));
163
+ player.on("ad:end", ({ adId }) => console.log("ad ended", adId));
164
+
165
+ player.src = "https://example.com/ssai-stream.m3u8";
166
+ ```
167
+
168
+ ```ts
169
+ // Custom parser for vendor-specific metadata formats
170
+ player.use(ssai({
171
+ parser(raw) {
172
+ if (raw.source === "daterange" && raw.attributes["X-MY-AD"] === "true") {
173
+ return [{
174
+ id: raw.attributes.ID,
175
+ startTime: new Date(raw.attributes["START-DATE"]).getTime() / 1000,
176
+ duration: Number(raw.attributes.DURATION || 0),
177
+ trackingUrls: [raw.attributes["X-TRACKING-URL"]].filter(Boolean),
178
+ }];
179
+ }
180
+ return [];
181
+ },
182
+ }));
183
+ ```
184
+
185
+ ### UI
186
+
187
+ Headless by default — JS creates DOM and wires behavior, styling is yours.
188
+ Import `theme.css` for a ready-made look, or target the BEM classes (`vide-play`, `vide-progress__bar`, …) yourself.
189
+
190
+ ```ts
191
+ import { createPlayer } from "@videts/vide";
192
+ import { ui } from "@videts/vide/ui";
193
+ import "@videts/vide/ui/theme.css"; // optional — brings default skin
194
+
195
+ const player = createPlayer(document.querySelector("video")!);
196
+ player.use(ui({ container: document.getElementById("player-container")! }));
197
+ ```
198
+
199
+ ```ts
200
+ // exclude: play, progress, time, volume, fullscreen, loader, error,
201
+ // bigplay, poster, keyboard, clickplay, autohide,
202
+ // ad-countdown, ad-skip, ad-overlay, ad-label
203
+ player.use(ui({
204
+ container: el,
205
+ exclude: ["volume", "fullscreen"],
206
+ poster: "https://example.com/poster.jpg",
207
+ }));
208
+ ```
209
+
210
+ Components can also be used individually:
211
+
212
+ ```ts
213
+ import { createPlayButton, createProgress } from "@videts/vide/ui";
214
+
215
+ const play = createPlayButton();
216
+ play.mount(controls);
217
+ play.connect(player);
218
+ ```
219
+
220
+ #### UI + VAST Ads
221
+
222
+ ```ts
223
+ import { ui } from "@videts/vide/ui";
224
+ import { vast } from "@videts/vide/vast";
225
+
226
+ // UI plugin provides ad components (countdown, skip, overlay, label)
227
+ // that integrate with VAST playback via getAdPlugin()
228
+ const uiPlugin = ui({ container: el });
229
+ player.use(uiPlugin);
230
+ player.use(vast({
231
+ tagUrl: "https://example.com/vast.xml",
232
+ adPlugins: uiPlugin.getAdPlugin(),
233
+ }));
234
+ ```
235
+
236
+ ### VAST Ads
237
+
238
+ ```ts
239
+ import { vast } from "@videts/vide/vast";
240
+ player.use(vast({ tagUrl: "https://example.com/vast.xml" }));
241
+ ```
242
+
243
+ ### VMAP Ad Scheduling
244
+
245
+ ```ts
246
+ import { vmap } from "@videts/vide/vmap";
247
+ player.use(vmap({ vmapUrl: "https://example.com/vmap.xml" }));
248
+ ```
249
+
250
+ ### OMID Viewability
251
+
252
+ ```ts
253
+ import { vast } from "@videts/vide/vast";
254
+ import { omid } from "@videts/vide/omid";
255
+
256
+ player.use(vast({
257
+ tagUrl: "https://example.com/vast.xml",
258
+ adPlugins: () => [omid({ partner: { name: "your-company", version: "1.0.0" } })],
259
+ }));
260
+ ```
261
+
262
+ ### SIMID Interactive Ads
263
+
264
+ ```ts
265
+ import { vast } from "@videts/vide/vast";
266
+ import { simid } from "@videts/vide/simid";
267
+
268
+ player.use(vast({
269
+ tagUrl: "https://example.com/vast.xml",
270
+ adPlugins: () => [simid({ container: document.getElementById("ad-container")! })],
271
+ }));
272
+ ```
273
+
274
+ ## License
275
+
276
+ MIT
@@ -0,0 +1 @@
1
+ function C(e){let r=new DOMParser().parseFromString(e,"text/xml");if(r.querySelector("parsererror"))return {version:"",ads:[],errors:["VAST XML parse error"]};let n=r.documentElement;if(n.tagName!=="VAST")return {version:"",ads:[],errors:["Document is not a VAST response"]};let s=n.getAttribute("version")??"",o=A(n,"Error"),a=g(n,"Ad"),c=[];for(let l of a){let u=S(l);u&&c.push(u);}return {version:s,ads:c,errors:o}}function S(e){let t=T(e,"InLine");if(!t)return null;let r=e.getAttribute("id")??"",i=e.getAttribute("sequence"),n=m(i,void 0),s=v(t,"AdSystem"),o=v(t,"AdTitle"),a=k(t,"Impression"),c=A(t,"Error"),l=t.querySelector("Creatives"),u=[];if(l){let d=g(l,"Creative");for(let E of d)u.push(N(E));}let f=x(t),p=F(t);return {id:r,sequence:n,adSystem:s,adTitle:o,impressions:a,creatives:u,errors:c,verifications:f,categories:p}}function x(e){let t=e.querySelector("AdVerifications");if(!t)return;let r=[],i=g(t,"Verification");for(let n of i){let s=n.getAttribute("vendor")??"",o="",a,c=n.querySelector("JavaScriptResource");if(c)o=(c.textContent??"").trim(),a=c.getAttribute("apiFramework")??void 0;else {let f=n.querySelector("ExecutableResource");f&&(o=(f.textContent??"").trim(),a=f.getAttribute("apiFramework")??void 0);}let l=n.querySelector("VerificationParameters"),u=l&&(l.textContent??"").trim()||void 0;r.push({vendor:s,resourceUrl:o,apiFramework:a,parameters:u});}return r.length>0?r:void 0}function F(e){let t=g(e,"Category");if(t.length===0)return;let r=[];for(let i of t){let n=i.getAttribute("authority")??"",s=(i.textContent??"").trim();s&&r.push({authority:n,value:s});}return r.length>0?r:void 0}function N(e){let t=e.getAttribute("id")??void 0,r=e.getAttribute("sequence"),i=m(r,void 0),n=e.querySelector("Linear"),s=n?w(n):null;return {id:t,sequence:i,linear:s}}function w(e){let t=v(e,"Duration"),r=b(t),i=e.getAttribute("skipoffset"),n=i!==null?y(i,r):void 0,s=q(e),o=I(e),a=V(e),c=e.querySelector("VideoClicks"),l=c&&v(c,"ClickThrough")||void 0,u=c?k(c,"ClickTracking"):[];return {duration:r,skipOffset:n,mediaFiles:s,interactiveCreativeFiles:o,trackingEvents:a,clickThrough:l,clickTracking:u}}function q(e){let t=e.querySelector("MediaFiles");if(!t)return [];let r=[],i=g(t,"MediaFile");for(let n of i){let s=(n.textContent??"").trim();if(!s)continue;let o=n.getAttribute("delivery");r.push({url:s,mimeType:n.getAttribute("type")??"",width:m(n.getAttribute("width"),0),height:m(n.getAttribute("height"),0),bitrate:m(n.getAttribute("bitrate"),void 0),delivery:o==="streaming"?"streaming":"progressive"});}return r}function I(e){let t=e.querySelector("MediaFiles");if(!t)return [];let r=[],i=g(t,"InteractiveCreativeFile");for(let n of i){let s=(n.textContent??"").trim();if(!s)continue;let o=n.getAttribute("apiFramework")??"",a=n.getAttribute("variableDuration"),c=a==="true"?true:a==="false"?false:void 0;r.push({url:s,apiFramework:o,variableDuration:c});}return r}var M=new Set(["start","firstQuartile","midpoint","thirdQuartile","complete","pause","resume","skip","loaded","mute","unmute","rewind","playerExpand","playerCollapse","closeLinear","notUsed","otherAdInteraction","creativeView"]);function V(e){let t=h(),r=e.querySelector("TrackingEvents");if(!r)return t;let i=r.querySelectorAll("Tracking");for(let n of i){let s=n.getAttribute("event"),o=(n.textContent??"").trim();if(!(!s||!o))if(s==="progress"){let a=n.getAttribute("offset"),c=a?y(a,0):0;t.progress.push({offset:c,url:o});}else M.has(s)&&t[s].push(o);}return t}function b(e){if(!e)return 0;let t=e.split(":");if(t.length!==3)return 0;let r=Number.parseInt(t[0],10),i=Number.parseInt(t[1],10),n=Number.parseFloat(t[2]);return Number.isNaN(r)||Number.isNaN(i)||Number.isNaN(n)?0:r*3600+i*60+n}function y(e,t){if(e.endsWith("%")){let r=Number.parseFloat(e);return Number.isNaN(r)?0:r/100*t}return b(e)}function g(e,t){let r=[];for(let i=0;i<e.children.length;i++)e.children[i].tagName===t&&r.push(e.children[i]);return r}function T(e,t){for(let r=0;r<e.children.length;r++)if(e.children[r].tagName===t)return e.children[r];return null}function A(e,t){let r=[];for(let i of g(e,t)){let n=(i.textContent??"").trim();n&&r.push(n);}return r}function v(e,t){let r=e.querySelector(t);return r?(r.textContent??"").trim():""}function k(e,t){let r=e.querySelectorAll(t),i=[];for(let n of r){let s=(n.textContent??"").trim();s&&i.push(s);}return i}async function D(e,t){let r=t?.timeout??5e3,i=new AbortController,n=setTimeout(()=>i.abort(),r);try{let s=await fetch(e,{signal:i.signal});if(!s.ok)throw new Error(`VAST fetch failed: ${s.status}`);return await s.text()}finally{clearTimeout(n);}}async function U(e,t){let r=t?.timeout??1e4,i=t?.maxDepth??5,n=Date.now()+r,s=new Set,o=[],a=e;for(let c=0;c<=i;c++){let l=n-Date.now();if(l<=0)return {version:"",ads:[],errors:["VAST resolve timeout"]};if(s.has(a))return {version:"",ads:[],errors:["VAST circular reference detected"]};s.add(a);let u;try{u=await D(a,{timeout:l});}catch(d){return {version:"",ads:[],errors:[d instanceof Error?d.message:String(d)]}}let f=C(u);if(f.ads.length>0)return {version:f.version,ads:f.ads.map(d=>O(d,o)),errors:f.errors};let p=R(u);if(!p)return f;o.push(p),a=p.adTagUri;}return {version:"",ads:[],errors:["VAST wrapper depth limit exceeded"]}}function R(e){let i=new DOMParser().parseFromString(e,"text/xml").documentElement;if(i.tagName!=="VAST")return null;for(let n of g(i,"Ad")){let s=T(n,"Wrapper");if(!s)continue;let o=v(s,"VASTAdTagURI").trim();if(!o)continue;let a=A(s,"Error"),c=k(s,"Impression"),l=h(),u=[],f=s.querySelector("Creatives");if(f)for(let p of g(f,"Creative")){let d=p.querySelector("Linear");if(d){l=V(d);let E=d.querySelector("VideoClicks");E&&(u=k(E,"ClickTracking"));break}}return {adTagUri:o,errors:a,impressions:c,trackingEvents:l,clickTracking:u}}return null}function h(){return {start:[],firstQuartile:[],midpoint:[],thirdQuartile:[],complete:[],pause:[],resume:[],skip:[],loaded:[],mute:[],unmute:[],rewind:[],playerExpand:[],playerCollapse:[],closeLinear:[],notUsed:[],otherAdInteraction:[],creativeView:[],progress:[]}}function L(e,t){let r=h();for(let i of Object.keys(r)){if(i==="progress")continue;let n=r[i];for(let s of e)n.push(...s[i]);n.push(...t[i]);}for(let i of e)r.progress.push(...i.progress);return r.progress.push(...t.progress),r}function O(e,t){if(t.length===0)return e;let r=[...t.flatMap(s=>s.errors),...e.errors],i=[...t.flatMap(s=>s.impressions),...e.impressions],n=e.creatives.map(s=>s.linear?{...s,linear:{...s.linear,trackingEvents:L(t.map(o=>o.trackingEvents),s.linear.trackingEvents),clickTracking:[...t.flatMap(o=>o.clickTracking),...s.linear.clickTracking]}}:s);return {...e,errors:r,impressions:i,creatives:n}}function m(e,t){if(e==null)return t;let r=Number.parseInt(e,10);return Number.isNaN(r)?t:r}export{C as a,D as b,U as c};
@@ -0,0 +1 @@
1
+ function c(r){for(let e of r)typeof navigator<"u"&&typeof navigator.sendBeacon=="function"?navigator.sendBeacon(e):new Image().src=e;}function f(r,e){if(e<=0)return null;let t=r/e;return t>=1?"complete":t>=.75?"thirdQuartile":t>=.5?"midpoint":t>=.25?"firstQuartile":r>=0?"start":null}function s(r,e){let t=new Set,o=["start","firstQuartile","midpoint","thirdQuartile","complete"];return a=>{let n=f(a,r);if(!n||t.has(n))return;let l=o.indexOf(n);for(let i=0;i<=l;i++){let u=o[i];t.has(u)||(t.add(u),e(u));}}}export{c as a,f as b,s as c};
@@ -0,0 +1,11 @@
1
+ import { e as Plugin } from '../types-BxRa9Jvl.js';
2
+
3
+ interface DashPluginOptions {
4
+ /** dash.js MediaPlayerSettingClass — passed to updateSettings(). */
5
+ dashConfig?: Record<string, unknown> | undefined;
6
+ }
7
+
8
+ /** Create a DASH streaming plugin for vide. */
9
+ declare function dash(options?: DashPluginOptions): Plugin;
10
+
11
+ export { type DashPluginOptions, dash };
@@ -0,0 +1,2 @@
1
+ var h="application/dash+xml";function m(t){try{return new URL(t,"https://placeholder.invalid").pathname.endsWith(".mpd")}catch{return t.includes(".mpd")}}function f(t){return t.toLowerCase()===h}function p(t={}){return {name:"dash",setup(e){let o=null,d=false,l={canHandle(r,n){return n&&f(n)?true:m(r)},load(r,n){this.unload(n),g(r,n);},unload(r){o&&(o.destroy(),o=null);}};function g(r,n){import('dashjs').then(s=>{if(d)return;let u=s.default,a=u.MediaPlayer().create();o=a,e.setPluginData("dash",a);let c=e.getPluginData("drm");c?.dashConfig&&a.updateSettings(c.dashConfig),t.dashConfig&&a.updateSettings(t.dashConfig),a.on(u.MediaPlayer.events.ERROR,i=>{typeof i.error=="object"&&i.error!==null?e.emit("error",{code:i.error.code,message:i.error.message}):e.emit("error",{code:0,message:`DASH error: ${String(i.error)}`});}),a.initialize(n,r,n.autoplay);}).catch(s=>{d||e.emit("error",{code:0,message:s instanceof Error?`Failed to load dashjs: ${s.message}`:"Failed to load dashjs"});});}return e.registerSourceHandler(l),()=>{d=true,l.unload(e.el);}}}}
2
+ export{p as dash};
@@ -0,0 +1,51 @@
1
+ import { e as Plugin } from '../types-BxRa9Jvl.js';
2
+
3
+ /** Widevine DRM configuration. */
4
+ interface WidevineConfig {
5
+ licenseUrl: string;
6
+ headers?: Record<string, string> | undefined;
7
+ prepareLicenseRequest?: ((payload: Uint8Array) => Uint8Array | Promise<Uint8Array>) | undefined;
8
+ processLicenseResponse?: ((response: Uint8Array) => Uint8Array | Promise<Uint8Array>) | undefined;
9
+ }
10
+ /** FairPlay DRM configuration. */
11
+ interface FairPlayConfig {
12
+ licenseUrl: string;
13
+ certificateUrl: string;
14
+ headers?: Record<string, string> | undefined;
15
+ prepareLicenseRequest?: ((payload: Uint8Array) => Uint8Array | Promise<Uint8Array>) | undefined;
16
+ processLicenseResponse?: ((response: Uint8Array) => Uint8Array | Promise<Uint8Array>) | undefined;
17
+ }
18
+ /** Options for the DRM plugin. */
19
+ interface DrmPluginOptions {
20
+ widevine?: WidevineConfig | undefined;
21
+ fairplay?: FairPlayConfig | undefined;
22
+ }
23
+ /** Key system identifier string. */
24
+ type KeySystem = "com.widevine.alpha" | "com.apple.fps.1_0";
25
+ /** Resolved DRM configuration stored via setPluginData("drm"). */
26
+ interface ResolvedDrmConfig {
27
+ keySystem: KeySystem;
28
+ hlsConfig: Record<string, unknown>;
29
+ dashConfig: Record<string, unknown>;
30
+ }
31
+
32
+ /**
33
+ * Detect the first supported key system from the given candidates.
34
+ * Returns the KeySystem string, or null if none are supported.
35
+ */
36
+ declare function detectKeySystem(candidates: KeySystem[]): Promise<KeySystem | null>;
37
+
38
+ interface BridgeInput {
39
+ keySystem: KeySystem;
40
+ widevine?: WidevineConfig | undefined;
41
+ fairplay?: FairPlayConfig | undefined;
42
+ }
43
+ /** Generate hls.js config fragment from resolved DRM info. */
44
+ declare function hlsDrmConfig(input: BridgeInput): Record<string, unknown>;
45
+ /** Generate dash.js settings fragment from resolved DRM info. */
46
+ declare function dashDrmConfig(input: BridgeInput): Record<string, unknown>;
47
+
48
+ /** Create a DRM plugin for vide. */
49
+ declare function drm(options: DrmPluginOptions): Plugin;
50
+
51
+ export { type DrmPluginOptions, type FairPlayConfig, type KeySystem, type ResolvedDrmConfig, type WidevineConfig, dashDrmConfig, detectKeySystem, drm, hlsDrmConfig };
@@ -0,0 +1 @@
1
+ function f(e){let r={licenseUrl:e.licenseUrl,serverCertificateUrl:e.certificateUrl};if(e.headers){let n=e.headers;r.licenseXhrSetup=t=>{for(let[i,o]of Object.entries(n))t.setRequestHeader(i,o);};}return {emeEnabled:true,drmSystems:{"com.apple.fps.1_0":r}}}function m(e){let r={serverURL:e.licenseUrl,serverCertificateURL:e.certificateUrl};return e.headers&&(r.httpRequestHeaders=e.headers),{streaming:{protection:{data:{"com.apple.fps.1_0":r}}}}}function p(e){let r={licenseUrl:e.licenseUrl};if(e.headers){let n=e.headers;r.licenseXhrSetup=t=>{for(let[i,o]of Object.entries(n))t.setRequestHeader(i,o);};}return {emeEnabled:true,drmSystems:{"com.widevine.alpha":r}}}function y(e){let r={serverURL:e.licenseUrl};return e.headers&&(r.httpRequestHeaders=e.headers),{streaming:{protection:{data:{"com.widevine.alpha":r}}}}}function s(e){return e.keySystem==="com.widevine.alpha"&&e.widevine?p(e.widevine):e.keySystem==="com.apple.fps.1_0"&&e.fairplay?f(e.fairplay):{}}function a(e){return e.keySystem==="com.widevine.alpha"&&e.widevine?y(e.widevine):e.keySystem==="com.apple.fps.1_0"&&e.fairplay?m(e.fairplay):{}}var l="com.apple.fps.1_0",u=[{initDataTypes:["cenc"],videoCapabilities:[{contentType:'video/mp4;codecs="avc1.42E01E"'}]}],g=[{initDataTypes:["sinf"],videoCapabilities:[{contentType:'video/mp4;codecs="avc1.42E01E"'}]}];async function d(e){for(let r of e)try{let n=r===l?g:u;return await navigator.requestMediaKeySystemAccess(r,n),r}catch{}return null}function k(e){return {name:"drm",setup(r){let n=false,t=[];return e.widevine&&t.push("com.widevine.alpha"),e.fairplay&&t.push("com.apple.fps.1_0"),t.length===0?(console.warn("[vide/drm] No DRM configuration provided"),()=>{}):(d(t).then(i=>{if(n)return;if(!i){r.emit("error",{code:0,message:"No supported DRM key system found"});return}let o={keySystem:i,widevine:e.widevine,fairplay:e.fairplay},c={keySystem:i,hlsConfig:s(o),dashConfig:a(o)};r.setPluginData("drm",c);}).catch(i=>{n||r.emit("error",{code:0,message:i instanceof Error?`DRM detection failed: ${i.message}`:"DRM detection failed"});}),()=>{n=true;})}}}export{a as dashDrmConfig,d as detectKeySystem,k as drm,s as hlsDrmConfig};
@@ -0,0 +1,11 @@
1
+ import { e as Plugin } from '../types-BxRa9Jvl.js';
2
+
3
+ interface HlsPluginOptions {
4
+ /** Configuration passed directly to the hls.js constructor. */
5
+ hlsConfig?: Record<string, unknown> | undefined;
6
+ }
7
+
8
+ /** Create an HLS streaming plugin for vide. */
9
+ declare function hls(options?: HlsPluginOptions): Plugin;
10
+
11
+ export { type HlsPluginOptions, hls };
@@ -0,0 +1,2 @@
1
+ var c=["application/vnd.apple.mpegurl","application/x-mpegurl"];function m(e){if(e.startsWith("data:")){let t=e.indexOf(";");return t===-1?false:c.includes(e.slice(5,t).toLowerCase())}if(e.startsWith("blob:"))return e.includes(".m3u8");try{return new URL(e,"https://placeholder.invalid").pathname.endsWith(".m3u8")}catch{return e.includes(".m3u8")}}function h(e){return c.includes(e.toLowerCase())}function L(e={}){return {name:"hls",setup(t){let r=null,a=false,u={canHandle(s,n){return n&&h(n)?true:m(s)},load(s,n){this.unload(n),p(s,n);},unload(s){r&&(r.destroy(),r=null);}};function p(s,n){import('hls.js').then(o=>{if(a)return;let l=o.default;if(!l.isSupported()){if(n.canPlayType("application/vnd.apple.mpegurl")){n.src=s;return}t.emit("error",{code:0,message:"HLS is not supported in this browser"});return}let f=t.getPluginData("drm"),g={...e.hlsConfig??{},...f?.hlsConfig??{}},i=new l(g);r=i,t.setPluginData("hls",i),i.on(l.Events.ERROR,(H,d)=>{d.fatal&&t.emit("error",{code:1,message:`HLS fatal error: ${d.type} - ${d.details}`});}),i.attachMedia(n),i.loadSource(s);}).catch(o=>{a||t.emit("error",{code:0,message:o instanceof Error?`Failed to load hls.js: ${o.message}`:"Failed to load hls.js"});});}return t.registerSourceHandler(u),()=>{a=true,u.unload(t.el);}}}}
2
+ export{L as hls};
@@ -0,0 +1,6 @@
1
+ import { P as Player } from './types-BxRa9Jvl.js';
2
+ export { A as AdQuartile, E as EventBus, a as EventHandler, b as PlayerEvent, c as PlayerEventMap, d as PlayerState, e as Plugin, S as SourceHandler } from './types-BxRa9Jvl.js';
3
+
4
+ declare function createPlayer(el: HTMLVideoElement): Player;
5
+
6
+ export { Player, createPlayer };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var C={idle:["loading","error"],loading:["ready","error"],ready:["playing","loading","ad:loading","error"],playing:["paused","buffering","loading","ad:loading","ended","error"],paused:["playing","loading","ad:loading","ended","error"],buffering:["playing","loading","error"],"ad:loading":["ad:playing","playing","error"],"ad:playing":["ad:paused","playing","error"],"ad:paused":["ad:playing","playing","error"],ended:["idle","loading","error"],error:["idle","loading"]};function D(e,r){return C[e].includes(r)}function K(e){return e.readyState>=3?e.paused?"ready":"playing":e.readyState>=1?"loading":"idle"}function U(e){let r=K(e),g=new Map,v=[],p=false,f=[],i=null,y=e.getAttribute("src")??"",m=false,E=new Map;function b(t){let n=g.get(t);return n||(n=new Set,g.set(t,n)),n}function d(t,n){let a=g.get(t);if(a)for(let l of a)try{l(n);}catch(c){console.error("[vide] Event handler error:",c);}}function o(t){if(t===r)return;if(!D(r,t)){console.warn(`[vide] Invalid transition: ${r} \u2192 ${t}`);return}let n=r;r=t,d("statechange",{from:n,to:t});}function s(){return r==="ad:loading"||r==="ad:playing"||r==="ad:paused"}function S(){s()||o("loading");}function L(){r==="loading"&&o("ready");}function P(){s()||o("playing"),d("play",void 0);}function k(){s()||o("paused"),d("pause",void 0);}function w(){r==="playing"&&o("buffering");}function H(){r==="buffering"&&o("playing");}function h(){s()||o("ended"),d("ended",void 0);}function M(){d("timeupdate",{currentTime:e.currentTime,duration:e.duration});}function T(){let t=e.error;s()||o("error"),d("error",{code:t?.code??0,message:t?.message??"Unknown error"});}e.addEventListener("loadstart",S),e.addEventListener("canplay",L),e.addEventListener("play",P),e.addEventListener("pause",k),e.addEventListener("waiting",w),e.addEventListener("playing",H),e.addEventListener("ended",h),e.addEventListener("timeupdate",M),e.addEventListener("error",T);let O=new Set(["statechange","play","pause","ended","timeupdate","error","ad:start","ad:end","ad:skip","ad:click","ad:error","ad:impression","ad:loaded","ad:quartile","ad:mute","ad:unmute","ad:volumeChange","ad:fullscreen","ad:breakStart","ad:breakEnd","destroy"]);function R(){e.removeEventListener("loadstart",S),e.removeEventListener("canplay",L),e.removeEventListener("play",P),e.removeEventListener("pause",k),e.removeEventListener("waiting",w),e.removeEventListener("playing",H),e.removeEventListener("ended",h),e.removeEventListener("timeupdate",M),e.removeEventListener("error",T);}function A(){if(i||m)return;let t=e.querySelectorAll("source");for(let n of t){let a=n.getAttribute("src"),l=n.getAttribute("type")??void 0;if(a){for(let c of f)if(c.canHandle(a,l)){i=c,y=a,o("loading"),c.load(a,e);for(let j of t)j.remove();return}}}}let u={get el(){return e},get state(){return r},on(t,n){O.has(t)?b(t).add(n):e.addEventListener(t,n);},off(t,n){O.has(t)?b(t).delete(n):e.removeEventListener(t,n);},emit:d,once(t,n){let a=l=>{u.off(t,a),n(l);};u.on(t,a);},play(){return e.play()},pause(){e.pause();},get currentTime(){return e.currentTime},set currentTime(t){e.currentTime=t;},get duration(){return e.duration},set duration(t){},get volume(){return e.volume},set volume(t){e.volume=t;},get muted(){return e.muted},set muted(t){e.muted=t;},get playbackRate(){return e.playbackRate},set playbackRate(t){e.playbackRate=t;},get paused(){return e.paused},get ended(){return e.ended},get readyState(){return e.readyState},get buffered(){return e.buffered},get seekable(){return e.seekable},get seeking(){return e.seeking},get videoWidth(){return e.videoWidth},get videoHeight(){return e.videoHeight},get networkState(){return e.networkState},get loop(){return e.loop},set loop(t){e.loop=t;},get autoplay(){return e.autoplay},set autoplay(t){e.autoplay=t;},get poster(){return e.poster},set poster(t){e.poster=t;},get preload(){return e.preload},set preload(t){e.preload=t;},get defaultPlaybackRate(){return e.defaultPlaybackRate},set defaultPlaybackRate(t){e.defaultPlaybackRate=t;},get defaultMuted(){return e.defaultMuted},set defaultMuted(t){e.defaultMuted=t;},get crossOrigin(){return e.crossOrigin},set crossOrigin(t){e.crossOrigin=t;},get controls(){return e.controls},set controls(t){e.controls=t;},get src(){return y},set src(t){if(i&&(i.unload(e),i=null),m=true,y=t,!t){e.removeAttribute("src");return}for(let n of f)if(n.canHandle(t)){i=n,o("loading"),n.load(t,e);return}e.src=t;},registerSourceHandler(t){if(p){console.warn("[vide] Cannot register source handler after destroy");return}f.push(t),!m&&!i&&A();},addEventListener(t,n,a){e.addEventListener(t,n,a);},removeEventListener(t,n,a){e.removeEventListener(t,n,a);},use(t){if(p){console.warn("[vide] Cannot use plugin after destroy");return}let n=t.setup(u);n&&v.push(n);},setPluginData(t,n){E.set(t,n);},getPluginData(t){return E.get(t)},destroy(){if(!p){p=true,i&&(i.unload(e),i=null);for(let t of v)try{t();}catch(n){console.error("[vide] Plugin cleanup error:",n);}v.length=0,d("destroy",void 0),R(),g.clear(),E.clear();}}};return u._setState=o,u}export{U as createPlayer};
@@ -0,0 +1,25 @@
1
+ import { b as AdPlugin } from '../types-BryM58LE.js';
2
+ import '../types-BxRa9Jvl.js';
3
+
4
+ interface OmidPluginOptions {
5
+ /** Partner identification for the OM SDK. */
6
+ partner: {
7
+ name: string;
8
+ version: string;
9
+ };
10
+ /**
11
+ * URL to the OM SDK service script (omweb-v1.js).
12
+ * Defaults to the Google-hosted release.
13
+ * In production, host the script on your own CDN.
14
+ */
15
+ serviceScriptUrl?: string | undefined;
16
+ /** URL to the OM SDK session client script. If omitted, assumes OmidSessionClient is already global. */
17
+ sessionClientUrl?: string | undefined;
18
+ /** Timeout in ms for loading OM SDK scripts. Defaults to 5000. */
19
+ timeout?: number | undefined;
20
+ }
21
+
22
+ /** Create an OMID (Open Measurement) ad plugin for use with VAST adPlugins. */
23
+ declare function omid(options: OmidPluginOptions): AdPlugin;
24
+
25
+ export { type OmidPluginOptions, omid };
@@ -0,0 +1,2 @@
1
+ function E(e,t,r){let i=true;t.adEvents.loaded(t.vastProperties),t.adEvents.impressionOccurred(),t.mediaEvents.start(r,e.el.muted?0:e.el.volume);function o(n){i&&(n.quartile==="firstQuartile"?t.mediaEvents.firstQuartile():n.quartile==="midpoint"?t.mediaEvents.midpoint():n.quartile==="thirdQuartile"&&t.mediaEvents.thirdQuartile());}function s(n){i&&(n.to==="ad:paused"?t.mediaEvents.pause():n.to==="ad:playing"&&n.from==="ad:paused"&&t.mediaEvents.resume());}function d(){i&&(i=false,t.mediaEvents.complete(),t.finish());}function a(){i&&(i=false,t.mediaEvents.skipped(),t.finish());}function u(){i&&(i=false,t.error("Ad playback error"),t.finish());}function c(){i&&(i=false,t.finish());}function l(n){i&&t.mediaEvents.volumeChange(n.volume);}function p(n){if(!i)return;let v=n.fullscreen?"fullscreen":"normal";t.mediaEvents.playerStateChange(v);}return e.on("ad:quartile",o),e.on("statechange",s),e.on("ad:end",d),e.on("ad:skip",a),e.on("ad:error",u),e.on("destroy",c),e.on("ad:volumeChange",l),e.on("ad:fullscreen",p),()=>{i=false,e.off("ad:quartile",o),e.off("statechange",s),e.off("ad:end",d),e.off("ad:skip",a),e.off("ad:error",u),e.off("destroy",c),e.off("ad:volumeChange",l),e.off("ad:fullscreen",p);}}function w(e,t){return new Promise((r,i)=>{let o=document.createElement("script");o.src=e,o.async=true;let s=setTimeout(()=>{o.remove(),i(new Error(`OM SDK script load timeout: ${e}`));},t);o.onload=()=>{clearTimeout(s),r();},o.onerror=()=>{clearTimeout(s),o.remove(),i(new Error(`OM SDK script load failed: ${e}`));},document.head.appendChild(o);})}function b(){let t=globalThis.OmidSessionClient;if(!t)return null;let r=t.default??t;return typeof r.AdSession!="function"?null:r}async function h(e,t,r){let i=Date.now();if(await w(e,r),t){let s=Date.now()-i,d=Math.max(r-s,1e3);await w(t,d);}let o=b();if(!o)throw new Error("OM SDK namespace not found after script load");return o}function P(e,t,r){let i=new e.Partner(r.partner.name,r.partner.version),o=r.verifications.filter(m=>m.resourceUrl).map(m=>new e.VerificationScriptResource(m.resourceUrl,m.vendor,m.parameters,"full")),s=new e.Context(i,o,r.contentUrl,r.customReferenceData);s.setVideoElement(t);let d=t.parentElement;d&&s.setSlotElement(d),s.setServiceWindow(window);let a=new e.AdSession(s);if(a.setCreativeType("video"),a.setImpressionType("beginToRender"),!a.isSupported())throw new Error("OM SDK session not supported in this environment");let u=false,c=false,l=null;a.registerSessionObserver(m=>{m.type==="sessionStart"&&(u=true,l&&(l(true),l=null));}),a.start();let p=new e.AdEvents(a),n=new e.MediaEvents(a),v=r.position??"standalone",f=r.skipOffset!==void 0,O=r.skipOffset??-1,S=r.isAutoPlay??true,y=new e.VastProperties(f,O,S,v);return {get adEvents(){return p},get mediaEvents(){return n},get vastProperties(){return y},get started(){return u},waitForStart(m){return u?Promise.resolve(true):new Promise(g=>{l=g,setTimeout(()=>{u||(l=null,g(false));},m);})},finish(){c||(c=true,a.finish());},error(m){a.error("video",m);}}}var A="https://pagead2.googlesyndication.com/omsdk/releases/live/omweb-v1.js";function D(e){return {name:"omid",setup(t,r){let i=r.verifications??[];if(i.length===0)return;let o=false,s=null,d=null,a=e.timeout??5e3,u=e.serviceScriptUrl??A,c={...e,serviceScriptUrl:u,verifications:i,skipOffset:r.creatives[0]?.linear?.skipOffset},l=h(u,e.sessionClientUrl,a).catch(n=>n);async function p(){if(!o)try{let n=await l;if(o)return;if(n instanceof Error)throw n;let f=P(n,t.el,c);if(d=f,o){f.finish();return}let O=await f.waitForStart(a);if(o){f.finish();return}if(!O){console.warn("[vide:omid] Session start timed out"),f.finish();return}let S=Number.isFinite(t.el.duration)?t.el.duration:0;s=E(t,f,S);}catch(n){if(o)return;console.warn("[vide:omid] Failed to initialize:",n instanceof Error?n.message:String(n)),t.emit("ad:error",{error:n instanceof Error?n:new Error(String(n))});}}return p(),()=>{o=true,s&&(s(),s=null),d&&(d.finish(),d=null);}}}}
2
+ export{D as omid};
@@ -0,0 +1,26 @@
1
+ import { b as AdPlugin } from '../types-BryM58LE.js';
2
+ import '../types-BxRa9Jvl.js';
3
+
4
+ interface SimidPluginOptions {
5
+ /** Container element to mount the SIMID iframe into. */
6
+ container: HTMLElement;
7
+ /** Request policy overrides. */
8
+ policy?: Partial<SimidRequestPolicy> | undefined;
9
+ /** Handshake timeout in ms. Default: 5000. */
10
+ handshakeTimeout?: number | undefined;
11
+ }
12
+ interface SimidRequestPolicy {
13
+ /** Allow creative to pause media. Default: true. */
14
+ allowPause: boolean;
15
+ /** Allow creative to resume media. Default: true. */
16
+ allowPlay: boolean;
17
+ /** Allow creative to resize ad slot. Default: false. */
18
+ allowResize: boolean;
19
+ /** How to handle requestNavigation. Default: 'new-tab'. */
20
+ navigation: "new-tab" | "deny";
21
+ }
22
+
23
+ /** Create a SIMID (Secure Interactive Media Interface) ad plugin. */
24
+ declare function simid(options: SimidPluginOptions): AdPlugin;
25
+
26
+ export { type SimidPluginOptions, type SimidRequestPolicy, simid };
@@ -0,0 +1 @@
1
+ function k(t,r){let i=document.createElement("iframe");i.sandbox.add("allow-scripts","allow-same-origin"),i.style.cssText="position:absolute;top:0;left:0;width:100%;height:100%;border:none;display:none;pointer-events:auto;",i.src=t;let a=new MessageChannel,o=a.port1,l=()=>{i.contentWindow?.postMessage("simid:connect","*",[a.port2]);};i.addEventListener("load",l,{once:true}),r.appendChild(i);let m=false;return {iframe:i,port:o,show(){m||(i.style.display="");},destroy(){m||(m=true,i.removeEventListener("load",l),i.remove(),o.close());}}}function h(t,r,i,a){return {sessionId:t,messageId:r,timestamp:Date.now(),type:i,args:a}}function j(t,r,i,a){let o={messageId:i};return a!==void 0&&(o.value=a),h(t,r,"resolve",o)}function T(t,r,i,a,o){let l={errorCode:a};return o!==void 0&&(l.message=o),h(t,r,"reject",{messageId:i,value:l})}function b(t){if(typeof t!="object"||t===null)return null;let r=t;return typeof r.sessionId!="string"||typeof r.messageId!="number"||typeof r.timestamp!="number"||typeof r.type!="string"?null:{sessionId:r.sessionId,messageId:r.messageId,timestamp:r.timestamp,type:r.type,args:r.args}}function x(t){return t.type==="createSession"}function C(t){return t.type==="resolve"}function y(t){return t.type==="reject"}function L(t,r,i,a){let o=false,l="",m=0,f=[],d=new Map;function w(){return m++}function S(e,n){let s=w(),u=h(l,s,e,n);return r.postMessage(u),s}function g(e,n){let s=w();r.postMessage(j(l,s,e,n));}function M(e,n,s){let u=w();r.postMessage(T(l,u,e,n,s));}function P(e,n,s){return new Promise((u,c)=>{let v=S(e,n),I=setTimeout(()=>{d.delete(v),c(new Error(`SIMID timeout waiting for response to ${e}`));},i.handshakeTimeout);d.set(v,{resolve:p=>{clearTimeout(I),d.delete(v),u(p);},reject:p=>{clearTimeout(I),d.delete(v),c(p);}});})}function q(){let e=t.el.getBoundingClientRect();return {x:Math.round(e.x),y:Math.round(e.y),width:Math.round(e.width),height:Math.round(e.height)}}function A(){let e=q();return {videoDimensions:e,creativeDimensions:e,fullscreen:!!document.fullscreenElement,fullscreenAllowed:!!document.fullscreenEnabled,variableDurationAllowed:false,skippableState:"playerHandles",version:"1.2",muted:t.muted,volume:t.volume,navigationSupport:i.policy.navigation==="new-tab"?"playerHandles":"notSupported"}}function N(){return {adParameters:"",clickThruUrl:a.creatives[0]?.linear?.clickThrough}}function O(){return {currentTime:t.el.currentTime,duration:t.el.duration,ended:t.el.ended,muted:t.muted,paused:t.el.paused,volume:t.volume,fullscreen:!!document.fullscreenElement}}function H(){let e=t.el,n=["play","pause","playing","ended","seeking","seeked","stalled"];for(let I of n){let p=()=>{o||S(`SIMID:Media:${I}`);};e.addEventListener(I,p),f.push(()=>e.removeEventListener(I,p));}let s=()=>{o||S("SIMID:Media:timeupdate",{currentTime:e.currentTime});};e.addEventListener("timeupdate",s),f.push(()=>e.removeEventListener("timeupdate",s));let u=()=>{o||S("SIMID:Media:durationchange",{duration:e.duration});};e.addEventListener("durationchange",u),f.push(()=>e.removeEventListener("durationchange",u));let c=()=>{o||S("SIMID:Media:volumechange",{volume:e.volume,muted:e.muted});};e.addEventListener("volumechange",c),f.push(()=>e.removeEventListener("volumechange",c));let v=()=>{o||S("SIMID:Media:error",{error:e.error?.code??0,message:e.error?.message??""});};e.addEventListener("error",v),f.push(()=>e.removeEventListener("error",v));}function V(e){if(o)return;if(C(e)||y(e)){let u=e.args?.messageId;if(u!==void 0){let c=d.get(u);c&&(C(e)?c.resolve(e):c.reject(new Error(`SIMID creative rejected: ${JSON.stringify(e.args)}`)));}return}let n=e.type;if(n==="SIMID:Creative:requestPause"){i.policy.allowPause?(t.pause(),g(e.messageId)):M(e.messageId,1203,"Pause not allowed");return}if(n==="SIMID:Creative:requestPlay"){i.policy.allowPlay?(t.play(),g(e.messageId)):M(e.messageId,1203,"Play not allowed");return}if(n==="SIMID:Creative:requestResize"){i.policy.allowResize?g(e.messageId):M(e.messageId,1203,"Resize not allowed");return}if(n==="SIMID:Creative:requestNavigation"){let s=e.args;i.policy.navigation==="new-tab"&&s?.uri?(window.open(s.uri,"_blank"),g(e.messageId)):M(e.messageId,1214,"Navigation not supported");return}if(n==="SIMID:Creative:getMediaState"){g(e.messageId,O());return}if(n==="SIMID:Creative:requestSkip"){g(e.messageId),t.emit("ad:skip",{adId:a.id});return}if(n==="SIMID:Creative:requestStop"){g(e.messageId),S("SIMID:Player:adStopped",{code:4}),D(),t.emit("ad:skip",{adId:a.id});return}if(n!=="SIMID:Creative:clickThru"){if(n==="SIMID:Creative:fatalError"){t.emit("ad:error",{error:new Error(`SIMID creative fatal error: ${JSON.stringify(e.args)}`)}),D();return}if(n==="SIMID:Creative:log"){let s=e.args;console.debug("[vide:simid] creative:",s?.message);return}if(n==="SIMID:Creative:reportTracking"){g(e.messageId);return}if(n==="SIMID:Creative:requestChangeVolume"){let s=e.args;s?.volume!==void 0&&(t.volume=s.volume),s?.muted!==void 0&&(t.muted=s.muted),g(e.messageId);return}if(n==="SIMID:Creative:requestFullscreen"||n==="SIMID:Creative:requestExitFullscreen"||n==="SIMID:Creative:requestChangeAdDuration"){M(e.messageId,1203,"Not supported");return}if(n==="SIMID:Creative:expandNonlinear"||n==="SIMID:Creative:collapseNonlinear"){M(e.messageId,1203,"Not supported");return}}}function R(e){let n=b(e.data);n&&V(n);}function D(){if(!o){o=true,r.removeEventListener("message",R);for(let e of f)e();f.length=0;for(let[,e]of d)e.reject(new Error("SIMID host destroyed"));d.clear();}}async function F(){r.addEventListener("message",R),r.start();let e=await new Promise((u,c)=>{let v=setTimeout(()=>{c(new Error("SIMID handshake timeout: no createSession"));},i.handshakeTimeout),I=p=>{let E=b(p.data);!E||!x(E)||(clearTimeout(v),r.removeEventListener("message",I),u(E));};r.addEventListener("message",I);});if(o)throw new Error("SIMID host destroyed during handshake");l=e.sessionId,g(e.messageId);let n=await P("SIMID:Player:init",{environmentData:A(),creativeData:N()});if(o)throw new Error("SIMID host destroyed during handshake");if(y(n))throw new Error(`SIMID creative rejected init: ${JSON.stringify(n.args)}`);let s=await P("SIMID:Player:startCreative");if(o)throw new Error("SIMID host destroyed during handshake");if(y(s))throw new Error(`SIMID creative rejected startCreative: ${JSON.stringify(s.args)}`);H();}return {start:F,destroy:D}}var z={allowPause:true,allowPlay:true,allowResize:false,navigation:"new-tab"};function G(t){return {name:"simid",setup(r,i){let a=i.creatives.flatMap(d=>d.linear?.interactiveCreativeFiles??[]).find(d=>d.apiFramework==="SIMID");if(!a)return;let o={...z,...t.policy},l=t.handshakeTimeout??5e3,m=k(a.url,t.container),f=L(r,m.port,{policy:o,handshakeTimeout:l},i);return f.start().then(()=>m.show()).catch(d=>{r.emit("ad:error",{error:d instanceof Error?d:new Error(String(d))}),m.destroy();}),()=>{f.destroy(),m.destroy();}}}}export{G as simid};
@@ -0,0 +1,61 @@
1
+ import { e as Plugin } from '../types-BxRa9Jvl.js';
2
+
3
+ /** Parsed ad break metadata from stream signals. */
4
+ interface AdBreakMetadata {
5
+ id: string;
6
+ /** Absolute start time in seconds relative to stream timeline. */
7
+ startTime: number;
8
+ /** Duration of the ad break in seconds. */
9
+ duration: number;
10
+ trackingUrls?: string[];
11
+ clickThrough?: string;
12
+ customData?: Record<string, string>;
13
+ }
14
+ /** Discriminated union of raw metadata from different stream sources. */
15
+ type RawMetadata = {
16
+ source: "daterange";
17
+ attributes: Record<string, string>;
18
+ } | {
19
+ source: "id3";
20
+ samples: Array<{
21
+ type: string;
22
+ data: Uint8Array;
23
+ }>;
24
+ } | {
25
+ source: "eventstream";
26
+ schemeIdUri: string;
27
+ value: string;
28
+ startTime: number;
29
+ duration: number;
30
+ messageData?: string | undefined;
31
+ };
32
+ /** Custom parser: receives raw metadata, returns zero or more ad breaks. */
33
+ type MetadataParser = (raw: RawMetadata) => AdBreakMetadata[];
34
+ interface SsaiPluginOptions {
35
+ /** Custom metadata parser. Overrides default auto-detection. */
36
+ parser?: MetadataParser;
37
+ /** Tolerance in seconds for time-based ad break matching. Default: 0.5. */
38
+ tolerance?: number;
39
+ }
40
+
41
+ /**
42
+ * Parse a DATERANGE into an ad break. Returns null if not an ad marker.
43
+ *
44
+ * @param pdtAnchorMs - The PROGRAM-DATE-TIME epoch (ms) of the first
45
+ * fragment. When provided, START-DATE is converted to a stream-relative
46
+ * offset so it can be compared against `currentTime`.
47
+ */
48
+ declare function parseDateRange(attributes: Record<string, string>, pdtAnchorMs?: number): AdBreakMetadata | null;
49
+ /** Parse ID3 timed metadata samples. Returns null if no SCTE-35 signal. */
50
+ declare function parseId3Samples(samples: Array<{
51
+ type: string;
52
+ data: Uint8Array;
53
+ }>, pts: number): AdBreakMetadata | null;
54
+
55
+ /** Parse a dash.js EventStream event. Returns null if not an ad marker. */
56
+ declare function parseEventStream(schemeIdUri: string, value: string, startTime: number, duration: number, messageData?: string, id?: string): AdBreakMetadata | null;
57
+
58
+ /** Create an SSAI (Server-Side Ad Insertion) plugin for vide. */
59
+ declare function ssai(options?: SsaiPluginOptions): Plugin;
60
+
61
+ export { type AdBreakMetadata, type MetadataParser, type RawMetadata, type SsaiPluginOptions, parseDateRange, parseEventStream, parseId3Samples, ssai };
@@ -0,0 +1 @@
1
+ import {a}from'../chunk-G4Q7R3SH.mjs';var w="urn:scte:scte35:2013:xml",A="urn:scte:scte35:2014:xml+bin";function k(e,t,r,i,l,g){return e===w||e===A||e.startsWith("urn:scte:scte35:")?{id:g??`dash-event-${r}`,startTime:r,duration:i,customData:{schemeIdUri:e,value:t,...l?{messageData:l}:{}}}:null}function D(e,t,r){function i(l){let a=l?.event;if(a)if(t){let n={source:"eventstream",schemeIdUri:a.schemeIdUri,value:a.value,startTime:a.calculatedPresentationTime,duration:a.duration,messageData:a.messageData},o=t(n);o.length>0&&r(o);}else {let n=k(a.schemeIdUri,a.value,a.calculatedPresentationTime,a.duration,a.messageData,a.id);n&&r([n]);}}return e.on("eventModeOnReceive",i),e.on("eventModeOnStart",i),()=>{e.off("eventModeOnReceive",i),e.off("eventModeOnStart",i);}}var R="com.apple.hls.interstitial",b="SCTE35-OUT";function M(e,t){let r=e.ID;if(!r)return null;let l=e.CLASS===R,g=b in e;if(!l&&!g)return null;let a=e["START-DATE"],n=e.DURATION??e["PLANNED-DURATION"],o=0;if(a){let v=new Date(a).getTime();o=t!=null?(v-t)/1e3:v/1e3;}let u=n?Number.parseFloat(n):0;return {id:r,startTime:o,duration:u,customData:{...e}}}function L(e){try{return new TextDecoder().decode(e)}catch{return null}}function S(e,t){for(let r of e){let i=L(r.data);if(i?.includes("SCTE35"))return {id:`id3-${t}`,startTime:t,duration:0,customData:{raw:i}}}return null}function T(e,t,r){let i=new Set;function l(n){let o=n?.dateRanges;if(!o)return;let u,v=n?.fragments;if(v){for(let f of v)if(f.programDateTime!=null){u=f.programDateTime-f.start*1e3;break}}for(let[f,m]of Object.entries(o)){if(i.has(f))continue;i.add(f);let d=m.attr??m;if(t){let c=t({source:"daterange",attributes:d});c.length>0&&r(c);}else {let s=M(d,u);s&&r([s]);}}}function g(n,o){let u=o;u?.details&&l(u.details);}function a(n,o){let u=o;if(!u?.samples?.length)return;let v=u.samples[0]?.pts??0;if(t){let f={source:"id3",samples:u.samples.map(d=>({type:d.type,data:d.data}))},m=t(f);m.length>0&&r(m);}else {let f=u.samples.map(d=>({type:d.type,data:d.data})),m=S(f,v);m&&r([m]);}}if(e.on("hlsLevelUpdated",g),e.on("hlsFragParsingMetadata",a),e.levels&&e.currentLevel!=null&&e.currentLevel>=0){let n=e.levels[e.currentLevel]?.details;n&&l(n);}return ()=>{e.off("hlsLevelUpdated",g),e.off("hlsFragParsingMetadata",a);}}var E=.5;function B(e={}){return {name:"ssai",setup(t){let r=e.tolerance??E,i=e.parser,l=new Map,g=new Set,a$1=new Set,n=null,o=false;function u(d){for(let s of d)l.has(s.id)||l.set(s.id,s);}function v(){if(n)return true;let d=t.getPluginData("hls");if(d)return n=T(d,i,u),true;let s=t.getPluginData("dash");return s?(n=D(s,i,u),true):false}function f({currentTime:d}){if(!o){for(let[s,c]of l)g.has(s)||d>=c.startTime-r&&(g.add(s),t.emit("ad:breakStart",{breakId:c.id}),t.emit("ad:start",{adId:c.id}),c.trackingUrls?.length&&a(c.trackingUrls),t.emit("ad:impression",{adId:c.id}));for(let[s,c]of l){if(!g.has(s)||a$1.has(s))continue;let h=c.startTime+c.duration;c.duration>0&&d>=h-r&&(a$1.add(s),t.emit("ad:end",{adId:c.id}),t.emit("ad:breakEnd",{breakId:c.id}));}}}t.on("timeupdate",f),v();function m(){if(n||o){t.off("statechange",m);return}v()&&t.off("statechange",m);}return n||t.on("statechange",m),()=>{o=true,t.off("timeupdate",f),t.off("statechange",m),n&&n();}}}}export{M as parseDateRange,k as parseEventStream,S as parseId3Samples,B as ssai};