branch-video-player-sdk 0.1.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/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # BranchVideo Player SDK
2
+
3
+ `@ndhy/branch-video-player-sdk` embeds a static BranchVideo Runtime in an iframe.
4
+
5
+ ```ts
6
+ import { createBranchVideoPlayer } from '@ndhy/branch-video-player-sdk'
7
+
8
+ const player = createBranchVideoPlayer({
9
+ container: '#player',
10
+ runtimeUrl: 'https://player.example.com/player.html',
11
+ scriptUrl: 'https://cdn.example.com/release/script.json',
12
+ })
13
+ player.on('ended', (result) => saveProgress(result))
14
+ ```
15
+
16
+ The ESM entry is `@ndhy/branch-video-player-sdk`; the UMD build exposes
17
+ `BranchVideoPlayerSDK`. For a WeChat `web-view` or another non-DOM host, import
18
+ the pure URL entry instead:
19
+
20
+ ```ts
21
+ import { buildBranchVideoPlayerUrl } from '@ndhy/branch-video-player-sdk/url'
22
+
23
+ const src = buildBranchVideoPlayerUrl({
24
+ runtimeUrl: 'https://player.example.com/player.html',
25
+ scriptUrl: 'https://cdn.example.com/release/script.json',
26
+ })
27
+ ```
28
+
29
+ `runtimeUrl` and `scriptUrl` must be absolute HTTP(S) URLs. The script CDN must
30
+ allow the Runtime origin with CORS. `parentOrigin`, when provided, must be an
31
+ HTTP(S) origin only (no path, query, or fragment).
32
+
33
+ Default Runtime builds are Service Worker off and may be deployed below a
34
+ versioned subpath. The explicit SW-on Runtime requires `/player.html` and
35
+ `/sw.js` at the root of a dedicated origin; do not deploy multiple SW-on builds
36
+ under paths on one origin.
37
+
38
+ Subscribe with `player.on()` to `loaded`, `ready`, `statechange`, `progress`,
39
+ `ended`, `error`, `bufferchange`, `milestone`, and `exitrequested`. `play`,
40
+ `pause`, and `seek` issued before trusted `ready` are queued in order.
@@ -0,0 +1,18 @@
1
+ import { type BranchVideoPlayerUrlOptions } from './url';
2
+ export { buildBranchVideoPlayerUrl } from './url';
3
+ export type { BranchVideoPlayerUrlOptions };
4
+ export interface CreateBranchVideoPlayerOptions extends BranchVideoPlayerUrlOptions {
5
+ container: HTMLElement | string;
6
+ title?: string;
7
+ className?: string;
8
+ }
9
+ export type BranchVideoPlayerEvent = 'loaded' | 'ready' | 'statechange' | 'progress' | 'ended' | 'error' | 'bufferchange' | 'milestone' | 'exitrequested';
10
+ export interface BranchVideoPlayer {
11
+ readonly iframe: HTMLIFrameElement;
12
+ play(): void;
13
+ pause(): void;
14
+ seek(position: number): void;
15
+ on(event: BranchVideoPlayerEvent, handler: (data: unknown) => void): () => void;
16
+ destroy(): void;
17
+ }
18
+ export declare function createBranchVideoPlayer(options: CreateBranchVideoPlayerOptions): BranchVideoPlayer;
package/dist/index.js ADDED
@@ -0,0 +1,112 @@
1
+ const g = (e) => /^\d+$/.test(e) && Number(e) > 0 && Number(e) <= 65535, w = (e) => {
2
+ const t = e.split(".");
3
+ return t.length === 4 && t.every((r) => /^\d+$/.test(r) && Number(r) <= 255);
4
+ }, P = (e) => {
5
+ if (!/^[0-9a-f:]+$/i.test(e)) return !1;
6
+ const t = e.split("::");
7
+ if (t.length > 2) return !1;
8
+ const r = t.flatMap((s) => s ? s.split(":") : []);
9
+ return r.every((s) => /^[0-9a-f]{1,4}$/i.test(s)) ? t.length === 2 ? r.length < 8 : r.length === 8 : !1;
10
+ }, h = (e) => {
11
+ const t = e.endsWith(".") ? e.slice(0, -1) : e;
12
+ return /^[\d.]+$/.test(t) ? w(t) : !!t && !t.includes("..") && t.split(".").every((r) => /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(r));
13
+ }, V = (e) => {
14
+ if (!e || e.includes("@")) return !1;
15
+ if (e.startsWith("[")) {
16
+ const s = e.indexOf("]"), n = e.slice(1, s), c = e.slice(s + 1);
17
+ return s <= 1 || !P(n) ? !1 : !c || c.startsWith(":") && g(c.slice(1));
18
+ }
19
+ const t = e.lastIndexOf(":");
20
+ if (t === -1) return h(e);
21
+ const r = e.slice(0, t);
22
+ return h(r) && !r.includes(":") && g(e.slice(t + 1));
23
+ }, _ = (e) => {
24
+ const t = /^(https?):\/\/([^\s/?#]+)([/\?#].*)?$/i.exec(e);
25
+ return !t || !V(t[2]) ? null : { authority: t[2], suffix: t[3] || "" };
26
+ }, T = (e) => _(e) !== null, E = (e, t) => {
27
+ if (!T(t) || e === "runtimeUrl" && t.includes("#")) throw new TypeError(`${e} must be an absolute HTTP(S) URL`);
28
+ return t;
29
+ }, U = (e) => {
30
+ const t = _(e);
31
+ if (!t || t.suffix && t.suffix !== "/") throw new TypeError("parentOrigin must be an HTTP(S) origin");
32
+ return e.endsWith("/") ? e.slice(0, -1) : e;
33
+ };
34
+ function W(e) {
35
+ const t = E("runtimeUrl", e.runtimeUrl), r = E("scriptUrl", e.scriptUrl), s = e.parentOrigin === void 0 ? void 0 : U(e.parentOrigin), n = [
36
+ `script=${encodeURIComponent(r)}`,
37
+ "embedPlatform=web_player_sdk",
38
+ "sdkProtocol=1"
39
+ ];
40
+ return s && n.push(`parentOrigin=${encodeURIComponent(s)}`), e.cshost && n.push(`cshost=${encodeURIComponent(e.cshost)}`), e.controls !== void 0 && n.push(`controls=${e.controls}`), e.debug !== void 0 && n.push(`debug=${e.debug}`), `${t}${t.includes("?") ? "&" : "?"}${n.join("&")}`;
41
+ }
42
+ const $ = {
43
+ WPS_EVT_LOADED: "loaded",
44
+ WPS_EVT_READY: "ready",
45
+ WPS_EVT_STATE_CHANGE: "statechange",
46
+ WPS_EVT_PROGRESS: "progress",
47
+ WPS_EVT_ENDED: "ended",
48
+ WPS_EVT_ERROR: "error",
49
+ WPS_EVT_BUFFER_CHANGE: "bufferchange",
50
+ WPS_EVT_MILESTONE: "milestone",
51
+ WPS_EVT_EXIT_REQUESTED: "exitrequested"
52
+ }, O = (e) => {
53
+ if (typeof e != "string") return e;
54
+ const t = document.querySelector(e);
55
+ if (!t) throw new Error(`BranchVideo player container not found: ${e}`);
56
+ return t;
57
+ };
58
+ function b(e) {
59
+ const t = e.parentOrigin ?? window.location.origin, r = W({ ...e, parentOrigin: t }), s = new URL(e.runtimeUrl).origin, n = document.createElement("iframe");
60
+ n.src = r, n.allow = "autoplay; fullscreen", n.title = e.title || "BranchVideo player", e.className && (n.className = e.className), O(e.container).appendChild(n);
61
+ const c = /* @__PURE__ */ new Map(), d = [];
62
+ let l = "pending", f = !1;
63
+ const u = (i, o) => {
64
+ if (!f) {
65
+ if (l === "pending") {
66
+ d.push({ eventName: i, data: o });
67
+ return;
68
+ }
69
+ l !== "failed" && n.contentWindow?.postMessage({ eventName: i, data: o, timestamp: Date.now() }, s);
70
+ }
71
+ }, S = () => {
72
+ for (; d.length; ) {
73
+ const i = d.shift();
74
+ n.contentWindow?.postMessage({ ...i, timestamp: Date.now() }, s);
75
+ }
76
+ }, p = (i) => {
77
+ if (f || i.source !== n.contentWindow || i.origin !== s) return;
78
+ const o = i.data;
79
+ if (!o || typeof o.eventName != "string") return;
80
+ const a = $[o.eventName];
81
+ if (a) {
82
+ if (a === "ready") {
83
+ if (o.data?.protocolVersion !== 1) {
84
+ l === "pending" && (l = "failed", d.length = 0);
85
+ return;
86
+ }
87
+ if (l !== "pending") return;
88
+ l = "ready", S();
89
+ }
90
+ a === "error" && l === "pending" && (l = "failed", d.length = 0), c.get(a)?.forEach((m) => m(o.data));
91
+ }
92
+ };
93
+ return window.addEventListener("message", p), {
94
+ iframe: n,
95
+ play: () => u("WPS_CMD_PLAY"),
96
+ pause: () => u("WPS_CMD_PAUSE"),
97
+ seek: (i) => {
98
+ Number.isFinite(i) && u("WPS_CMD_SEEK", { position: Math.max(0, i) });
99
+ },
100
+ on: (i, o) => {
101
+ const a = c.get(i) || /* @__PURE__ */ new Set();
102
+ return a.add(o), c.set(i, a), () => a.delete(o);
103
+ },
104
+ destroy: () => {
105
+ f || (f = !0, d.length = 0, c.clear(), window.removeEventListener("message", p), n.remove());
106
+ }
107
+ };
108
+ }
109
+ export {
110
+ W as buildBranchVideoPlayerUrl,
111
+ b as createBranchVideoPlayer
112
+ };
@@ -0,0 +1 @@
1
+ (function(d,f){typeof exports=="object"&&typeof module<"u"?f(exports):typeof define=="function"&&define.amd?define(["exports"],f):(d=typeof globalThis<"u"?globalThis:d||self,f(d.BranchVideoPlayerSDK={}))})(this,(function(d){"use strict";const f=e=>/^\d+$/.test(e)&&Number(e)>0&&Number(e)<=65535,V=e=>{const n=e.split(".");return n.length===4&&n.every(r=>/^\d+$/.test(r)&&Number(r)<=255)},w=e=>{if(!/^[0-9a-f:]+$/i.test(e))return!1;const n=e.split("::");if(n.length>2)return!1;const r=n.flatMap(s=>s?s.split(":"):[]);return r.every(s=>/^[0-9a-f]{1,4}$/i.test(s))?n.length===2?r.length<8:r.length===8:!1},g=e=>{const n=e.endsWith(".")?e.slice(0,-1):e;return/^[\d.]+$/.test(n)?V(n):!!n&&!n.includes("..")&&n.split(".").every(r=>/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(r))},T=e=>{if(!e||e.includes("@"))return!1;if(e.startsWith("[")){const s=e.indexOf("]"),t=e.slice(1,s),c=e.slice(s+1);return s<=1||!w(t)?!1:!c||c.startsWith(":")&&f(c.slice(1))}const n=e.lastIndexOf(":");if(n===-1)return g(e);const r=e.slice(0,n);return g(r)&&!r.includes(":")&&f(e.slice(n+1))},h=e=>{const n=/^(https?):\/\/([^\s/?#]+)([/\?#].*)?$/i.exec(e);return!n||!T(n[2])?null:{authority:n[2],suffix:n[3]||""}},U=e=>h(e)!==null,E=(e,n)=>{if(!U(n)||e==="runtimeUrl"&&n.includes("#"))throw new TypeError(`${e} must be an absolute HTTP(S) URL`);return n},y=e=>{const n=h(e);if(!n||n.suffix&&n.suffix!=="/")throw new TypeError("parentOrigin must be an HTTP(S) origin");return e.endsWith("/")?e.slice(0,-1):e};function _(e){const n=E("runtimeUrl",e.runtimeUrl),r=E("scriptUrl",e.scriptUrl),s=e.parentOrigin===void 0?void 0:y(e.parentOrigin),t=[`script=${encodeURIComponent(r)}`,"embedPlatform=web_player_sdk","sdkProtocol=1"];return s&&t.push(`parentOrigin=${encodeURIComponent(s)}`),e.cshost&&t.push(`cshost=${encodeURIComponent(e.cshost)}`),e.controls!==void 0&&t.push(`controls=${e.controls}`),e.debug!==void 0&&t.push(`debug=${e.debug}`),`${n}${n.includes("?")?"&":"?"}${t.join("&")}`}const W={WPS_EVT_LOADED:"loaded",WPS_EVT_READY:"ready",WPS_EVT_STATE_CHANGE:"statechange",WPS_EVT_PROGRESS:"progress",WPS_EVT_ENDED:"ended",WPS_EVT_ERROR:"error",WPS_EVT_BUFFER_CHANGE:"bufferchange",WPS_EVT_MILESTONE:"milestone",WPS_EVT_EXIT_REQUESTED:"exitrequested"},b=e=>{if(typeof e!="string")return e;const n=document.querySelector(e);if(!n)throw new Error(`BranchVideo player container not found: ${e}`);return n};function $(e){const n=e.parentOrigin??window.location.origin,r=_({...e,parentOrigin:n}),s=new URL(e.runtimeUrl).origin,t=document.createElement("iframe");t.src=r,t.allow="autoplay; fullscreen",t.title=e.title||"BranchVideo player",e.className&&(t.className=e.className),b(e.container).appendChild(t);const c=new Map,u=[];let l="pending",p=!1;const m=(i,o)=>{if(!p){if(l==="pending"){u.push({eventName:i,data:o});return}l!=="failed"&&t.contentWindow?.postMessage({eventName:i,data:o,timestamp:Date.now()},s)}},O=()=>{for(;u.length;){const i=u.shift();t.contentWindow?.postMessage({...i,timestamp:Date.now()},s)}},S=i=>{if(p||i.source!==t.contentWindow||i.origin!==s)return;const o=i.data;if(!o||typeof o.eventName!="string")return;const a=W[o.eventName];if(a){if(a==="ready"){if(o.data?.protocolVersion!==1){l==="pending"&&(l="failed",u.length=0);return}if(l!=="pending")return;l="ready",O()}a==="error"&&l==="pending"&&(l="failed",u.length=0),c.get(a)?.forEach(P=>P(o.data))}};return window.addEventListener("message",S),{iframe:t,play:()=>m("WPS_CMD_PLAY"),pause:()=>m("WPS_CMD_PAUSE"),seek:i=>{Number.isFinite(i)&&m("WPS_CMD_SEEK",{position:Math.max(0,i)})},on:(i,o)=>{const a=c.get(i)||new Set;return a.add(o),c.set(i,a),()=>a.delete(o)},destroy:()=>{p||(p=!0,u.length=0,c.clear(),window.removeEventListener("message",S),t.remove())}}}d.buildBranchVideoPlayerUrl=_,d.createBranchVideoPlayer=$,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
package/dist/url.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=e=>/^\d+$/.test(e)&&Number(e)>0&&Number(e)<=65535,u=e=>{const t=e.split(".");return t.length===4&&t.every(r=>/^\d+$/.test(r)&&Number(r)<=255)},f=e=>{if(!/^[0-9a-f:]+$/i.test(e))return!1;const t=e.split("::");if(t.length>2)return!1;const r=t.flatMap(s=>s?s.split(":"):[]);return r.every(s=>/^[0-9a-f]{1,4}$/i.test(s))?t.length===2?r.length<8:r.length===8:!1},l=e=>{const t=e.endsWith(".")?e.slice(0,-1):e;return/^[\d.]+$/.test(t)?u(t):!!t&&!t.includes("..")&&t.split(".").every(r=>/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(r))},p=e=>{if(!e||e.includes("@"))return!1;if(e.startsWith("[")){const s=e.indexOf("]"),n=e.slice(1,s),i=e.slice(s+1);return s<=1||!f(n)?!1:!i||i.startsWith(":")&&c(i.slice(1))}const t=e.lastIndexOf(":");if(t===-1)return l(e);const r=e.slice(0,t);return l(r)&&!r.includes(":")&&c(e.slice(t+1))},d=e=>{const t=/^(https?):\/\/([^\s/?#]+)([/\?#].*)?$/i.exec(e);return!t||!p(t[2])?null:{authority:t[2],suffix:t[3]||""}},a=e=>d(e)!==null,o=(e,t)=>{if(!a(t)||e==="runtimeUrl"&&t.includes("#"))throw new TypeError(`${e} must be an absolute HTTP(S) URL`);return t},g=e=>{const t=d(e);if(!t||t.suffix&&t.suffix!=="/")throw new TypeError("parentOrigin must be an HTTP(S) origin");return e.endsWith("/")?e.slice(0,-1):e};function m(e){const t=o("runtimeUrl",e.runtimeUrl),r=o("scriptUrl",e.scriptUrl),s=e.parentOrigin===void 0?void 0:g(e.parentOrigin),n=[`script=${encodeURIComponent(r)}`,"embedPlatform=web_player_sdk","sdkProtocol=1"];return s&&n.push(`parentOrigin=${encodeURIComponent(s)}`),e.cshost&&n.push(`cshost=${encodeURIComponent(e.cshost)}`),e.controls!==void 0&&n.push(`controls=${e.controls}`),e.debug!==void 0&&n.push(`debug=${e.debug}`),`${t}${t.includes("?")?"&":"?"}${n.join("&")}`}exports.buildBranchVideoPlayerUrl=m;
package/dist/url.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export interface BranchVideoPlayerUrlOptions {
2
+ runtimeUrl: string;
3
+ scriptUrl: string;
4
+ parentOrigin?: string;
5
+ cshost?: string;
6
+ controls?: boolean;
7
+ debug?: boolean;
8
+ }
9
+ export declare function buildBranchVideoPlayerUrl(options: BranchVideoPlayerUrlOptions): string;
package/dist/url.js ADDED
@@ -0,0 +1,44 @@
1
+ const c = (t) => /^\d+$/.test(t) && Number(t) > 0 && Number(t) <= 65535, d = (t) => {
2
+ const e = t.split(".");
3
+ return e.length === 4 && e.every((r) => /^\d+$/.test(r) && Number(r) <= 255);
4
+ }, u = (t) => {
5
+ if (!/^[0-9a-f:]+$/i.test(t)) return !1;
6
+ const e = t.split("::");
7
+ if (e.length > 2) return !1;
8
+ const r = e.flatMap((s) => s ? s.split(":") : []);
9
+ return r.every((s) => /^[0-9a-f]{1,4}$/i.test(s)) ? e.length === 2 ? r.length < 8 : r.length === 8 : !1;
10
+ }, l = (t) => {
11
+ const e = t.endsWith(".") ? t.slice(0, -1) : t;
12
+ return /^[\d.]+$/.test(e) ? d(e) : !!e && !e.includes("..") && e.split(".").every((r) => /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(r));
13
+ }, p = (t) => {
14
+ if (!t || t.includes("@")) return !1;
15
+ if (t.startsWith("[")) {
16
+ const s = t.indexOf("]"), n = t.slice(1, s), i = t.slice(s + 1);
17
+ return s <= 1 || !u(n) ? !1 : !i || i.startsWith(":") && c(i.slice(1));
18
+ }
19
+ const e = t.lastIndexOf(":");
20
+ if (e === -1) return l(t);
21
+ const r = t.slice(0, e);
22
+ return l(r) && !r.includes(":") && c(t.slice(e + 1));
23
+ }, f = (t) => {
24
+ const e = /^(https?):\/\/([^\s/?#]+)([/\?#].*)?$/i.exec(t);
25
+ return !e || !p(e[2]) ? null : { authority: e[2], suffix: e[3] || "" };
26
+ }, a = (t) => f(t) !== null, o = (t, e) => {
27
+ if (!a(e) || t === "runtimeUrl" && e.includes("#")) throw new TypeError(`${t} must be an absolute HTTP(S) URL`);
28
+ return e;
29
+ }, m = (t) => {
30
+ const e = f(t);
31
+ if (!e || e.suffix && e.suffix !== "/") throw new TypeError("parentOrigin must be an HTTP(S) origin");
32
+ return t.endsWith("/") ? t.slice(0, -1) : t;
33
+ };
34
+ function g(t) {
35
+ const e = o("runtimeUrl", t.runtimeUrl), r = o("scriptUrl", t.scriptUrl), s = t.parentOrigin === void 0 ? void 0 : m(t.parentOrigin), n = [
36
+ `script=${encodeURIComponent(r)}`,
37
+ "embedPlatform=web_player_sdk",
38
+ "sdkProtocol=1"
39
+ ];
40
+ return s && n.push(`parentOrigin=${encodeURIComponent(s)}`), t.cshost && n.push(`cshost=${encodeURIComponent(t.cshost)}`), t.controls !== void 0 && n.push(`controls=${t.controls}`), t.debug !== void 0 && n.push(`debug=${t.debug}`), `${e}${e.includes("?") ? "&" : "?"}${n.join("&")}`;
41
+ }
42
+ export {
43
+ g as buildBranchVideoPlayerUrl
44
+ };
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "branch-video-player-sdk",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.umd.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "unpkg": "./dist/index.umd.cjs",
9
+ "exports": {
10
+ ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js", "require": "./dist/index.umd.cjs" },
11
+ "./url": { "types": "./dist/url.d.ts", "import": "./dist/url.js", "require": "./dist/url.cjs" }
12
+ },
13
+ "files": ["dist", "README.md"]
14
+ }
15
+