@oddin-gg/havik-player 2.7.0 → 2.9.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/docs/API.md CHANGED
@@ -203,7 +203,7 @@ live wait itself never blocks the promise and is surfaced through `'waiting'` ev
203
203
  ```ts
204
204
  const player = await createPlayer({
205
205
  video: document.querySelector('video')!,
206
- baseUrl: 'https://feed-dev.oddin-video.gg',
206
+ env: 'integration', // or 'production' — see baseUrlForEnv for Modes B/C
207
207
  matchUrn: 'od:match:1234',
208
208
  credential: { apiKey: 'pk_test_…' },
209
209
  autoplay: true,
@@ -222,7 +222,8 @@ player.on('error', (e) => console.error(e.code, e.httpStatus, e.message));
222
222
  | Option | Type | Default | Description |
223
223
  | --------------------- | --------------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
224
224
  | `video` | `HTMLVideoElement` | — | **Required.** The element the SDK will control. |
225
- | `baseUrl` | `string` | — | **Required.** API base URL, e.g. `https://feed-dev.oddin-video.gg`. |
225
+ | `env` | `'integration' \| 'production'` | — | **Required unless `baseUrl` is given.** Which Oddin environment to play against. Preferred: the host is correct by construction, and so is everything derived from it (the SSE events host, the QoE beacons host). |
226
+ | `baseUrl` | `string` | — | **Required unless `env` is given.** API base URL, e.g. `https://feed-dev.oddin-video.gg`. Use for a deployment the named environments do not cover: your own CDN or gateway fronting the streams API, the CN plane, or a pinned build that must outlive a domain change. Passing both `env` and `baseUrl` — or neither — is a compile error in TypeScript and throws at runtime in JavaScript. |
226
227
  | `matchUrn` | `string` | — | **Required.** The match to play, e.g. `od:match:1234`. |
227
228
  | `credential` | [`CredentialSource`](#credentialsource) | — | **Required.** Your api‑key (or a function returning one). |
228
229
  | `autoplay` | `boolean` | `true` | Start playback once ready. With `false`, the player holds in a pre-play `'paused'` state (poster + play card, no spinner) and fetches no media and no DRM license until the first `play()`. On the hls.js engine the manifest is still parsed pre-play, so `'ready'` and the track lists keep working; the native (Safari) engine defers all fetching and emits `'ready'` at attach instead. Note: if a programmatic `play()` is policy-blocked (`autoplayblocked`), the loader keeps warming the buffer — media and DRM traffic flows from that kick, not from a viewer gesture. |
@@ -529,6 +530,32 @@ const stream = await resolveStream({
529
530
  | `waitForLive` | [`WaitForLive`](#waitforlive) | — | Poll until live before resolving. |
530
531
  | `signal` | `AbortSignal` | — | Cancel the resolution (and any live wait). |
531
532
 
533
+ ### `baseUrlForEnv`
534
+
535
+ ```ts
536
+ function baseUrlForEnv(env: 'integration' | 'production'): string;
537
+ ```
538
+
539
+ The API base URL for a named environment. `integration` is the shared
540
+ pre-production stack, `production` the production one; they are separate
541
+ deployments, not aliases.
542
+
543
+ Mode A takes `env` directly, so this is for **Modes B and C**, which still take a
544
+ `baseUrl`. Call it rather than copying a hostname into your own config:
545
+
546
+ ```ts
547
+ const stream = await resolveStream({
548
+ baseUrl: baseUrlForEnv('production'),
549
+ matchUrn: 'od:match:1234',
550
+ credential: { apiKey: 'pk_live_…' },
551
+ });
552
+ ```
553
+
554
+ Throws a [`PlaybackError`](#playbackerror) (`INTERNAL`) on any other value, rather
555
+ than returning `undefined`. Callers reach it from plain JavaScript where the type
556
+ gives no protection, and a silent `undefined` becomes a relative URL against the
557
+ embedding page.
558
+
532
559
  ### `licenseRequestHeaders`
533
560
 
534
561
  ```ts
@@ -921,15 +948,16 @@ api-key. Otherwise (dev/demo) config comes from the query string. The postMessag
921
948
  **fails closed**: with no `parentOrigin`, the embed neither accepts commands nor posts
922
949
  events.
923
950
 
924
- | Field | Type | Default | Description |
925
- | -------------- | ----------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
926
- | `baseUrl` | `string` | — | **Required.** API base URL. |
927
- | `matchUrn` | `string` | — | **Required.** Match to play. |
928
- | `apiKey` | `string` | — | **Required.** Inject server‑side in production; query param is dev‑only. |
929
- | `parentOrigin` | `string` | — | Origin to post events to and accept commands from. **Set this in production** (`mountEmbed` sets it automatically). When absent, the iframe posts to `*` and skips the inbound origin check. |
930
- | `autoplay` | `boolean` | `true` | Start playback once ready. |
931
- | `muted` | `boolean` | `true` | Start muted (recommended for autoplay). |
932
- | `waitForLive` | [`WaitForLive`](#waitforlive) | `true` | Arm and auto‑play at go‑live. |
951
+ | Field | Type | Default | Description |
952
+ | -------------- | ---------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
953
+ | `baseUrl` | `string` | — | **Required.** API base URL. |
954
+ | `matchUrn` | `string` | — | **Required.** Match to play. |
955
+ | `apiKey` | `string` | — | **Required.** Inject server‑side in production; query param is dev‑only. |
956
+ | `parentOrigin` | `string` | — | Origin to post events to and accept commands from. **Set this in production** (`mountEmbed` sets it automatically). When absent, the iframe posts to `*` and skips the inbound origin check. |
957
+ | `autoplay` | `boolean` | `true` | Start playback once ready. |
958
+ | `muted` | `boolean` | `true` | Start muted (recommended for autoplay). |
959
+ | `waitForLive` | [`WaitForLive`](#waitforlive) | `true` | Arm and auto‑play at go‑live. |
960
+ | `analytics` | `boolean \| { endpoint?: string }` | `true` | QoE beacons, forwarded verbatim to [`createPlayer`](#createplayer). **Injected config only** — never read from the query string, so a link cannot redirect a session's beacons. Set `{ endpoint }` when `baseUrl` is not a `feed[-dev].<domain>` host, since nothing can be derived and analytics is otherwise off. ⚠️ [`mountEmbed`](#mountembed) configures the page via query string, so it cannot carry this: a `mountEmbed` integration on a non-feed `baseUrl` has no way to enable beacons and must self-host the embed page instead. |
933
961
 
934
962
  <a id="frametohost"></a>
935
963
  <a id="hosttoframe"></a>
package/embed/index.html CHANGED
@@ -22,8 +22,13 @@
22
22
  2) INJECT config server-side as window.HAVIK_EMBED_CONFIG (baseUrl, matchUrn,
23
23
  apiKey, parentOrigin). When injected, the URL query string is IGNORED for
24
24
  security; the api-key must NOT travel in the query in production.
25
+ 3) If baseUrl is NOT a feed[-dev].<domain> host (your own CDN or gateway
26
+ fronts the streams API), also inject
27
+ analytics: { endpoint: 'https://beacons[-dev].<domain>' } — otherwise no
28
+ beacons endpoint can be derived and QoE analytics is silently off.
29
+ `analytics` is honoured from the injected config only, never the query.
25
30
  -->
26
- <script src="https://cdn.jsdelivr.net/npm/@oddin-gg/havik-player@2.7.0/dist/havik-player.global.js" integrity="sha384-QAeGusQhTrvI7aMO/QJcBMohkNvH6RW4Oew7gW/+XQZXsV7Hs1I/3tkyEyyr9XxY" crossorigin="anonymous"></script>
31
+ <script src="https://cdn.jsdelivr.net/npm/@oddin-gg/havik-player@2.9.0/dist/havik-player.global.js" integrity="sha384-5V0pran43W6WqIOavxGbPUnt6qcuOrXuS2bH0nm/Wv0KIyP2aZFr8ecmpvsDQU9j" crossorigin="anonymous"></script>
27
32
  <script>
28
33
  HavikPlayer.bootEmbed();
29
34
  </script>
@@ -12,7 +12,7 @@
12
12
  shipped in each npm release is pinned to that release with Subresource
13
13
  Integrity, injected at publish time (scripts/inject-sri.mjs). In
14
14
  production, always use a pinned + SRI'd tag like the released copy. -->
15
- <script src="https://cdn.jsdelivr.net/npm/@oddin-gg/havik-player@2.7.0/dist/havik-player.global.js" integrity="sha384-QAeGusQhTrvI7aMO/QJcBMohkNvH6RW4Oew7gW/+XQZXsV7Hs1I/3tkyEyyr9XxY" crossorigin="anonymous"></script>
15
+ <script src="https://cdn.jsdelivr.net/npm/@oddin-gg/havik-player@2.9.0/dist/havik-player.global.js" integrity="sha384-5V0pran43W6WqIOavxGbPUnt6qcuOrXuS2bH0nm/Wv0KIyP2aZFr8ecmpvsDQU9j" crossorigin="anonymous"></script>
16
16
  <script>
17
17
  (async () => {
18
18
  const player = await HavikPlayer.createPlayer({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oddin-gg/havik-player",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "Havik HTML5 player SDK — LL-HLS + DRM playback for Oddin live streams (managed, bring-your-own-player, and iframe-embed modes).",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -77,7 +77,9 @@
77
77
  "sbom": "npx --yes @cyclonedx/cyclonedx-npm@2 --omit dev --output-file sbom.json",
78
78
  "prepack": "npm run build",
79
79
  "test:localqoe": "playwright test -c localqoe/playwright.config.ts",
80
- "localqoe:media": "bash localqoe/make-media.sh"
80
+ "localqoe:media": "bash localqoe/make-media.sh && bash localqoe/make-live-media.sh",
81
+ "test:blackhole": "npm run build:global && playwright test -c blackhole/playwright.config.ts",
82
+ "blackhole:serve": "npm run build:global && node blackhole/server.mjs"
81
83
  },
82
84
  "dependencies": {
83
85
  "hls.js": "1.7.2"