avbridge 2.6.0 → 2.8.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.
package/dist/element.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk6SOFJV44_cjs = require('./chunk-6SOFJV44.cjs');
3
+ var chunkIUSFLVLJ_cjs = require('./chunk-IUSFLVLJ.cjs');
4
4
  require('./chunk-S4WAZC2T.cjs');
5
5
  require('./chunk-ZCUXHW55.cjs');
6
6
  require('./chunk-2IJ66NTD.cjs');
@@ -18,6 +18,8 @@ var PREFERRED_STRATEGY_VALUES = /* @__PURE__ */ new Set([
18
18
  "hybrid",
19
19
  "fallback"
20
20
  ]);
21
+ var FIT_VALUES = /* @__PURE__ */ new Set(["contain", "cover", "fill"]);
22
+ var DEFAULT_FIT = "contain";
21
23
  var FORWARDED_VIDEO_EVENTS = [
22
24
  "loadstart",
23
25
  "loadedmetadata",
@@ -52,7 +54,9 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
52
54
  "crossorigin",
53
55
  "disableremoteplayback",
54
56
  "diagnostics",
55
- "preferstrategy"
57
+ "preferstrategy",
58
+ "fit",
59
+ "no-orientation-lock"
56
60
  ];
57
61
  // ── Internal state ─────────────────────────────────────────────────────
58
62
  /** The shadow DOM `<video>` element that strategies render into. */
@@ -104,23 +108,38 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
104
108
  * native fails.
105
109
  */
106
110
  _preferredStrategy = "auto";
111
+ /** Current fit mode. Applied to the inner `<video>` via object-fit, and
112
+ * to the fallback canvas via the `--avbridge-fit` CSS custom property on
113
+ * the stage wrapper (see `src/strategies/fallback/video-renderer.ts`). */
114
+ _fit = DEFAULT_FIT;
115
+ /** The stage wrapper — the element the canvas attaches into, and where
116
+ * the `--avbridge-fit` CSS custom property lives. */
117
+ _stageEl;
107
118
  /** Set if currentTime was assigned before the player was ready. */
108
119
  _pendingSeek = null;
109
120
  /** Set if play() was called before the player was ready. */
110
121
  _pendingPlay = false;
111
122
  /** MutationObserver tracking light-DOM `<track>` children. */
112
123
  _trackObserver = null;
124
+ /** Document-level fullscreenchange handler — installed while connected so
125
+ * the element can lock/unlock screen orientation to match the video's
126
+ * intrinsic aspect. */
127
+ _fullscreenChangeHandler = null;
128
+ /** True if we successfully called screen.orientation.lock() on the last
129
+ * fullscreen entry. Used to know whether to unlock on exit. */
130
+ _orientationLocked = false;
113
131
  // ── Construction & lifecycle ───────────────────────────────────────────
114
132
  constructor() {
115
133
  super();
116
134
  const root = this.attachShadow({ mode: "open" });
117
135
  const stage = document.createElement("div");
118
136
  stage.setAttribute("part", "stage");
119
- stage.style.cssText = "position:relative;width:100%;height:100%;display:block;";
137
+ stage.style.cssText = `position:relative;width:100%;height:100%;display:block;--avbridge-fit:${DEFAULT_FIT};`;
120
138
  root.appendChild(stage);
139
+ this._stageEl = stage;
121
140
  this._videoEl = document.createElement("video");
122
141
  this._videoEl.setAttribute("part", "video");
123
- this._videoEl.style.cssText = "width:100%;height:100%;display:block;background:#000;";
142
+ this._videoEl.style.cssText = `width:100%;height:100%;display:block;background:#000;object-fit:var(--avbridge-fit, ${DEFAULT_FIT});`;
124
143
  this._videoEl.playsInline = true;
125
144
  stage.appendChild(this._videoEl);
126
145
  this._videoEl.addEventListener("progress", () => {
@@ -141,6 +160,10 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
141
160
  this._trackObserver = new MutationObserver(() => this._syncTextTracks());
142
161
  this._trackObserver.observe(this, { childList: true, subtree: false });
143
162
  }
163
+ if (!this._fullscreenChangeHandler) {
164
+ this._fullscreenChangeHandler = () => this._onFullscreenChange();
165
+ document.addEventListener("fullscreenchange", this._fullscreenChangeHandler);
166
+ }
144
167
  const source = this._activeSource();
145
168
  if (source != null) {
146
169
  void this._bootstrap(source);
@@ -152,6 +175,11 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
152
175
  this._trackObserver.disconnect();
153
176
  this._trackObserver = null;
154
177
  }
178
+ if (this._fullscreenChangeHandler) {
179
+ document.removeEventListener("fullscreenchange", this._fullscreenChangeHandler);
180
+ this._fullscreenChangeHandler = null;
181
+ }
182
+ this._releaseOrientationLock();
155
183
  this._bootstrapId++;
156
184
  void this._teardown();
157
185
  }
@@ -185,6 +213,14 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
185
213
  this._preferredStrategy = "auto";
186
214
  }
187
215
  break;
216
+ case "fit": {
217
+ const next = newValue && FIT_VALUES.has(newValue) ? newValue : DEFAULT_FIT;
218
+ if (next === this._fit) break;
219
+ this._fit = next;
220
+ this._stageEl.style.setProperty("--avbridge-fit", next);
221
+ this._dispatch("fitchange", { fit: next });
222
+ break;
223
+ }
188
224
  }
189
225
  }
190
226
  // ── Source handling ────────────────────────────────────────────────────
@@ -260,7 +296,7 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
260
296
  this._dispatch("loadstart", {});
261
297
  let player;
262
298
  try {
263
- player = await chunk6SOFJV44_cjs.createPlayer({
299
+ player = await chunkIUSFLVLJ_cjs.createPlayer({
264
300
  source,
265
301
  target: this._videoEl,
266
302
  // Honor the consumer's preferred initial strategy. "auto" means
@@ -426,6 +462,13 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
426
462
  if (value) this.setAttribute("diagnostics", "");
427
463
  else this.removeAttribute("diagnostics");
428
464
  }
465
+ get fit() {
466
+ return this._fit;
467
+ }
468
+ set fit(value) {
469
+ if (!FIT_VALUES.has(value)) return;
470
+ this.setAttribute("fit", value);
471
+ }
429
472
  get preferredStrategy() {
430
473
  return this._preferredStrategy;
431
474
  }
@@ -599,6 +642,87 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
599
642
  }
600
643
  );
601
644
  }
645
+ /**
646
+ * Disable the automatic `screen.orientation.lock()` that runs on
647
+ * fullscreen entry. Set when you want to honor the device's native
648
+ * auto-rotate instead of matching the video's intrinsic orientation.
649
+ */
650
+ get noOrientationLock() {
651
+ return this.hasAttribute("no-orientation-lock");
652
+ }
653
+ set noOrientationLock(value) {
654
+ if (value) this.setAttribute("no-orientation-lock", "");
655
+ else this.removeAttribute("no-orientation-lock");
656
+ }
657
+ // ── Fullscreen orientation lock ────────────────────────────────────────
658
+ /** Called whenever `document.fullscreenchange` fires. If this element (or
659
+ * any of its ancestors) is now fullscreen, derive the target orientation
660
+ * from the video's intrinsic size and call `screen.orientation.lock()`.
661
+ * On exit, release the lock we took. iOS Safari rejects `lock()` — we
662
+ * swallow the rejection so nothing breaks on that path. */
663
+ _onFullscreenChange() {
664
+ if (this._destroyed) return;
665
+ const fsEl = document.fullscreenElement;
666
+ const nowFullscreen = fsEl != null && this._isInsideOrEquals(fsEl);
667
+ if (nowFullscreen && !this._orientationLocked) {
668
+ if (this.noOrientationLock) return;
669
+ const target = this._desiredOrientation();
670
+ if (!target) return;
671
+ void this._lockOrientation(target);
672
+ } else if (!nowFullscreen && this._orientationLocked) {
673
+ this._releaseOrientationLock();
674
+ }
675
+ }
676
+ /** Walk composed-tree ancestors to see if `target` is this element or
677
+ * any ancestor across shadow boundaries. `Node.contains()` can't cross
678
+ * shadow roots, so when `<avbridge-player>` (the fullscreen element)
679
+ * hosts this `<avbridge-video>` inside its shadow DOM, `contains()`
680
+ * returns false. */
681
+ _isInsideOrEquals(target) {
682
+ let node = this;
683
+ while (node) {
684
+ if (node === target) return true;
685
+ const parent = node.parentNode;
686
+ if (parent instanceof ShadowRoot) node = parent.host;
687
+ else node = parent;
688
+ }
689
+ return false;
690
+ }
691
+ /** Derive "landscape" / "portrait" from the intrinsic video dimensions.
692
+ * Returns null when dimensions aren't known yet or the video is square.
693
+ * Uses `videoWidth` / `videoHeight` from the inner `<video>`, which the
694
+ * browser sets to the display-aspect-corrected size (so anamorphic
695
+ * content is judged by its display aspect, not pixel aspect). */
696
+ _desiredOrientation() {
697
+ const w = this._videoEl.videoWidth;
698
+ const h = this._videoEl.videoHeight;
699
+ if (!w || !h) return null;
700
+ if (w === h) return null;
701
+ return w > h ? "landscape" : "portrait";
702
+ }
703
+ /** Attempt to lock screen orientation. Swallows rejections — iOS Safari
704
+ * doesn't implement `lock()`, and desktop / non-fullscreen contexts will
705
+ * reject too. Records success so we know whether to unlock on exit. */
706
+ async _lockOrientation(target) {
707
+ const so = screen.orientation;
708
+ if (!so || typeof so.lock !== "function") return;
709
+ try {
710
+ await so.lock(target);
711
+ this._orientationLocked = true;
712
+ } catch {
713
+ }
714
+ }
715
+ _releaseOrientationLock() {
716
+ if (!this._orientationLocked) return;
717
+ this._orientationLocked = false;
718
+ const so = screen.orientation;
719
+ if (so && typeof so.unlock === "function") {
720
+ try {
721
+ so.unlock();
722
+ } catch {
723
+ }
724
+ }
725
+ }
602
726
  // ── Public methods ─────────────────────────────────────────────────────
603
727
  /** Force a (re-)bootstrap if a source is currently set. */
604
728
  async load() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/element/avbridge-video.ts","../src/element.ts"],"names":["createPlayer"],"mappings":";;;;;;;;;;;;;AAgCA,IAAM,yBAAA,uBAAgC,GAAA,CAAuB;AAAA,EAC3D,MAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAC,CAAA;AAeD,IAAM,sBAAA,GAAyB;AAAA,EAC7B,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,gBAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA;AAeA,IAAM,eAAA,GACJ,OAAO,WAAA,KAAgB,WAAA,GACnB,cACC,MAAM;AAAC,CAAA;AASP,IAAM,oBAAA,GAAN,cAAmC,eAAA,CAAgB;AAAA,EACxD,OAAgB,kBAAA,GAAqB;AAAA,IACnC,KAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA;AAAA,IACA,aAAA;AAAA,IACA,uBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA;AAAA,EAKQ,QAAA;AAAA;AAAA,EAGA,OAAA,GAAgC,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhC,YAAA,GAAe,CAAA;AAAA;AAAA,EAGf,UAAA,GAAa,KAAA;AAAA;AAAA,EAGb,IAAA,GAAsB,IAAA;AAAA,EACtB,OAAA,GAA6B,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7B,wBAAA,GAA2B,KAAA;AAAA;AAAA,EAG3B,SAAA,GAAiC,IAAA;AAAA,EACjC,cAAA,GAAuC,IAAA;AAAA,EACvC,eAAiC,EAAC;AAAA;AAAA;AAAA,EAGlC,kBAAuC,EAAC;AAAA;AAAA;AAAA;AAAA,EAIxC,iBAAsC,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQvC,UAAA,GAAuF,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUvF,kBAAA,GAAwC,MAAA;AAAA;AAAA,EAGxC,YAAA,GAA8B,IAAA;AAAA;AAAA,EAE9B,YAAA,GAAe,KAAA;AAAA;AAAA,EAGf,cAAA,GAA0C,IAAA;AAAA;AAAA,EAIlD,WAAA,GAAc;AACZ,IAAA,KAAA,EAAM;AACN,IAAA,MAAM,OAAO,IAAA,CAAK,YAAA,CAAa,EAAE,IAAA,EAAM,QAAQ,CAAA;AAO/C,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC1C,IAAA,KAAA,CAAM,YAAA,CAAa,QAAQ,OAAO,CAAA;AAClC,IAAA,KAAA,CAAM,MAAM,OAAA,GAAU,yDAAA;AACtB,IAAA,IAAA,CAAK,YAAY,KAAK,CAAA;AAEtB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC9C,IAAA,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,MAAA,EAAQ,OAAO,CAAA;AAC1C,IAAA,IAAA,CAAK,QAAA,CAAS,MAAM,OAAA,GAAU,uDAAA;AAC9B,IAAA,IAAA,CAAK,SAAS,WAAA,GAAc,IAAA;AAC5B,IAAA,KAAA,CAAM,WAAA,CAAY,KAAK,QAAQ,CAAA;AAO/B,IAAA,IAAA,CAAK,QAAA,CAAS,gBAAA,CAAiB,UAAA,EAAY,MAAM;AAC/C,MAAA,IAAI,KAAK,UAAA,EAAY;AACrB,MAAA,IAAA,CAAK,UAAU,UAAA,EAAY,EAAE,UAAU,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA;AAAA,IACjE,CAAC,CAAA;AAMD,IAAA,KAAA,MAAW,aAAa,sBAAA,EAAwB;AAC9C,MAAA,IAAA,CAAK,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,MAAM;AAC9C,QAAA,IAAI,KAAK,UAAA,EAAY;AACrB,QAAA,IAAA,CAAK,aAAA,CAAc,IAAI,KAAA,CAAM,SAAA,EAAW,EAAE,OAAA,EAAS,KAAA,EAAO,CAAC,CAAA;AAAA,MAC7D,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,iBAAA,GAA0B;AACxB,IAAA,IAAI,KAAK,UAAA,EAAY;AAGrB,IAAA,IAAA,CAAK,eAAA,EAAgB;AACrB,IAAA,IAAI,CAAC,KAAK,cAAA,EAAgB;AACxB,MAAA,IAAA,CAAK,iBAAiB,IAAI,gBAAA,CAAiB,MAAM,IAAA,CAAK,iBAAiB,CAAA;AACvE,MAAA,IAAA,CAAK,cAAA,CAAe,QAAQ,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,OAAO,CAAA;AAAA,IACvE;AAGA,IAAA,MAAM,MAAA,GAAS,KAAK,aAAA,EAAc;AAClC,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,KAAK,IAAA,CAAK,WAAW,MAAM,CAAA;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,oBAAA,GAA6B;AAC3B,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,IAAA,CAAK,eAAe,UAAA,EAAW;AAC/B,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,IACxB;AAKA,IAAA,IAAA,CAAK,YAAA,EAAA;AACL,IAAA,KAAK,KAAK,SAAA,EAAU;AAAA,EACtB;AAAA,EAEA,wBAAA,CAAyB,IAAA,EAAc,SAAA,EAA0B,QAAA,EAA+B;AAC9F,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,QAAQ,IAAA;AAAM,MACZ,KAAK,KAAA;AACH,QAAA,IAAI,KAAK,wBAAA,EAA0B;AACnC,QAAA,IAAA,CAAK,gBAAgB,QAAQ,CAAA;AAC7B,QAAA;AAAA,MACF,KAAK,UAAA;AAAA,MACL,KAAK,OAAA;AAAA,MACL,KAAK,MAAA;AAAA,MACL,KAAK,aAAA;AAAA,MACL,KAAK,uBAAA;AAEH,QAAA,IAAI,QAAA,IAAY,IAAA,EAAM,IAAA,CAAK,QAAA,CAAS,gBAAgB,IAAI,CAAA;AAAA,aACnD,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,IAAA,EAAM,QAAQ,CAAA;AAC9C,QAAA;AAAA,MACF,KAAK,SAAA;AAAA,MACL,KAAK,QAAA;AAAA,MACL,KAAK,aAAA;AACH,QAAA,IAAI,QAAA,IAAY,IAAA,EAAM,IAAA,CAAK,QAAA,CAAS,gBAAgB,IAAI,CAAA;AAAA,aACnD,IAAA,CAAK,QAAA,CAAS,YAAA,CAAa,IAAA,EAAM,QAAQ,CAAA;AAC9C,QAAA;AAAA,MACF,KAAK,aAAA;AAEH,QAAA;AAAA,MACF,KAAK,gBAAA;AACH,QAAA,IAAI,QAAA,IAAY,yBAAA,CAA0B,GAAA,CAAI,QAA6B,CAAA,EAAG;AAC5E,UAAA,IAAA,CAAK,kBAAA,GAAqB,QAAA;AAAA,QAC5B,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,kBAAA,GAAqB,MAAA;AAAA,QAC5B;AACA,QAAA;AAAA;AACJ,EACF;AAAA;AAAA;AAAA,EAKQ,aAAA,GAAmC;AACzC,IAAA,IAAI,IAAA,CAAK,OAAA,IAAW,IAAA,EAAM,OAAO,IAAA,CAAK,OAAA;AACtC,IAAA,IAAI,IAAA,CAAK,IAAA,IAAQ,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA;AACnC,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,eAAA,GAAwB;AAE9B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,gBAAA,CAAiB,OAAO,CAAA;AACvD,IAAA,KAAA,MAAW,KAAK,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA,IAAK,MAAA,EAAO;AAM/C,IAAA,IAAA,CAAK,iBAAiB,EAAC;AACvB,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC7C,MAAA,IAAI,KAAA,CAAM,YAAY,OAAA,EAAS;AAC7B,QAAA,MAAM,KAAA,GAAQ,KAAA;AACd,QAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,SAAA,CAAU,IAAI,CAAA;AAClC,QAAA,IAAA,CAAK,QAAA,CAAS,YAAY,KAAK,CAAA;AAC/B,QAAA,MAAM,GAAA,GAAM,KAAA,CAAM,YAAA,CAAa,KAAK,CAAA,IAAK,MAAA;AACzC,QAAA,MAAM,SAAS,GAAA,EAAK,WAAA,GAAc,QAAA,CAAS,MAAM,IAAI,KAAA,GAAQ,KAAA;AAC7D,QAAA,IAAA,CAAK,eAAe,IAAA,CAAK;AAAA,UACvB,IAAI,GAAA,GAAQ,OAAA;AAAA,UACZ,MAAA;AAAA,UACA,UAAU,KAAA,CAAM,OAAA,IAAW,KAAA,CAAM,YAAA,CAAa,OAAO,CAAA,IAAK,MAAA;AAAA,UAC1D,UAAA,EAAY;AAAA,SACb,CAAA;AACD,QAAA,OAAA,EAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,UAAU,cAAA,EAAgB;AAAA,MAC7B,aAAa,IAAA,CAAK,YAAA;AAAA,MAClB,gBAAgB,IAAA,CAAK;AAAA,KACtB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA,EAIQ,gBAAgB,KAAA,EAA4B;AAElD,IAAA,IAAI,KAAA,KAAU,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,WAAW,IAAA,EAAM;AACjD,IAAA,IAAA,CAAK,IAAA,GAAO,KAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,EACxB;AAAA;AAAA,EAGQ,gBAAA,GAAyB;AAC/B,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,MAAM,MAAA,GAAS,KAAK,aAAA,EAAc;AAClC,IAAA,IAAI,UAAU,IAAA,EAAM;AAElB,MAAA,IAAA,CAAK,YAAA,EAAA;AACL,MAAA,KAAK,KAAK,SAAA,EAAU;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,KAAK,WAAA,EAAa;AACpB,MAAA,KAAK,IAAA,CAAK,WAAW,MAAM,CAAA;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA,EAIA,MAAc,WAAW,MAAA,EAAmC;AAC1D,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,MAAM,EAAA,GAAK,EAAE,IAAA,CAAK,YAAA;AAKlB,IAAA,MAAM,IAAA,CAAK,UAAU,EAAE,CAAA;AACvB,IAAA,IAAI,EAAA,KAAO,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,UAAA,EAAY;AAEjD,IAAA,IAAA,CAAK,SAAA,CAAU,WAAA,EAAa,EAAE,CAAA;AAE9B,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,MAAMA,8BAAA,CAAa;AAAA,QAC1B,MAAA;AAAA,QACA,QAAQ,IAAA,CAAK,QAAA;AAAA;AAAA;AAAA;AAAA,QAIb,GAAI,KAAK,kBAAA,KAAuB,MAAA,GAC5B,EAAE,eAAA,EAAiB,IAAA,CAAK,kBAAA,EAAmB,GAC3C,EAAC;AAAA,QACL,GAAI,KAAK,UAAA,GAAa,EAAE,WAAW,IAAA,CAAK,UAAA,KAAe;AAAC,OACzD,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AAEZ,MAAA,IAAI,EAAA,KAAO,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,UAAA,EAAY;AACjD,MAAA,IAAA,CAAK,eAAe,GAAG,CAAA;AACvB,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,OAAO,IAAA,CAAK,YAAA,IAAgB,KAAK,UAAA,IAAc,CAAC,KAAK,WAAA,EAAa;AACpE,MAAA,IAAI;AAAE,QAAA,MAAM,OAAO,OAAA,EAAQ;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAe;AACrD,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAKf,IAAA,IAAA,CAAK,eAAA,EAAgB;AAIrB,IAAA,MAAA,CAAO,GAAG,UAAA,EAAY,CAAC,EAAE,QAAA,EAAU,QAAO,KAAM;AAE9C,MAAA,MAAM,GAAA,GAAM,MAAA,CAAO,cAAA,EAAe,CAAE,aAAA;AACpC,MAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,MAAA,IAAA,CAAK,cAAA,GAAiB,GAAA,KAAQ,SAAA,GAAY,IAAA,GAAO,GAAA;AACjD,MAAA,IAAA,CAAK,UAAU,gBAAA,EAAkB;AAAA,QAC/B,QAAA;AAAA,QACA,eAAe,IAAA,CAAK,cAAA;AAAA,QACpB,MAAA;AAAA,QACA,WAAA,EAAa,OAAO,cAAA;AAAe,OACpC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,kBAAkB,CAAC,EAAE,MAAM,EAAA,EAAI,MAAA,EAAQ,aAAY,KAAM;AACjE,MAAA,IAAA,CAAK,UAAU,gBAAA,EAAkB;AAAA,QAC/B,IAAA;AAAA,QACA,QAAA,EAAU,EAAA;AAAA,QACV,aAAA,EAAe,OAAO,cAAA,EAAe,CAAE,kBAAkB,SAAA,GAAY,IAAA,GAAO,MAAA,CAAO,cAAA,EAAe,CAAE,aAAA;AAAA,QACpG,MAAA;AAAA,QACA,WAAA;AAAA,QACA,WAAA,EAAa,OAAO,cAAA;AAAe,OACpC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,UAAU,CAAC,EAAE,OAAO,EAAA,EAAI,KAAA,EAAO,UAAS,KAAM;AACtD,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,MAAA,IAAA,CAAK,eAAA,GAAkB,QAAA;AACvB,MAAA,IAAA,CAAK,UAAU,cAAA,EAAgB;AAAA,QAC7B,WAAA,EAAa,KAAA;AAAA,QACb,cAAA,EAAgB;AAAA,OACjB,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAe;AACjC,MAAA,IAAA,CAAK,eAAe,GAAG,CAAA;AAAA,IACzB,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,YAAA,EAAc,CAAC,EAAE,aAAY,KAAM;AAC3C,MAAA,IAAA,CAAK,SAAA,CAAU,YAAA,EAAc,EAAE,WAAA,EAAa,CAAA;AAAA,IAC9C,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,SAAS,MAAM;AACvB,MAAA,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS,EAAE,CAAA;AAAA,IAC5B,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,SAAS,MAAM;AACvB,MAAA,IAAA,CAAK,UAAU,OAAA,EAAS,EAAE,aAAa,MAAA,CAAO,cAAA,IAAkB,CAAA;AAEhE,MAAA,IAAI,IAAA,CAAK,gBAAgB,IAAA,EAAM;AAC7B,QAAA,MAAM,IAAI,IAAA,CAAK,YAAA;AACf,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,QAAA,KAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,CAAE,MAAM,MAAM;AAAA,QAAe,CAAC,CAAA;AAAA,MAClD;AAEA,MAAA,IAAI,KAAK,YAAA,EAAc;AACrB,QAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,QAAA,KAAK,MAAA,CAAO,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM;AAAA,QAAyC,CAAC,CAAA;AAAA,MAC3E,CAAA,MAAA,IAAW,KAAK,QAAA,EAAU;AACxB,QAAA,KAAK,MAAA,CAAO,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM;AAAA,QAAe,CAAC,CAAA;AAAA,MACjD;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,UAAU,kBAAA,EAA4C;AAClE,IAAA,IAAI,sBAAsB,IAAA,EAAM;AAI9B,MAAA,IAAA,CAAK,YAAA,EAAA;AAAA,IACP;AACA,IAAA,MAAM,SAAS,IAAA,CAAK,OAAA;AACpB,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,IAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AACtB,IAAA,IAAA,CAAK,eAAe,EAAC;AACrB,IAAA,IAAA,CAAK,kBAAkB,EAAC;AACxB,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAI;AAAE,QAAA,MAAM,OAAO,OAAA,EAAQ;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAe;AAAA,IACvD;AAAA,EACF;AAAA;AAAA,EAIA,IAAI,GAAA,GAAqB;AACvB,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EACd;AAAA,EAEA,IAAI,IAAI,KAAA,EAAsB;AAC5B,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,IAAA,CAAK,gBAAgB,KAAK,CAAA;AAAA,IAC5B,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,YAAA,CAAa,OAAO,KAAK,CAAA;AAAA,IAChC;AAAA,EAEF;AAAA,EAEA,IAAI,MAAA,GAA4B;AAC9B,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA,EAEA,IAAI,OAAO,KAAA,EAA0B;AAEnC,IAAA,IAAI,KAAA,KAAU,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,QAAQ,IAAA,EAAM;AACjD,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAI,SAAS,IAAA,EAAM;AAGjB,MAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,MAAA,IAAI,IAAA,CAAK,YAAA,CAAa,KAAK,CAAA,EAAG;AAC5B,QAAA,IAAA,CAAK,wBAAA,GAA2B,IAAA;AAChC,QAAA,IAAI;AACF,UAAA,IAAA,CAAK,gBAAgB,KAAK,CAAA;AAAA,QAC5B,CAAA,SAAE;AACA,UAAA,IAAA,CAAK,wBAAA,GAA2B,KAAA;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,EACxB;AAAA,EAEA,IAAI,QAAA,GAAoB;AACtB,IAAA,OAAO,IAAA,CAAK,aAAa,UAAU,CAAA;AAAA,EACrC;AAAA,EAEA,IAAI,SAAS,KAAA,EAAgB;AAC3B,IAAA,IAAI,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,UAAA,EAAY,EAAE,CAAA;AAAA,SACtC,IAAA,CAAK,gBAAgB,UAAU,CAAA;AAAA,EACtC;AAAA,EAEA,IAAI,KAAA,GAAiB;AACnB,IAAA,OAAO,IAAA,CAAK,aAAa,OAAO,CAAA;AAAA,EAClC;AAAA,EAEA,IAAI,MAAM,KAAA,EAAgB;AACxB,IAAA,IAAI,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,OAAA,EAAS,EAAE,CAAA;AAAA,SACnC,IAAA,CAAK,gBAAgB,OAAO,CAAA;AAAA,EACnC;AAAA,EAEA,IAAI,IAAA,GAAgB;AAClB,IAAA,OAAO,IAAA,CAAK,aAAa,MAAM,CAAA;AAAA,EACjC;AAAA,EAEA,IAAI,KAAK,KAAA,EAAgB;AACvB,IAAA,IAAI,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ,EAAE,CAAA;AAAA,SAClC,IAAA,CAAK,gBAAgB,MAAM,CAAA;AAAA,EAClC;AAAA,EAEA,IAAI,OAAA,GAAwC;AAC1C,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA;AACrC,IAAA,OAAO,MAAM,MAAA,IAAU,CAAA,KAAM,UAAA,IAAc,CAAA,KAAM,SAAS,CAAA,GAAI,MAAA;AAAA,EAChE;AAAA,EAEA,IAAI,QAAQ,KAAA,EAAqC;AAC/C,IAAA,IAAA,CAAK,YAAA,CAAa,WAAW,KAAK,CAAA;AAAA,EACpC;AAAA,EAEA,IAAI,WAAA,GAAuB;AACzB,IAAA,OAAO,IAAA,CAAK,aAAa,aAAa,CAAA;AAAA,EACxC;AAAA,EAEA,IAAI,YAAY,KAAA,EAAgB;AAC9B,IAAA,IAAI,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,aAAA,EAAe,EAAE,CAAA;AAAA,SACzC,IAAA,CAAK,gBAAgB,aAAa,CAAA;AAAA,EACzC;AAAA,EAEA,IAAI,iBAAA,GAAuC;AACzC,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EACd;AAAA,EAEA,IAAI,kBAAkB,KAAA,EAA0B;AAC9C,IAAA,IAAI,yBAAA,CAA0B,GAAA,CAAI,KAAK,CAAA,EAAG;AACxC,MAAA,IAAA,CAAK,YAAA,CAAa,kBAAkB,KAAK,CAAA;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,IAAI,WAAA,GAAsB;AACxB,IAAA,OAAO,IAAA,CAAK,OAAA,EAAS,cAAA,EAAe,IAAK,CAAA;AAAA,EAC3C;AAAA,EAEA,IAAI,YAAY,KAAA,EAAe;AAC7B,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,KAAK,KAAK,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,CAAE,MAAM,MAAM;AAAA,MAAe,CAAC,CAAA;AAAA,IAC5D,CAAA,MAAO;AAEL,MAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,IAAI,QAAA,GAAmB;AACrB,IAAA,OAAO,IAAA,CAAK,OAAA,EAAS,WAAA,EAAY,IAAK,GAAA;AAAA,EACxC;AAAA,EAEA,IAAI,MAAA,GAAkB;AACpB,IAAA,OAAO,KAAK,QAAA,CAAS,MAAA;AAAA,EACvB;AAAA,EAEA,IAAI,KAAA,GAAiB;AACnB,IAAA,OAAO,KAAK,QAAA,CAAS,KAAA;AAAA,EACvB;AAAA,EAEA,IAAI,UAAA,GAAqB;AACvB,IAAA,OAAO,KAAK,QAAA,CAAS,UAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IAAI,QAAA,GAAuB;AACzB,IAAA,OAAO,KAAK,QAAA,CAAS,QAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,MAAA,GAAiB;AACnB,IAAA,OAAO,KAAK,QAAA,CAAS,MAAA;AAAA,EACvB;AAAA,EACA,IAAI,OAAO,KAAA,EAAe;AACxB,IAAA,IAAI,SAAS,IAAA,IAAQ,KAAA,KAAU,EAAA,EAAI,IAAA,CAAK,gBAAgB,QAAQ,CAAA;AAAA,SAC3D,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,KAAK,CAAA;AAAA,EACxC;AAAA,EAEA,IAAI,MAAA,GAAiB;AACnB,IAAA,OAAO,KAAK,QAAA,CAAS,MAAA;AAAA,EACvB;AAAA,EACA,IAAI,OAAO,KAAA,EAAe;AACxB,IAAA,IAAA,CAAK,SAAS,MAAA,GAAS,KAAA;AAAA,EACzB;AAAA,EAEA,IAAI,YAAA,GAAuB;AACzB,IAAA,OAAO,KAAK,QAAA,CAAS,YAAA;AAAA,EACvB;AAAA,EACA,IAAI,aAAa,KAAA,EAAe;AAC9B,IAAA,IAAA,CAAK,SAAS,YAAA,GAAe,KAAA;AAAA,EAC/B;AAAA,EAEA,IAAI,UAAA,GAAqB;AACvB,IAAA,OAAO,KAAK,QAAA,CAAS,UAAA;AAAA,EACvB;AAAA,EAEA,IAAI,WAAA,GAAsB;AACxB,IAAA,OAAO,KAAK,QAAA,CAAS,WAAA;AAAA,EACvB;AAAA,EAEA,IAAI,MAAA,GAAqB;AACvB,IAAA,OAAO,KAAK,QAAA,CAAS,MAAA;AAAA,EACvB;AAAA,EAEA,IAAI,QAAA,GAAuB;AACzB,IAAA,OAAO,KAAK,QAAA,CAAS,QAAA;AAAA,EACvB;AAAA,EAEA,IAAI,WAAA,GAA6B;AAC/B,IAAA,OAAO,KAAK,QAAA,CAAS,WAAA;AAAA,EACvB;AAAA,EACA,IAAI,YAAY,KAAA,EAAsB;AACpC,IAAA,IAAI,KAAA,IAAS,IAAA,EAAM,IAAA,CAAK,eAAA,CAAgB,aAAa,CAAA;AAAA,SAChD,IAAA,CAAK,YAAA,CAAa,aAAA,EAAe,KAAK,CAAA;AAAA,EAC7C;AAAA,EAEA,IAAI,qBAAA,GAAiC;AACnC,IAAA,OAAO,KAAK,QAAA,CAAS,qBAAA;AAAA,EACvB;AAAA,EACA,IAAI,sBAAsB,KAAA,EAAgB;AACxC,IAAA,IAAI,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,uBAAA,EAAyB,EAAE,CAAA;AAAA,SACnD,IAAA,CAAK,gBAAgB,uBAAuB,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,QAAA,EAAqC;AAC/C,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,WAAA,CAAY,QAAQ,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,IAAI,YAAA,GAAiC;AACnC,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA,EAEA,IAAI,QAAA,GAAgC;AAClC,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EACd;AAAA,EAEA,IAAI,aAAA,GAAsC;AACxC,IAAA,OAAO,IAAA,CAAK,cAAA;AAAA,EACd;AAAA,EAEA,IAAI,MAAA,GAA+B;AACjC,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA,EAEA,IAAI,WAAA,GAAgC;AAClC,IAAA,OAAO,IAAA,CAAK,YAAA;AAAA,EACd;AAAA,EAEA,IAAI,cAAA,GAAsC;AAKxC,IAAA,OAAO,IAAA,CAAK,cAAA,CAAe,MAAA,KAAW,CAAA,GAClC,IAAA,CAAK,eAAA,GACL,CAAC,GAAG,IAAA,CAAK,eAAA,EAAiB,GAAG,IAAA,CAAK,cAAc,CAAA;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAI,SAAA,GAAsF;AACxF,IAAA,OAAO,IAAA,CAAK,UAAA;AAAA,EACd;AAAA,EAEA,IAAI,UAAU,KAAA,EAAiF;AAC7F,IAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YAAY,QAAA,EAAqF;AACrG,IAAA,MAAM,EAAE,oBAAA,EAAqB,GAAI,MAAM,OAAO,0BAAuB,CAAA;AACrE,IAAA,MAAM,MAAA,GAAS,SAAS,MAAA,KAAW,QAAA,CAAS,IAAI,QAAA,CAAS,MAAM,IAAI,KAAA,GAAQ,KAAA,CAAA;AAC3E,IAAA,MAAM,KAAA,GAAQ;AAAA,MACZ,EAAA,EAAI,KAAK,eAAA,CAAgB,MAAA;AAAA,MACzB,MAAA;AAAA,MACA,UAAU,QAAA,CAAS,QAAA;AAAA,MACnB,YAAY,QAAA,CAAS;AAAA,KACvB;AACA,IAAA,IAAA,CAAK,eAAA,CAAgB,KAAK,KAAK,CAAA;AAC/B,IAAA,MAAM,oBAAA;AAAA,MACJ,IAAA,CAAK,QAAA;AAAA,MACL,IAAA,CAAK,eAAA;AAAA,MACL,MAAA;AAAA,MACA,CAAC,KAAK,CAAA,KAAM;AAEV,QAAA,OAAA,CAAQ,KAAK,CAAA,oBAAA,EAAuB,CAAA,CAAE,EAAE,CAAA,SAAA,EAAY,GAAA,CAAI,OAAO,CAAA,CAAE,CAAA;AAAA,MACnE;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,MAAM,IAAA,GAAsB;AAC1B,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,MAAM,MAAA,GAAS,KAAK,aAAA,EAAc;AAClC,IAAA,IAAI,UAAU,IAAA,EAAM;AACpB,IAAA,MAAM,IAAA,CAAK,WAAW,MAAM,CAAA;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAA,GAAsB;AAC1B,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,IAAA,CAAK,QAAQ,IAAA,EAAK;AAAA,IAC1B,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,IAAA,CAAK,YAAA,GAAe,KAAA;AACpB,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAA,GAAyB;AAC7B,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,MAAM,KAAK,SAAA,EAAU;AACrB,IAAA,IAAA,CAAK,SAAA,CAAU,SAAA,EAAW,EAAE,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,cAAc,EAAA,EAA2B;AAC7C,IAAA,IAAI,IAAA,CAAK,UAAA,IAAc,CAAC,IAAA,CAAK,OAAA,EAAS;AACtC,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,EAAE,CAAA;AAAA,EACrC;AAAA,EAEA,MAAM,iBAAiB,EAAA,EAAkC;AACvD,IAAA,IAAI,IAAA,CAAK,UAAA,IAAc,CAAC,IAAA,CAAK,OAAA,EAAS;AACtC,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,gBAAA,CAAiB,EAAE,CAAA;AAAA,EACxC;AAAA,EAEA,cAAA,GAA6C;AAC3C,IAAA,OAAO,IAAA,CAAK,OAAA,EAAS,cAAA,EAAe,IAAK,IAAA;AAAA,EAC3C;AAAA,EAqBS,gBAAA,CACP,IAAA,EACA,QAAA,EACA,OAAA,EACM;AACN,IAAA,KAAA,CAAM,gBAAA,CAAiB,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAAA,EAChD;AAAA,EAiBS,mBAAA,CACP,IAAA,EACA,QAAA,EACA,OAAA,EACM;AACN,IAAA,KAAA,CAAM,mBAAA,CAAoB,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAAA,EACnD;AAAA;AAAA,EAIQ,SAAA,CAAa,MAAc,MAAA,EAAiB;AAClD,IAAA,IAAA,CAAK,aAAA,CAAc,IAAI,WAAA,CAAY,IAAA,EAAM,EAAE,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAO,CAAC,CAAA;AAAA,EACtE;AAAA,EAEQ,eAAe,GAAA,EAAoB;AACzC,IAAA,MAAM,KAAA,GAAQ,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AAChE,IAAA,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS,EAAE,KAAA,EAAO,WAAA,EAAa,KAAK,OAAA,EAAS,cAAA,EAAe,IAAK,IAAA,EAAM,CAAA;AAAA,EACxF;AACF;;;AC53BA,IAAI,OAAO,cAAA,KAAmB,WAAA,IAAe,CAAC,cAAA,CAAe,GAAA,CAAI,gBAAgB,CAAA,EAAG;AAClF,EAAA,cAAA,CAAe,MAAA,CAAO,kBAAkB,oBAAoB,CAAA;AAC9D","file":"element.cjs","sourcesContent":["/**\n * `<avbridge-video>` — `HTMLMediaElement`-compatible primitive backed by the\n * avbridge engine. Drop-in replacement for a `<video>` element with no\n * built-in UI.\n *\n * Purpose:\n *\n * 1. Validate the public API by being a real consumer of `createPlayer()`.\n * 2. Drive lifecycle correctness in the core via adversarial integration tests.\n * 3. Give consumers a `<video>`-compatible primitive they can wrap with\n * their own UI.\n *\n * **It is not a player UI framework.** The tag name `<avbridge-player>` is\n * reserved for a future controls-bearing element. See\n * `docs/dev/WEB_COMPONENT_SPEC.md` for the full spec, lifecycle invariants,\n * and edge case list.\n */\n\nimport { createPlayer, type UnifiedPlayer } from \"../player.js\";\nimport type {\n MediaInput,\n StrategyName,\n StrategyClass,\n AudioTrackInfo,\n SubtitleTrackInfo,\n DiagnosticsSnapshot,\n AvbridgeVideoElementEventMap,\n} from \"../types.js\";\n\n/** Strategy preference passed via the `preferstrategy` attribute. */\ntype PreferredStrategy = \"auto\" | StrategyName;\n\nconst PREFERRED_STRATEGY_VALUES = new Set<PreferredStrategy>([\n \"auto\",\n \"native\",\n \"remux\",\n \"hybrid\",\n \"fallback\",\n]);\n\n/**\n * Standard `HTMLMediaElement` events we forward from the inner `<video>`\n * to the wrapper element so consumers can `el.addEventListener(\"loadedmetadata\", ...)`\n * exactly like they would with a real `<video>`. The element also dispatches\n * its own custom events (`strategychange`, `ready`, `error`, etc.) — those\n * are NOT in this list because they're avbridge-specific.\n *\n * Note: `progress` and `timeupdate` are deliberately NOT forwarded here.\n * `progress` is dispatched by the constructor with our own `{ buffered }`\n * detail. `timeupdate` is dispatched by the player layer (so it works for\n * canvas-rendered fallback playback too, where the inner <video> never\n * fires its own timeupdate).\n */\nconst FORWARDED_VIDEO_EVENTS = [\n \"loadstart\",\n \"loadedmetadata\",\n \"loadeddata\",\n \"canplay\",\n \"canplaythrough\",\n \"play\",\n \"playing\",\n \"pause\",\n \"seeking\",\n \"seeked\",\n \"volumechange\",\n \"ratechange\",\n \"durationchange\",\n \"waiting\",\n \"stalled\",\n \"emptied\",\n \"resize\",\n \"error\",\n] as const;\n\n/**\n * `HTMLElement` is a browser-only global. SSR frameworks (Next.js, Astro,\n * Remix, etc.) commonly import library modules on the server to extract\n * types or do tree-shaking, even if the user only ends up using them in\n * the browser. If we extended `HTMLElement` directly, the `class extends`\n * expression would be evaluated at module load time and crash in Node.\n *\n * The fix: in non-browser environments, fall back to an empty stub class.\n * The element is never *constructed* server-side (the registration in\n * `element.ts` is guarded by `typeof customElements !== \"undefined\"`), so\n * the stub is never instantiated — it just lets the class declaration\n * evaluate cleanly so the module can be imported anywhere.\n */\nconst HTMLElementCtor: typeof HTMLElement =\n typeof HTMLElement !== \"undefined\"\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n/**\n * Custom element. Lifecycle correctness is enforced via a monotonically\n * increasing `_bootstrapId`: every async bootstrap captures the ID at start\n * and discards itself if the ID has changed by the time it resolves. This\n * single pattern handles disconnect-during-bootstrap, rapid src reassignment,\n * bootstrap races, and destroy-during-bootstrap.\n */\nexport class AvbridgeVideoElement extends HTMLElementCtor {\n static readonly observedAttributes = [\n \"src\",\n \"autoplay\",\n \"muted\",\n \"loop\",\n \"preload\",\n \"poster\",\n \"playsinline\",\n \"crossorigin\",\n \"disableremoteplayback\",\n \"diagnostics\",\n \"preferstrategy\",\n ];\n\n // ── Internal state ─────────────────────────────────────────────────────\n\n /** The shadow DOM `<video>` element that strategies render into. */\n private _videoEl!: HTMLVideoElement;\n\n /** Active player session, if any. Cleared on teardown. */\n private _player: UnifiedPlayer | null = null;\n\n /**\n * Monotonic counter incremented on every (re)bootstrap. Async bootstrap\n * work captures the current ID; if it doesn't match by the time the work\n * resolves, the work is discarded.\n */\n private _bootstrapId = 0;\n\n /** True after destroy() — element is permanently unusable. */\n private _destroyed = false;\n\n /** Internal source state. Either string-form (src) OR rich (source). */\n private _src: string | null = null;\n private _source: MediaInput | null = null;\n\n /**\n * Set when the `source` property setter is in the middle of clearing the\n * `src` attribute as part of mutual exclusion. The attributeChangedCallback\n * checks this flag and skips its normal \"clear source\" side effect, which\n * would otherwise wipe the value we just set.\n */\n private _suppressSrcAttrCallback = false;\n\n /** Last-known runtime state surfaced via getters. */\n private _strategy: StrategyName | null = null;\n private _strategyClass: StrategyClass | null = null;\n private _audioTracks: AudioTrackInfo[] = [];\n /** Subtitle tracks reported by the active UnifiedPlayer (options.subtitles\n * + embedded container tracks + programmatic addSubtitle calls). */\n private _subtitleTracks: SubtitleTrackInfo[] = [];\n /** Subtitle tracks derived from light-DOM `<track>` children. Maintained\n * by _syncTextTracks on every mutation. Merged into the public\n * `subtitleTracks` getter so the player's settings menu sees them. */\n private _htmlTrackInfo: SubtitleTrackInfo[] = [];\n\n /**\n * External subtitle list forwarded to `createPlayer()` on the next\n * bootstrap. Setting this after bootstrap queues it for the next\n * source change; consumers that need to swap subtitles mid-playback\n * should set `source` to reload.\n */\n private _subtitles: Array<{ url: string; language?: string; format?: \"vtt\" | \"srt\" }> | null = null;\n\n /**\n * Initial strategy preference. `\"auto\"` means \"let the classifier decide\";\n * any other value is passed to `createPlayer({ initialStrategy })` and\n * skips classification on the next bootstrap. Note that this only affects\n * the *initial* pick — runtime fallback escalation still applies, so a\n * preference of `\"native\"` may still escalate to remux/hybrid/fallback if\n * native fails.\n */\n private _preferredStrategy: PreferredStrategy = \"auto\";\n\n /** Set if currentTime was assigned before the player was ready. */\n private _pendingSeek: number | null = null;\n /** Set if play() was called before the player was ready. */\n private _pendingPlay = false;\n\n /** MutationObserver tracking light-DOM `<track>` children. */\n private _trackObserver: MutationObserver | null = null;\n\n // ── Construction & lifecycle ───────────────────────────────────────────\n\n constructor() {\n super();\n const root = this.attachShadow({ mode: \"open\" });\n\n // A positioned wrapper inside the shadow root. The fallback strategy\n // overlays a canvas on top of the <video> via `target.parentNode` —\n // that only works if the parent is a real Element with layout. Without\n // this wrapper, `target.parentElement` would be null (ShadowRoot is\n // not an Element) and the canvas would never attach to the DOM.\n const stage = document.createElement(\"div\");\n stage.setAttribute(\"part\", \"stage\");\n stage.style.cssText = \"position:relative;width:100%;height:100%;display:block;\";\n root.appendChild(stage);\n\n this._videoEl = document.createElement(\"video\");\n this._videoEl.setAttribute(\"part\", \"video\");\n this._videoEl.style.cssText = \"width:100%;height:100%;display:block;background:#000;\";\n this._videoEl.playsInline = true;\n stage.appendChild(this._videoEl);\n\n // Forward the underlying <video>'s `progress` event so consumers can\n // observe buffered-range updates without reaching into the shadow DOM.\n // This works for native + remux (real video element with buffered\n // ranges) and is a no-op for hybrid/fallback (canvas-rendered, no\n // buffered ranges yet).\n this._videoEl.addEventListener(\"progress\", () => {\n if (this._destroyed) return;\n this._dispatch(\"progress\", { buffered: this._videoEl.buffered });\n });\n\n // Forward all standard HTMLMediaElement events from the inner <video>\n // so consumers can use the element as a drop-in <video> replacement.\n // Each event is re-dispatched on the wrapper element with no detail —\n // listeners that need state should read it from the element directly.\n for (const eventName of FORWARDED_VIDEO_EVENTS) {\n this._videoEl.addEventListener(eventName, () => {\n if (this._destroyed) return;\n this.dispatchEvent(new Event(eventName, { bubbles: false }));\n });\n }\n }\n\n connectedCallback(): void {\n if (this._destroyed) return;\n // Pick up any <track> children that were declared in HTML before the\n // element upgraded, and watch for future additions/removals.\n this._syncTextTracks();\n if (!this._trackObserver) {\n this._trackObserver = new MutationObserver(() => this._syncTextTracks());\n this._trackObserver.observe(this, { childList: true, subtree: false });\n }\n // Connection is the trigger for bootstrap. If we have a pending source\n // (set before connect), kick off bootstrap now.\n const source = this._activeSource();\n if (source != null) {\n void this._bootstrap(source);\n }\n }\n\n disconnectedCallback(): void {\n if (this._destroyed) return;\n if (this._trackObserver) {\n this._trackObserver.disconnect();\n this._trackObserver = null;\n }\n // Bump the bootstrap token so any in-flight async work is invalidated\n // before we tear down. _teardown() also bumps but we want the bump to\n // happen synchronously here so any awaited promise that resolves\n // between `disconnect` and `_teardown` sees the new ID.\n this._bootstrapId++;\n void this._teardown();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (this._destroyed) return;\n switch (name) {\n case \"src\":\n if (this._suppressSrcAttrCallback) break;\n this._setSrcInternal(newValue);\n break;\n case \"autoplay\":\n case \"muted\":\n case \"loop\":\n case \"playsinline\":\n case \"disableremoteplayback\":\n // Reflect onto the underlying <video> element.\n if (newValue == null) this._videoEl.removeAttribute(name);\n else this._videoEl.setAttribute(name, newValue);\n break;\n case \"preload\":\n case \"poster\":\n case \"crossorigin\":\n if (newValue == null) this._videoEl.removeAttribute(name);\n else this._videoEl.setAttribute(name, newValue);\n break;\n case \"diagnostics\":\n // Phase A: no UI. Property is observable for users via getDiagnostics().\n break;\n case \"preferstrategy\":\n if (newValue && PREFERRED_STRATEGY_VALUES.has(newValue as PreferredStrategy)) {\n this._preferredStrategy = newValue as PreferredStrategy;\n } else {\n this._preferredStrategy = \"auto\";\n }\n break;\n }\n }\n\n // ── Source handling ────────────────────────────────────────────────────\n\n /** Returns the currently-active source (src or source), whichever is set. */\n private _activeSource(): MediaInput | null {\n if (this._source != null) return this._source;\n if (this._src != null) return this._src;\n return null;\n }\n\n /**\n * Mirror light-DOM `<track>` children into the shadow `<video>` so that\n * the browser's native text-track machinery picks them up. Called on\n * connect, on every mutation of light-DOM children, and once after each\n * source change so newly-set tracks survive a fresh `<video>`.\n *\n * Strategy: clone the children. We don't move them because the user's\n * code may still hold references to the originals (e.g. to set `default`).\n * The shadow copies are throwaway — we wipe them on every sync.\n */\n private _syncTextTracks(): void {\n // Remove existing shadow tracks.\n const existing = this._videoEl.querySelectorAll(\"track\");\n for (const t of Array.from(existing)) t.remove();\n // Clone every <track> light-DOM child into the shadow video, and\n // rebuild the HTML-derived subtitle info list so the `<avbridge-player>`\n // settings menu can render them alongside options-sourced tracks.\n // HTML tracks are assigned high, stable IDs (10000+index) to avoid\n // colliding with container-embedded ids (typically < 32).\n this._htmlTrackInfo = [];\n let htmlIdx = 0;\n for (const child of Array.from(this.children)) {\n if (child.tagName === \"TRACK\") {\n const track = child as HTMLTrackElement;\n const clone = track.cloneNode(true) as HTMLTrackElement;\n this._videoEl.appendChild(clone);\n const src = track.getAttribute(\"src\") ?? undefined;\n const format = src?.toLowerCase().endsWith(\".srt\") ? \"srt\" : \"vtt\";\n this._htmlTrackInfo.push({\n id: 10000 + htmlIdx,\n format,\n language: track.srclang || track.getAttribute(\"label\") || undefined,\n sidecarUrl: src,\n });\n htmlIdx++;\n }\n }\n this._dispatch(\"trackschange\", {\n audioTracks: this._audioTracks,\n subtitleTracks: this.subtitleTracks,\n });\n }\n\n /** Internal src setter — separate from the property setter so the\n * attributeChangedCallback can use it without re-entering reflection. */\n private _setSrcInternal(value: string | null): void {\n // Same-value reassignment: no-op (#11 in the lifecycle list).\n if (value === this._src && this._source == null) return;\n this._src = value;\n this._source = null;\n this._onSourceChanged();\n }\n\n /** Called whenever the active source changes (src or source). */\n private _onSourceChanged(): void {\n if (this._destroyed) return;\n const source = this._activeSource();\n if (source == null) {\n // Null transition: tear down and stay idle.\n this._bootstrapId++;\n void this._teardown();\n return;\n }\n // Only bootstrap if we're connected to the DOM.\n if (this.isConnected) {\n void this._bootstrap(source);\n }\n }\n\n // ── Bootstrap (the only place a UnifiedPlayer is created) ──────────────\n\n private async _bootstrap(source: MediaInput): Promise<void> {\n if (this._destroyed) return;\n const id = ++this._bootstrapId;\n\n // Tear down any existing player before starting a new one. Pass the\n // bootstrap id we just claimed so teardown doesn't bump it again\n // (which would invalidate ourselves).\n await this._teardown(id);\n if (id !== this._bootstrapId || this._destroyed) return;\n\n this._dispatch(\"loadstart\", {});\n\n let player: UnifiedPlayer;\n try {\n player = await createPlayer({\n source,\n target: this._videoEl,\n // Honor the consumer's preferred initial strategy. \"auto\" means\n // \"let the classifier decide\" — the createPlayer call simply doesn't\n // pass initialStrategy in that case.\n ...(this._preferredStrategy !== \"auto\"\n ? { initialStrategy: this._preferredStrategy }\n : {}),\n ...(this._subtitles ? { subtitles: this._subtitles } : {}),\n });\n } catch (err) {\n // Stale or destroyed — silently abandon.\n if (id !== this._bootstrapId || this._destroyed) return;\n this._dispatchError(err);\n return;\n }\n\n // Race check: if anything happened during the await above, bail.\n if (id !== this._bootstrapId || this._destroyed || !this.isConnected) {\n try { await player.destroy(); } catch { /* ignore */ }\n return;\n }\n\n this._player = player;\n\n // Resync any light-DOM <track> children into the (possibly fresh) shadow\n // <video>. Strategies that swap or reset the inner video state would\n // otherwise lose the tracks the user declared in HTML.\n this._syncTextTracks();\n\n // Wire events. The unsubscribe handles are not stored individually\n // because destroy() will tear down the whole session anyway.\n player.on(\"strategy\", ({ strategy, reason }) => {\n // strategy event fires on initial classification AND any escalation.\n const cls = player.getDiagnostics().strategyClass;\n this._strategy = strategy;\n this._strategyClass = cls === \"pending\" ? null : cls;\n this._dispatch(\"strategychange\", {\n strategy,\n strategyClass: this._strategyClass,\n reason,\n diagnostics: player.getDiagnostics(),\n });\n });\n\n player.on(\"strategychange\", ({ from, to, reason, currentTime }) => {\n this._dispatch(\"strategychange\", {\n from,\n strategy: to,\n strategyClass: player.getDiagnostics().strategyClass === \"pending\" ? null : player.getDiagnostics().strategyClass,\n reason,\n currentTime,\n diagnostics: player.getDiagnostics(),\n });\n });\n\n player.on(\"tracks\", ({ video: _v, audio, subtitle }) => {\n this._audioTracks = audio;\n this._subtitleTracks = subtitle;\n this._dispatch(\"trackschange\", {\n audioTracks: audio,\n subtitleTracks: subtitle,\n });\n });\n\n player.on(\"error\", (err: Error) => {\n this._dispatchError(err);\n });\n\n player.on(\"timeupdate\", ({ currentTime }) => {\n this._dispatch(\"timeupdate\", { currentTime });\n });\n\n player.on(\"ended\", () => {\n this._dispatch(\"ended\", {});\n });\n\n player.on(\"ready\", () => {\n this._dispatch(\"ready\", { diagnostics: player.getDiagnostics() });\n // Apply any pending seek that was set before the player existed.\n if (this._pendingSeek != null) {\n const t = this._pendingSeek;\n this._pendingSeek = null;\n void player.seek(t).catch(() => { /* ignore */ });\n }\n // Honor any pending play() that was queued before bootstrap finished.\n if (this._pendingPlay) {\n this._pendingPlay = false;\n void player.play().catch(() => { /* ignore — autoplay may be blocked */ });\n } else if (this.autoplay) {\n void player.play().catch(() => { /* ignore */ });\n }\n });\n }\n\n /**\n * Tear down the active player and reset runtime state. Idempotent.\n * If `currentBootstrapId` is provided, the bootstrap counter is NOT\n * incremented (used by `_bootstrap()` to avoid invalidating itself).\n */\n private async _teardown(currentBootstrapId?: number): Promise<void> {\n if (currentBootstrapId == null) {\n // External callers (disconnect, destroy, source change) should bump\n // the counter so any in-flight bootstrap is invalidated. The internal\n // _bootstrap() call passes its own ID and we skip the bump.\n this._bootstrapId++;\n }\n const player = this._player;\n this._player = null;\n this._strategy = null;\n this._strategyClass = null;\n this._audioTracks = [];\n this._subtitleTracks = [];\n if (player) {\n try { await player.destroy(); } catch { /* ignore */ }\n }\n }\n\n // ── Public properties ──────────────────────────────────────────────────\n\n get src(): string | null {\n return this._src;\n }\n\n set src(value: string | null) {\n if (value == null) {\n this.removeAttribute(\"src\");\n } else {\n this.setAttribute(\"src\", value);\n }\n // attributeChangedCallback handles the rest.\n }\n\n get source(): MediaInput | null {\n return this._source;\n }\n\n set source(value: MediaInput | null) {\n // Same-value reassignment for rich values is identity-based.\n if (value === this._source && this._src == null) return;\n this._source = value;\n if (value != null) {\n // Setting source clears src. Suppress the attribute callback so\n // removing the src attribute doesn't wipe the source we just set.\n this._src = null;\n if (this.hasAttribute(\"src\")) {\n this._suppressSrcAttrCallback = true;\n try {\n this.removeAttribute(\"src\");\n } finally {\n this._suppressSrcAttrCallback = false;\n }\n }\n }\n this._onSourceChanged();\n }\n\n get autoplay(): boolean {\n return this.hasAttribute(\"autoplay\");\n }\n\n set autoplay(value: boolean) {\n if (value) this.setAttribute(\"autoplay\", \"\");\n else this.removeAttribute(\"autoplay\");\n }\n\n get muted(): boolean {\n return this.hasAttribute(\"muted\");\n }\n\n set muted(value: boolean) {\n if (value) this.setAttribute(\"muted\", \"\");\n else this.removeAttribute(\"muted\");\n }\n\n get loop(): boolean {\n return this.hasAttribute(\"loop\");\n }\n\n set loop(value: boolean) {\n if (value) this.setAttribute(\"loop\", \"\");\n else this.removeAttribute(\"loop\");\n }\n\n get preload(): \"none\" | \"metadata\" | \"auto\" {\n const v = this.getAttribute(\"preload\");\n return v === \"none\" || v === \"metadata\" || v === \"auto\" ? v : \"auto\";\n }\n\n set preload(value: \"none\" | \"metadata\" | \"auto\") {\n this.setAttribute(\"preload\", value);\n }\n\n get diagnostics(): boolean {\n return this.hasAttribute(\"diagnostics\");\n }\n\n set diagnostics(value: boolean) {\n if (value) this.setAttribute(\"diagnostics\", \"\");\n else this.removeAttribute(\"diagnostics\");\n }\n\n get preferredStrategy(): PreferredStrategy {\n return this._preferredStrategy;\n }\n\n set preferredStrategy(value: PreferredStrategy) {\n if (PREFERRED_STRATEGY_VALUES.has(value)) {\n this.setAttribute(\"preferstrategy\", value);\n }\n }\n\n get currentTime(): number {\n return this._player?.getCurrentTime() ?? 0;\n }\n\n set currentTime(value: number) {\n if (this._player) {\n void this._player.seek(value).catch(() => { /* ignore */ });\n } else {\n // Defer to the next bootstrap. The `ready` handler applies it.\n this._pendingSeek = value;\n }\n }\n\n get duration(): number {\n return this._player?.getDuration() ?? NaN;\n }\n\n get paused(): boolean {\n return this._videoEl.paused;\n }\n\n get ended(): boolean {\n return this._videoEl.ended;\n }\n\n get readyState(): number {\n return this._videoEl.readyState;\n }\n\n /**\n * Buffered time ranges for the active source. Mirrors the standard\n * `<video>.buffered` `TimeRanges` API. For the native and remux strategies\n * this reflects the underlying SourceBuffer / progressive download state.\n * For the hybrid and fallback (canvas-rendered) strategies it currently\n * returns an empty TimeRanges; a future release will synthesize a coarse\n * range from the decoder's read position.\n */\n get buffered(): TimeRanges {\n return this._videoEl.buffered;\n }\n\n // ── HTMLMediaElement parity ───────────────────────────────────────────\n // Mirror the standard <video> surface so consumers can drop the element\n // in as a <video> replacement. Each property is a thin passthrough to the\n // shadow `<video>`.\n\n get poster(): string {\n return this._videoEl.poster;\n }\n set poster(value: string) {\n if (value == null || value === \"\") this.removeAttribute(\"poster\");\n else this.setAttribute(\"poster\", value);\n }\n\n get volume(): number {\n return this._videoEl.volume;\n }\n set volume(value: number) {\n this._videoEl.volume = value;\n }\n\n get playbackRate(): number {\n return this._videoEl.playbackRate;\n }\n set playbackRate(value: number) {\n this._videoEl.playbackRate = value;\n }\n\n get videoWidth(): number {\n return this._videoEl.videoWidth;\n }\n\n get videoHeight(): number {\n return this._videoEl.videoHeight;\n }\n\n get played(): TimeRanges {\n return this._videoEl.played;\n }\n\n get seekable(): TimeRanges {\n return this._videoEl.seekable;\n }\n\n get crossOrigin(): string | null {\n return this._videoEl.crossOrigin;\n }\n set crossOrigin(value: string | null) {\n if (value == null) this.removeAttribute(\"crossorigin\");\n else this.setAttribute(\"crossorigin\", value);\n }\n\n get disableRemotePlayback(): boolean {\n return this._videoEl.disableRemotePlayback;\n }\n set disableRemotePlayback(value: boolean) {\n if (value) this.setAttribute(\"disableremoteplayback\", \"\");\n else this.removeAttribute(\"disableremoteplayback\");\n }\n\n /**\n * Native `HTMLMediaElement.canPlayType()` passthrough. Note that this\n * answers about the *browser's* native support, not avbridge's full\n * capabilities — avbridge can play many formats this method returns \"\"\n * for, by routing them to the remux/hybrid/fallback strategies.\n */\n canPlayType(mimeType: string): CanPlayTypeResult {\n return this._videoEl.canPlayType(mimeType);\n }\n\n /**\n * **Escape hatch.** The underlying shadow-DOM `<video>` element.\n *\n * Use for native browser APIs the wrapper doesn't expose:\n * - `el.videoElement.requestPictureInPicture()`\n * - `el.videoElement.audioTracks` (browser native, not avbridge's track list)\n * - direct integration with libraries that need a real HTMLVideoElement\n *\n * **Caveat:** When the active strategy is `\"fallback\"` or `\"hybrid\"`,\n * frames are rendered to a canvas overlay, not into this `<video>`.\n * APIs that depend on the actual pixels (Picture-in-Picture, captureStream)\n * will not show the playing content in those modes. Check `el.strategy`\n * before using such APIs.\n */\n get videoElement(): HTMLVideoElement {\n return this._videoEl;\n }\n\n get strategy(): StrategyName | null {\n return this._strategy;\n }\n\n get strategyClass(): StrategyClass | null {\n return this._strategyClass;\n }\n\n get player(): UnifiedPlayer | null {\n return this._player;\n }\n\n get audioTracks(): AudioTrackInfo[] {\n return this._audioTracks;\n }\n\n get subtitleTracks(): SubtitleTrackInfo[] {\n // Merge player-sourced tracks with light-DOM `<track>` children.\n // Both sources coexist: options.subtitles + embedded-in-container\n // tracks contribute to _subtitleTracks; HTML `<track>` children\n // contribute _htmlTrackInfo with ids in the 10000+ range.\n return this._htmlTrackInfo.length === 0\n ? this._subtitleTracks\n : [...this._subtitleTracks, ...this._htmlTrackInfo];\n }\n\n /**\n * External subtitle files to attach when the source loads. Takes effect\n * on the next bootstrap — set before assigning `source`, or reload via\n * `load()` after changing. For dynamic post-bootstrap addition, use\n * `addSubtitle()` instead.\n *\n * @example\n * el.subtitles = [{ url: \"/en.srt\", format: \"srt\", language: \"en\" }];\n * el.src = \"/movie.mp4\";\n */\n get subtitles(): Array<{ url: string; language?: string; format?: \"vtt\" | \"srt\" }> | null {\n return this._subtitles;\n }\n\n set subtitles(value: Array<{ url: string; language?: string; format?: \"vtt\" | \"srt\" }> | null) {\n this._subtitles = value;\n }\n\n /**\n * Attach a subtitle track to the current playback without rebuilding\n * the player. Works while the element is playing — converts SRT to\n * VTT if needed, adds a `<track>` to the inner `<video>`. Canvas\n * strategies pick up the new track via their textTracks watcher.\n */\n async addSubtitle(subtitle: { url: string; language?: string; format?: \"vtt\" | \"srt\" }): Promise<void> {\n const { attachSubtitleTracks } = await import(\"../subtitles/index.js\");\n const format = subtitle.format ?? (subtitle.url.endsWith(\".srt\") ? \"srt\" : \"vtt\");\n const track = {\n id: this._subtitleTracks.length,\n format,\n language: subtitle.language,\n sidecarUrl: subtitle.url,\n };\n this._subtitleTracks.push(track);\n await attachSubtitleTracks(\n this._videoEl,\n this._subtitleTracks,\n undefined,\n (err, t) => {\n // eslint-disable-next-line no-console\n console.warn(`[avbridge] subtitle ${t.id} failed: ${err.message}`);\n },\n );\n }\n\n // ── Public methods ─────────────────────────────────────────────────────\n\n /** Force a (re-)bootstrap if a source is currently set. */\n async load(): Promise<void> {\n if (this._destroyed) return;\n const source = this._activeSource();\n if (source == null) return;\n await this._bootstrap(source);\n }\n\n /**\n * Begin or resume playback. If the player isn't ready yet, the call is\n * queued and applied once `ready` fires.\n */\n async play(): Promise<void> {\n if (this._destroyed) return;\n if (this._player) {\n await this._player.play();\n } else {\n this._pendingPlay = true;\n }\n }\n\n pause(): void {\n if (this._destroyed) return;\n this._pendingPlay = false;\n this._player?.pause();\n }\n\n /**\n * Tear down the element permanently. After destroy(), the element ignores\n * all method calls and attribute changes.\n */\n async destroy(): Promise<void> {\n if (this._destroyed) return;\n this._destroyed = true;\n await this._teardown();\n this._dispatch(\"destroy\", {});\n }\n\n async setAudioTrack(id: number): Promise<void> {\n if (this._destroyed || !this._player) return;\n await this._player.setAudioTrack(id);\n }\n\n async setSubtitleTrack(id: number | null): Promise<void> {\n if (this._destroyed || !this._player) return;\n await this._player.setSubtitleTrack(id);\n }\n\n getDiagnostics(): DiagnosticsSnapshot | null {\n return this._player?.getDiagnostics() ?? null;\n }\n\n // ── Typed addEventListener / removeEventListener overloads ────────────\n // Consumers using avbridge-specific events get a typed CustomEvent\n // payload; standard HTMLMediaElement events retain their native types.\n\n override addEventListener<K extends keyof AvbridgeVideoElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: AvbridgeVideoElementEventMap[K]) => unknown,\n options?: boolean | AddEventListenerOptions,\n ): void;\n override addEventListener<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: HTMLElementEventMap[K]) => unknown,\n options?: boolean | AddEventListenerOptions,\n ): void;\n override addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n override addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.addEventListener(type, listener, options);\n }\n\n override removeEventListener<K extends keyof AvbridgeVideoElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: AvbridgeVideoElementEventMap[K]) => unknown,\n options?: boolean | EventListenerOptions,\n ): void;\n override removeEventListener<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: HTMLElementEventMap[K]) => unknown,\n options?: boolean | EventListenerOptions,\n ): void;\n override removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n override removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void {\n super.removeEventListener(type, listener, options);\n }\n\n // ── Event helpers ──────────────────────────────────────────────────────\n\n private _dispatch<T>(name: string, detail: T): void {\n this.dispatchEvent(new CustomEvent(name, { detail, bubbles: false }));\n }\n\n private _dispatchError(err: unknown): void {\n const error = err instanceof Error ? err : new Error(String(err));\n this._dispatch(\"error\", { error, diagnostics: this._player?.getDiagnostics() ?? null });\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"avbridge-video\": AvbridgeVideoElement;\n }\n}\n","/**\n * Subpath entry: `import \"avbridge/element\"` registers the\n * `<avbridge-video>` custom element.\n *\n * This is a separate entry point from the core (`avbridge`) so that consumers\n * who only want the engine don't pay for the element code, and consumers who\n * want both pay for the element code exactly once.\n *\n * The registration is guarded so re-importing this module (e.g. via HMR or\n * multiple bundles) does not throw a \"name already defined\" error.\n *\n * The tag name `<avbridge-player>` is reserved for a future controls-bearing\n * element. Today, only `<avbridge-video>` (the bare HTMLMediaElement-compatible\n * primitive) is registered.\n */\n\nimport { AvbridgeVideoElement } from \"./element/avbridge-video.js\";\n\nexport { AvbridgeVideoElement };\n\nif (typeof customElements !== \"undefined\" && !customElements.get(\"avbridge-video\")) {\n customElements.define(\"avbridge-video\", AvbridgeVideoElement);\n}\n"]}
1
+ {"version":3,"sources":["../src/element/avbridge-video.ts","../src/element.ts"],"names":["createPlayer"],"mappings":"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","file":"element.cjs","sourcesContent":["/**\n * `<avbridge-video>` — `HTMLMediaElement`-compatible primitive backed by the\n * avbridge engine. Drop-in replacement for a `<video>` element with no\n * built-in UI.\n *\n * Purpose:\n *\n * 1. Validate the public API by being a real consumer of `createPlayer()`.\n * 2. Drive lifecycle correctness in the core via adversarial integration tests.\n * 3. Give consumers a `<video>`-compatible primitive they can wrap with\n * their own UI.\n *\n * **It is not a player UI framework.** For YouTube-style chrome (seek\n * bar, play/pause, settings menu, fullscreen, auto-hiding controls) use\n * `<avbridge-player>` — it wraps this element with a full UI. See\n * `docs/dev/WEB_COMPONENT_SPEC.md` for the full spec, lifecycle invariants,\n * and edge case list.\n */\n\nimport { createPlayer, type UnifiedPlayer } from \"../player.js\";\nimport type {\n MediaInput,\n StrategyName,\n StrategyClass,\n AudioTrackInfo,\n SubtitleTrackInfo,\n DiagnosticsSnapshot,\n AvbridgeVideoElementEventMap,\n} from \"../types.js\";\n\n/** Strategy preference passed via the `preferstrategy` attribute. */\ntype PreferredStrategy = \"auto\" | StrategyName;\n\nconst PREFERRED_STRATEGY_VALUES = new Set<PreferredStrategy>([\n \"auto\",\n \"native\",\n \"remux\",\n \"hybrid\",\n \"fallback\",\n]);\n\n/** Fit mode — how the video fills the element's box. Mirrors CSS object-fit. */\ntype FitMode = \"contain\" | \"cover\" | \"fill\";\nconst FIT_VALUES = new Set<FitMode>([\"contain\", \"cover\", \"fill\"]);\nconst DEFAULT_FIT: FitMode = \"contain\";\n\n/**\n * Standard `HTMLMediaElement` events we forward from the inner `<video>`\n * to the wrapper element so consumers can `el.addEventListener(\"loadedmetadata\", ...)`\n * exactly like they would with a real `<video>`. The element also dispatches\n * its own custom events (`strategychange`, `ready`, `error`, etc.) — those\n * are NOT in this list because they're avbridge-specific.\n *\n * Note: `progress` and `timeupdate` are deliberately NOT forwarded here.\n * `progress` is dispatched by the constructor with our own `{ buffered }`\n * detail. `timeupdate` is dispatched by the player layer (so it works for\n * canvas-rendered fallback playback too, where the inner <video> never\n * fires its own timeupdate).\n */\nconst FORWARDED_VIDEO_EVENTS = [\n \"loadstart\",\n \"loadedmetadata\",\n \"loadeddata\",\n \"canplay\",\n \"canplaythrough\",\n \"play\",\n \"playing\",\n \"pause\",\n \"seeking\",\n \"seeked\",\n \"volumechange\",\n \"ratechange\",\n \"durationchange\",\n \"waiting\",\n \"stalled\",\n \"emptied\",\n \"resize\",\n \"error\",\n] as const;\n\n/**\n * `HTMLElement` is a browser-only global. SSR frameworks (Next.js, Astro,\n * Remix, etc.) commonly import library modules on the server to extract\n * types or do tree-shaking, even if the user only ends up using them in\n * the browser. If we extended `HTMLElement` directly, the `class extends`\n * expression would be evaluated at module load time and crash in Node.\n *\n * The fix: in non-browser environments, fall back to an empty stub class.\n * The element is never *constructed* server-side (the registration in\n * `element.ts` is guarded by `typeof customElements !== \"undefined\"`), so\n * the stub is never instantiated — it just lets the class declaration\n * evaluate cleanly so the module can be imported anywhere.\n */\nconst HTMLElementCtor: typeof HTMLElement =\n typeof HTMLElement !== \"undefined\"\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n/**\n * Custom element. Lifecycle correctness is enforced via a monotonically\n * increasing `_bootstrapId`: every async bootstrap captures the ID at start\n * and discards itself if the ID has changed by the time it resolves. This\n * single pattern handles disconnect-during-bootstrap, rapid src reassignment,\n * bootstrap races, and destroy-during-bootstrap.\n */\nexport class AvbridgeVideoElement extends HTMLElementCtor {\n static readonly observedAttributes = [\n \"src\",\n \"autoplay\",\n \"muted\",\n \"loop\",\n \"preload\",\n \"poster\",\n \"playsinline\",\n \"crossorigin\",\n \"disableremoteplayback\",\n \"diagnostics\",\n \"preferstrategy\",\n \"fit\",\n \"no-orientation-lock\",\n ];\n\n // ── Internal state ─────────────────────────────────────────────────────\n\n /** The shadow DOM `<video>` element that strategies render into. */\n private _videoEl!: HTMLVideoElement;\n\n /** Active player session, if any. Cleared on teardown. */\n private _player: UnifiedPlayer | null = null;\n\n /**\n * Monotonic counter incremented on every (re)bootstrap. Async bootstrap\n * work captures the current ID; if it doesn't match by the time the work\n * resolves, the work is discarded.\n */\n private _bootstrapId = 0;\n\n /** True after destroy() — element is permanently unusable. */\n private _destroyed = false;\n\n /** Internal source state. Either string-form (src) OR rich (source). */\n private _src: string | null = null;\n private _source: MediaInput | null = null;\n\n /**\n * Set when the `source` property setter is in the middle of clearing the\n * `src` attribute as part of mutual exclusion. The attributeChangedCallback\n * checks this flag and skips its normal \"clear source\" side effect, which\n * would otherwise wipe the value we just set.\n */\n private _suppressSrcAttrCallback = false;\n\n /** Last-known runtime state surfaced via getters. */\n private _strategy: StrategyName | null = null;\n private _strategyClass: StrategyClass | null = null;\n private _audioTracks: AudioTrackInfo[] = [];\n /** Subtitle tracks reported by the active UnifiedPlayer (options.subtitles\n * + embedded container tracks + programmatic addSubtitle calls). */\n private _subtitleTracks: SubtitleTrackInfo[] = [];\n /** Subtitle tracks derived from light-DOM `<track>` children. Maintained\n * by _syncTextTracks on every mutation. Merged into the public\n * `subtitleTracks` getter so the player's settings menu sees them. */\n private _htmlTrackInfo: SubtitleTrackInfo[] = [];\n\n /**\n * External subtitle list forwarded to `createPlayer()` on the next\n * bootstrap. Setting this after bootstrap queues it for the next\n * source change; consumers that need to swap subtitles mid-playback\n * should set `source` to reload.\n */\n private _subtitles: Array<{ url: string; language?: string; format?: \"vtt\" | \"srt\" }> | null = null;\n\n /**\n * Initial strategy preference. `\"auto\"` means \"let the classifier decide\";\n * any other value is passed to `createPlayer({ initialStrategy })` and\n * skips classification on the next bootstrap. Note that this only affects\n * the *initial* pick — runtime fallback escalation still applies, so a\n * preference of `\"native\"` may still escalate to remux/hybrid/fallback if\n * native fails.\n */\n private _preferredStrategy: PreferredStrategy = \"auto\";\n\n /** Current fit mode. Applied to the inner `<video>` via object-fit, and\n * to the fallback canvas via the `--avbridge-fit` CSS custom property on\n * the stage wrapper (see `src/strategies/fallback/video-renderer.ts`). */\n private _fit: FitMode = DEFAULT_FIT;\n /** The stage wrapper — the element the canvas attaches into, and where\n * the `--avbridge-fit` CSS custom property lives. */\n private _stageEl!: HTMLDivElement;\n\n /** Set if currentTime was assigned before the player was ready. */\n private _pendingSeek: number | null = null;\n /** Set if play() was called before the player was ready. */\n private _pendingPlay = false;\n\n /** MutationObserver tracking light-DOM `<track>` children. */\n private _trackObserver: MutationObserver | null = null;\n\n /** Document-level fullscreenchange handler — installed while connected so\n * the element can lock/unlock screen orientation to match the video's\n * intrinsic aspect. */\n private _fullscreenChangeHandler: (() => void) | null = null;\n /** True if we successfully called screen.orientation.lock() on the last\n * fullscreen entry. Used to know whether to unlock on exit. */\n private _orientationLocked = false;\n\n // ── Construction & lifecycle ───────────────────────────────────────────\n\n constructor() {\n super();\n const root = this.attachShadow({ mode: \"open\" });\n\n // A positioned wrapper inside the shadow root. The fallback strategy\n // overlays a canvas on top of the <video> via `target.parentNode` —\n // that only works if the parent is a real Element with layout. Without\n // this wrapper, `target.parentElement` would be null (ShadowRoot is\n // not an Element) and the canvas would never attach to the DOM.\n const stage = document.createElement(\"div\");\n stage.setAttribute(\"part\", \"stage\");\n stage.style.cssText = `position:relative;width:100%;height:100%;display:block;--avbridge-fit:${DEFAULT_FIT};`;\n root.appendChild(stage);\n this._stageEl = stage;\n\n this._videoEl = document.createElement(\"video\");\n this._videoEl.setAttribute(\"part\", \"video\");\n this._videoEl.style.cssText = `width:100%;height:100%;display:block;background:#000;object-fit:var(--avbridge-fit, ${DEFAULT_FIT});`;\n this._videoEl.playsInline = true;\n stage.appendChild(this._videoEl);\n\n // Forward the underlying <video>'s `progress` event so consumers can\n // observe buffered-range updates without reaching into the shadow DOM.\n // This works for native + remux (real video element with buffered\n // ranges) and is a no-op for hybrid/fallback (canvas-rendered, no\n // buffered ranges yet).\n this._videoEl.addEventListener(\"progress\", () => {\n if (this._destroyed) return;\n this._dispatch(\"progress\", { buffered: this._videoEl.buffered });\n });\n\n // Forward all standard HTMLMediaElement events from the inner <video>\n // so consumers can use the element as a drop-in <video> replacement.\n // Each event is re-dispatched on the wrapper element with no detail —\n // listeners that need state should read it from the element directly.\n for (const eventName of FORWARDED_VIDEO_EVENTS) {\n this._videoEl.addEventListener(eventName, () => {\n if (this._destroyed) return;\n this.dispatchEvent(new Event(eventName, { bubbles: false }));\n });\n }\n }\n\n connectedCallback(): void {\n if (this._destroyed) return;\n // Pick up any <track> children that were declared in HTML before the\n // element upgraded, and watch for future additions/removals.\n this._syncTextTracks();\n if (!this._trackObserver) {\n this._trackObserver = new MutationObserver(() => this._syncTextTracks());\n this._trackObserver.observe(this, { childList: true, subtree: false });\n }\n if (!this._fullscreenChangeHandler) {\n this._fullscreenChangeHandler = () => this._onFullscreenChange();\n document.addEventListener(\"fullscreenchange\", this._fullscreenChangeHandler);\n }\n // Connection is the trigger for bootstrap. If we have a pending source\n // (set before connect), kick off bootstrap now.\n const source = this._activeSource();\n if (source != null) {\n void this._bootstrap(source);\n }\n }\n\n disconnectedCallback(): void {\n if (this._destroyed) return;\n if (this._trackObserver) {\n this._trackObserver.disconnect();\n this._trackObserver = null;\n }\n if (this._fullscreenChangeHandler) {\n document.removeEventListener(\"fullscreenchange\", this._fullscreenChangeHandler);\n this._fullscreenChangeHandler = null;\n }\n // If we were fullscreen via some ancestor and got disconnected, release\n // any orientation lock we had taken.\n this._releaseOrientationLock();\n // Bump the bootstrap token so any in-flight async work is invalidated\n // before we tear down. _teardown() also bumps but we want the bump to\n // happen synchronously here so any awaited promise that resolves\n // between `disconnect` and `_teardown` sees the new ID.\n this._bootstrapId++;\n void this._teardown();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (this._destroyed) return;\n switch (name) {\n case \"src\":\n if (this._suppressSrcAttrCallback) break;\n this._setSrcInternal(newValue);\n break;\n case \"autoplay\":\n case \"muted\":\n case \"loop\":\n case \"playsinline\":\n case \"disableremoteplayback\":\n // Reflect onto the underlying <video> element.\n if (newValue == null) this._videoEl.removeAttribute(name);\n else this._videoEl.setAttribute(name, newValue);\n break;\n case \"preload\":\n case \"poster\":\n case \"crossorigin\":\n if (newValue == null) this._videoEl.removeAttribute(name);\n else this._videoEl.setAttribute(name, newValue);\n break;\n case \"diagnostics\":\n // Phase A: no UI. Property is observable for users via getDiagnostics().\n break;\n case \"preferstrategy\":\n if (newValue && PREFERRED_STRATEGY_VALUES.has(newValue as PreferredStrategy)) {\n this._preferredStrategy = newValue as PreferredStrategy;\n } else {\n this._preferredStrategy = \"auto\";\n }\n break;\n case \"fit\": {\n const next: FitMode = newValue && FIT_VALUES.has(newValue as FitMode)\n ? (newValue as FitMode)\n : DEFAULT_FIT;\n if (next === this._fit) break;\n this._fit = next;\n this._stageEl.style.setProperty(\"--avbridge-fit\", next);\n this._dispatch(\"fitchange\", { fit: next });\n break;\n }\n }\n }\n\n // ── Source handling ────────────────────────────────────────────────────\n\n /** Returns the currently-active source (src or source), whichever is set. */\n private _activeSource(): MediaInput | null {\n if (this._source != null) return this._source;\n if (this._src != null) return this._src;\n return null;\n }\n\n /**\n * Mirror light-DOM `<track>` children into the shadow `<video>` so that\n * the browser's native text-track machinery picks them up. Called on\n * connect, on every mutation of light-DOM children, and once after each\n * source change so newly-set tracks survive a fresh `<video>`.\n *\n * Strategy: clone the children. We don't move them because the user's\n * code may still hold references to the originals (e.g. to set `default`).\n * The shadow copies are throwaway — we wipe them on every sync.\n */\n private _syncTextTracks(): void {\n // Remove existing shadow tracks.\n const existing = this._videoEl.querySelectorAll(\"track\");\n for (const t of Array.from(existing)) t.remove();\n // Clone every <track> light-DOM child into the shadow video, and\n // rebuild the HTML-derived subtitle info list so the `<avbridge-player>`\n // settings menu can render them alongside options-sourced tracks.\n // HTML tracks are assigned high, stable IDs (10000+index) to avoid\n // colliding with container-embedded ids (typically < 32).\n this._htmlTrackInfo = [];\n let htmlIdx = 0;\n for (const child of Array.from(this.children)) {\n if (child.tagName === \"TRACK\") {\n const track = child as HTMLTrackElement;\n const clone = track.cloneNode(true) as HTMLTrackElement;\n this._videoEl.appendChild(clone);\n const src = track.getAttribute(\"src\") ?? undefined;\n const format = src?.toLowerCase().endsWith(\".srt\") ? \"srt\" : \"vtt\";\n this._htmlTrackInfo.push({\n id: 10000 + htmlIdx,\n format,\n language: track.srclang || track.getAttribute(\"label\") || undefined,\n sidecarUrl: src,\n });\n htmlIdx++;\n }\n }\n this._dispatch(\"trackschange\", {\n audioTracks: this._audioTracks,\n subtitleTracks: this.subtitleTracks,\n });\n }\n\n /** Internal src setter — separate from the property setter so the\n * attributeChangedCallback can use it without re-entering reflection. */\n private _setSrcInternal(value: string | null): void {\n // Same-value reassignment: no-op (#11 in the lifecycle list).\n if (value === this._src && this._source == null) return;\n this._src = value;\n this._source = null;\n this._onSourceChanged();\n }\n\n /** Called whenever the active source changes (src or source). */\n private _onSourceChanged(): void {\n if (this._destroyed) return;\n const source = this._activeSource();\n if (source == null) {\n // Null transition: tear down and stay idle.\n this._bootstrapId++;\n void this._teardown();\n return;\n }\n // Only bootstrap if we're connected to the DOM.\n if (this.isConnected) {\n void this._bootstrap(source);\n }\n }\n\n // ── Bootstrap (the only place a UnifiedPlayer is created) ──────────────\n\n private async _bootstrap(source: MediaInput): Promise<void> {\n if (this._destroyed) return;\n const id = ++this._bootstrapId;\n\n // Tear down any existing player before starting a new one. Pass the\n // bootstrap id we just claimed so teardown doesn't bump it again\n // (which would invalidate ourselves).\n await this._teardown(id);\n if (id !== this._bootstrapId || this._destroyed) return;\n\n this._dispatch(\"loadstart\", {});\n\n let player: UnifiedPlayer;\n try {\n player = await createPlayer({\n source,\n target: this._videoEl,\n // Honor the consumer's preferred initial strategy. \"auto\" means\n // \"let the classifier decide\" — the createPlayer call simply doesn't\n // pass initialStrategy in that case.\n ...(this._preferredStrategy !== \"auto\"\n ? { initialStrategy: this._preferredStrategy }\n : {}),\n ...(this._subtitles ? { subtitles: this._subtitles } : {}),\n });\n } catch (err) {\n // Stale or destroyed — silently abandon.\n if (id !== this._bootstrapId || this._destroyed) return;\n this._dispatchError(err);\n return;\n }\n\n // Race check: if anything happened during the await above, bail.\n if (id !== this._bootstrapId || this._destroyed || !this.isConnected) {\n try { await player.destroy(); } catch { /* ignore */ }\n return;\n }\n\n this._player = player;\n\n // Resync any light-DOM <track> children into the (possibly fresh) shadow\n // <video>. Strategies that swap or reset the inner video state would\n // otherwise lose the tracks the user declared in HTML.\n this._syncTextTracks();\n\n // Wire events. The unsubscribe handles are not stored individually\n // because destroy() will tear down the whole session anyway.\n player.on(\"strategy\", ({ strategy, reason }) => {\n // strategy event fires on initial classification AND any escalation.\n const cls = player.getDiagnostics().strategyClass;\n this._strategy = strategy;\n this._strategyClass = cls === \"pending\" ? null : cls;\n this._dispatch(\"strategychange\", {\n strategy,\n strategyClass: this._strategyClass,\n reason,\n diagnostics: player.getDiagnostics(),\n });\n });\n\n player.on(\"strategychange\", ({ from, to, reason, currentTime }) => {\n this._dispatch(\"strategychange\", {\n from,\n strategy: to,\n strategyClass: player.getDiagnostics().strategyClass === \"pending\" ? null : player.getDiagnostics().strategyClass,\n reason,\n currentTime,\n diagnostics: player.getDiagnostics(),\n });\n });\n\n player.on(\"tracks\", ({ video: _v, audio, subtitle }) => {\n this._audioTracks = audio;\n this._subtitleTracks = subtitle;\n this._dispatch(\"trackschange\", {\n audioTracks: audio,\n subtitleTracks: subtitle,\n });\n });\n\n player.on(\"error\", (err: Error) => {\n this._dispatchError(err);\n });\n\n player.on(\"timeupdate\", ({ currentTime }) => {\n this._dispatch(\"timeupdate\", { currentTime });\n });\n\n player.on(\"ended\", () => {\n this._dispatch(\"ended\", {});\n });\n\n player.on(\"ready\", () => {\n this._dispatch(\"ready\", { diagnostics: player.getDiagnostics() });\n // Apply any pending seek that was set before the player existed.\n if (this._pendingSeek != null) {\n const t = this._pendingSeek;\n this._pendingSeek = null;\n void player.seek(t).catch(() => { /* ignore */ });\n }\n // Honor any pending play() that was queued before bootstrap finished.\n if (this._pendingPlay) {\n this._pendingPlay = false;\n void player.play().catch(() => { /* ignore — autoplay may be blocked */ });\n } else if (this.autoplay) {\n void player.play().catch(() => { /* ignore */ });\n }\n });\n }\n\n /**\n * Tear down the active player and reset runtime state. Idempotent.\n * If `currentBootstrapId` is provided, the bootstrap counter is NOT\n * incremented (used by `_bootstrap()` to avoid invalidating itself).\n */\n private async _teardown(currentBootstrapId?: number): Promise<void> {\n if (currentBootstrapId == null) {\n // External callers (disconnect, destroy, source change) should bump\n // the counter so any in-flight bootstrap is invalidated. The internal\n // _bootstrap() call passes its own ID and we skip the bump.\n this._bootstrapId++;\n }\n const player = this._player;\n this._player = null;\n this._strategy = null;\n this._strategyClass = null;\n this._audioTracks = [];\n this._subtitleTracks = [];\n if (player) {\n try { await player.destroy(); } catch { /* ignore */ }\n }\n }\n\n // ── Public properties ──────────────────────────────────────────────────\n\n get src(): string | null {\n return this._src;\n }\n\n set src(value: string | null) {\n if (value == null) {\n this.removeAttribute(\"src\");\n } else {\n this.setAttribute(\"src\", value);\n }\n // attributeChangedCallback handles the rest.\n }\n\n get source(): MediaInput | null {\n return this._source;\n }\n\n set source(value: MediaInput | null) {\n // Same-value reassignment for rich values is identity-based.\n if (value === this._source && this._src == null) return;\n this._source = value;\n if (value != null) {\n // Setting source clears src. Suppress the attribute callback so\n // removing the src attribute doesn't wipe the source we just set.\n this._src = null;\n if (this.hasAttribute(\"src\")) {\n this._suppressSrcAttrCallback = true;\n try {\n this.removeAttribute(\"src\");\n } finally {\n this._suppressSrcAttrCallback = false;\n }\n }\n }\n this._onSourceChanged();\n }\n\n get autoplay(): boolean {\n return this.hasAttribute(\"autoplay\");\n }\n\n set autoplay(value: boolean) {\n if (value) this.setAttribute(\"autoplay\", \"\");\n else this.removeAttribute(\"autoplay\");\n }\n\n get muted(): boolean {\n return this.hasAttribute(\"muted\");\n }\n\n set muted(value: boolean) {\n if (value) this.setAttribute(\"muted\", \"\");\n else this.removeAttribute(\"muted\");\n }\n\n get loop(): boolean {\n return this.hasAttribute(\"loop\");\n }\n\n set loop(value: boolean) {\n if (value) this.setAttribute(\"loop\", \"\");\n else this.removeAttribute(\"loop\");\n }\n\n get preload(): \"none\" | \"metadata\" | \"auto\" {\n const v = this.getAttribute(\"preload\");\n return v === \"none\" || v === \"metadata\" || v === \"auto\" ? v : \"auto\";\n }\n\n set preload(value: \"none\" | \"metadata\" | \"auto\") {\n this.setAttribute(\"preload\", value);\n }\n\n get diagnostics(): boolean {\n return this.hasAttribute(\"diagnostics\");\n }\n\n set diagnostics(value: boolean) {\n if (value) this.setAttribute(\"diagnostics\", \"\");\n else this.removeAttribute(\"diagnostics\");\n }\n\n get fit(): FitMode {\n return this._fit;\n }\n\n set fit(value: FitMode) {\n if (!FIT_VALUES.has(value)) return;\n this.setAttribute(\"fit\", value);\n }\n\n get preferredStrategy(): PreferredStrategy {\n return this._preferredStrategy;\n }\n\n set preferredStrategy(value: PreferredStrategy) {\n if (PREFERRED_STRATEGY_VALUES.has(value)) {\n this.setAttribute(\"preferstrategy\", value);\n }\n }\n\n get currentTime(): number {\n return this._player?.getCurrentTime() ?? 0;\n }\n\n set currentTime(value: number) {\n if (this._player) {\n void this._player.seek(value).catch(() => { /* ignore */ });\n } else {\n // Defer to the next bootstrap. The `ready` handler applies it.\n this._pendingSeek = value;\n }\n }\n\n get duration(): number {\n return this._player?.getDuration() ?? NaN;\n }\n\n get paused(): boolean {\n return this._videoEl.paused;\n }\n\n get ended(): boolean {\n return this._videoEl.ended;\n }\n\n get readyState(): number {\n return this._videoEl.readyState;\n }\n\n /**\n * Buffered time ranges for the active source. Mirrors the standard\n * `<video>.buffered` `TimeRanges` API. For the native and remux strategies\n * this reflects the underlying SourceBuffer / progressive download state.\n * For the hybrid and fallback (canvas-rendered) strategies it currently\n * returns an empty TimeRanges; a future release will synthesize a coarse\n * range from the decoder's read position.\n */\n get buffered(): TimeRanges {\n return this._videoEl.buffered;\n }\n\n // ── HTMLMediaElement parity ───────────────────────────────────────────\n // Mirror the standard <video> surface so consumers can drop the element\n // in as a <video> replacement. Each property is a thin passthrough to the\n // shadow `<video>`.\n\n get poster(): string {\n return this._videoEl.poster;\n }\n set poster(value: string) {\n if (value == null || value === \"\") this.removeAttribute(\"poster\");\n else this.setAttribute(\"poster\", value);\n }\n\n get volume(): number {\n return this._videoEl.volume;\n }\n set volume(value: number) {\n this._videoEl.volume = value;\n }\n\n get playbackRate(): number {\n return this._videoEl.playbackRate;\n }\n set playbackRate(value: number) {\n this._videoEl.playbackRate = value;\n }\n\n get videoWidth(): number {\n return this._videoEl.videoWidth;\n }\n\n get videoHeight(): number {\n return this._videoEl.videoHeight;\n }\n\n get played(): TimeRanges {\n return this._videoEl.played;\n }\n\n get seekable(): TimeRanges {\n return this._videoEl.seekable;\n }\n\n get crossOrigin(): string | null {\n return this._videoEl.crossOrigin;\n }\n set crossOrigin(value: string | null) {\n if (value == null) this.removeAttribute(\"crossorigin\");\n else this.setAttribute(\"crossorigin\", value);\n }\n\n get disableRemotePlayback(): boolean {\n return this._videoEl.disableRemotePlayback;\n }\n set disableRemotePlayback(value: boolean) {\n if (value) this.setAttribute(\"disableremoteplayback\", \"\");\n else this.removeAttribute(\"disableremoteplayback\");\n }\n\n /**\n * Native `HTMLMediaElement.canPlayType()` passthrough. Note that this\n * answers about the *browser's* native support, not avbridge's full\n * capabilities — avbridge can play many formats this method returns \"\"\n * for, by routing them to the remux/hybrid/fallback strategies.\n */\n canPlayType(mimeType: string): CanPlayTypeResult {\n return this._videoEl.canPlayType(mimeType);\n }\n\n /**\n * **Escape hatch.** The underlying shadow-DOM `<video>` element.\n *\n * Use for native browser APIs the wrapper doesn't expose:\n * - `el.videoElement.requestPictureInPicture()`\n * - `el.videoElement.audioTracks` (browser native, not avbridge's track list)\n * - direct integration with libraries that need a real HTMLVideoElement\n *\n * **Caveat:** When the active strategy is `\"fallback\"` or `\"hybrid\"`,\n * frames are rendered to a canvas overlay, not into this `<video>`.\n * APIs that depend on the actual pixels (Picture-in-Picture, captureStream)\n * will not show the playing content in those modes. Check `el.strategy`\n * before using such APIs.\n */\n get videoElement(): HTMLVideoElement {\n return this._videoEl;\n }\n\n get strategy(): StrategyName | null {\n return this._strategy;\n }\n\n get strategyClass(): StrategyClass | null {\n return this._strategyClass;\n }\n\n get player(): UnifiedPlayer | null {\n return this._player;\n }\n\n get audioTracks(): AudioTrackInfo[] {\n return this._audioTracks;\n }\n\n get subtitleTracks(): SubtitleTrackInfo[] {\n // Merge player-sourced tracks with light-DOM `<track>` children.\n // Both sources coexist: options.subtitles + embedded-in-container\n // tracks contribute to _subtitleTracks; HTML `<track>` children\n // contribute _htmlTrackInfo with ids in the 10000+ range.\n return this._htmlTrackInfo.length === 0\n ? this._subtitleTracks\n : [...this._subtitleTracks, ...this._htmlTrackInfo];\n }\n\n /**\n * External subtitle files to attach when the source loads. Takes effect\n * on the next bootstrap — set before assigning `source`, or reload via\n * `load()` after changing. For dynamic post-bootstrap addition, use\n * `addSubtitle()` instead.\n *\n * @example\n * el.subtitles = [{ url: \"/en.srt\", format: \"srt\", language: \"en\" }];\n * el.src = \"/movie.mp4\";\n */\n get subtitles(): Array<{ url: string; language?: string; format?: \"vtt\" | \"srt\" }> | null {\n return this._subtitles;\n }\n\n set subtitles(value: Array<{ url: string; language?: string; format?: \"vtt\" | \"srt\" }> | null) {\n this._subtitles = value;\n }\n\n /**\n * Attach a subtitle track to the current playback without rebuilding\n * the player. Works while the element is playing — converts SRT to\n * VTT if needed, adds a `<track>` to the inner `<video>`. Canvas\n * strategies pick up the new track via their textTracks watcher.\n */\n async addSubtitle(subtitle: { url: string; language?: string; format?: \"vtt\" | \"srt\" }): Promise<void> {\n const { attachSubtitleTracks } = await import(\"../subtitles/index.js\");\n const format = subtitle.format ?? (subtitle.url.endsWith(\".srt\") ? \"srt\" : \"vtt\");\n const track = {\n id: this._subtitleTracks.length,\n format,\n language: subtitle.language,\n sidecarUrl: subtitle.url,\n };\n this._subtitleTracks.push(track);\n await attachSubtitleTracks(\n this._videoEl,\n this._subtitleTracks,\n undefined,\n (err, t) => {\n // eslint-disable-next-line no-console\n console.warn(`[avbridge] subtitle ${t.id} failed: ${err.message}`);\n },\n );\n }\n\n /**\n * Disable the automatic `screen.orientation.lock()` that runs on\n * fullscreen entry. Set when you want to honor the device's native\n * auto-rotate instead of matching the video's intrinsic orientation.\n */\n get noOrientationLock(): boolean {\n return this.hasAttribute(\"no-orientation-lock\");\n }\n\n set noOrientationLock(value: boolean) {\n if (value) this.setAttribute(\"no-orientation-lock\", \"\");\n else this.removeAttribute(\"no-orientation-lock\");\n }\n\n // ── Fullscreen orientation lock ────────────────────────────────────────\n\n /** Called whenever `document.fullscreenchange` fires. If this element (or\n * any of its ancestors) is now fullscreen, derive the target orientation\n * from the video's intrinsic size and call `screen.orientation.lock()`.\n * On exit, release the lock we took. iOS Safari rejects `lock()` — we\n * swallow the rejection so nothing breaks on that path. */\n private _onFullscreenChange(): void {\n if (this._destroyed) return;\n const fsEl = document.fullscreenElement;\n const nowFullscreen = fsEl != null && this._isInsideOrEquals(fsEl);\n if (nowFullscreen && !this._orientationLocked) {\n if (this.noOrientationLock) return;\n const target = this._desiredOrientation();\n if (!target) return; // square or unknown — don't lock\n void this._lockOrientation(target);\n } else if (!nowFullscreen && this._orientationLocked) {\n this._releaseOrientationLock();\n }\n }\n\n /** Walk composed-tree ancestors to see if `target` is this element or\n * any ancestor across shadow boundaries. `Node.contains()` can't cross\n * shadow roots, so when `<avbridge-player>` (the fullscreen element)\n * hosts this `<avbridge-video>` inside its shadow DOM, `contains()`\n * returns false. */\n private _isInsideOrEquals(target: Element): boolean {\n let node: Node | null = this;\n while (node) {\n if (node === target) return true;\n const parent: Node | null = node.parentNode;\n if (parent instanceof ShadowRoot) node = parent.host;\n else node = parent;\n }\n return false;\n }\n\n /** Derive \"landscape\" / \"portrait\" from the intrinsic video dimensions.\n * Returns null when dimensions aren't known yet or the video is square.\n * Uses `videoWidth` / `videoHeight` from the inner `<video>`, which the\n * browser sets to the display-aspect-corrected size (so anamorphic\n * content is judged by its display aspect, not pixel aspect). */\n private _desiredOrientation(): \"landscape\" | \"portrait\" | null {\n const w = this._videoEl.videoWidth;\n const h = this._videoEl.videoHeight;\n if (!w || !h) return null;\n if (w === h) return null;\n return w > h ? \"landscape\" : \"portrait\";\n }\n\n /** Attempt to lock screen orientation. Swallows rejections — iOS Safari\n * doesn't implement `lock()`, and desktop / non-fullscreen contexts will\n * reject too. Records success so we know whether to unlock on exit. */\n private async _lockOrientation(target: \"landscape\" | \"portrait\"): Promise<void> {\n const so = (screen as Screen & {\n orientation?: ScreenOrientation & { lock?: (o: string) => Promise<void> };\n }).orientation;\n if (!so || typeof so.lock !== \"function\") return;\n try {\n await so.lock(target);\n this._orientationLocked = true;\n } catch {\n // iOS Safari, desktop, or user denied — ignore.\n }\n }\n\n private _releaseOrientationLock(): void {\n if (!this._orientationLocked) return;\n this._orientationLocked = false;\n const so = screen.orientation as ScreenOrientation | undefined;\n if (so && typeof so.unlock === \"function\") {\n try { so.unlock(); } catch { /* ignore */ }\n }\n }\n\n // ── Public methods ─────────────────────────────────────────────────────\n\n /** Force a (re-)bootstrap if a source is currently set. */\n async load(): Promise<void> {\n if (this._destroyed) return;\n const source = this._activeSource();\n if (source == null) return;\n await this._bootstrap(source);\n }\n\n /**\n * Begin or resume playback. If the player isn't ready yet, the call is\n * queued and applied once `ready` fires.\n */\n async play(): Promise<void> {\n if (this._destroyed) return;\n if (this._player) {\n await this._player.play();\n } else {\n this._pendingPlay = true;\n }\n }\n\n pause(): void {\n if (this._destroyed) return;\n this._pendingPlay = false;\n this._player?.pause();\n }\n\n /**\n * Tear down the element permanently. After destroy(), the element ignores\n * all method calls and attribute changes.\n */\n async destroy(): Promise<void> {\n if (this._destroyed) return;\n this._destroyed = true;\n await this._teardown();\n this._dispatch(\"destroy\", {});\n }\n\n async setAudioTrack(id: number): Promise<void> {\n if (this._destroyed || !this._player) return;\n await this._player.setAudioTrack(id);\n }\n\n async setSubtitleTrack(id: number | null): Promise<void> {\n if (this._destroyed || !this._player) return;\n await this._player.setSubtitleTrack(id);\n }\n\n getDiagnostics(): DiagnosticsSnapshot | null {\n return this._player?.getDiagnostics() ?? null;\n }\n\n // ── Typed addEventListener / removeEventListener overloads ────────────\n // Consumers using avbridge-specific events get a typed CustomEvent\n // payload; standard HTMLMediaElement events retain their native types.\n\n override addEventListener<K extends keyof AvbridgeVideoElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: AvbridgeVideoElementEventMap[K]) => unknown,\n options?: boolean | AddEventListenerOptions,\n ): void;\n override addEventListener<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: HTMLElementEventMap[K]) => unknown,\n options?: boolean | AddEventListenerOptions,\n ): void;\n override addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void;\n override addEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ): void {\n super.addEventListener(type, listener, options);\n }\n\n override removeEventListener<K extends keyof AvbridgeVideoElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: AvbridgeVideoElementEventMap[K]) => unknown,\n options?: boolean | EventListenerOptions,\n ): void;\n override removeEventListener<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: AvbridgeVideoElement, ev: HTMLElementEventMap[K]) => unknown,\n options?: boolean | EventListenerOptions,\n ): void;\n override removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void;\n override removeEventListener(\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | EventListenerOptions,\n ): void {\n super.removeEventListener(type, listener, options);\n }\n\n // ── Event helpers ──────────────────────────────────────────────────────\n\n private _dispatch<T>(name: string, detail: T): void {\n this.dispatchEvent(new CustomEvent(name, { detail, bubbles: false }));\n }\n\n private _dispatchError(err: unknown): void {\n const error = err instanceof Error ? err : new Error(String(err));\n this._dispatch(\"error\", { error, diagnostics: this._player?.getDiagnostics() ?? null });\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"avbridge-video\": AvbridgeVideoElement;\n }\n}\n","/**\n * Subpath entry: `import \"avbridge/element\"` registers the\n * `<avbridge-video>` custom element.\n *\n * This is a separate entry point from the core (`avbridge`) so that consumers\n * who only want the engine don't pay for the element code, and consumers who\n * want both pay for the element code exactly once.\n *\n * The registration is guarded so re-importing this module (e.g. via HMR or\n * multiple bundles) does not throw a \"name already defined\" error.\n *\n * Only `<avbridge-video>` (the bare HTMLMediaElement-compatible primitive)\n * is registered here. The chrome-bearing `<avbridge-player>` lives at the\n * `avbridge/player-element` subpath.\n */\n\nimport { AvbridgeVideoElement } from \"./element/avbridge-video.js\";\n\nexport { AvbridgeVideoElement };\n\nif (typeof customElements !== \"undefined\" && !customElements.get(\"avbridge-video\")) {\n customElements.define(\"avbridge-video\", AvbridgeVideoElement);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { a as MediaInput, n as StrategyName, S as StrategyClass, U as UnifiedPlayer, e as AudioTrackInfo, o as SubtitleTrackInfo, D as DiagnosticsSnapshot, s as AvbridgeVideoElementEventMap } from './player-DGXeCNfD.cjs';
1
+ import { a as MediaInput, n as StrategyName, S as StrategyClass, U as UnifiedPlayer, e as AudioTrackInfo, o as SubtitleTrackInfo, D as DiagnosticsSnapshot, s as AvbridgeVideoElementEventMap } from './player-DXEKOky8.cjs';
2
2
 
3
3
  /**
4
4
  * `<avbridge-video>` — `HTMLMediaElement`-compatible primitive backed by the
@@ -12,14 +12,17 @@ import { a as MediaInput, n as StrategyName, S as StrategyClass, U as UnifiedPla
12
12
  * 3. Give consumers a `<video>`-compatible primitive they can wrap with
13
13
  * their own UI.
14
14
  *
15
- * **It is not a player UI framework.** The tag name `<avbridge-player>` is
16
- * reserved for a future controls-bearing element. See
15
+ * **It is not a player UI framework.** For YouTube-style chrome (seek
16
+ * bar, play/pause, settings menu, fullscreen, auto-hiding controls) use
17
+ * `<avbridge-player>` — it wraps this element with a full UI. See
17
18
  * `docs/dev/WEB_COMPONENT_SPEC.md` for the full spec, lifecycle invariants,
18
19
  * and edge case list.
19
20
  */
20
21
 
21
22
  /** Strategy preference passed via the `preferstrategy` attribute. */
22
23
  type PreferredStrategy = "auto" | StrategyName;
24
+ /** Fit mode — how the video fills the element's box. Mirrors CSS object-fit. */
25
+ type FitMode = "contain" | "cover" | "fill";
23
26
  /**
24
27
  * `HTMLElement` is a browser-only global. SSR frameworks (Next.js, Astro,
25
28
  * Remix, etc.) commonly import library modules on the server to extract
@@ -92,12 +95,26 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
92
95
  * native fails.
93
96
  */
94
97
  private _preferredStrategy;
98
+ /** Current fit mode. Applied to the inner `<video>` via object-fit, and
99
+ * to the fallback canvas via the `--avbridge-fit` CSS custom property on
100
+ * the stage wrapper (see `src/strategies/fallback/video-renderer.ts`). */
101
+ private _fit;
102
+ /** The stage wrapper — the element the canvas attaches into, and where
103
+ * the `--avbridge-fit` CSS custom property lives. */
104
+ private _stageEl;
95
105
  /** Set if currentTime was assigned before the player was ready. */
96
106
  private _pendingSeek;
97
107
  /** Set if play() was called before the player was ready. */
98
108
  private _pendingPlay;
99
109
  /** MutationObserver tracking light-DOM `<track>` children. */
100
110
  private _trackObserver;
111
+ /** Document-level fullscreenchange handler — installed while connected so
112
+ * the element can lock/unlock screen orientation to match the video's
113
+ * intrinsic aspect. */
114
+ private _fullscreenChangeHandler;
115
+ /** True if we successfully called screen.orientation.lock() on the last
116
+ * fullscreen entry. Used to know whether to unlock on exit. */
117
+ private _orientationLocked;
101
118
  constructor();
102
119
  connectedCallback(): void;
103
120
  disconnectedCallback(): void;
@@ -141,6 +158,8 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
141
158
  set preload(value: "none" | "metadata" | "auto");
142
159
  get diagnostics(): boolean;
143
160
  set diagnostics(value: boolean);
161
+ get fit(): FitMode;
162
+ set fit(value: FitMode);
144
163
  get preferredStrategy(): PreferredStrategy;
145
164
  set preferredStrategy(value: PreferredStrategy);
146
165
  get currentTime(): number;
@@ -230,6 +249,36 @@ declare class AvbridgeVideoElement extends HTMLElementCtor {
230
249
  language?: string;
231
250
  format?: "vtt" | "srt";
232
251
  }): Promise<void>;
252
+ /**
253
+ * Disable the automatic `screen.orientation.lock()` that runs on
254
+ * fullscreen entry. Set when you want to honor the device's native
255
+ * auto-rotate instead of matching the video's intrinsic orientation.
256
+ */
257
+ get noOrientationLock(): boolean;
258
+ set noOrientationLock(value: boolean);
259
+ /** Called whenever `document.fullscreenchange` fires. If this element (or
260
+ * any of its ancestors) is now fullscreen, derive the target orientation
261
+ * from the video's intrinsic size and call `screen.orientation.lock()`.
262
+ * On exit, release the lock we took. iOS Safari rejects `lock()` — we
263
+ * swallow the rejection so nothing breaks on that path. */
264
+ private _onFullscreenChange;
265
+ /** Walk composed-tree ancestors to see if `target` is this element or
266
+ * any ancestor across shadow boundaries. `Node.contains()` can't cross
267
+ * shadow roots, so when `<avbridge-player>` (the fullscreen element)
268
+ * hosts this `<avbridge-video>` inside its shadow DOM, `contains()`
269
+ * returns false. */
270
+ private _isInsideOrEquals;
271
+ /** Derive "landscape" / "portrait" from the intrinsic video dimensions.
272
+ * Returns null when dimensions aren't known yet or the video is square.
273
+ * Uses `videoWidth` / `videoHeight` from the inner `<video>`, which the
274
+ * browser sets to the display-aspect-corrected size (so anamorphic
275
+ * content is judged by its display aspect, not pixel aspect). */
276
+ private _desiredOrientation;
277
+ /** Attempt to lock screen orientation. Swallows rejections — iOS Safari
278
+ * doesn't implement `lock()`, and desktop / non-fullscreen contexts will
279
+ * reject too. Records success so we know whether to unlock on exit. */
280
+ private _lockOrientation;
281
+ private _releaseOrientationLock;
233
282
  /** Force a (re-)bootstrap if a source is currently set. */
234
283
  load(): Promise<void>;
235
284
  /**