@oddin-gg/havik-player 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,25 +24,28 @@ function n(e) {
24
24
  default: return "INTERNAL";
25
25
  }
26
26
  }
27
- var r = /* @__PURE__ */ new Set([
27
+ function r(e) {
28
+ return e === 401 ? "UNAUTHORIZED" : e === 403 ? "FORBIDDEN" : "DRM_CLIENT";
29
+ }
30
+ var i = /* @__PURE__ */ new Set([
28
31
  "TOO_EARLY",
29
32
  "UNAVAILABLE",
30
33
  "RATE_LIMITED",
31
34
  "NETWORK"
32
35
  ]);
33
- function i(e) {
34
- return r.has(e);
36
+ function a(e) {
37
+ return i.has(e);
35
38
  }
36
39
  //#endregion
37
40
  //#region src/core/types.ts
38
- async function a(e) {
41
+ async function o(e) {
39
42
  let t = typeof e == "function" ? await e() : e;
40
43
  if (!t || !t.apiKey) throw Error("havik-player: credential is missing an apiKey");
41
44
  return t;
42
45
  }
43
46
  //#endregion
44
47
  //#region src/core/http.ts
45
- function o(e, n) {
48
+ function s(e, n) {
46
49
  let r = e.replace(/\/+$/, ""), i;
47
50
  try {
48
51
  i = new URL(r + n);
@@ -52,15 +55,15 @@ function o(e, n) {
52
55
  if (i.protocol !== "https:" && i.protocol !== "http:") throw new t("INTERNAL", 0, `baseUrl must be http(s), got: ${JSON.stringify(e)}`);
53
56
  return i.toString();
54
57
  }
55
- function s(e) {
58
+ function c(e) {
56
59
  if (!e) return;
57
60
  let t = Number(e);
58
61
  if (Number.isFinite(t)) return Math.max(0, Math.round(t * 1e3));
59
62
  let n = Date.parse(e);
60
63
  if (!Number.isNaN(n)) return Math.max(0, n - Date.now());
61
64
  }
62
- async function c(e, n) {
63
- let r = await a(n.credential), i = n.headers ?? new Headers();
65
+ async function l(e, n) {
66
+ let r = await o(n.credential), i = n.headers ?? new Headers();
64
67
  i.set("x-api-key", r.apiKey);
65
68
  try {
66
69
  return await fetch(e, {
@@ -73,49 +76,49 @@ async function c(e, n) {
73
76
  mode: "cors"
74
77
  });
75
78
  } catch (e) {
76
- throw n.signal?.aborted ? new t("ABORTED", 0, "request aborted", { cause: e }) : new t("NETWORK", 0, `network request failed: ${l(e)}`, { cause: e });
79
+ throw n.signal?.aborted ? new t("ABORTED", 0, "request aborted", { cause: e }) : new t("NETWORK", 0, `network request failed: ${u(e)}`, { cause: e });
77
80
  }
78
81
  }
79
- function l(e) {
82
+ function u(e) {
80
83
  return e instanceof Error ? e.message : String(e);
81
84
  }
82
85
  //#endregion
83
86
  //#region src/core/waitForLive.ts
84
- var u = 1e3, d = 3e4, f = 600 * 1e3, p = 300 * 1e3, m = 1e3, h = {
87
+ var d = 1e3, f = 3e4, p = 600 * 1e3, m = 300 * 1e3, h = 1e3, g = {
85
88
  TOO_EARLY: "tooEarly",
86
89
  UNAVAILABLE: "unavailable",
87
90
  RATE_LIMITED: "rateLimited",
88
91
  NETWORK: "network"
89
92
  };
90
- function g(e) {
91
- let t = e === !0 || e === !1 ? {} : e, n = Math.max(m, t.floorMs ?? u), r = Math.max(n, t.ceilMs ?? d), i = Math.max(0, t.imminentMs ?? f), a = Math.max(r, t.sanityFloorMs ?? p);
93
+ function ee(e) {
94
+ let t = e === !0 || e === !1 ? {} : e, n = Math.max(h, t.floorMs ?? d), r = Math.max(n, t.ceilMs ?? f), i = Math.max(0, t.imminentMs ?? p), a = Math.max(r, t.sanityFloorMs ?? m);
92
95
  return {
93
96
  timeoutMs: t.timeoutMs,
94
97
  floorMs: n,
95
98
  ceilMs: r,
96
99
  imminentMs: i,
97
100
  sanityFloorMs: a,
98
- kickoffMs: ee(t.kickoffAt),
101
+ kickoffMs: te(t.kickoffAt),
99
102
  jitter: t.jitter ?? !0,
100
103
  onState: t.onState
101
104
  };
102
105
  }
103
- function ee(e) {
106
+ function te(e) {
104
107
  if (e == null) return;
105
108
  if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
106
109
  let t = Date.parse(e);
107
110
  return Number.isFinite(t) ? t : void 0;
108
111
  }
109
- function te(e, t, n) {
112
+ function ne(e, t, n) {
110
113
  return Math.min(n, Math.max(t, e));
111
114
  }
112
- function ne(e) {
115
+ function _(e) {
113
116
  return Math.round(e * (1 + .15 * Math.random()));
114
117
  }
115
118
  function re(e, t, n, r) {
116
119
  let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
117
120
  if (a == null || a <= n.imminentMs) return {
118
- delay: te(e ?? n.floorMs, o, n.ceilMs),
121
+ delay: ne(e ?? n.floorMs, o, n.ceilMs),
119
122
  ttkMs: a
120
123
  };
121
124
  let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
@@ -138,22 +141,22 @@ function ie(e, n) {
138
141
  n?.addEventListener("abort", a, { once: !0 });
139
142
  });
140
143
  }
141
- async function _(e, n, r) {
142
- let a = g(n), o = Date.now(), s = a.timeoutMs == null ? Infinity : o + a.timeoutMs, c = 0, l;
144
+ async function v(e, n, r) {
145
+ let i = ee(n), o = Date.now(), s = i.timeoutMs == null ? Infinity : o + i.timeoutMs, c = 0, l;
143
146
  for (;;) {
144
147
  if (r?.aborted) throw new t("ABORTED", 0, "wait-for-live aborted");
145
148
  try {
146
149
  return await e();
147
150
  } catch (e) {
148
- if (!(e instanceof t) || !i(e.code)) throw e;
151
+ if (!(e instanceof t) || !a(e.code)) throw e;
149
152
  c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
150
- let n = Date.now(), u = re(e.retryAfterMs, n, a, l), d = u.ttkMs, f = u.delay;
151
- if (a.jitter && (f = ne(f)), n + f > s) throw new t("TIMEOUT", e.httpStatus, `timed out after ${a.timeoutMs}ms waiting for the stream to go live`, {
153
+ let n = Date.now(), u = re(e.retryAfterMs, n, i, l), d = u.ttkMs, f = u.delay;
154
+ if (i.jitter && (f = _(f)), n + f > s) throw new t("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
152
155
  retryAfterMs: e.retryAfterMs,
153
156
  cause: e
154
157
  });
155
- a.onState?.({
156
- phase: h[e.code] ?? "unavailable",
158
+ i.onState?.({
159
+ phase: g[e.code] ?? "unavailable",
157
160
  retryInMs: f,
158
161
  attempt: c,
159
162
  elapsedMs: n - o,
@@ -164,33 +167,33 @@ async function _(e, n, r) {
164
167
  }
165
168
  //#endregion
166
169
  //#region src/core/resolve.ts
167
- async function v(e) {
170
+ async function y(e) {
168
171
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new t("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
169
- let n = await c(o(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
172
+ let n = await l(s(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
170
173
  credential: e.credential,
171
174
  signal: e.signal
172
175
  });
173
176
  if (!n.ok) throw await ae(n);
174
- return se(await n.json(), e.matchUrn);
177
+ return S(await n.json(), e.matchUrn);
175
178
  }
176
- function y(e) {
177
- let t = () => v(e);
178
- return e.waitForLive ? _(t, e.waitForLive, e.signal) : t();
179
+ function b(e) {
180
+ let t = () => y(e);
181
+ return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
179
182
  }
180
183
  async function ae(e) {
181
- let r = s(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, c;
184
+ let r = c(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
182
185
  try {
183
186
  let t = await e.json();
184
187
  if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
185
188
  let e = Date.parse(t.liveStartsAt);
186
- Number.isFinite(e) && (c = e);
189
+ Number.isFinite(e) && (s = e);
187
190
  }
188
191
  } catch {}
189
192
  return new t(n(e.status), e.status, a, {
190
193
  retryAfterMs: r,
191
194
  requestId: i,
192
195
  serverCode: o,
193
- liveStartsAtMs: c
196
+ liveStartsAtMs: s
194
197
  });
195
198
  }
196
199
  var oe = /* @__PURE__ */ new Set([
@@ -204,7 +207,7 @@ var oe = /* @__PURE__ */ new Set([
204
207
  "expiresAt",
205
208
  "analytics"
206
209
  ]);
207
- function b(e, n) {
210
+ function x(e, n) {
208
211
  let r;
209
212
  try {
210
213
  r = new URL(n);
@@ -214,20 +217,20 @@ function b(e, n) {
214
217
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new t("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
215
218
  return n;
216
219
  }
217
- function se(e, n) {
220
+ function S(e, n) {
218
221
  if (!e.manifestUrl) throw new t("INTERNAL", 0, "playback response is missing manifestUrl");
219
222
  let r = e.drmEnabled ?? !!e.drm, i = {
220
223
  matchUrn: e.matchUrn ?? n,
221
224
  protocol: "hls",
222
225
  drmEnabled: r,
223
- manifestUrl: b("manifestUrl", e.manifestUrl),
226
+ manifestUrl: x("manifestUrl", e.manifestUrl),
224
227
  serverTime: e.serverTime ?? ""
225
228
  };
226
229
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid && (i.analytics = { sid: e.analytics.sid }), r && e.drm) {
227
230
  let t = {};
228
- e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
229
- licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
230
- certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
231
+ e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
232
+ licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
233
+ certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
231
234
  }), (t.widevine || t.fairplay) && (i.drm = t);
232
235
  }
233
236
  let a = {};
@@ -236,29 +239,29 @@ function se(e, n) {
236
239
  }
237
240
  //#endregion
238
241
  //#region src/core/catalog.ts
239
- async function x(e) {
242
+ async function C(e) {
240
243
  let r = new URLSearchParams();
241
244
  e.status && r.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && r.set("sport", e.sport);
242
- let i = r.toString(), a = o(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), s = new Headers();
243
- e.etag && s.set("If-None-Match", e.etag);
244
- let l = await c(a, {
245
+ let i = r.toString(), a = s(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
246
+ e.etag && o.set("If-None-Match", e.etag);
247
+ let c = await l(a, {
245
248
  credential: e.credential,
246
249
  signal: e.signal,
247
- headers: s
250
+ headers: o
248
251
  });
249
- if (l.status === 304) return {
252
+ if (c.status === 304) return {
250
253
  tournaments: [],
251
254
  etag: e.etag,
252
255
  notModified: !0
253
256
  };
254
- if (!l.ok) throw new t(n(l.status), l.status, `catalog request failed (HTTP ${l.status})`);
257
+ if (!c.ok) throw new t(n(c.status), c.status, `catalog request failed (HTTP ${c.status})`);
255
258
  return {
256
- tournaments: S(await l.json()),
257
- etag: l.headers.get("etag") ?? void 0,
259
+ tournaments: se(await c.json()),
260
+ etag: c.headers.get("etag") ?? void 0,
258
261
  notModified: !1
259
262
  };
260
263
  }
261
- function S(e) {
264
+ function se(e) {
262
265
  return (e.tournaments ?? []).map((e) => {
263
266
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
264
267
  return {
@@ -279,9 +282,9 @@ function S(e) {
279
282
  });
280
283
  }
281
284
  async function ce(e) {
282
- let r = o(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
285
+ let r = s(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
283
286
  e.etag && i.set("If-None-Match", e.etag);
284
- let a = await c(r, {
287
+ let a = await l(r, {
285
288
  credential: e.credential,
286
289
  signal: e.signal,
287
290
  headers: i
@@ -327,22 +330,22 @@ function ue(e) {
327
330
  //#endregion
328
331
  //#region src/core/poll.ts
329
332
  function de(e) {
330
- let r = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, s, l, u = !1, d = () => {
333
+ let r = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, c, u = !1, d = () => {
331
334
  u || (a = setTimeout(f, r));
332
335
  }, f = async () => {
333
336
  try {
334
- let r = o(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
335
- s && a.set("If-None-Match", s);
336
- let u = await c(r, {
337
+ let r = s(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
338
+ o && a.set("If-None-Match", o);
339
+ let u = await l(r, {
337
340
  credential: e.credential,
338
341
  signal: i.signal,
339
342
  headers: a
340
343
  });
341
344
  if (u.status !== 304) {
342
345
  if (!u.ok) throw new t(n(u.status), u.status, `match status request failed (HTTP ${u.status})`);
343
- s = u.headers.get("etag") ?? s;
346
+ o = u.headers.get("etag") ?? o;
344
347
  let r = await u.json(), i = r.status ?? "upcoming";
345
- i !== l && (l = i, e.onChange({
348
+ i !== c && (c = i, e.onChange({
346
349
  matchUrn: r.matchUrn ?? e.matchUrn,
347
350
  matchName: r.matchName,
348
351
  status: i,
@@ -361,8 +364,8 @@ function de(e) {
361
364
  }
362
365
  //#endregion
363
366
  //#region src/core/events.ts
364
- function C(e) {
365
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, s = (e) => new Promise((t) => {
367
+ function w(e) {
368
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, a = (e) => new Promise((t) => {
366
369
  if (r.signal.aborted) return t();
367
370
  let n = setTimeout(t, e);
368
371
  r.signal.addEventListener("abort", () => {
@@ -400,9 +403,9 @@ function C(e) {
400
403
  let c = t;
401
404
  for (; !i;) {
402
405
  try {
403
- let n = await a(e.credential);
406
+ let n = await o(e.credential);
404
407
  if (i) return;
405
- let s = o(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`), l = await fetch(s, {
408
+ let a = s(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`), l = await fetch(a, {
406
409
  method: "GET",
407
410
  headers: {
408
411
  "x-api-key": n.apiKey,
@@ -422,13 +425,13 @@ function C(e) {
422
425
  e.onError?.(t);
423
426
  }
424
427
  if (i) return;
425
- await s(c), c = Math.min(n, c * 2);
428
+ await a(c), c = Math.min(n, c * 2);
426
429
  }
427
430
  })(), { close() {
428
431
  i || (i = !0, r.abort());
429
432
  } };
430
433
  }
431
- function w(e) {
434
+ function T(e) {
432
435
  try {
433
436
  let t = new URL(e);
434
437
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -438,24 +441,24 @@ function w(e) {
438
441
  }
439
442
  //#endregion
440
443
  //#region src/core/drm/deviceId.ts
441
- var T = "havik.player.deviceId", E;
442
- function D() {
443
- if (E) return E;
444
+ var E = "havik.player.deviceId", D;
445
+ function O() {
446
+ if (D) return D;
444
447
  try {
445
- let e = globalThis.localStorage?.getItem(T);
446
- if (e) return E = e, e;
448
+ let e = globalThis.localStorage?.getItem(E);
449
+ if (e) return D = e, e;
447
450
  } catch {}
448
451
  let e = pe();
449
- E = e;
452
+ D = e;
450
453
  try {
451
- globalThis.localStorage?.setItem(T, e);
454
+ globalThis.localStorage?.setItem(E, e);
452
455
  } catch {}
453
456
  return e;
454
457
  }
455
458
  function fe() {
456
- E = void 0;
459
+ D = void 0;
457
460
  try {
458
- globalThis.localStorage?.removeItem(T);
461
+ globalThis.localStorage?.removeItem(E);
459
462
  } catch {}
460
463
  }
461
464
  function pe() {
@@ -474,14 +477,14 @@ function me(e, t, n = {}) {
474
477
  let r = {
475
478
  "x-api-key": t.apiKey,
476
479
  "X-Match-Urn": e.matchUrn,
477
- "X-Device-Id": n.deviceId ?? D(),
480
+ "X-Device-Id": n.deviceId ?? O(),
478
481
  "Content-Type": "application/octet-stream"
479
482
  };
480
483
  return n.userId && (r["X-User-Id"] = n.userId), r;
481
484
  }
482
485
  //#endregion
483
486
  //#region src/core/drm/support.ts
484
- var he = 5e3, O = "video/mp4; codecs=\"avc1.42E01E\"", k = "audio/mp4; codecs=\"mp4a.40.2\"", ge = {
487
+ var he = 5e3, k = "video/mp4; codecs=\"avc1.42E01E\"", A = "audio/mp4; codecs=\"mp4a.40.2\"", ge = {
485
488
  widevine: ["com.widevine.alpha"],
486
489
  fairplay: ["com.apple.fps"]
487
490
  };
@@ -493,30 +496,30 @@ function _e(e) {
493
496
  "cenc"
494
497
  ],
495
498
  videoCapabilities: [{
496
- contentType: O,
499
+ contentType: k,
497
500
  robustness: "",
498
501
  encryptionScheme: "cbcs"
499
502
  }],
500
503
  audioCapabilities: [{
501
- contentType: k,
504
+ contentType: A,
502
505
  robustness: "",
503
506
  encryptionScheme: "cbcs"
504
507
  }]
505
508
  }] : [{
506
509
  initDataTypes: ["cenc"],
507
510
  videoCapabilities: [{
508
- contentType: O,
511
+ contentType: k,
509
512
  robustness: "SW_SECURE_DECODE",
510
513
  encryptionScheme: "cbcs"
511
514
  }],
512
515
  audioCapabilities: [{
513
- contentType: k,
516
+ contentType: A,
514
517
  robustness: "SW_SECURE_CRYPTO",
515
518
  encryptionScheme: "cbcs"
516
519
  }]
517
520
  }];
518
521
  }
519
- function A(e, t) {
522
+ function j(e, t) {
520
523
  return new Promise((n, r) => {
521
524
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
522
525
  e.then((e) => {
@@ -526,7 +529,7 @@ function A(e, t) {
526
529
  });
527
530
  });
528
531
  }
529
- async function j(e = {}) {
532
+ async function M(e = {}) {
530
533
  let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? he, r = {};
531
534
  if (typeof window < "u" && window.isSecureContext === !1) return {
532
535
  verdict: "insecure-context",
@@ -550,7 +553,7 @@ async function j(e = {}) {
550
553
  break;
551
554
  }
552
555
  try {
553
- return await A((await A(i(n, _e(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
556
+ return await j((await j(i(n, _e(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
554
557
  verdict: "supported",
555
558
  system: e,
556
559
  detail: r
@@ -574,17 +577,17 @@ async function j(e = {}) {
574
577
  }
575
578
  //#endregion
576
579
  //#region src/core/manifest.ts
577
- var M = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
578
- function N(e) {
579
- return M.test(e);
580
+ var N = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
581
+ function P(e) {
582
+ return N.test(e);
580
583
  }
581
584
  //#endregion
582
585
  //#region src/core/stats.ts
583
- var P = { droppedFrames: 0 };
584
- function F(e) {
586
+ var F = { droppedFrames: 0 };
587
+ function I(e) {
585
588
  return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
586
589
  }
587
- function I(e, t) {
590
+ function ve(e, t) {
588
591
  let n = [
589
592
  ["playing", () => t("playing")],
590
593
  ["waiting", () => t("buffering")],
@@ -601,7 +604,7 @@ function I(e, t) {
601
604
  }
602
605
  //#endregion
603
606
  //#region src/core/engine/native.ts
604
- function ve(e) {
607
+ function ye(e) {
605
608
  try {
606
609
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
607
610
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -636,7 +639,7 @@ var z = class {
636
639
  if (!n.drm?.fairplay) {
637
640
  r({
638
641
  type: "error",
639
- error: new t("INTERNAL", 0, "native HLS engine cannot satisfy this DRM (Widevine requires the hls.js engine); use engine \"auto\"/\"hls\" on a Widevine-capable browser"),
642
+ error: new t("DRM_CLIENT", 0, "native HLS engine cannot satisfy this DRM (Widevine requires the hls.js engine); use engine \"auto\"/\"hls\" on a Widevine-capable browser"),
640
643
  fatal: !0
641
644
  });
642
645
  return;
@@ -647,23 +650,23 @@ var z = class {
647
650
  type: "error",
648
651
  error: new t("INTERNAL", 0, "native HLS playback error"),
649
652
  fatal: !0
650
- }), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = ye(n.manifestUrl, n.analytics?.sid), e.load();
653
+ }), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = be(n.manifestUrl, n.analytics?.sid), e.load();
651
654
  }
652
655
  armFairPlay() {
653
- let { video: e, descriptor: n, credential: r, deviceId: i, userId: a, emit: o } = this.deps, s = n.drm?.fairplay;
654
- if (!s) return;
655
- this.fairplayLicenseUrl = s.licenseUrl;
656
- let c = (e, n, r) => o({
656
+ let { video: e, descriptor: n, credential: i, deviceId: a, userId: o, emit: s } = this.deps, c = n.drm?.fairplay;
657
+ if (!c) return;
658
+ this.fairplayLicenseUrl = c.licenseUrl;
659
+ let l = (e, n, i) => s({
657
660
  type: "error",
658
- error: new t(n === 403 ? "FORBIDDEN" : "INTERNAL", n, e),
659
- fatal: r
661
+ error: new t(r(n), n, e),
662
+ fatal: i
660
663
  });
661
664
  this.onEncrypted = (t) => {
662
- let o = t;
663
- !o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = ve(o.initData), (async () => {
665
+ let r = t;
666
+ !r.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = ye(r.initData), (async () => {
664
667
  try {
665
668
  let t = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
666
- initDataTypes: [o.initDataType],
669
+ initDataTypes: [r.initDataType],
667
670
  videoCapabilities: [{
668
671
  contentType: "application/vnd.apple.mpegurl",
669
672
  robustness: ""
@@ -671,36 +674,39 @@ var z = class {
671
674
  distinctiveIdentifier: "not-allowed",
672
675
  persistentState: "not-allowed",
673
676
  sessionTypes: ["temporary"]
674
- }])).createMediaKeys(), l = await fetch(s.certificateUrl, { headers: { "x-api-key": r.apiKey } });
675
- if (!l.ok) throw Error(`certificate ${l.status}`);
676
- await t.setServerCertificate(await l.arrayBuffer()), await e.setMediaKeys(t);
677
+ }])).createMediaKeys(), s = await fetch(c.certificateUrl, { headers: { "x-api-key": i.apiKey } });
678
+ if (!s.ok) {
679
+ this.fairplayArmed = !1, l(`FairPlay certificate request failed: ${s.status}`, s.status, !0);
680
+ return;
681
+ }
682
+ await t.setServerCertificate(await s.arrayBuffer()), await e.setMediaKeys(t);
677
683
  let u = t.createSession();
678
684
  this.keySession = u, u.addEventListener("message", (e) => {
679
685
  (async () => {
680
686
  try {
681
- let t = await fetch(this.fairplayLicenseUrl ?? s.licenseUrl, {
687
+ let t = await fetch(this.fairplayLicenseUrl ?? c.licenseUrl, {
682
688
  method: "POST",
683
689
  body: e.message,
684
690
  headers: {
685
- "x-api-key": r.apiKey,
691
+ "x-api-key": i.apiKey,
686
692
  "X-Match-Urn": n.matchUrn,
687
- "X-Device-Id": i,
688
- ...a ? { "X-User-Id": a } : {},
693
+ "X-Device-Id": a,
694
+ ...o ? { "X-User-Id": o } : {},
689
695
  ...this.fairplayKeyIV ? { "X-Key-Iv": this.fairplayKeyIV } : {}
690
696
  }
691
697
  });
692
698
  if (!t.ok) {
693
- c(`FairPlay license request failed: ${t.status}`, t.status, !0);
699
+ l(`FairPlay license request failed: ${t.status}`, t.status, !0);
694
700
  return;
695
701
  }
696
702
  await u.update(new Uint8Array(await t.arrayBuffer()));
697
703
  } catch (e) {
698
- c(`FairPlay license request failed: ${String(e)}`, 0, !0);
704
+ l(`FairPlay license request failed: ${String(e)}`, 0, !0);
699
705
  }
700
706
  })();
701
- }), await u.generateRequest(o.initDataType, o.initData);
707
+ }), await u.generateRequest(r.initDataType, r.initData);
702
708
  } catch (e) {
703
- this.fairplayArmed = !1, c(`FairPlay key session failed: ${String(e)}`, 0, !0);
709
+ this.fairplayArmed = !1, l(`FairPlay key session failed: ${String(e)}`, 0, !0);
704
710
  }
705
711
  })());
706
712
  }, e.addEventListener("encrypted", this.onEncrypted);
@@ -752,7 +758,7 @@ var z = class {
752
758
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
753
759
  }
754
760
  getStats() {
755
- let e = this.deps.video, t = { droppedFrames: F(e) };
761
+ let e = this.deps.video, t = { droppedFrames: I(e) };
756
762
  return e.duration === Infinity && (t.isLive = !0, e.seekable.length > 0 && (t.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), t;
757
763
  }
758
764
  stop() {
@@ -772,25 +778,25 @@ var z = class {
772
778
  } catch {}
773
779
  }
774
780
  };
775
- function ye(e, t) {
781
+ function be(e, t) {
776
782
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
777
783
  }
778
784
  //#endregion
779
785
  //#region src/core/engine/hls.ts
780
- function be() {
786
+ function xe() {
781
787
  return e.isSupported();
782
788
  }
783
- var xe = 3, Se = 5, Ce = 3, we = 3e4, Te = 12e3, Ee = 3e3, B = 6e3, De = 4e3, Oe = 2, ke = 5, Ae = 2, je = 9, Me = .5;
784
- function Ne(e) {
789
+ var Se = 3, Ce = 5, we = 3, Te = 3e4, Ee = 12e3, De = 3e3, B = 6e3, Oe = 4e3, ke = 2, Ae = 5, je = 2, Me = 9, Ne = .5;
790
+ function Pe(e) {
785
791
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
786
792
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
787
793
  return;
788
794
  }
789
- e.liveSyncDuration ??= Ae;
790
- let t = Math.max(12, e.liveSyncDuration + je);
791
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Pe(e, e.liveSyncDuration);
795
+ e.liveSyncDuration ??= je;
796
+ let t = Math.max(12, e.liveSyncDuration + Me);
797
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Fe(e, e.liveSyncDuration);
792
798
  }
793
- function Pe(e, t) {
799
+ function Fe(e, t) {
794
800
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
795
801
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
796
802
  }
@@ -831,7 +837,7 @@ var V = class {
831
837
  if (e.drmEnabled && !o) {
832
838
  i({
833
839
  type: "error",
834
- error: new t("INTERNAL", 0, e.drm?.fairplay?.licenseUrl && a ? "FairPlay cannot be played on the hls.js engine (WebKit binds keys via the media sinf box); use engine \"auto\" or \"native\"" : "DRM is required but none of the stream’s key systems is usable on this platform (WebKit takes FairPlay only; other browsers take Widevine only)"),
840
+ error: new t("DRM_CLIENT", 0, e.drm?.fairplay?.licenseUrl && a ? "FairPlay cannot be played on the hls.js engine (WebKit binds keys via the media sinf box); use engine \"auto\" or \"native\"" : "DRM is required but none of the stream’s key systems is usable on this platform (WebKit takes FairPlay only; other browsers take Widevine only)"),
835
841
  fatal: !0
836
842
  });
837
843
  return;
@@ -851,7 +857,7 @@ var V = class {
851
857
  let t = e.liveSyncPosition;
852
858
  if (typeof t != "number" || !Number.isFinite(t)) return;
853
859
  let { video: n } = this.deps;
854
- n.currentTime <= t + Me || (n.currentTime = t);
860
+ n.currentTime <= t + Ne || (n.currentTime = t);
855
861
  }
856
862
  startHls() {
857
863
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps, u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
@@ -887,14 +893,14 @@ var V = class {
887
893
  } } : {},
888
894
  ...c
889
895
  };
890
- Ne(d);
896
+ Pe(d);
891
897
  let f = new e(d);
892
898
  this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
893
899
  this.mediaRecoveries = 0, this.networkRecoveries = 0, l({ type: "ready" });
894
900
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
895
901
  t?.frag?.type === "main" && (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
896
902
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.recoveryResetTimer = null;
897
- }, we));
903
+ }, Te));
898
904
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
899
905
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
900
906
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -910,7 +916,7 @@ var V = class {
910
916
  }));
911
917
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => {
912
918
  this.checkEndStale(), this.checkStarvation();
913
- }, Ee), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
919
+ }, De), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
914
920
  this.renditionSwitches += 1, l({
915
921
  type: "qualitychange",
916
922
  index: t.level
@@ -981,7 +987,7 @@ var V = class {
981
987
  }
982
988
  getStats() {
983
989
  let e = this.hls, t = {
984
- droppedFrames: F(this.deps.video),
990
+ droppedFrames: I(this.deps.video),
985
991
  lowLatency: this.detectedLowLatency,
986
992
  bytesLoaded: this.bytesLoaded,
987
993
  playlistBytesLoaded: this.playlistBytesLoaded,
@@ -1014,7 +1020,7 @@ var V = class {
1014
1020
  return;
1015
1021
  }
1016
1022
  let e = Date.now() - this.lastAdvanceMs;
1017
- !this.chaseSuspended && e > B && this.suspendChasing(), e > Te && this.emitEnded("stalled");
1023
+ !this.chaseSuspended && e > B && this.suspendChasing(), e > Ee && this.emitEnded("stalled");
1018
1024
  }
1019
1025
  checkStarvation() {
1020
1026
  let e = this.hls, { video: t } = this.deps;
@@ -1023,12 +1029,12 @@ var V = class {
1023
1029
  this.starvedTicks = 0;
1024
1030
  return;
1025
1031
  }
1026
- let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > De;
1032
+ let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > Oe;
1027
1033
  if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
1028
1034
  this.starvedTicks = 0;
1029
1035
  return;
1030
1036
  }
1031
- if (!(++this.starvedTicks < Oe) && (this.starvedTicks = 0, !(this.starvationKicks >= ke))) {
1037
+ if (!(++this.starvedTicks < ke) && (this.starvedTicks = 0, !(this.starvationKicks >= Ae))) {
1032
1038
  this.starvationKicks += 1, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting load at the live edge");
1033
1039
  try {
1034
1040
  e.stopLoad(), e.startLoad(-1);
@@ -1077,7 +1083,7 @@ var V = class {
1077
1083
  scheduleLicenseRetry(t) {
1078
1084
  if (!(t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED || t.details === e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED)) return !1;
1079
1085
  let n = t.response?.code ?? 0;
1080
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ce) return !1;
1086
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= we) return !1;
1081
1087
  this.licenseRecoveries += 1;
1082
1088
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1083
1089
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1105,7 +1111,7 @@ var V = class {
1105
1111
  return;
1106
1112
  }
1107
1113
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1108
- if (this.networkRecoveries < Se) {
1114
+ if (this.networkRecoveries < Ce) {
1109
1115
  this.networkRecoveries += 1;
1110
1116
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1111
1117
  this.networkRetryTimer = setTimeout(() => {
@@ -1121,7 +1127,7 @@ var V = class {
1121
1127
  return;
1122
1128
  }
1123
1129
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1124
- if (this.mediaRecoveries < xe) {
1130
+ if (this.mediaRecoveries < Se) {
1125
1131
  this.mediaRecoveries += 1, n.recoverMediaError();
1126
1132
  return;
1127
1133
  }
@@ -1140,10 +1146,10 @@ var V = class {
1140
1146
  }
1141
1147
  }
1142
1148
  toError(e, n = "PLAYBACK") {
1143
- let r = e.response?.code ?? 0, i = e.details ?? e.type, a = e.reason ?? e.error?.message ?? "";
1144
- return new t(r === 401 ? "UNAUTHORIZED" : r === 403 || n === "DRM" ? "FORBIDDEN" : "INTERNAL", r, `${n} error: ${i}${a ? ` (${a})` : ""}`);
1149
+ let i = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1150
+ return new t(n === "DRM" ? r(i) : i === 401 ? "UNAUTHORIZED" : i === 403 ? "FORBIDDEN" : "INTERNAL", i, `${n} error: ${a}${o ? ` (${o})` : ""}`);
1145
1151
  }
1146
- }, Fe = 15e3, Ie = 100, H = 1, U = {
1152
+ }, Ie = 15e3, Le = 100, H = 1, U = {
1147
1153
  idle: "PLAYER_STATE_IDLE",
1148
1154
  waiting: "PLAYER_STATE_WAITING",
1149
1155
  loading: "PLAYER_STATE_LOADING",
@@ -1153,7 +1159,7 @@ var V = class {
1153
1159
  ended: "PLAYER_STATE_ENDED",
1154
1160
  error: "PLAYER_STATE_ERROR"
1155
1161
  };
1156
- function Le(e) {
1162
+ function Re(e) {
1157
1163
  try {
1158
1164
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1159
1165
  return !n || r.length === 0 || n !== "feed" && !n.startsWith("feed-") ? void 0 : (t.hostname = [n.replace(/^feed/, "beacons"), ...r].join("."), t.pathname = "", t.search = "", t.origin);
@@ -1161,7 +1167,7 @@ function Le(e) {
1161
1167
  return;
1162
1168
  }
1163
1169
  }
1164
- var Re = class {
1170
+ var ze = class {
1165
1171
  opts;
1166
1172
  url;
1167
1173
  now;
@@ -1196,7 +1202,7 @@ var Re = class {
1196
1202
  constructor(e) {
1197
1203
  this.opts = {
1198
1204
  ...e,
1199
- heartbeatMs: e.heartbeatMs ?? Fe
1205
+ heartbeatMs: e.heartbeatMs ?? Ie
1200
1206
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now();
1201
1207
  }
1202
1208
  start() {
@@ -1288,7 +1294,7 @@ var Re = class {
1288
1294
  };
1289
1295
  }
1290
1296
  enqueue(e) {
1291
- for (this.pending.push(this.wrap(e)); this.pending.length > Ie;) {
1297
+ for (this.pending.push(this.wrap(e)); this.pending.length > Le;) {
1292
1298
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
1293
1299
  this.pending.splice(e >= 0 ? e : 0, 1);
1294
1300
  }
@@ -1308,7 +1314,7 @@ var Re = class {
1308
1314
  keepalive: !0
1309
1315
  }).catch(() => {});
1310
1316
  }
1311
- }, ze = "1.12.0", W = {
1317
+ }, Be = "1.13.0", W = {
1312
1318
  accent: "#E1B600",
1313
1319
  accentText: "#1B1C23",
1314
1320
  background: "#0e0f13",
@@ -1341,15 +1347,15 @@ function K(e, t) {
1341
1347
  }
1342
1348
  //#endregion
1343
1349
  //#region src/ui/styles.ts
1344
- var q = "havik-player-styles", Be = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
1345
- function Ve(e = document) {
1350
+ var q = "havik-player-styles", Ve = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
1351
+ function He(e = document) {
1346
1352
  if (e.getElementById(q)) return;
1347
1353
  let t = e.createElement("style");
1348
- t.id = q, t.textContent = Be, e.head.appendChild(t);
1354
+ t.id = q, t.textContent = Ve, e.head.appendChild(t);
1349
1355
  }
1350
1356
  //#endregion
1351
1357
  //#region src/ui/icons.ts
1352
- var He = {
1358
+ var Ue = {
1353
1359
  play: "<path d=\"M8 5v14l11-7z\"/>",
1354
1360
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
1355
1361
  volumeHigh: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4zm-2.5-9v2.06A7 7 0 0 1 14 19v2a9 9 0 0 0 0-18z\"/>",
@@ -1363,20 +1369,20 @@ var He = {
1363
1369
  retry: "<path d=\"M17.65 6.35A8 8 0 1 0 19.73 13h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>"
1364
1370
  };
1365
1371
  function J(e) {
1366
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${He[e]}</svg>`;
1372
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Ue[e]}</svg>`;
1367
1373
  }
1368
1374
  //#endregion
1369
1375
  //#region src/ui/controls.ts
1370
- var Ue = 3e3, We = /* @__PURE__ */ new Set([
1376
+ var We = 3e3, Ge = /* @__PURE__ */ new Set([
1371
1377
  "GONE",
1372
1378
  "NOT_FOUND",
1373
1379
  "INVALID_URN",
1374
1380
  "UNAUTHORIZED"
1375
1381
  ]);
1376
- function Ge(e) {
1377
- return new Ke(e);
1382
+ function Ke(e) {
1383
+ return new qe(e);
1378
1384
  }
1379
- var Ke = class {
1385
+ var qe = class {
1380
1386
  root;
1381
1387
  video;
1382
1388
  player;
@@ -1416,7 +1422,7 @@ var Ke = class {
1416
1422
  scrubbing = !1;
1417
1423
  offFns = [];
1418
1424
  constructor(e) {
1419
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ue, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ve(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
1425
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? We, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, He(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
1420
1426
  let t = (e, t, n) => {
1421
1427
  let r = this.doc.createElement(e);
1422
1428
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -1503,7 +1509,7 @@ var Ke = class {
1503
1509
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = J("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
1504
1510
  } else {
1505
1511
  let n = this.doc.createElement("div");
1506
- if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !We.has(this.lastError.code)) {
1512
+ if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !Ge.has(this.lastError.code)) {
1507
1513
  let e = this.doc.createElement("button");
1508
1514
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${J("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
1509
1515
  }
@@ -1594,17 +1600,17 @@ var Ke = class {
1594
1600
  renderQualityMenu() {
1595
1601
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
1596
1602
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
1597
- for (let n of e) this.menu.append(this.menuItem(qe(n), t === n.index, () => this.player.setQuality(n.index)));
1603
+ for (let n of e) this.menu.append(this.menuItem(Je(n), t === n.index, () => this.player.setQuality(n.index)));
1598
1604
  }
1599
1605
  renderAudioMenu() {
1600
1606
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
1601
1607
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
1602
- for (let t of e) this.menu.append(this.menuItem(Je(t), t.default, () => this.player.setAudioTrack(t.id)));
1608
+ for (let t of e) this.menu.append(this.menuItem(Ye(t), t.default, () => this.player.setAudioTrack(t.id)));
1603
1609
  }
1604
1610
  renderCcMenu() {
1605
1611
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
1606
1612
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
1607
- for (let t of e) this.menu.append(this.menuItem(Ye(t), !1, () => this.player.setTextTrack(t.id)));
1613
+ for (let t of e) this.menu.append(this.menuItem(Xe(t), !1, () => this.player.setTextTrack(t.id)));
1608
1614
  }
1609
1615
  onTracksChanged() {
1610
1616
  this.openMenu && this.renderMenu(this.openMenu);
@@ -1710,27 +1716,27 @@ function Y(e) {
1710
1716
  let t = Math.floor(e % 60), n = Math.floor(e / 60 % 60), r = Math.floor(e / 3600), i = r > 0 ? String(n).padStart(2, "0") : String(n), a = String(t).padStart(2, "0");
1711
1717
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
1712
1718
  }
1713
- function qe(e) {
1719
+ function Je(e) {
1714
1720
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
1715
1721
  }
1716
- function Je(e) {
1722
+ function Ye(e) {
1717
1723
  return e.name || e.lang || `Track ${e.id}`;
1718
1724
  }
1719
- function Ye(e) {
1725
+ function Xe(e) {
1720
1726
  return e.name || e.lang || `Track ${e.id}`;
1721
1727
  }
1722
1728
  //#endregion
1723
1729
  //#region src/managed/index.ts
1724
- var Xe = 6e3, X = 45e3, Z = 2e3, Ze = 3, Qe = 2e3, $e = 480 * 1e3;
1730
+ var Ze = 6e3, X = 45e3, Qe = 2e3, $e = 3, Z = 2e3, et = 480 * 1e3;
1725
1731
  async function Q(e) {
1726
1732
  if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
1727
1733
  if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
1728
1734
  if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
1729
1735
  if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
1730
- let n = new et(e);
1736
+ let n = new tt(e);
1731
1737
  return await n.start(), n;
1732
1738
  }
1733
- var et = class {
1739
+ var tt = class {
1734
1740
  opts;
1735
1741
  abort = new AbortController();
1736
1742
  listeners = {};
@@ -1766,13 +1772,13 @@ var et = class {
1766
1772
  this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
1767
1773
  let e = ++this.loadGen, n = this.resolveOptions();
1768
1774
  try {
1769
- let t = await v(n);
1775
+ let t = await y(n);
1770
1776
  if (await this.onResolved(t, e), e === this.loadGen && this._state === "error" && this._lastError) {
1771
1777
  let e = this._lastError;
1772
1778
  throw this.destroy(), e;
1773
1779
  }
1774
1780
  } catch (n) {
1775
- if (this.opts.waitForLive && n instanceof t && i(n.code)) {
1781
+ if (this.opts.waitForLive && n instanceof t && a(n.code)) {
1776
1782
  this.setState("waiting"), this.beginArming(e, n.liveStartsAtMs);
1777
1783
  return;
1778
1784
  }
@@ -1788,11 +1794,11 @@ var et = class {
1788
1794
  };
1789
1795
  }
1790
1796
  beginArming(e, t) {
1791
- let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? w(this.opts.baseUrl);
1797
+ let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
1792
1798
  n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
1793
1799
  }
1794
1800
  beginArmingByPolling(e) {
1795
- y({
1801
+ b({
1796
1802
  ...this.resolveOptions(),
1797
1803
  signal: this.abort.signal,
1798
1804
  waitForLive: this.buildWaitConfig(e)
@@ -1803,11 +1809,11 @@ var et = class {
1803
1809
  });
1804
1810
  }
1805
1811
  armWithSse(e, n, r) {
1806
- let a = !1, o = !1, s = new AbortController();
1812
+ let i = !1, o = !1, s = new AbortController();
1807
1813
  this.armFallbackCtrl = s, this.setState("waiting");
1808
1814
  let c = this.opts.waitForLive, l = c && c !== !0 ? c.kickoffAt : void 0, u = typeof l == "number" ? l : typeof l == "string" ? Date.parse(l) : NaN, d = r ?? (Number.isFinite(u) ? u : void 0);
1809
1815
  setTimeout(() => {
1810
- a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
1816
+ i || this.destroyed || e !== this.loadGen || this.emit("waiting", {
1811
1817
  phase: "tooEarly",
1812
1818
  retryInMs: X,
1813
1819
  attempt: 1,
@@ -1816,8 +1822,8 @@ var et = class {
1816
1822
  });
1817
1823
  }, 0);
1818
1824
  let f = () => this.destroyed || this.abort.signal.aborted || e !== this.loadGen, p = async (n) => {
1819
- if (!(a || f())) {
1820
- a = !0, this.closeArming(), s.abort();
1825
+ if (!(i || f())) {
1826
+ i = !0, this.closeArming(), s.abort();
1821
1827
  try {
1822
1828
  await this.onResolved(n, e);
1823
1829
  } catch (e) {
@@ -1826,29 +1832,29 @@ var et = class {
1826
1832
  }
1827
1833
  }
1828
1834
  }, m = () => {
1829
- a || o || f() || (o = !0, y({
1835
+ i || o || f() || (o = !0, b({
1830
1836
  ...this.resolveOptions(),
1831
1837
  signal: s.signal,
1832
1838
  waitForLive: this.buildWaitConfig(e)
1833
1839
  }).then((e) => p(e)).catch((e) => {
1834
- a || f() || s.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
1840
+ i || f() || s.signal.aborted || (i = !0, this.closeArming(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
1835
1841
  }));
1836
1842
  }, h = () => {
1837
- a || f() || v(this.resolveOptions()).then((e) => p(e)).catch((e) => {
1838
- a || f() || e instanceof t && i(e.code) || (a = !0, this.closeArming(), s.abort(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
1843
+ i || f() || y(this.resolveOptions()).then((e) => p(e)).catch((e) => {
1844
+ i || f() || e instanceof t && a(e.code) || (i = !0, this.closeArming(), s.abort(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
1839
1845
  });
1840
1846
  }, g = (e) => {
1841
1847
  this.armSseTimer && clearTimeout(this.armSseTimer), this.armSseTimer = setTimeout(() => {
1842
- !a && !f() && m();
1848
+ !i && !f() && m();
1843
1849
  }, e);
1844
1850
  };
1845
- g(Xe), this.armingSub = C({
1851
+ g(Ze), this.armingSub = w({
1846
1852
  eventsBaseUrl: n,
1847
1853
  matchUrn: this.opts.matchUrn,
1848
1854
  credential: this.opts.credential,
1849
1855
  onAlive: () => g(X),
1850
1856
  onState: (e) => {
1851
- a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Z);
1857
+ i || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Qe);
1852
1858
  },
1853
1859
  onError: () => m()
1854
1860
  });
@@ -1868,10 +1874,10 @@ var et = class {
1868
1874
  async onResolved(e, t) {
1869
1875
  if (this.destroyed || t !== this.loadGen) return;
1870
1876
  this._descriptor = e, this.endedHandled = !1;
1871
- let n = await a(this.opts.credential);
1877
+ let n = await o(this.opts.credential);
1872
1878
  if (this.destroyed || t !== this.loadGen) return;
1873
1879
  this.setState("loading");
1874
- let r = this.createEngine(e, n), i = I(this.opts.video, (e) => {
1880
+ let r = this.createEngine(e, n), i = ve(this.opts.video, (e) => {
1875
1881
  this._state === "ended" || this._state === "error" || this.setState(e);
1876
1882
  });
1877
1883
  if (await r.load(), this.destroyed || t !== this.loadGen) {
@@ -1888,15 +1894,15 @@ var et = class {
1888
1894
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachSeekListener?.(), this.opts.analytics === !1) return;
1889
1895
  let n = e.analytics?.sid;
1890
1896
  if (!n) return;
1891
- let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? Le(this.opts.baseUrl);
1897
+ let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? Re(this.opts.baseUrl);
1892
1898
  if (!r) return;
1893
- let i = this.opts.video, a = new Re({
1899
+ let i = this.opts.video, a = new ze({
1894
1900
  endpoint: r,
1895
1901
  sid: n,
1896
1902
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
1897
- sdkVersion: ze,
1903
+ sdkVersion: Be,
1898
1904
  sample: () => {
1899
- let e = this.engine?.getStats() ?? P, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
1905
+ let e = this.engine?.getStats() ?? F, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
1900
1906
  return {
1901
1907
  ...e,
1902
1908
  bufferedMs: Math.round(t * 1e3),
@@ -1916,7 +1922,7 @@ var et = class {
1916
1922
  video: this.opts.video,
1917
1923
  descriptor: e,
1918
1924
  credential: n,
1919
- deviceId: D(),
1925
+ deviceId: O(),
1920
1926
  userId: this.opts.userId,
1921
1927
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
1922
1928
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -1927,7 +1933,7 @@ var et = class {
1927
1933
  if (a === "native") return new z(i);
1928
1934
  if (a === "hls") return new V(i);
1929
1935
  if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && L(this.opts.video) && R()) return new z(i);
1930
- if (be()) return new V(i);
1936
+ if (xe()) return new V(i);
1931
1937
  if (L(this.opts.video)) return new z(i);
1932
1938
  throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
1933
1939
  }
@@ -1958,11 +1964,11 @@ var et = class {
1958
1964
  }
1959
1965
  startLiveState(e) {
1960
1966
  if (this.opts.liveStateEvents === !1) return;
1961
- let n = this.opts.eventsBaseUrl ?? w(this.opts.baseUrl);
1967
+ let n = this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
1962
1968
  if (!n) return;
1963
1969
  this.closeLiveState();
1964
1970
  let r = 0, i = !1;
1965
- this.liveStateSub = C({
1971
+ this.liveStateSub = w({
1966
1972
  eventsBaseUrl: n,
1967
1973
  matchUrn: this.opts.matchUrn,
1968
1974
  credential: this.opts.credential,
@@ -1973,7 +1979,7 @@ var et = class {
1973
1979
  r = 0, i = !1;
1974
1980
  },
1975
1981
  onError: () => {
1976
- this.destroyed || e !== this.loadGen || i || (r += 1, r >= Ze && (i = !0, this.emit("warning", new t("NETWORK", 0, `live-state events unreachable at ${n} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
1982
+ this.destroyed || e !== this.loadGen || i || (r += 1, r >= $e && (i = !0, this.emit("warning", new t("NETWORK", 0, `live-state events unreachable at ${n} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
1977
1983
  }
1978
1984
  });
1979
1985
  }
@@ -1995,7 +2001,7 @@ var et = class {
1995
2001
  }
1996
2002
  t.controls = !1;
1997
2003
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
1998
- r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar = Ge({
2004
+ r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar = Ke({
1999
2005
  root: n,
2000
2006
  video: t,
2001
2007
  player: this,
@@ -2018,7 +2024,7 @@ var et = class {
2018
2024
  }
2019
2025
  startStats() {
2020
2026
  this.stopStats();
2021
- let e = Math.max(500, this.opts.statsIntervalMs ?? Qe);
2027
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Z);
2022
2028
  this.statsTimer = setInterval(() => {
2023
2029
  if (!this.engine) return;
2024
2030
  let e = this.engine.getStats();
@@ -2030,7 +2036,7 @@ var et = class {
2030
2036
  }
2031
2037
  scheduleLicenseRefresh() {
2032
2038
  this.stopRefresh();
2033
- let e = this.opts.licenseRefreshMs ?? $e;
2039
+ let e = this.opts.licenseRefreshMs ?? et;
2034
2040
  !e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
2035
2041
  }
2036
2042
  stopRefresh() {
@@ -2039,7 +2045,7 @@ var et = class {
2039
2045
  async refreshLicense() {
2040
2046
  let e = this.engine;
2041
2047
  if (!(this.destroyed || !e)) try {
2042
- let t = await v(this.resolveOptions());
2048
+ let t = await y(this.resolveOptions());
2043
2049
  if (this.destroyed || this.engine !== e) return;
2044
2050
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
2045
2051
  (n || r) && (e.setLicenseUrls({
@@ -2047,7 +2053,7 @@ var et = class {
2047
2053
  fairplay: r
2048
2054
  }), this._descriptor = t);
2049
2055
  } catch (e) {
2050
- e instanceof t && !i(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
2056
+ e instanceof t && !a(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
2051
2057
  }
2052
2058
  }
2053
2059
  async play() {
@@ -2067,7 +2073,7 @@ var et = class {
2067
2073
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
2068
2074
  }
2069
2075
  getStats() {
2070
- return this.engine?.getStats() ?? P;
2076
+ return this.engine?.getStats() ?? F;
2071
2077
  }
2072
2078
  getQualityLevels() {
2073
2079
  return this.engine?.getQualityLevels() ?? [];
@@ -2113,7 +2119,7 @@ var et = class {
2113
2119
  let e = ++this.loadGen;
2114
2120
  this.stopStats(), this.stopRefresh(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
2115
2121
  try {
2116
- let t = await y({
2122
+ let t = await b({
2117
2123
  ...this.resolveOptions(),
2118
2124
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
2119
2125
  });
@@ -2174,7 +2180,7 @@ function $(e) {
2174
2180
  }
2175
2181
  //#endregion
2176
2182
  //#region src/embed/host.ts
2177
- function tt(e) {
2183
+ function nt(e) {
2178
2184
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
2179
2185
  if (!e.src) throw Error("mountEmbed: opts.src is required");
2180
2186
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -2233,8 +2239,8 @@ function tt(e) {
2233
2239
  }
2234
2240
  //#endregion
2235
2241
  //#region src/embed/page.ts
2236
- var nt = /^[A-Za-z0-9:_.-]{1,128}$/;
2237
- function rt() {
2242
+ var rt = /^[A-Za-z0-9:_.-]{1,128}$/;
2243
+ function it() {
2238
2244
  let e = window.HAVIK_EMBED_CONFIG;
2239
2245
  if (e) return {
2240
2246
  baseUrl: e.baseUrl ?? "",
@@ -2256,9 +2262,9 @@ function rt() {
2256
2262
  waitForLive: !0
2257
2263
  };
2258
2264
  }
2259
- async function it() {
2260
- let e = rt();
2261
- ot();
2265
+ async function at() {
2266
+ let e = it();
2267
+ st();
2262
2268
  let n = document.createElement("video");
2263
2269
  n.setAttribute("playsinline", ""), n.muted = e.muted ?? !0, n.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(n);
2264
2270
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -2313,7 +2319,7 @@ async function it() {
2313
2319
  code: e.code,
2314
2320
  message: e.message
2315
2321
  })), e.on("autoplayblocked", () => {
2316
- i({ type: "oddin:autoplayblocked" }), at(n, e);
2322
+ i({ type: "oddin:autoplayblocked" }), ot(n, e);
2317
2323
  });
2318
2324
  }, s = async (r) => {
2319
2325
  a?.destroy(), a = null;
@@ -2379,7 +2385,7 @@ async function it() {
2379
2385
  a?.retry();
2380
2386
  break;
2381
2387
  case "oddin:load":
2382
- typeof e.matchUrn == "string" && nt.test(e.matchUrn) && s(e.matchUrn);
2388
+ typeof e.matchUrn == "string" && rt.test(e.matchUrn) && s(e.matchUrn);
2383
2389
  break;
2384
2390
  case "oddin:destroy":
2385
2391
  c();
@@ -2393,18 +2399,18 @@ async function it() {
2393
2399
  protocol: 1
2394
2400
  });
2395
2401
  }
2396
- function at(e, t) {
2402
+ function ot(e, t) {
2397
2403
  if (document.getElementById("havik-tap")) return;
2398
2404
  let n = document.createElement("button");
2399
2405
  n.id = "havik-tap", n.textContent = "▶ Tap to play", n.style.cssText = "position:fixed;inset:0;width:100%;height:100%;border:0;background:rgba(0,0,0,.55);color:#fff;font:600 18px system-ui,sans-serif;cursor:pointer;z-index:9", n.addEventListener("click", () => {
2400
2406
  n.remove(), t.play();
2401
2407
  }), document.body.appendChild(n);
2402
2408
  }
2403
- function ot() {
2409
+ function st() {
2404
2410
  let e = document.createElement("style");
2405
2411
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
2406
2412
  }
2407
2413
  //#endregion
2408
- export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme, it as bootEmbed, fe as clearDeviceId, Q as createPlayer, w as deriveEventsBaseUrl, j as detectDrmSupport, x as fetchCatalog, ce as fetchTournament, ue as flattenMatches, D as getDeviceId, N as isLowLatencyManifest, $ as isOddinMessage, me as licenseRequestHeaders, tt as mountEmbed, _ as pollToLive, y as resolveStream, C as subscribeLiveState, de as watchStatus };
2414
+ export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme, at as bootEmbed, fe as clearDeviceId, Q as createPlayer, T as deriveEventsBaseUrl, M as detectDrmSupport, C as fetchCatalog, ce as fetchTournament, ue as flattenMatches, O as getDeviceId, P as isLowLatencyManifest, $ as isOddinMessage, me as licenseRequestHeaders, nt as mountEmbed, v as pollToLive, b as resolveStream, w as subscribeLiveState, de as watchStatus };
2409
2415
 
2410
2416
  //# sourceMappingURL=index.js.map